ant-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gin...@apache.org
Subject [1/5] ant git commit: ImageIO task (a replacement for Image task)
Date Sun, 12 Aug 2018 20:10:10 GMT
Repository: ant
Updated Branches:
  refs/heads/master 86bba8643 -> ed567daf3


http://git-wip-us.apache.org/repos/asf/ant/blob/ed567daf/src/main/org/apache/tools/ant/types/optional/imageio/ColorMapper.java
----------------------------------------------------------------------
diff --git a/src/main/org/apache/tools/ant/types/optional/imageio/ColorMapper.java b/src/main/org/apache/tools/ant/types/optional/imageio/ColorMapper.java
new file mode 100644
index 0000000..997a99d
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/optional/imageio/ColorMapper.java
@@ -0,0 +1,108 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.imageio;
+
+import java.awt.Color;
+import java.util.Locale;
+
+/**
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.ImageIOTask
+ */
+public final class ColorMapper {
+
+    /** black string */
+    public static final String COLOR_BLACK = "black";
+    /** blue string */
+    public static final String COLOR_BLUE = "blue";
+    /** cyan string */
+    public static final String COLOR_CYAN = "cyan";
+    /** black string */
+    public static final String COLOR_DARKGRAY = "darkgray";
+    /** gray string */
+    public static final String COLOR_GRAY = "gray";
+    /** lightgray string */
+    public static final String COLOR_LIGHTGRAY = "lightgray";
+    // Gotta at least put in the proper spelling :-P
+    /** darkgrey string */
+    public static final String COLOR_DARKGREY = "darkgrey";
+    /** grey string */
+    public static final String COLOR_GREY = "grey";
+    /** lightgrey string */
+    public static final String COLOR_LIGHTGREY = "lightgrey";
+    /** green string */
+    public static final String COLOR_GREEN = "green";
+    /** magenta string */
+    public static final String COLOR_MAGENTA = "magenta";
+    /** orange string */
+    public static final String COLOR_ORANGE = "orange";
+    /** pink string */
+    public static final String COLOR_PINK = "pink";
+    /** reg string */
+    public static final String COLOR_RED = "red";
+    /** white string */
+    public static final String COLOR_WHITE = "white";
+    /** yellow string */
+    public static final String COLOR_YELLOW = "yellow";
+
+    /**
+     * Convert a color name to a color value.
+     * @param colorName a string repr of the color.
+     * @return the color value.
+     * @todo refactor to use an EnumeratedAttribute (maybe?)
+     */
+    public static Color getColorByName(String colorName) {
+        switch (colorName.toLowerCase(Locale.ENGLISH)) {
+        case COLOR_BLUE:
+            return Color.blue;
+        case COLOR_CYAN:
+            return Color.cyan;
+        case COLOR_DARKGRAY:
+        case COLOR_DARKGREY:
+            return Color.darkGray;
+        case COLOR_GRAY:
+        case COLOR_GREY:
+            return Color.gray;
+        case COLOR_LIGHTGRAY:
+        case COLOR_LIGHTGREY:
+            return Color.lightGray;
+        case COLOR_GREEN:
+            return Color.green;
+        case COLOR_MAGENTA:
+            return Color.magenta;
+        case COLOR_ORANGE:
+            return Color.orange;
+        case COLOR_PINK:
+            return Color.pink;
+        case COLOR_RED:
+            return Color.red;
+        case COLOR_WHITE:
+            return Color.white;
+        case COLOR_YELLOW:
+            return Color.yellow;
+        case COLOR_BLACK:
+        default:
+            return Color.black;
+        }
+    }
+
+    /** private constructor for Utility class */
+    private ColorMapper() {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/ant/blob/ed567daf/src/main/org/apache/tools/ant/types/optional/imageio/Draw.java
----------------------------------------------------------------------
diff --git a/src/main/org/apache/tools/ant/types/optional/imageio/Draw.java b/src/main/org/apache/tools/ant/types/optional/imageio/Draw.java
new file mode 100644
index 0000000..2862bb9
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/optional/imageio/Draw.java
@@ -0,0 +1,98 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.imageio;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+
+/**
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.ImageIOTask
+ */
+public class Draw extends TransformOperation {
+    private int xloc = 0;
+    private int yloc = 0;
+
+    /**
+     * Set the X location.
+     * @param x the value to use.
+     */
+    public void setXloc(int x) {
+        xloc = x;
+    }
+
+    /**
+     * Set the Y location.
+     * @param y the value to use.
+     */
+    public void setYloc(int y) {
+        yloc = y;
+    }
+
+    /**
+     * Add text to the operation.
+     * @param text the text to add.
+     */
+    public void addText(Text text) {
+        instructions.add(text);
+    }
+
+    /**
+     * Add a rectangle to the operation.
+     * @param rect the rectangle to add.
+     */
+    public void addRectangle(Rectangle rect) {
+        instructions.add(rect);
+    }
+
+    /**
+     * Add an ellipse.
+     * @param elip the ellipse to add.
+     */
+    public void addEllipse(Ellipse elip) {
+        instructions.add(elip);
+    }
+
+    /**
+     * Add an arc.
+     * @param arc the arc to add.
+     */
+    public void addArc(Arc arc) {
+        instructions.add(arc);
+    }
+
+    /** {@inheritDoc}. */
+    @Override
+    public BufferedImage executeTransformOperation(BufferedImage bi) {
+        Graphics2D graphics = bi.createGraphics();
+
+        for (ImageOperation instr : instructions) {
+            if (instr instanceof DrawOperation) {
+                BufferedImage op = ((DrawOperation) instr).executeDrawOperation();
+                log("\tDrawing to x=" + xloc + " y=" + yloc);
+                graphics.drawImage(op, null, xloc, yloc);
+            } else if (instr instanceof TransformOperation) {
+                BufferedImage child
+                    = ((TransformOperation) instr).executeTransformOperation(null);
+                log("\tDrawing to x=" + xloc + " y=" + yloc);
+                graphics.drawImage(child, null, xloc, yloc);
+            }
+        }
+        return bi;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ant/blob/ed567daf/src/main/org/apache/tools/ant/types/optional/imageio/DrawOperation.java
----------------------------------------------------------------------
diff --git a/src/main/org/apache/tools/ant/types/optional/imageio/DrawOperation.java b/src/main/org/apache/tools/ant/types/optional/imageio/DrawOperation.java
new file mode 100644
index 0000000..b525536
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/optional/imageio/DrawOperation.java
@@ -0,0 +1,39 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.imageio;
+
+import java.awt.image.BufferedImage;
+
+/**
+ * Interface which represents an Operation which is "drawable", such
+ * as a Rectangle, Circle or Text.  The Operation is responsible for
+ * creating its own image buffer and drawing itself into it, then
+ * wrapping and returning it as a PlanarImage.  This allows multiple
+ * "drawable" objects to be nested.
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.ImageIOTask
+ */
+public interface DrawOperation {
+    /**
+     * Abstract method which is intended to create an image buffer
+     * and return it so it can be drawn into another object.  Use
+     * an Alpha channel for a "transparent" background.
+     * @return a planar image
+     */
+    BufferedImage executeDrawOperation();
+}

http://git-wip-us.apache.org/repos/asf/ant/blob/ed567daf/src/main/org/apache/tools/ant/types/optional/imageio/Ellipse.java
----------------------------------------------------------------------
diff --git a/src/main/org/apache/tools/ant/types/optional/imageio/Ellipse.java b/src/main/org/apache/tools/ant/types/optional/imageio/Ellipse.java
new file mode 100644
index 0000000..20b732d
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/optional/imageio/Ellipse.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.imageio;
+
+import java.awt.BasicStroke;
+import java.awt.Graphics2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.image.BufferedImage;
+
+/**
+ * Draw an ellipse.
+ * @see org.apache.tools.ant.taskdefs.optional.image.ImageIOTask
+ */
+public class Ellipse extends BasicShape implements DrawOperation {
+    /** {@inheritDoc}. */
+    @Override
+    public BufferedImage executeDrawOperation() {
+        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR_PRE);
+
+        Graphics2D graphics = bi.createGraphics();
+
+        if (!"transparent".equalsIgnoreCase(stroke)) {
+            BasicStroke bStroke = new BasicStroke(strokeWidth);
+            graphics.setColor(ColorMapper.getColorByName(stroke));
+            graphics.setStroke(bStroke);
+            graphics.draw(new Ellipse2D.Double(0, 0, width, height));
+        }
+
+        if (!"transparent".equalsIgnoreCase(fill)) {
+            graphics.setColor(ColorMapper.getColorByName(fill));
+            graphics.fill(new Ellipse2D.Double(0, 0, width, height));
+        }
+
+        for (ImageOperation instr : instructions) {
+            if (instr instanceof DrawOperation) {
+                BufferedImage img = ((DrawOperation) instr).executeDrawOperation();
+                graphics.drawImage(img, null, 0, 0);
+            } else if (instr instanceof TransformOperation) {
+                bi = ((TransformOperation) instr).executeTransformOperation(bi);
+                graphics = bi.createGraphics();
+            }
+        }
+        return bi;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ant/blob/ed567daf/src/main/org/apache/tools/ant/types/optional/imageio/ImageOperation.java
----------------------------------------------------------------------
diff --git a/src/main/org/apache/tools/ant/types/optional/imageio/ImageOperation.java b/src/main/org/apache/tools/ant/types/optional/imageio/ImageOperation.java
new file mode 100644
index 0000000..9d25d4d
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/optional/imageio/ImageOperation.java
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.imageio;
+
+import org.apache.tools.ant.types.DataType;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.ImageIOTask
+ */
+public abstract class ImageOperation extends DataType {
+     // CheckStyle:VisibilityModifier OFF - bc
+    protected final List<ImageOperation> instructions = new ArrayList<>();
+     // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Add a rotate to the operation.
+     * @param instr the rotate to add.
+     */
+    public void addRotate(Rotate instr) {
+        instructions.add(instr);
+    }
+
+    /**
+     * Add a draw to the operation.
+     * @param instr the draw to add.
+     */
+    public void addDraw(Draw instr) {
+        instructions.add(instr);
+    }
+
+    /**
+     * Add a scale to the operation.
+     * @param instr the scale to add.
+     */
+    public void addScale(Scale instr) {
+        instructions.add(instr);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ant/blob/ed567daf/src/main/org/apache/tools/ant/types/optional/imageio/Rectangle.java
----------------------------------------------------------------------
diff --git a/src/main/org/apache/tools/ant/types/optional/imageio/Rectangle.java b/src/main/org/apache/tools/ant/types/optional/imageio/Rectangle.java
new file mode 100644
index 0000000..bc4fb25
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/optional/imageio/Rectangle.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.imageio;
+
+import java.awt.BasicStroke;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+
+/**
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.ImageIOTask
+ */
+public class Rectangle extends BasicShape implements DrawOperation {
+    private int arcwidth = 0;
+    private int archeight = 0;
+
+    /**
+     * Set the arc width.
+     * @param w the value to use.
+     */
+    public void setArcwidth(int w) {
+        arcwidth = w;
+    }
+
+    /**
+     * Set the arc height.
+     * @param h the value to use.
+     */
+    public void setArcheight(int h) {
+        archeight = h;
+    }
+
+    /** {@inheritDoc}. */
+    @Override
+    public BufferedImage executeDrawOperation() {
+        log("\tCreating Rectangle w=" + width + " h=" + height + " arcw="
+            + arcwidth + " arch=" + archeight);
+        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR_PRE);
+
+        Graphics2D graphics = bi.createGraphics();
+
+        if (!"transparent".equalsIgnoreCase(stroke)) {
+            BasicStroke bStroke = new BasicStroke(strokeWidth);
+            graphics.setColor(ColorMapper.getColorByName(stroke));
+            graphics.setStroke(bStroke);
+
+            if (arcwidth == 0 && archeight == 0) {
+                graphics.drawRect(0, 0, width, height);
+            } else {
+                graphics.drawRoundRect(0, 0, width, height, arcwidth, archeight);
+            }
+        }
+
+        if (!"transparent".equalsIgnoreCase(fill)) {
+            graphics.setColor(ColorMapper.getColorByName(fill));
+            if (arcwidth == 0 && archeight == 0) {
+                graphics.fillRect(strokeWidth, strokeWidth,
+                    width - (strokeWidth * 2), height - (strokeWidth * 2));
+            } else {
+                graphics.fillRoundRect(strokeWidth, strokeWidth,
+                    width - (strokeWidth * 2), height - (strokeWidth * 2),
+                    arcwidth, archeight);
+            }
+        }
+
+        for (ImageOperation instr : instructions) {
+            if (instr instanceof DrawOperation) {
+                BufferedImage img = ((DrawOperation) instr).executeDrawOperation();
+                graphics.drawImage(img, null, 0, 0);
+            } else if (instr instanceof TransformOperation) {
+                bi = ((TransformOperation) instr).executeTransformOperation(bi);
+                graphics = bi.createGraphics();
+            }
+        }
+        return bi;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ant/blob/ed567daf/src/main/org/apache/tools/ant/types/optional/imageio/Rotate.java
----------------------------------------------------------------------
diff --git a/src/main/org/apache/tools/ant/types/optional/imageio/Rotate.java b/src/main/org/apache/tools/ant/types/optional/imageio/Rotate.java
new file mode 100644
index 0000000..98bf5c0
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/optional/imageio/Rotate.java
@@ -0,0 +1,151 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.imageio;
+
+import org.apache.tools.ant.Project;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+import java.util.Arrays;
+
+/**
+ * ImageOperation to rotate an image by a certain degree
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.ImageIOTask
+ */
+public class Rotate extends TransformOperation implements DrawOperation {
+    private static final float HALF_CIRCLE = 180.0F;
+
+    private float angle = 0.0F;
+
+    /**
+     * Sets the angle of rotation in degrees.
+     * @param ang The angle at which to rotate the image
+     */
+    public void setAngle(String ang) {
+        angle = Float.parseFloat(ang) % (2 * HALF_CIRCLE);
+    }
+
+    /**
+     * Rotate an image.
+     * @param image the image to rotate.
+     * @return the rotated image.
+     */
+    public BufferedImage performRotate(BufferedImage image) {
+        // Float zero can be negative
+        if (Float.compare(Math.abs(angle), 0.0F) == 0) {
+            return image;
+        }
+
+        if (angle < 0) {
+            angle += 2 * HALF_CIRCLE;
+        }
+
+        // 180 degree rotation == flip the image vertically and horizontally
+        if (Float.compare(angle, HALF_CIRCLE) == 0) {
+            log("Flipping an image", Project.MSG_DEBUG);
+            AffineTransform tx = AffineTransform.getScaleInstance(-1, -1);
+            tx.translate(-image.getWidth(null), -image.getHeight(null));
+            AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
+            return op.filter(image, null);
+        }
+
+        AffineTransform tx = AffineTransform.getRotateInstance((float) (angle
+                * (Math.PI / HALF_CIRCLE)));
+        // Figure out the new bounding box
+        Rectangle2D box = getBoundingBox(image, tx);
+        AffineTransform translation = AffineTransform.getTranslateInstance(-box.getMinX(),
+                -box.getMinY());
+        tx.preConcatenate(translation);
+        BufferedImage rotatedImage = new BufferedImage((int) Math.round(box.getWidth()),
+                (int) Math.round(box.getHeight()), image.getType());
+        // Avoid black space around the rotated image
+        Graphics2D graphics = rotatedImage.createGraphics();
+        graphics.setPaint(new Color(image.getRGB(0, 0)));
+        graphics.fillRect(0, 0, rotatedImage.getWidth(), rotatedImage.getHeight());
+        graphics.dispose();
+        // Rotate
+        AffineTransformOp rotateOp = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
+        rotateOp.filter(image, rotatedImage);
+        return rotatedImage;
+    }
+
+    private Rectangle2D getBoundingBox(BufferedImage image, AffineTransform tx) {
+        int xmax = image.getWidth() - 1;
+        int ymax = image.getHeight() - 1;
+        Point2D[] corners = new Point2D.Double[4];
+        corners[0] = new Point2D.Double(0, 0);
+        corners[1] = new Point2D.Double(xmax, 0);
+        corners[2] = new Point2D.Double(xmax, ymax);
+        corners[3] = new Point2D.Double(0, ymax);
+        tx.transform(corners, 0, corners, 0, 4);
+
+        // Create bounding box of transformed corner points
+        Rectangle2D boundingBox = new Rectangle2D.Double();
+        Arrays.stream(corners, 0, 4).forEach(boundingBox::add);
+        return boundingBox;
+    }
+
+    /**
+     * Performs the image rotation when being handled as a TransformOperation.
+     * @param image The image to perform the transformation on.
+     * @return the transformed image.
+     */
+    @Override
+    public BufferedImage executeTransformOperation(BufferedImage image) {
+        for (ImageOperation instr : instructions) {
+            if (instr instanceof DrawOperation) {
+                // If this TransformOperation has DrawOperation children
+                // then Rotate the first child and return.
+                BufferedImage op = ((DrawOperation) instr).executeDrawOperation();
+                return performRotate(op);
+            }
+            if (instr instanceof TransformOperation) {
+                image = ((TransformOperation) instr).executeTransformOperation(image);
+            }
+        }
+        image = performRotate(image);
+        return image;
+    }
+
+    /**
+     *  Performs the image rotation when being handled as a DrawOperation.
+     *  It absolutely requires that there be a DrawOperation nested beneath it,
+     *  but only the FIRST DrawOperation will be handled since it can only return
+     *  ONE image.
+     * @return the image.
+     */
+    @Override
+    public BufferedImage executeDrawOperation() {
+        for (ImageOperation instr : instructions) {
+            if (instr instanceof DrawOperation) {
+                // If this TransformOperation has DrawOperation children
+                // then Rotate the first child and return.
+                BufferedImage op = ((DrawOperation) instr).executeDrawOperation();
+                return performRotate(op);
+            }
+        }
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/ant/blob/ed567daf/src/main/org/apache/tools/ant/types/optional/imageio/Scale.java
----------------------------------------------------------------------
diff --git a/src/main/org/apache/tools/ant/types/optional/imageio/Scale.java b/src/main/org/apache/tools/ant/types/optional/imageio/Scale.java
new file mode 100644
index 0000000..d745a79
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/optional/imageio/Scale.java
@@ -0,0 +1,170 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.imageio;
+
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+import java.awt.geom.AffineTransform;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+
+/**
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.ImageIOTask
+ */
+public class Scale extends TransformOperation implements DrawOperation {
+    private static final int HUNDRED = 100;
+
+    private String widthStr = "100%";
+    private String heightStr = "100%";
+    private boolean xPercent = true;
+    private boolean yPercent = true;
+    private String proportions = "ignore";
+
+    /** Enumerated class for proportions attribute. */
+    public static class ProportionsAttribute extends EnumeratedAttribute {
+        /** {@inheritDoc}. */
+        @Override
+        public String[] getValues() {
+            return new String[] { "ignore", "width", "height", "cover", "fit" };
+        }
+    }
+
+    /**
+     *  Sets the behaviour regarding the image proportions.
+     * @param pa the enumerated value.
+     */
+    public void setProportions(ProportionsAttribute pa) {
+        proportions = pa.getValue();
+    }
+
+    /**
+     * Sets the width of the image, either as an integer or a %.
+     * Defaults to 100%.
+     * @param width the value to use.
+     */
+    public void setWidth(String width) {
+        widthStr = width;
+    }
+
+    /**
+     *  Sets the height of the image, either as an integer or a %.  Defaults to 100%.
+     * @param height the value to use.
+     */
+    public void setHeight(String height) {
+        heightStr = height;
+    }
+
+    /**
+     * Get the width.
+     * @return the value converted from the width string.
+     */
+    public float getWidth() {
+        int percIndex = widthStr.indexOf('%');
+        if (percIndex > 0) {
+            xPercent = true;
+            float width = Float.parseFloat(widthStr.substring(0, percIndex));
+            return width / HUNDRED;
+        }
+        xPercent = false;
+        return Float.parseFloat(widthStr);
+    }
+
+    /**
+     * Get the height.
+     * @return the value converted from the height string.
+     */
+    public float getHeight() {
+        int percIndex = heightStr.indexOf('%');
+        if (percIndex > 0) {
+            yPercent = true;
+            return Float.parseFloat(heightStr.substring(0, percIndex)) / HUNDRED;
+        }
+        yPercent = false;
+        return Float.parseFloat(heightStr);
+    }
+
+    /**
+     * Scale an image.
+     * @param image the image to scale.
+     * @return the scaled image.
+     */
+    public BufferedImage performScale(BufferedImage image) {
+        float xFl = getWidth();
+        float yFl = getHeight();
+
+        if (!xPercent) {
+            xFl /= image.getWidth();
+        }
+        if (!yPercent) {
+            yFl /= image.getHeight();
+        }
+
+        if ("width".equals(proportions)) {
+            yFl = xFl;
+        } else if ("height".equals(proportions)) {
+            xFl = yFl;
+        } else if ("fit".equals(proportions)) {
+            yFl = Math.min(xFl, yFl);
+            xFl = yFl;
+        } else if ("cover".equals(proportions)) {
+            yFl = Math.max(xFl, yFl);
+            xFl = yFl;
+        }
+
+        log("\tScaling to " + (xFl * HUNDRED) + "% x "
+            + (yFl * HUNDRED) + "%");
+
+        AffineTransform tx = AffineTransform.getScaleInstance(xFl, yFl);
+        BufferedImage scaleImage = new BufferedImage((int) (xFl * image.getWidth()),
+                (int) (yFl * image.getHeight()), image.getType());
+        AffineTransformOp scaleOp = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
+        scaleOp.filter(image, scaleImage);
+        return scaleImage;
+    }
+
+    /** {@inheritDoc}. */
+    @Override
+    public BufferedImage executeTransformOperation(BufferedImage image) {
+        for (ImageOperation instr : instructions) {
+            if (instr instanceof DrawOperation) {
+                return performScale(image);
+            }
+            if (instr instanceof TransformOperation) {
+                image = ((TransformOperation) instr).executeTransformOperation(image);
+            }
+        }
+        return performScale(image);
+    }
+
+
+    /** {@inheritDoc}. */
+    @Override
+    public BufferedImage executeDrawOperation() {
+        for (ImageOperation instr : instructions) {
+            if (instr instanceof DrawOperation) {
+                BufferedImage image = null;
+                // If this TransformOperation has DrawOperation children
+                // then Rotate the first child and return.
+                performScale(image);
+                return image;
+            }
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ant/blob/ed567daf/src/main/org/apache/tools/ant/types/optional/imageio/Text.java
----------------------------------------------------------------------
diff --git a/src/main/org/apache/tools/ant/types/optional/imageio/Text.java b/src/main/org/apache/tools/ant/types/optional/imageio/Text.java
new file mode 100644
index 0000000..39ccc06
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/optional/imageio/Text.java
@@ -0,0 +1,134 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.imageio;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+
+/**
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.ImageIOTask
+ */
+public class Text extends ImageOperation implements DrawOperation {
+    private static final int DEFAULT_POINT = 10;
+
+    private String string = "";
+    private String font = "Arial";
+    private int point = DEFAULT_POINT;
+    private boolean bold = false;
+    private boolean italic = false;
+    private String color = "black";
+
+    /**
+     * Set the string to be used as text.
+     * @param str the string to be used.
+     */
+    public void setString(String str) {
+        string = str;
+    }
+
+    /**
+     * Set the font to be used to draw the text.
+     * @param f the font to be used.
+     */
+    public void setFont(String f) {
+        font = f;
+    }
+
+    /**
+     * Set the number of points to be used.
+     * @param p an integer value as a string.
+     */
+    public void setPoint(String p) {
+        point = Integer.parseInt(p);
+    }
+
+    /**
+     * Set the color of the text.
+     * @param c the color name.
+     */
+    public void setColor(String c) {
+        color = c;
+    }
+
+    /**
+     * @todo is this used?
+     * @param state not used at the moment.
+     */
+    public void setBold(boolean state) {
+        bold = state;
+    }
+
+    /**
+     * @todo is this used?
+     * @param state not used at the moment.
+     */
+    public void setItalic(boolean state) {
+        italic = state;
+    }
+
+    /**
+     * Draw the text.
+     * @return the resultant image.
+     */
+    @Override
+    public BufferedImage executeDrawOperation() {
+        log("\tCreating Text \"" + string + "\"");
+
+        int width = 1;
+        int height = 1;
+
+        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR_PRE);
+        Graphics2D graphics = bi.createGraphics();
+        graphics.setRenderingHint(
+            RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        graphics.setRenderingHint(
+            RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+        Font f = createFont();
+        FontMetrics fmetrics = graphics.getFontMetrics(f);
+        height = fmetrics.getMaxAscent() + fmetrics.getMaxDescent();
+        width = fmetrics.stringWidth(string);
+
+        bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR_PRE);
+        graphics = bi.createGraphics();
+
+        graphics.setRenderingHint(
+            RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        graphics.setRenderingHint(
+            RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+
+        graphics.setFont(f);
+        graphics.setColor(ColorMapper.getColorByName(color));
+        graphics.drawString(string, 0, height - fmetrics.getMaxDescent());
+        return bi;
+    }
+
+    private Font createFont() {
+        int style = Font.PLAIN;
+        if (bold) {
+            style |= Font.BOLD;
+        }
+        if (italic) {
+            style |= Font.ITALIC;
+        }
+        return new Font(font, style, point);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ant/blob/ed567daf/src/main/org/apache/tools/ant/types/optional/imageio/TransformOperation.java
----------------------------------------------------------------------
diff --git a/src/main/org/apache/tools/ant/types/optional/imageio/TransformOperation.java
b/src/main/org/apache/tools/ant/types/optional/imageio/TransformOperation.java
new file mode 100644
index 0000000..ba23cb1
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/optional/imageio/TransformOperation.java
@@ -0,0 +1,33 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.imageio;
+
+import java.awt.image.BufferedImage;
+
+/**
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.ImageIOTask
+ */
+public abstract class TransformOperation extends ImageOperation {
+    /**
+     * Performs the transformations.
+     * @param img The image to perform the transformation on.
+     * @return the transformed image.
+     */
+    public abstract BufferedImage executeTransformOperation(BufferedImage img);
+}

http://git-wip-us.apache.org/repos/asf/ant/blob/ed567daf/src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageIOTest.java
----------------------------------------------------------------------
diff --git a/src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageIOTest.java
b/src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageIOTest.java
new file mode 100644
index 0000000..c96691d
--- /dev/null
+++ b/src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageIOTest.java
@@ -0,0 +1,145 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.image;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildFileRule;
+import org.apache.tools.ant.util.FileUtils;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.io.File;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+/**
+ * Tests ImageIOTask.
+ *
+ * @since     Ant 1.10.6
+ */
+public class ImageIOTest {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    private static final String LARGEIMAGE = "largeimage.jpg";
+
+    @Rule
+    public BuildFileRule buildRule = new BuildFileRule();
+
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    @Before
+    public void setUp() {
+        buildRule.configureProject("src/etc/testcases/taskdefs/optional/image/imageio.xml");
+    }
+
+
+    @Test
+    public void testEchoToLog() {
+        buildRule.executeTarget("testEchoToLog");
+        assertThat(buildRule.getLog(), containsString("Processing File"));
+    }
+
+    @Test
+    public void testSimpleScale() {
+        buildRule.executeTarget("testSimpleScale");
+        assertThat(buildRule.getLog(), containsString("Processing File"));
+
+        File f = new File(buildRule.getOutputDir(), LARGEIMAGE);
+        assertTrue("Did not create " + f.getAbsolutePath(), f.exists());
+    }
+
+    @Test
+    public void testOverwriteTrue() {
+        buildRule.executeTarget("testSimpleScale");
+        assertThat(buildRule.getLog(), containsString("Processing File"));
+        File f = new File(buildRule.getOutputDir(), LARGEIMAGE);
+        assumeTrue("Could not change file modification date",
+                f.setLastModified(f.lastModified() - FILE_UTILS.getFileTimestampGranularity()
* 2));
+        long lastModified = f.lastModified();
+        buildRule.executeTarget("testOverwriteTrue");
+        assertThat(buildRule.getLog(), containsString("Processing File"));
+        f = new File(buildRule.getOutputDir(), LARGEIMAGE);
+        long overwrittenLastModified = f.lastModified();
+        assertTrue("File was not overwritten.", lastModified < overwrittenLastModified);
+    }
+
+    @Test
+    public void testDrawOverwriteTrue() {
+        buildRule.executeTarget("testSimpleScale");
+        assertThat(buildRule.getLog(), containsString("Processing File"));
+        File f = new File(buildRule.getOutputDir(), LARGEIMAGE);
+        assumeTrue("Could not change file modification date",
+                f.setLastModified(f.lastModified() - FILE_UTILS.getFileTimestampGranularity()
* 2));
+        long lastModified = f.lastModified();
+        buildRule.executeTarget("testDrawOverwriteTrue");
+        assertThat(buildRule.getLog(), containsString("Processing File"));
+        f = new File(buildRule.getOutputDir(), LARGEIMAGE);
+        long overwrittenLastModified = f.lastModified();
+        assertTrue("File was not overwritten.", lastModified < overwrittenLastModified);
+    }
+
+    @Test
+    public void testOverwriteFalse() {
+        buildRule.executeTarget("testSimpleScale");
+        assertThat(buildRule.getLog(), containsString("Processing File"));
+        File f = new File(buildRule.getOutputDir(), LARGEIMAGE);
+        long lastModified = f.lastModified();
+        buildRule.executeTarget("testOverwriteFalse");
+        assertThat(buildRule.getLog(), containsString("Processing File"));
+        f = new File(buildRule.getOutputDir(), LARGEIMAGE);
+        long overwrittenLastModified = f.lastModified();
+        assertEquals("File was overwritten.", lastModified, overwrittenLastModified);
+    }
+
+    @Test
+    public void testSimpleScaleWithMapper() {
+        buildRule.executeTarget("testSimpleScaleWithMapper");
+        assertThat(buildRule.getLog(), containsString("Processing File"));
+        File f = new File(buildRule.getOutputDir(), "scaled-" + LARGEIMAGE);
+        assertTrue("Did not create " + f.getAbsolutePath(), f.exists());
+    }
+
+    @Test
+    public void testFlip() {
+        buildRule.executeTarget("testFlip");
+        assertThat(buildRule.getFullLog(), containsString("Flipping an image"));
+        File f = new File(buildRule.getOutputDir(), LARGEIMAGE);
+        assertTrue("Did not create " + f.getAbsolutePath(), f.exists());
+    }
+
+    @Test
+    public void testFailOnError() {
+        final String message = "Unsupported Image Type";
+        thrown.expect(BuildException.class);
+        thrown.expectMessage(message);
+        try {
+            buildRule.executeTarget("testFailOnError");
+        } finally {
+            assertThat(buildRule.getLog(), containsString(message));
+        }
+    }
+
+}


Mime
View raw message