diff --git a/build.xml b/build.xml index 99b1eee676..43b68284ed 100644 --- a/build.xml +++ b/build.xml @@ -277,13 +277,21 @@ + + + + + + + - + + @@ -329,6 +337,7 @@ + @@ -444,6 +453,9 @@ + @@ -602,6 +614,7 @@ + @@ -770,6 +783,7 @@ + @@ -864,6 +878,7 @@ + diff --git a/manual/Tasks/image.graphml b/manual/Tasks/image.graphml new file mode 100644 index 0000000000..b9ba70763f --- /dev/null +++ b/manual/Tasks/image.graphml @@ -0,0 +1,501 @@ + + + + + + + + + + + + + + + + + + + + + + + + + org.apache.tools.ant.types.DataType + + + + + + + + + + + + + + + ImageOperation + + instructions : Vector + addRotate(Rotate : instr) +addDraw(Draw : instr) +addText(Text : instr) +addScale(Scale : instr) + + + + + + + + + + + + The setType() method forces type to +one of the values of java.awt.geom.Arc2D: +open = Arc2D.OPEN +pie = Arc2D.PIE +chord = Arc2D.CHORD +Parameter is not case-sensitive. + + + + + + + + + + + BasicShape + + stroke_width : int = 0 +fill : String = "transparent" +stroke : String = "black" + + + + + + + + + + + + + TransformOperation + + + executeTransformOperation(PlanarImage img) : PlanarImage +addRectangle(Rectangle instr) + + + + + + + + + + + + DrawOperation + + + executeDrawOperation() : PlanarImage + + + + + + + + + + + + The implementing class uses +ColorMapper to evaluate the color. +Only the values defined in +ColorMapper are used. + + + + + + + + + + + ColorMapper + + COLOR_BLACK : String = "black" +COLOR_BLUE : String = "blue" +COLOR_CYAN : String = "cyan" +COLOR_DARKGRAY : String = "darkgray" +COLOR_GRAY : String = "gray" +COLOR_LIGHTGRAY : String = "lightgray" +COLOR_DARKGREY : String = "darkgrey" +COLOR_GREY : String = "grey" +COLOR_LIGHTGREY : String = "lightgrey" +COLOR_GREEN : String = "green" +COLOR_MAGENTA : String = "magenta" +COLOR_ORANGE : String = "orange" +COLOR_PINK : String = "pink" +COLOR_RED : String = "red" +COLOR_WHITE : String = "white" +COLOR_YELLOW : String = "yellow" + + + + + + + + + + + + + Text + + string : String = "" +font : String = "Arial" +point : int = 10 +bold : boolean = false +color : String = "black" +italic : boolean = false + + + + + + + + + + + + + Rotate + + angle : float = 0.0F + + + + + + + + + + + + + Scale + + width : String = "100%" +height : String = "100%" +keepProportions : boolean = false + + + + + + + + + + + + + Draw + + xloc : int = 0 +yloc : int = 0 + addEllipse(Ellipse elip) +addArc(Arc arc) + + + + + + + + + + + + Rectangle + + height : int = 0 +width : int = 0 +archeight : int = 0 +arcwidth : int = 0 + + + + + + + + + + + + + Ellipse + + height : int = 0 +width : int = 0 + + + + + + + + + + + + + Arc + + height : int = 0 +width : int = 0 +start : int = 0 +stop : int = 0 +type : enumerated = open + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/manual/Tasks/image.html b/manual/Tasks/image.html index 8c920a4459..3d92b46160 100644 --- a/manual/Tasks/image.html +++ b/manual/Tasks/image.html @@ -25,13 +25,357 @@

Image

+

Deprecated

+

This task has been deprecated, because Java Advanced Image API depends on internal +classes which were removed in Java 9. Use the ImageIO task instead.

Description

Applies a chain of image operations on a set of files.

Requires Java Advanced Image API from Sun.

