KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > optional > RasterizerTask


1 /*
2
3    Copyright 2001-2002 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.tools.ant.taskdefs.optional;
19
20 // -- Ant classes ------------------------------------------------------------
21
import org.apache.tools.ant.Project;
22 import org.apache.tools.ant.BuildException;
23 import org.apache.tools.ant.Task;
24 import org.apache.tools.ant.DirectoryScanner;
25 import org.apache.tools.ant.taskdefs.MatchingTask;
26 import org.apache.tools.ant.types.EnumeratedAttribute;
27 import org.apache.tools.ant.types.FileSet;
28 import org.apache.tools.ant.util.JAXPUtils;
29
30 // -- Batik classes ----------------------------------------------------------
31
import org.apache.batik.apps.rasterizer.SVGConverter;
32 import org.apache.batik.apps.rasterizer.DestinationType;
33 import org.apache.batik.apps.rasterizer.SVGConverterException;
34 import org.apache.batik.transcoder.image.JPEGTranscoder;
35 import org.apache.batik.util.XMLResourceDescriptor;
36
37 // -- SAX classes ------------------------------------------------------------
38
import org.xml.sax.XMLReader JavaDoc;
39
40 // -- Java SDK classes -------------------------------------------------------
41
import java.awt.geom.Rectangle2D JavaDoc;
42 import java.awt.Color JavaDoc;
43 import java.io.File JavaDoc;
44 import java.util.StringTokenizer JavaDoc;
45 import java.util.Vector JavaDoc;
46 import java.util.Iterator JavaDoc;
47 import java.util.ArrayList JavaDoc;
48 import java.util.List JavaDoc;
49
50
51
52 /**
53  * This Ant task can be used to convert SVG images to raster images.
54  *
55  * <p>Possible result raster image formats are PNG, JPEG, TIFF, and PDF.
56  * Batik {@link SVGConverter} is used to execute the conversion. You need
57  * <em>Batik</em> to produce the first three raster image types and
58  * <em>FOP</em> to produce PDF.</p>
59  *
60  * @see SVGConverter SVGConverter
61  * @see org.apache.batik.apps.rasterizer.Main Main
62  *
63  * @author <a HREF="mailto:ruini@iki.fi">Henri Ruini</a>
64  * @version $Id: RasterizerTask.java,v 1.3 2004/08/18 07:11:29 vhardy Exp $
65  */