Overview of used datatypes
-Class-Diagram - + + ImageOperation class diagram + A diagram of Ant DataType classes used by Image task. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.apache.tools.ant.types.DataType + + + + + + + + + + + + + ImageOperation + + + + instructions : Vector + + addRotate(Rotate : instr) + addDraw(Draw : instr) + addText(Text : instr) + addScale(Scale : instr) + + + The setType() method forces type to + one of the values of java.awt.geom.Arc2D: + open = Arc2D.OPEN + pie = Arc2D.PIE + chord = Arc2D.CHORD + Parameter is not case-sensitive. + + + + + + + + BasicShape + + + + stroke_width : int = 0 + fill : String = "transparent" + stroke : String = "black" + + + + + + + + + TransformOperation + + + + + executeTransformOperation(PlanarImage img) : PlanarImage + addRectangle(Rectangle instr) + + + + + + <<interface>> + + + DrawOperation + + + + + executeDrawOperation() : PlanarImage + + + The implementing class uses + ColorMapper to evaluate the color. + Only the values defined in + ColorMapper are used. + + + + + + + + ColorMapper + + + + COLOR_BLACK : String = "black" + COLOR_BLUE : String = "blue" + COLOR_CYAN : String = "cyan" + COLOR_DARKGRAY : String = "darkgray" + COLOR_GRAY : String = "gray" + COLOR_LIGHTGRAY : String = "lightgray" + COLOR_DARKGREY : String = "darkgrey" + COLOR_GREY : String = "grey" + COLOR_LIGHTGREY : String = "lightgrey" + COLOR_GREEN : String = "green" + COLOR_MAGENTA : String = "magenta" + COLOR_ORANGE : String = "orange" + COLOR_PINK : String = "pink" + COLOR_RED : String = "red" + COLOR_WHITE : String = "white" + COLOR_YELLOW : String = "yellow" + + + + + + + + + Text + + + + string : String = "" + font : String = "Arial" + point : int = 10 + bold : boolean = false + color : String = "black" + italic : boolean = false + + + + + + + + + Rotate + + + + angle : float = 0.0F + + + + + + + + + Scale + + + + width : String = "100%" + height : String = "100%" + keepProportions : boolean = false + + + + + + + + + Draw + + + + xloc : int = 0 + yloc : int = 0 + + addEllipse(Ellipse elip) + addArc(Arc arc) + + + + + + + + Rectangle + + + + height : int = 0 + width : int = 0 + archeight : int = 0 + arcwidth : int = 0 + + + + + + + + + Ellipse + + + + height : int = 0 + width : int = 0 + + + + + + + + + Arc + + + + height : int = 0 + width : int = 0 + start : int = 0 + stop : int = 0 + type : enumerated = open + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Parameters

@@ -115,12 +459,8 @@

Parameters specified as nested elements

nested <include>, <exclude> and <patternset> elements.

-

ImageOperation

-

Adds an ImageOperation to chain.

-
Nested elements
-

ImageOperation can handle -nested Rotate, Draw, Rectangle, Text -and Scale objects.

+

The following ImageOperation objects can be specified as nested +elements: Rotate, Scale and Draw.

Rotate

Adds a Rotate ImageOperation to chain.

@@ -151,7 +491,7 @@
Parameters
- - + - - +
proportions Sets which dimension to control proportions from. Valid values are:
    -
  • ignore— treat the dimensions independently.
  • +
  • ignore—treat the dimensions independently.
  • height—keep proportions based on the width.
  • width—keep proportions based on the height.
  • cover—keep proportions and fit in the supplied dimensions.
  • @@ -162,14 +502,12 @@
    Parameters
widthSets the width of the image, either as an integer or a %.Sets the width of the image, either as an integer (pixels) or a %. No; defaults to 100%
heightSets the height of the image, either as an integer or a %.Sets the height of the image, either as an integer (pixels) or a %. No; defaults to 100%
@@ -195,6 +533,8 @@
Parameters
No; defaults to 0 +

For description of nested elements, please see the documentation +of ImageIO task.

mapper

Since Apache Ant 1.8.0

@@ -209,8 +549,8 @@

mapper

Examples

-

Create thumbnails of my images and make sure they all fit within the 160x160 size whether the -image is portrait or landscape.

+

Create thumbnails of my images and make sure they all fit within the 160×160 pixel size +whether the image is portrait or landscape.

 <image destdir="samples/low" overwrite="yes">
     <fileset dir="samples/full">
@@ -219,7 +559,7 @@ 

Examples

<scale width="160" height="160" proportions="fit"/> </image>
-

Create a thumbnail for all PNG files in src of the size of 40 pixel keeping the +

Create a thumbnail for all PNG files in src of the size of 40 pixels keeping the proportions and store the src.

 <image srcdir="src" includes="*.png">
diff --git a/manual/Tasks/imageio.graphml b/manual/Tasks/imageio.graphml
new file mode 100644
index 0000000000..99c2a14b76
--- /dev/null
+++ b/manual/Tasks/imageio.graphml
@@ -0,0 +1,498 @@
+
+
+
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+    
+    
+      
+      
+        
+          
+          
+          
+          org.apache.tools.ant.types.DataType
+          
+            
+             
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+          ImageOperation
+          
+            instructions : List
+            addDraw(Draw : instr)
+addRotate(Rotate : instr)
+addScale(Scale : instr)
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+          The setType() method forces type to
+one of the values of java.awt.geom.Arc2D:
+open = Arc2D.OPEN
+pie = Arc2D.PIE
+chord = Arc2D.CHORD
+Parameter is not case-sensitive.
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+          BasicShape
+          
+            height : int = 0
+width : int = 0
+strokeWidth : int = 0
+stroke : String = "black"
+fill : String = "transparent"
+            
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+          TransformOperation
+          
+            
+            executeTransformOperation(BufferedImage img) : BufferedImage
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+          DrawOperation
+          
+            
+            executeDrawOperation() : BufferedImage
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+          The implementing class uses
+ColorMapper to evaluate the color.
+Only the values defined in
+ColorMapper are used.
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+          ColorMapper
+          
+            COLOR_BLACK : String = "black"
+COLOR_BLUE : String = "blue"
+COLOR_CYAN : String = "cyan"
+COLOR_DARKGRAY : String = "darkgray"
+COLOR_GRAY : String = "gray"
+COLOR_LIGHTGRAY : String = "lightgray"
+COLOR_DARKGREY : String = "darkgrey"
+COLOR_GREY : String = "grey"
+COLOR_LIGHTGREY : String = "lightgrey"
+COLOR_GREEN : String = "green"
+COLOR_MAGENTA : String = "magenta"
+COLOR_ORANGE : String = "orange"
+COLOR_PINK : String = "pink"
+COLOR_RED : String = "red"
+COLOR_WHITE : String = "white"
+COLOR_YELLOW : String = "yellow"
+            
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+          Text
+          
+            string : String = ""
+font : String = "Arial"
+point : int = 10
+bold : boolean = false
+color : String = "black"
+italic : boolean = false
+            
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+          Rotate
+          
+            angle : float = 0.0F
+            
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+          Scale
+          
+            width : String = "100%"
+height : String = "100%"
+keepProportions : boolean = false
+            
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+          Draw
+          
+            xloc : int = 0
+yloc : int = 0
+            addText(Text : text)
+addRectangle(Rectangle rect)
+addEllipse(Ellipse elip)
+addArc(Arc arc)
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+          Rectangle
+          
+            archeight : int = 0
+arcwidth : int = 0
+            
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+          Ellipse
+          
+            
+             
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+          Arc
+          
+            start : int = 0
+stop : int = 0
+type : enumerated = open
+            
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+    
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+    
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+    
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+    
+      
+      
+        
+          
+          
+          
+           
+          
+        
+      
+    
+  
+  
+    
+  
+
diff --git a/manual/Tasks/imageio.html b/manual/Tasks/imageio.html
new file mode 100644
index 0000000000..cce503ca9c
--- /dev/null
+++ b/manual/Tasks/imageio.html
@@ -0,0 +1,693 @@
+
+
+
+
+
+
+Image Task
+
+
+
+
+

ImageIO

+

Description

+

Applies a chain of image operations on a set of files.

+

Uses AWT and ImageIO; replaces image task for Java 9+. The task can be +used with Java 8 as well, see parameter table for limitations.

+ +
Overview of used datatypes
+ + ImageOperation class diagram + A diagram of Ant DataType classes used by ImageIO task. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.apache.tools.ant.types.DataType + + + + + + + + + + + + + ImageOperation + + + + instructions : List + + addDraw(Draw : instr) + addRotate(Rotate : instr) + addScale(Scale : instr) + + + The setType() method forces type to + one of the values of java.awt.geom.Arc2D: + open = Arc2D.OPEN + pie = Arc2D.PIE + chord = Arc2D.CHORD + Parameter is not case-sensitive. + + + + + + + + BasicShape + + + + height : int = 0 + width : int = 0 + strokeWidth : int = 0 + stroke : String = "black" + fill : String = "transparent" + + + + + + + + + TransformOperation + + + + + executeTransformOperation(BufferedImage img) : BufferedImage + + + + + + <<interface>> + + + DrawOperation + + + + + executeDrawOperation() : BufferedImage + + + The implementing class uses + ColorMapper to evaluate the color. + Only the values defined in + ColorMapper are used. + + + + + + + + ColorMapper + + + + COLOR_BLACK : String = "black" + COLOR_BLUE : String = "blue" + COLOR_CYAN : String = "cyan" + COLOR_DARKGRAY : String = "darkgray" + COLOR_GRAY : String = "gray" + COLOR_LIGHTGRAY : String = "lightgray" + COLOR_DARKGREY : String = "darkgrey" + COLOR_GREY : String = "grey" + COLOR_LIGHTGREY : String = "lightgrey" + COLOR_GREEN : String = "green" + COLOR_MAGENTA : String = "magenta" + COLOR_ORANGE : String = "orange" + COLOR_PINK : String = "pink" + COLOR_RED : String = "red" + COLOR_WHITE : String = "white" + COLOR_YELLOW : String = "yellow" + + + + + + + + + Text + + + + string : String = "" + font : String = "Arial" + point : int = 10 + bold : boolean = false + color : String = "black" + italic : boolean = false + + + + + + + + + Rotate + + + + angle : float = 0.0F + + + + + + + + + Scale + + + + width : String = "100%" + height : String = "100%" + keepProportions : boolean = false + + + + + + + + + Draw + + + + xloc : int = 0 + yloc : int = 0 + + addText(Text : text) + addRectangle(Rectangle rect) + addEllipse(Ellipse elip) + addArc(Arc arc) + + + + + + + + Rectangle + + + + archeight : int = 0 + arcwidth : int = 0 + + + + + + + + + Ellipse + + + + + + + + + + + + + Arc + + + + start : int = 0 + stop : int = 0 + type : enumerated = open + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
failonerrorBoolean value. If false, note errors to the output but keep going.No; defaults to true
srcdirDirectory containing the images.Yes, unless nested fileset is used
encodingImage format.
Valid (case insensitive) + are: bmp, gif, jpeg, jpg, png, tif, tiff, wbmp + (Java 8 VM lacks support for TIFF, which can be provided + by external libraries).
No; defaults to the format of the first original file
overwriteBoolean value. Sets whether or not to overwrite a file if there is naming conflict.No; defaults to false
gcBoolean value. Enables garbage collection after each image processed.No; defaults to false
destdirDirectory where the result images are stored.No; defaults to value of srcdir
includescomma- or space-separated list of patterns of files that must be included.No; defaults to all (**)
includesfilename of a file. Each line of this file is taken to be an include patternNo
excludescomma- or space-separated list of patterns of files that must be excluded.No; defaults to default excludes or none if defaultexcludes is no
excludesfilename of a file. Each line of this file is taken to be an exclude patternNo
defaultexcludesindicates whether default excludes should be used or not (yes|no).No; defaults to yes
caseSensitiveBoolean value. Sets case sensitivity of the file system.No; defaults to false
followSymlinksBoolean value. Sets whether or not symbolic links should be followed.No; defaults to true
+ +