66 public class RasterizerTask extends MatchingTask {
67
68     // -- Constants ----------------------------------------------------------
69
/**
70      * Default quality value for JPEGs. This value is used when
71      * the user doesn't set the quality.
72      */

73     private static final float DEFAULT_QUALITY = 0.99f;
74     /**
75      * Magic string indicating that any JAXP conforming XML parser can
76      * be used.
77      */

78     private static final String JavaDoc JAXP_PARSER = "jaxp";
79
80     // -- Variables ----------------------------------------------------------
81
/** Result image type. The default is PNG. */
82     protected DestinationType resultType = DestinationType.PNG;
83
84     /** Output image height. */
85     protected float height = Float.NaN;
86     /** Output image width. */
87     protected float width = Float.NaN;
88     /** Maximum output image height. */
89     protected float maxHeight = Float.NaN;
90     /** Maximum output image width. */
91     protected float maxWidth = Float.NaN;
92     /** Output image quality. */
93     protected float quality = Float.NaN;
94     /** Output Area of Interest (AOI) area. */
95     protected String JavaDoc area = null;
96     /** Output background color. */
97     protected String JavaDoc background = null;
98     /** Media type of CSS file used to produce output images. */
99     protected String JavaDoc mediaType = null;
100     /** Output pixel size - dots per inch. */
101     protected float dpi = Float.NaN;
102     /** Output image language. */
103     protected String JavaDoc language = null;
104     /** XML parser class currently in use. */
105     protected String JavaDoc readerClassName = XMLResourceDescriptor.getXMLParserClassName();
106
107
108     /** Source image path. */
109     protected File JavaDoc srcFile = null;
110     /** Destination image path. */
111     protected File JavaDoc destFile = null;
112     /** Source directory of images. */
113     protected File JavaDoc srcDir = null;
114     /** Destination directory for output images. */
115     protected File JavaDoc destDir = null;
116     /** Contents of <code>fileset</code> elements. */
117     protected Vector JavaDoc filesets = new Vector JavaDoc();
118
119     /** Converter object used to convert SVG images to raster images. */
120     protected SVGConverter converter;
121
122
123
124     // -- Constructors -------------------------------------------------------
125
/**
126      * Initializes a new rasterizer task.
127      */

128     public RasterizerTask() {
129         converter = new SVGConverter(new RasterizerTaskSVGConverterController(this));
130     }
131
132
133
134     // -- Methods required by Ant --------------------------------------------
135
/**
136      * Gets <code>result</code> attribute value.
137      *
138      * <p>See the documentation for valid values.</p>
139      *
140      * @param type Attribute value.
141      */

142     public void setResult(ValidImageTypes type) {
143         this.resultType = getResultType(type.getValue());
144     }
145
146     /**
147      * Gets <code>height</code> attribute value.
148      *
149      * <p>The attribute is optional.</p>
150      *
151      * @param height Attribute value.
152      */

153     public void setHeight(float height) {
154         this.height = height;
155     }
156
157     /**
158      * Gets <code>width</code> attribute value.
159      *
160      * <p>The attribute is optional.</p>
161      *
162      * @param width Attribute value.
163      */

164     public void setWidth(float width) {
165         this.width = width;
166     }
167
168     /**
169      * Gets <code>maxheight</code> attribute value.
170      *
171      * <p>The attribute is optional.</p>
172      *
173      * @param height Attribute value.
174      */

175     public void setMaxheight(float height) {
176         this.maxHeight = height;
177     }
178
179     /**
180      * Gets <code>maxwidth</code> attribute value.
181      *
182      * <p>The attribute is optional.</p>
183      *
184      * @param width Attribute value.
185      */

186     public void setMaxwidth(float width) {
187         this.maxWidth = width;
188     }
189
190     /**
191      * Gets <code>quality</code> attribute value.
192      *
193      * <p>The value have to be a float between 0 and 1 excluded.
194      * The attribute is optional.</p>
195      *
196      * @param quality Attribute value.
197      */

198     public void setQuality(float quality) {
199         this.quality = quality;
200     }
201
202     /**
203      * Gets <code>area</code> attribute value.
204      *
205      * <p>The value have to be four integers separated with whitespaces or
206      * commas.
207      * The attribute is optional.</p>
208      *
209      * @param area Attribute value.
210      */

211     public void setArea(String JavaDoc area) {
212         this.area = area;
213     }
214
215     /**
216      * Gets <code>bg</code> attribute value.
217      *
218      * <p>The value have to be three or four integers separated with
219      * whitespaces or commas.
220      * The attribute is optional.</p>
221      *
222      * @param bg Attribute value.
223      */

224     public void setBg(String JavaDoc bg) {
225         this.background = bg;
226     }
227
228     /**
229      * Gets <code>media</code> attribute value.
230      *
231      * <p>The value have to a media type defined in CSS2 specifications.
232      * Only visual media group is supported.</p>
233      *
234      * @param media Attribute value.
235      */

236     public void setMedia(ValidMediaTypes media) {
237         this.mediaType = media.getValue();
238     }
239
240     /**
241      * Gets <code>dpi</code> attribute value.
242      *
243      * <p>The value have to be a positive float.
244      * The attribute is optional.</p>
245      *
246      * @param dpi Attribute value.
247      */

248     public void setDpi(float dpi) {
249         this.dpi = dpi;
250     }
251
252     /**
253      * Gets <code>lang</code> attribute value.
254      *
255      * <p>See SVG specification for valid values.
256      * The attribute is optional.</p>
257      *
258      * @param lang Attribute value.
259      */

260     public void setLang(String JavaDoc language) {
261         this.language = language;
262     }
263
264     /**
265      * Sets classname of an XML parser.
266      * The attribute is optional.
267      *
268      * @param value Java classname of an XML parser.
269      */

270     public void setClassname(String JavaDoc value) {
271         this.readerClassName = value;
272     }
273
274     /**
275      * Gets <code>src</code> attribute value.
276      *
277      * <p>One of the following have to have a value: this attribute,
278      * <code>srcdir</code> attribute or <code>fileset</code> element.</p>
279      *
280      * @param file Attribute value.
281      */

282     public void setSrc(File JavaDoc file) {
283         this.srcFile = file;
284     }
285
286     /**
287      * Gets <code>dest</code> attribute value.
288      *
289      * <p>The attribute have to have a value when
290      * <code>src</code> attribute has a value.</p>
291      *
292      * @param file Attribute value.
293      */

294     public void setDest(File JavaDoc file) {
295         this.destFile = file;
296     }
297
298     /**
299      * Gets <code>srcdir</code> attribute value.
300      *
301      * <p>If <code>srcfile</code> attribute doesn't have a value then
302      * either this attribute have to have a value or the element have
303      * to contain <code>fileset</code> elements.</p>
304      *
305      * @param dir Attribute value.
306      */

307     public void setSrcdir(File JavaDoc dir) {
308         this.srcDir = dir;
309     }
310
311     /**
312      * Gets <code>destdir</code> attribute value.
313      *
314      * <p>This attribute have to have a value if either
315      * <code>srcdir</code> attribute or <code>fileset</code> elements
316      * exists.</p>
317      *
318      * @param dir Attribute value.
319      */

320     public void setDestdir(File JavaDoc dir) {
321         this.destDir = dir;
322     }
323
324     /**
325      * Reads <code>fileset</code> elements.
326      *
327      * <p><code>fileset</code> elements can be used when there are many files
328      * to be rasterized.</p>
329      *
330      * @param set <code>fileset</code> elements
331      */

332     public void addFileset(FileSet set) {
333         filesets.addElement(set);
334     }
335
336     /**
337      * Validates and sets input values and files, then starts the conversion
338      * process.
339      *
340      * <p>See Ant documentation to find out more about the meaning of
341      * <code>execute</code> in Ant task.</p>
342      *
343      * @throws BuildException Parameters are not set correctly or the conversion fails.
344      */

345     public void execute() throws BuildException {
346
347         String JavaDoc[] sources; // Array of input files.
348

349         // Store default XML parser information and set user class.
350
String JavaDoc defaultParser = XMLResourceDescriptor.getXMLParserClassName();
351         // Throws BuildException.
352
XMLResourceDescriptor.setXMLParserClassName(getParserClassName(readerClassName));
353
354         try {
355             // Check file and directory values.
356
if(this.srcFile != null) {
357                 if(this.destFile == null) {
358                     throw new BuildException("dest attribute is not set.");
359                 }
360             } else {
361                 if((this.srcDir == null) && (filesets.size() == 0)) {
362                     throw new BuildException("No input files! Either srcdir or fileset have to be set.");
363                 }
364                 if(this.destDir == null) {
365                     throw new BuildException("destdir attribute is not set!");
366                 }
367             }
368
369             // Throws BuildException.
370
setRasterizingParameters();
371
372             // Get and set source(s).
373
sources = getSourceFiles();
374             converter.setSources(sources);
375
376             // Set destination.
377
if(this.srcFile != null) {
378                 converter.setDst(this.destFile);
379             } else {
380                 converter.setDst(this.destDir);
381             }
382
383             // Input filenames are stored in the converter and
384
// everything is ready for the conversion.
385

386             log("Rasterizing " + sources.length +
387                 (sources.length == 1 ? " image " : " images ") +
388                 "from SVG to " + this.resultType.toString() + ".");
389
390             try {
391                 converter.execute();
392             } catch(SVGConverterException sce) {
393                 throw new BuildException(sce.getMessage());
394             }
395         } finally {
396             // Restore default XML parser for the next execute.
397
XMLResourceDescriptor.setXMLParserClassName(defaultParser);
398         }
399     }
400
401
402
403     // -- Internal methods ---------------------------------------------------
404
/**
405      * Checks and sets parameter values to the converter.
406      *
407      * <p>Some invalid values are just swallowed and default values are
408      * used instead. This is done when the invalid value cannot
409      * be correctly differentiated from the default value and the default
410      * value doesn't cause any harm. <code>BuildException</code> is thrown
411      * if the invalid value is clearly recognized.</p>
412      *
413      * @throws BuildException Invalid parameter value.
414      */

415     protected void setRasterizingParameters()
416         throws BuildException {
417         if(this.resultType != null) {
418             converter.setDestinationType(this.resultType);
419         } else {
420             throw new BuildException("Unknown value in result parameter.");
421         }
422         // Set size values.
423
if(!Float.isNaN(this.width)) {
424             if(this.width < 0) {
425                 throw new BuildException("Value of width parameter must positive.");
426             }
427             converter.setWidth(this.width);
428         }
429         if(!Float.isNaN(this.height)) {
430             if(this.height < 0) {
431                 throw new BuildException("Value of height parameter must positive.");
432             }
433             converter.setHeight(this.height);
434         }
435         // Set maximum size values.
436
if(!Float.isNaN(this.maxWidth)) {
437             if(this.maxWidth < 0) {
438                 throw new BuildException("Value of maxwidth parameter must positive.");
439             }
440             converter.setMaxWidth(this.maxWidth);
441         }
442         if(!Float.isNaN(this.maxHeight)) {
443             if(this.maxHeight < 0) {
444                 throw new BuildException("Value of maxheight parameter must positive.");
445             }
446             converter.setMaxHeight(this.maxHeight);
447         }
448         // The quality is just swallowed if the result type is not correct.
449
if(allowedToSetQuality(resultType)) {
450             if(!Float.isNaN(this.quality)) {
451                 // Throws BuildException.
452
converter.setQuality(getQuality(this.quality));
453             } else {
454                 // Set something to quiet irritating error
455
// from JPEGTranscoder.
456
converter.setQuality(DEFAULT_QUALITY);
457             }
458         }
459         if(this.area != null) {
460             // Throws BuildException.
461
converter.setArea(getAreaOfInterest(this.area));
462         }
463         if(this.background != null) {
464             // Throws BuildException.
465
converter.setBackgroundColor(getBackgroundColor(this.background));
466         }
467         if(this.mediaType != null) {
468             // Ant takes care of the correct media type values.
469
converter.setMediaType(this.mediaType);
470         }
471         if(!Float.isNaN(this.dpi)) {
472             if(this.dpi < 0) {
473                 throw new BuildException("Value of dpi parameter must positive.");
474             }
475             // The calculation is the same as 2.54/dpi*10 where
476
converter.setPixelUnitToMillimeter(25.4f/this.dpi);
477         }
478         if(this.language != null) {
479             converter.setLanguage(this.language);
480         }
481     }
482
483     /**
484      * Gets source files from the task parameters and child elements,
485      * combines those to a one list, and returns the list.
486      *
487      * @return Array of source filename strings.
488      */

489     protected String JavaDoc[] getSourceFiles() {
490
491         List JavaDoc inputFiles = new ArrayList JavaDoc(); // Input files in temp list.
492

493         if(this.srcFile != null) {
494             // Only one source and destination file have been set.
495
inputFiles.add(this.srcFile.getAbsolutePath());
496         } else {
497             // Unknown number of files have to be converted. destdir
498
// attribute and either srcdir attribute or fileset element
499
// have been set.
500

501             // Read source files from the child patterns.
502
// The value of srcdir attribute overrides the dir attribute in
503
// fileset element.
504
if(this.srcDir != null) {
505                 // fileset is declared in the super class.
506
// Scan to get all the files in srcdir directory that
507
// should be in input files.
508
fileset.setDir(this.srcDir);
509                 DirectoryScanner ds = fileset.getDirectoryScanner(project);
510                 String JavaDoc[] includedFiles = ds.getIncludedFiles();
511                 // Add file and its path to the input file vector.
512
for (int j = 0 ; j < includedFiles.length ; j++) {
513                     File JavaDoc newFile = new File JavaDoc(srcDir.getPath(), includedFiles[j]);
514                     inputFiles.add(newFile.getAbsolutePath());
515                 }
516             }
517             // Read source files from child filesets.
518
for (int i = 0 ; i < filesets.size() ; i++) {
519                 // Scan to get all the files in this fileset that
520
// should be in input files.
521
FileSet fs = (FileSet) filesets.elementAt(i);
522                 DirectoryScanner ds = fs.getDirectoryScanner(project);
523                 String JavaDoc[] includedFiles = ds.getIncludedFiles();
524                 // Add file and its path to the input file vector.
525
for (int j = 0 ; j < includedFiles.length ; j++) {
526                     File JavaDoc newFile = new File JavaDoc(fs.getDir(project).getPath(), includedFiles[j]);
527                     inputFiles.add(newFile.getAbsolutePath());
528                 }
529             }
530         }
531
532         // Convert List to array and return the array.
533
return (String JavaDoc[])inputFiles.toArray(new String JavaDoc[0]);
534     }
535
536     /**
537      * Returns the correct result image type object.
538      *
539      * @param type Result image type as a string.
540      *
541      * @return Result image type as an object or <code>null</code> if the parameter doesn't have corresponding object.
542      */

543     protected DestinationType getResultType(String JavaDoc type) {
544         if(type.equals(DestinationType.PNG_STR)) {
545             return DestinationType.PNG;
546         } else if(type.equals(DestinationType.JPEG_STR)) {
547             return DestinationType.JPEG;
548         } else if(type.equals(DestinationType.TIFF_STR)) {
549             return DestinationType.TIFF;
550         } else if(type.equals(DestinationType.PDF_STR)) {
551             return DestinationType.PDF;
552         }
553         return null;
554     }
555
556     /**
557      * Checks if the quality value can be set. Only result image type
558      * is checked.
559      *
560      * @param type Result image type.
561      *
562      * @return <code>true</code> if the quality can be set and <code>false</code> otherwise.
563      */

564     protected boolean allowedToSetQuality(DestinationType type) {
565         if(!type.toString().equals(DestinationType.JPEG_STR)) {
566             return false;
567         }
568         return true;
569     }
570
571     /**
572      * Returns a valid quality value.
573      *
574      * @param quality Input quality value to be tested.
575      *
576      * @return Valid quality value.
577      *
578      * @throws BuildException Input quality value is not valid.
579      */

580     protected float getQuality(float quality)
581         throws BuildException {
582         if((quality <= 0) || (quality >= 1)) {
583             throw new BuildException("quality parameter value have to be between 0 and 1.");
584         }
585         return quality;
586     }
587
588     /**
589      * Returns a valid Area of Interest (AOI) as a Rectangle2D object.
590      *
591      * @param area AOI input area.
592      *
593      * @return A valid AOI rectangle.
594      *
595      * @throws BuildException AOI area is invalid.
596      */

597     protected Rectangle2D JavaDoc getAreaOfInterest(String JavaDoc area)
598         throws BuildException {
599
600         float x; // Upper left x point value of the area.
601
float y; // Upper left y point value of the area.
602
float width; // Area width value.
603
float height; // Area height value.
604
String JavaDoc token; // A token from the input string.
605
StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(area, ", \t\n\r\f");
606                             // Input string tokenizer.
607

608         if(tokenizer.countTokens() != 4) {
609             throw new BuildException("There must be four numbers in the area parameter: x, y, width, and height.");
610         }
611         try {
612             x = Float.parseFloat(tokenizer.nextToken());
613             y = Float.parseFloat(tokenizer.nextToken());
614             width = Float.parseFloat(tokenizer.nextToken());
615             height = Float.parseFloat(tokenizer.nextToken());
616         } catch(NumberFormatException JavaDoc nfe) {
617             throw new BuildException("Invalid area parameter value: " + nfe.toString());
618         }
619
620         // Negative values are not allowed.
621
if((x < 0) || (y < 0) || (width < 0) || (height < 0)) {
622             throw new BuildException("Negative values are not allowed in area parameter.");
623         }
624
625         return new Rectangle2D.Float JavaDoc(x, y, width, height);
626     }
627
628     /**
629      * Returns a valid background color object.
630      *
631      * @param argb String containing color channel values.
632      *
633      * @return A valid background color.
634      *
635      * @throws BuildException Input value is invalid.
636      */

637     protected Color JavaDoc getBackgroundColor(String JavaDoc argb)
638         throws BuildException {
639
640         int a; // Value of the alpha channel.
641
int r; // Value of the red channel.
642
int g; // Value of the green channel.
643
int b; // Value of the blue channel.
644
String JavaDoc token; // A token from the input string.
645
StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(argb, ", \t\n\r\f");
646                             // Input string tokenizer.
647

648         try {
649             if(tokenizer.countTokens() == 3) {
650                 // Default alpha channel is opaque.
651
a = 255;
652             } else if(tokenizer.countTokens() == 4) {
653                 a = Integer.parseInt(tokenizer.nextToken());
654             } else {
655                 throw new BuildException("There must be either three or four numbers in bg parameter: (alpha,) red, green, and blue.");
656             }
657             r = Integer.parseInt(tokenizer.nextToken());
658             g = Integer.parseInt(tokenizer.nextToken());
659             b = Integer.parseInt(tokenizer.nextToken());
660         } catch(NumberFormatException JavaDoc nfe) {
661             throw new BuildException("Invalid bg parameter value: " + nfe.toString());
662         }
663
664         // Check that the values are valid.
665
if((a < 0) ||(a > 255) || (r < 0) ||(r > 255) ||
666            (g < 0) ||(g > 255) || (b < 0) ||(b > 255)) {
667             throw new BuildException("bg parameter value is invalid. Numbers have to be between 0 and 255.");
668         }
669
670         return new Color JavaDoc(r, g, b, a);
671     }
672
673     /**
674      * Returns name of an XML parser.
675      * Magic string {@link #JAXP_PARSER} is also accepted.
676      *
677      * @param className Name of the XML parser class or a magic string.
678      *
679      * @return Name of an XML parser.
680      *
681      * @throws BuildException Unable to get the name of JAXP parser.
682      */

683     private String JavaDoc getParserClassName(final String JavaDoc className) {
684         String JavaDoc name = className;
685         if(className.equals(JAXP_PARSER)) {
686             // Set first JAXP parser.
687
// Throws BuildException.
688
XMLReader JavaDoc reader = JAXPUtils.getXMLReader();
689             name = reader.getClass().getName();
690         }
691
692         log("Using class '" + name + "' to parse SVG documents.", Project.MSG_VERBOSE);
693         return name;
694     }
695
696
697
698     // -----------------------------------------------------------------------
699
// Inner classes
700
// -----------------------------------------------------------------------
701

702     /**
703      * Defines the valid attribute values for <code>result</code> parameter.
704      *
705      * <p>See the Ant documentation for more information.</p>
706      *
707      * @author <a HREF="mailto:ruini@iki.fi">Henri Ruini</a>
708      * @version $Id: RasterizerTask.java,v 1.3 2004/08/18 07:11:29 vhardy Exp $
709      */

710     public static class ValidImageTypes extends EnumeratedAttribute {
711
712         /**
713          * Defines valid image types.
714          *
715          * @return Array of valid values as strings.
716          */

717         public String JavaDoc[] getValues() {
718             return new String JavaDoc[]
719                 {DestinationType.PNG_STR,
720                 DestinationType.JPEG_STR,
721                 DestinationType.TIFF_STR,
722                 DestinationType.PDF_STR};
723         }
724     }
725
726     /**
727      * Defines the valid attribute values for a media parameter.
728      *
729      * <p>See the Ant documentation for more information.</p>
730      *
731      * @author <a HREF="mailto:ruini@iki.fi">Henri Ruini</a>
732      * @version $Id: RasterizerTask.java,v 1.3 2004/08/18 07:11:29 vhardy Exp $
733      */

734     public static class ValidMediaTypes extends EnumeratedAttribute {
735
736         /**
737          * Defines valid media types.
738          *
739          * <p>The types are defined in CSS2 specification.
740          * Only visual media group is supported.</p>
741          *
742          * @return Array of valid values as strings.
743          */

744         public String JavaDoc[] getValues() {
745             return new String JavaDoc[] {"all", "handheld", "print",
746                 "projection", "screen", "tty", "tv"};
747         }
748     }
749
750 }
751
Popular Tags