Parameters specified as nested elements

+

This task forms an implicit FileSet and supports most +attributes of <fileset> as well as the +nested <include>, <exclude> +and <patternset> elements.

+ +

The following ImageOperation objects can be specified as nested +elements: Rotate, Scale and Draw.

+ +

Rotate

+

Adds a Rotate ImageOperation to chain.

+
Parameters
+ + + + + + + + + + + +
AttributeDescriptionRequired
angleFloat value. Sets the angle of rotation in degrees.No; defaults to 0.0F
+ +

Scale

+

Adds a Scale ImageOperation to chain.

+
Parameters
+ + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
proportionsSets which dimension to control proportions from. Valid values are: +
    +
  • ignore—treat the dimensions independently.
  • +
  • height—keep proportions based on the width.
  • +
  • width—keep proportions based on the height.
  • +
  • cover—keep proportions and fit in the supplied dimensions.
  • +
  • fit—keep proportions and cover the supplied dimensions.
  • +
+
No; defaults to ignore
widthSets the width of the image, either as an integer (pixels) or a %.No; defaults to 100%
heightSets the height of the image, either as an integer (pixels) or a %.No; defaults to 100%
+ +

Draw

+

Adds a Draw ImageOperation to chain. DrawOperation DataType objects can be nested inside the Draw +object.

+
Parameters
+ + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
xlocX-Position where to draw nested image elements.No; defaults to 0
ylocY-Position where to draw nested image elements.No; defaults to 0
+
Nested elements
+

Both Text and BasicShape objects can be nested. Currently supported BasicShape objects are Arc, +Ellipse and Rectangle.

+
Common parameters of BasicShape objects
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
heightHeight of a BasicShape.No; defaults to 0
widthWidth of a BasicShape.No; defaults to 0
strokewidthStroke width of a BasicShape.No; defaults to 0
colorColor of a BasicShape.No; defaults to black
fillFill of a BasicShape.No; defaults to transparent
+
Parameters specific to Arc objects
+ + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
startStart angle of an arc in degrees.No; defaults to 0
stopAngle extent of an arc in degrees.No; defaults to 0
typeOne of chord, open, pie.No; defaults to open
+
Parameters specific to Ellipse objects
+

None.

+
Parameters specific to Rectangle objects
+ + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
archeightVertical diameter of the arc at the corners of the rectangle.No; defaults to 0
arcwidthHorisontal diameter of the arc at the corners of the rectangle.No; defaults to 0
+
Parameters of Text
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
stringThe text string.No; defaults to
fontThe font to set the text in.No; defaults to Arial
pointSize of the font in points.No; defaults to 10
boldWhether the font is bold.No; defaults to false
colorColor of the text.No; defaults to black
italicWhether the font is italic.No; defaults to false
+

mapper

+

You can define filename transformations by using a +nested mapper element. The default mapper used +by <image> is the identity +mapper.

+ +

You can also use a filenamemapper type in place of the mapper +element.

+ +

Examples

+ +

Create thumbnails of my images and make sure they all fit within the 160×160 pixel size +whether the image is portrait or landscape.

+
+<image destdir="samples/low" overwrite="yes">
+    <fileset dir="samples/full">
+        <include name="**/*.jpg"/>
+    </fileset>
+    <scale width="160" height="160" proportions="fit"/>
+</image>
+ +

Create a thumbnail for all PNG files in src of the size of 40 pixels keeping the +proportions and store the src.

+
+<image srcdir="src" includes="*.png">
+    <scale proportions="width" width="40"/>
+</image>
+ +

Same as above but store the result in dest.

+
+<image srcdir="src" destdir="dest" includes="*.png">
+    <scale proportions="width" width="40"/>
+</image>
+ +

Same as above but store the result to files with original names prefixed +by scaled-.

+
+<image srcdir="src" destdir="dest" includes="*.png">
+    <scale proportions="width" width="40"/>
+    <globmapper from="*" to="scaled-*"/>
+</image>
+ + + diff --git a/manual/install.html b/manual/install.html index 9bc54f1f3e..b5963f5548 100644 --- a/manual/install.html +++ b/manual/install.html @@ -898,10 +898,8 @@

Library Dependencies

activation.jar
- (included in Java 6 to Java 10 but - the java.activation module is deprecated and marked - for removal in Java 9 and needs to be enabled explicitly on Java - 10) + (included in Java 6 to Java 10 but the java.activation module is deprecated and marked for removal in + Java 9 and needs to be enabled explicitly on Java 10) mail task with MIME encoding, and deprecated mimemail task Library Dependencies https://download.java.net/media/jai/builds/release/1_1_3/INSTALL.html + + jai-imageio-core.jar + imageio task for TIFF support on Java 8, as well as PCX, PNM, RAW support + https://github.com/jai-imageio/jai-imageio-core/releases + XZ—XZ for Java 1.6 or later xz and unxz diff --git a/manual/tasklist.html b/manual/tasklist.html index 2a40149494..5325e3897a 100644 --- a/manual/tasklist.html +++ b/manual/tasklist.html @@ -89,7 +89,8 @@

Tasks

  • GUnzip
  • GZip
  • Hostinfo
  • -
  • Image
  • +
  • Image
  • +
  • ImageIO
  • Import
  • Include
  • Input
  • diff --git a/release/ivy.xml b/release/ivy.xml index b90252ff67..b66bf22169 100644 --- a/release/ivy.xml +++ b/release/ivy.xml @@ -91,6 +91,12 @@ + + + + + + diff --git a/src/etc/poms/ant-imageio/pom.xml b/src/etc/poms/ant-imageio/pom.xml new file mode 100644 index 0000000000..24829b60da --- /dev/null +++ b/src/etc/poms/ant-imageio/pom.xml @@ -0,0 +1,66 @@ + + + + + + org.apache.ant + ant-parent + ../pom.xml + 1.10.6-SNAPSHOT + + 4.0.0 + http://ant.apache.org/ + org.apache.ant + ant-imageio + 1.10.6-SNAPSHOT + Apache Ant + ImageIO + imageio task and corresponding types. + + + org.apache.ant + ant + 1.10.6-SNAPSHOT + compile + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org/apache/tools/ant/taskdefs/optional/image/ImageIOTask.java + org/apache/tools/ant/types/optional/imageio/* + + + + + ../../../../src/main + ../../../../src/testcases + ../../../../target/${project.artifactId}/classes + ../../../../target/${project.artifactId}/testcases + ../../../../target/${project.artifactId} + + diff --git a/src/etc/poms/ant-jai/pom.xml b/src/etc/poms/ant-jai/pom.xml index fe6c89881b..eae3626b04 100644 --- a/src/etc/poms/ant-jai/pom.xml +++ b/src/etc/poms/ant-jai/pom.xml @@ -70,7 +70,7 @@ maven-compiler-plugin - org/apache/tools/ant/taskdefs/optional/image/* + org/apache/tools/ant/taskdefs/optional/image/Image.java org/apache/tools/ant/types/optional/image/* diff --git a/src/etc/testcases/taskdefs/optional/image/imageio.xml b/src/etc/testcases/taskdefs/optional/image/imageio.xml new file mode 100644 index 0000000000..a7d6a23e20 --- /dev/null +++ b/src/etc/testcases/taskdefs/optional/image/imageio.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/org/apache/tools/ant/taskdefs/defaults.properties b/src/main/org/apache/tools/ant/taskdefs/defaults.properties index 7b4781c378..c77c200248 100644 --- a/src/main/org/apache/tools/ant/taskdefs/defaults.properties +++ b/src/main/org/apache/tools/ant/taskdefs/defaults.properties @@ -148,6 +148,7 @@ depend=org.apache.tools.ant.taskdefs.optional.depend.Depend ejbjar=org.apache.tools.ant.taskdefs.optional.ejb.EjbJar ftp=org.apache.tools.ant.taskdefs.optional.net.FTP image=org.apache.tools.ant.taskdefs.optional.image.Image +imageio=org.apache.tools.ant.taskdefs.optional.image.ImageIOTask iplanet-ejbc=org.apache.tools.ant.taskdefs.optional.ejb.IPlanetEjbcTask jarlib-available=org.apache.tools.ant.taskdefs.optional.extension.JarLibAvailableTask jarlib-display=org.apache.tools.ant.taskdefs.optional.extension.JarLibDisplayTask @@ -197,7 +198,6 @@ vsslabel=org.apache.tools.ant.taskdefs.optional.vss.MSVSSLABEL wljspc=org.apache.tools.ant.taskdefs.optional.jsp.WLJspc xmlvalidate=org.apache.tools.ant.taskdefs.optional.XMLValidateTask - # deprecated ant tasks (kept for back compatibility) copydir=org.apache.tools.ant.taskdefs.Copydir copyfile=org.apache.tools.ant.taskdefs.Copyfile diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java b/src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java index 1f36d3ef07..4d5be8a3bb 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java @@ -358,8 +358,8 @@ public void execute() throws BuildException { } // deal with the filesets for (FileSet fs : filesets) { - writeCount += processDir(fs.getDir(getProject()), - fs.getDirectoryScanner(getProject()).getIncludedFiles(), + writeCount += processDir(fs.getDir(), + fs.getDirectoryScanner().getIncludedFiles(), dest, mapper); } diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/image/ImageIOTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/image/ImageIOTask.java new file mode 100644 index 0000000000..5e4289c1e9 --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/optional/image/ImageIOTask.java @@ -0,0 +1,389 @@ +/* + * 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.Project; +import org.apache.tools.ant.taskdefs.MatchingTask; +import org.apache.tools.ant.types.FileSet; +import org.apache.tools.ant.types.Mapper; +import org.apache.tools.ant.types.optional.imageio.Draw; +import org.apache.tools.ant.types.optional.imageio.ImageOperation; +import org.apache.tools.ant.types.optional.imageio.Rotate; +import org.apache.tools.ant.types.optional.imageio.Scale; +import org.apache.tools.ant.types.optional.imageio.TransformOperation; +import org.apache.tools.ant.util.FileNameMapper; +import org.apache.tools.ant.util.IdentityMapper; +import org.apache.tools.ant.util.StringUtils; + +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * A MatchingTask which relies on Java ImageIO to read existing image files + * and write the results of AWT image manipulation operations. + * The operations are represented as ImageOperation DataType objects. + * The task replaces a JAI-based Image task which no longer works with Java 9+. + * + * @see ImageOperation + * @see org.apache.tools.ant.types.DataType + */ +public class ImageIOTask extends MatchingTask { + private final List instructions = new ArrayList<>(); + private boolean overwrite = false; + private final List filesets = new ArrayList<>(); + private File srcDir = null; + private File destDir = null; + + private String format; + + private boolean garbageCollect = false; + + private boolean failOnError = true; + + private Mapper mapperElement = null; + + /** + * Add a set of files to be deleted. + * @param set the FileSet to add. + */ + public void addFileset(FileSet set) { + filesets.add(set); + } + + /** + * Set whether to fail on error. + * If false, note errors to the output but keep going. + * @param flag true or false. + */ + public void setFailOnError(boolean flag) { + failOnError = flag; + } + + /** + * Set the source dir to find the image files. + * @param srcDir the directory in which the image files reside. + */ + public void setSrcdir(File srcDir) { + this.srcDir = srcDir; + } + + /** + * Set the image format. + * @param encoding the String image format. + */ + public void setEncoding(String encoding) { + format = encoding; + } + + /** + * Set whether to overwrite a file if there is a naming conflict. + * @param overwrite whether to overwrite. + */ + public void setOverwrite(boolean overwrite) { + this.overwrite = overwrite; + } + + /** + * Set whether to invoke Garbage Collection after each image processed. + * Defaults to false. + * @param gc whether to invoke the garbage collector. + */ + public void setGc(boolean gc) { + garbageCollect = gc; + } + + /** + * Set the destination directory for manipulated images. + * @param destDir The destination directory. + */ + public void setDestDir(File destDir) { + this.destDir = destDir; + } + + /** + * Add an ImageOperation to chain. + * @param instr The ImageOperation to append to the chain. + */ + public void addImageOperation(ImageOperation instr) { + instructions.add(instr); + } + + /** + * Add a Rotate ImageOperation to the chain. + * @param instr The Rotate operation to add to the chain. + * @see Rotate + */ + public void addRotate(Rotate instr) { + instructions.add(instr); + } + + /** + * Add a Scale ImageOperation to the chain. + * @param instr The Scale operation to add to the chain. + * @see Scale + */ + public void addScale(Scale instr) { + instructions.add(instr); + } + + /** + * Add a Draw ImageOperation to the chain. DrawOperation + * DataType objects can be nested inside the Draw object. + * @param instr The Draw operation to add to the chain. + * @see Draw + * @see org.apache.tools.ant.types.optional.image.DrawOperation + */ + public void addDraw(Draw instr) { + instructions.add(instr); + } + + /** + * Add an ImageOperation to chain. + * @param instr The ImageOperation to append to the chain. + * @since Ant 1.7 + */ + public void add(ImageOperation instr) { + addImageOperation(instr); + } + + /** + * Defines the mapper to map source to destination files. + * @return a mapper to be configured + * @exception BuildException if more than one mapper is defined + * @since Ant 1.8.0 + */ + public Mapper createMapper() throws BuildException { + if (mapperElement != null) { + throw new BuildException("Cannot define more than one mapper", + getLocation()); + } + mapperElement = new Mapper(getProject()); + return mapperElement; + } + + /** + * Add a nested filenamemapper. + * @param fileNameMapper the mapper to add. + * @since Ant 1.8.0 + */ + public void add(FileNameMapper fileNameMapper) { + createMapper().add(fileNameMapper); + } + + /** + * Executes all the chained ImageOperations on the files inside + * the directory. + * @param srcDir File + * @param srcNames String[] + * @param dstDir File + * @param mapper FileNameMapper + * @return int + * @since Ant 1.8.0 + */ + public int processDir(final File srcDir, final String[] srcNames, + final File dstDir, final FileNameMapper mapper) { + int writeCount = 0; + + for (final String srcName : srcNames) { + final File srcFile = new File(srcDir, srcName).getAbsoluteFile(); + + final String[] dstNames = mapper.mapFileName(srcName); + if (dstNames == null) { + log(srcFile + " skipped, don't know how to handle it", + Project.MSG_VERBOSE); + continue; + } + + for (String dstName : dstNames) { + final File dstFile = new File(dstDir, dstName).getAbsoluteFile(); + + if (dstFile.exists()) { + // avoid overwriting unless necessary + if (!overwrite + && srcFile.lastModified() <= dstFile.lastModified()) { + + log(srcFile + " omitted as " + dstFile + + " is up to date.", Project.MSG_VERBOSE); + + // don't overwrite the file + continue; + } + + // avoid extra work while overwriting + if (!srcFile.equals(dstFile)) { + dstFile.delete(); + } + } + processFile(srcFile, dstFile); + ++writeCount; + } + } + + // run the garbage collector if wanted + if (garbageCollect) { + System.gc(); + } + + return writeCount; + } + + /** + * Executes all the chained ImageOperations on the file + * specified. + * @param file The file to be processed. + * @deprecated this method isn't used anymore + */ + @Deprecated + public void processFile(File file) { + processFile(file, new File(destDir == null + ? srcDir : destDir, file.getName())); + } + + /** + * Executes all the chained ImageOperations on the file + * specified. + * @param file The file to be processed. + * @param newFile The file to write to. + * @since Ant 1.8.0 + */ + public void processFile(File file, File newFile) { + log("Processing File: " + file.getAbsolutePath()); + + try (ImageInputStream input = ImageIO.createImageInputStream(file)) { + Iterator readers = ImageIO.getImageReaders(input); + if (!readers.hasNext()) { + log("No decoder available, skipping"); + return; + } + ImageReader reader = readers.next(); + if (format == null) { + format = reader.getFormatName(); + } + reader.setInput(input); + + BufferedImage image = reader.read(0); + reader.dispose(); + + for (ImageOperation instr : instructions) { + if (instr instanceof TransformOperation) { + image = ((TransformOperation) instr).executeTransformOperation(image); + } else { + log("Not a TransformOperation: " + instr); + } + } + + File dstParent = newFile.getParentFile(); + if (!dstParent.isDirectory() + && !(dstParent.mkdirs() || dstParent.isDirectory())) { + throw new BuildException("Failed to create parent directory %s", + dstParent); + } + + if (overwrite && newFile.exists() && !newFile.equals(file)) { + newFile.delete(); + } + + if (!ImageIO.write(image, format, newFile)) { + log("Failed to save the transformed file"); + } + } catch (IOException | RuntimeException err) { + if (!file.equals(newFile)) { + newFile.delete(); + } + if (!failOnError) { + log("Error processing file: " + err); + } else { + throw new BuildException(err); + } + } + } + + /** + * Executes the Task. + * @throws BuildException on error. + */ + @Override + public void execute() throws BuildException { + + validateAttributes(); + + try { + File dest = (destDir != null) ? destDir : srcDir; + + int writeCount = 0; + + // build mapper + final FileNameMapper mapper = mapperElement == null + ? new IdentityMapper() : mapperElement.getImplementation(); + + // deal with specified srcDir + if (srcDir != null) { + writeCount += processDir(srcDir, + super.getDirectoryScanner(srcDir).getIncludedFiles(), dest, + mapper); + } + // deal with the filesets + for (FileSet fs : filesets) { + writeCount += processDir(fs.getDir(), + fs.getDirectoryScanner().getIncludedFiles(), + dest, mapper); + } + + if (writeCount > 0) { + log("Processed " + writeCount + (writeCount == 1 ? " image." : " images.")); + } + + } catch (Exception err) { + log(StringUtils.getStackTrace(err), Project.MSG_ERR); + throw new BuildException(err.getMessage()); + } + } + + /** + * Ensure we have a consistent and legal set of attributes, and set + * any internal flags necessary based on different combinations + * of attributes. + * @throws BuildException on error. + */ + protected void validateAttributes() throws BuildException { + if (srcDir == null && filesets.isEmpty()) { + throw new BuildException( + "Specify at least one source--a srcDir or a fileset."); + } + if (srcDir == null && destDir == null) { + throw new BuildException("Specify the destDir, or the srcDir."); + } + if (format != null && !Arrays.asList(ImageIO.getReaderFormatNames()).contains(format)) { + throw new BuildException("Unknown image format '" + format + "'" + + System.lineSeparator() + "Use any of " + + Arrays.stream(ImageIO.getReaderFormatNames()).sorted() + .collect(Collectors.joining(", "))); + } + } +} + diff --git a/src/main/org/apache/tools/ant/types/optional/image/Text.java b/src/main/org/apache/tools/ant/types/optional/image/Text.java index 4f92d31cb9..c064229128 100644 --- a/src/main/org/apache/tools/ant/types/optional/image/Text.java +++ b/src/main/org/apache/tools/ant/types/optional/image/Text.java @@ -32,7 +32,7 @@ public class Text extends ImageOperation implements DrawOperation { private static final int DEFAULT_POINT = 10; - private String strText = ""; + private String string = ""; private String font = "Arial"; private int point = DEFAULT_POINT; private boolean bold = false; @@ -44,7 +44,7 @@ public class Text extends ImageOperation implements DrawOperation { * @param str the string to be used. */ public void setString(String str) { - strText = str; + string = str; } /** @@ -93,7 +93,7 @@ public void setItalic(boolean state) { */ @Override public PlanarImage executeDrawOperation() { - log("\tCreating Text \"" + strText + "\""); + log("\tCreating Text \"" + string + "\""); int width = 1; int height = 1; @@ -107,7 +107,7 @@ public PlanarImage executeDrawOperation() { Font f = createFont(); FontMetrics fmetrics = graphics.getFontMetrics(f); height = fmetrics.getMaxAscent() + fmetrics.getMaxDescent(); - width = fmetrics.stringWidth(strText); + width = fmetrics.stringWidth(string); bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR_PRE); graphics = bi.createGraphics(); @@ -119,7 +119,7 @@ public PlanarImage executeDrawOperation() { graphics.setFont(f); graphics.setColor(ColorMapper.getColorByName(color)); - graphics.drawString(strText, 0, height - fmetrics.getMaxDescent()); + graphics.drawString(string, 0, height - fmetrics.getMaxDescent()); return PlanarImage.wrapRenderedImage(bi); } diff --git a/src/main/org/apache/tools/ant/types/optional/imageio/Arc.java b/src/main/org/apache/tools/ant/types/optional/imageio/Arc.java new file mode 100644 index 0000000000..0fdbaf7dcd --- /dev/null +++ b/src/main/org/apache/tools/ant/types/optional/imageio/Arc.java @@ -0,0 +1,97 @@ +/* + * 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.Arc2D; +import java.awt.image.BufferedImage; + +/** + * Draw an arc. + */ +public class Arc extends BasicShape implements DrawOperation { + private int start = 0; + private int stop = 0; + private int type = Arc2D.OPEN; + + /** + * Set the start of the arc. + * @param start the start of the arc. + */ + public void setStart(int start) { + this.start = start; + } + + /** + * Set the stop of the arc. + * @param stop the stop of the arc. + */ + public void setStop(int stop) { + this.stop = stop; + } + + /** + * Set the type of arc. + * @param strType the type to use - open, pie or chord. + * @todo refactor using an EnumeratedAttribute + */ + public void setType(String strType) { + if ("open".equalsIgnoreCase(strType)) { + type = Arc2D.OPEN; + } else if ("pie".equalsIgnoreCase(strType)) { + type = Arc2D.PIE; + } else if ("chord".equalsIgnoreCase(strType)) { + type = Arc2D.CHORD; + } + } + + /** {@inheritDoc}. */ + @Override + public BufferedImage executeDrawOperation() { + BufferedImage bi = new BufferedImage(width + (strokeWidth * 2), + height + (strokeWidth * 2), 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 Arc2D.Double(strokeWidth, strokeWidth, width, + height, start, stop, type)); + } + + if (!"transparent".equalsIgnoreCase(fill)) { + graphics.setColor(ColorMapper.getColorByName(fill)); + graphics.fill(new Arc2D.Double(strokeWidth, strokeWidth, + width, height, start, stop, type)); + } + + 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; + } +} diff --git a/src/main/org/apache/tools/ant/types/optional/imageio/BasicShape.java b/src/main/org/apache/tools/ant/types/optional/imageio/BasicShape.java new file mode 100644 index 0000000000..655931f8c6 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/optional/imageio/BasicShape.java @@ -0,0 +1,70 @@ +/* + * 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; + + +/** Draw a basic shape */ +public abstract class BasicShape extends ImageOperation implements DrawOperation { + // CheckStyle:VisibilityModifier OFF - bc + protected int width = 0; + protected int height = 0; + protected int strokeWidth = 0; + protected String stroke = "black"; + protected String fill = "transparent"; + // CheckStyle:VisibilityModifier ON + + /** + * Set the width. + * @param w the width of the shape. + */ + public void setWidth(int w) { + width = w; + } + + /** + * Set the height. + * @param h the height of the shape. + */ + public void setHeight(int h) { + height = h; + } + + /** + * Set the stroke width attribute. + * @param sw the value to use. + */ + public void setStrokewidth(int sw) { + strokeWidth = sw; + } + + /** + * Set the stroke attribute. + * @param col the color value to use. + */ + public void setStroke(String col) { + stroke = col; + } + + /** + * Set the fill attribute. + * @param col the color value to use. + */ + public void setFill(String col) { + fill = col; + } +} 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 0000000000..997a99ded7 --- /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() { + } + +} 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 0000000000..2862bb9102 --- /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; + } +} 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 0000000000..b525536395 --- /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(); +} 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 0000000000..20b732d9a1 --- /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; + } +} 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 0000000000..9d25d4d4a7 --- /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 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); + } +} 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 0000000000..bc4fb2563a --- /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; + } +} 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 0000000000..98bf5c05ea --- /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; + } + +} 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 0000000000..d745a79d9d --- /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; + } +} 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 0000000000..39ccc0605e --- /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); + } +} 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 0000000000..ba23cb14fb --- /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); +} 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 0000000000..c96691d0dd --- /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)); + } + } + +}