001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.tools.ant.taskdefs.optional.image;
019:
020: import com.sun.media.jai.codec.FileSeekableStream;
021: import org.apache.tools.ant.BuildException;
022: import org.apache.tools.ant.DirectoryScanner;
023: import org.apache.tools.ant.taskdefs.MatchingTask;
024: import org.apache.tools.ant.types.FileSet;
025: import org.apache.tools.ant.types.optional.image.Draw;
026: import org.apache.tools.ant.types.optional.image.ImageOperation;
027: import org.apache.tools.ant.types.optional.image.Rotate;
028: import org.apache.tools.ant.types.optional.image.Scale;
029: import org.apache.tools.ant.types.optional.image.TransformOperation;
030:
031: import javax.media.jai.JAI;
032: import javax.media.jai.PlanarImage;
033: import java.io.File;
034: import java.io.FileOutputStream;
035: import java.io.IOException;
036: import java.util.ArrayList;
037: import java.util.Iterator;
038: import java.util.Vector;
039:
040: /**
041: * A MatchingTask which relies on <a
042: * href="http://java.sun.com/products/java-media/jai">JAI (Java
043: * Advanced Imaging)</a> to perform image manipulation operations on
044: * existing images. The operations are represented as ImageOperation
045: * DataType objects. The operations are arranged to conform to the
046: * Chaining Model of JAI. Check out the <a
047: * href="http://java.sun.com/products/java-media/jai/forDevelopers/jai1_0_1guide-unc/">
048: * JAI Programming Guide</a>.
049: *
050: * @see org.apache.tools.ant.types.optional.image.ImageOperation
051: * @see org.apache.tools.ant.types.DataType
052: */
053: public class Image extends MatchingTask {
054: // CheckStyle:VisibilityModifier OFF - bc
055: protected Vector instructions = new Vector();
056: protected boolean overwrite = false;
057: protected Vector filesets = new Vector();
058: protected File srcDir = null;
059: protected File destDir = null;
060:
061: // CheckStyle:MemberNameCheck OFF - bc
062:
063: //cannot remove underscores due to protected visibility >:(
064: protected String str_encoding = "JPEG";
065: protected boolean garbage_collect = false;
066:
067: private boolean failonerror = true;
068:
069: // CheckStyle:MemberNameCheck ON
070:
071: // CheckStyle:VisibilityModifier ON
072:
073: /**
074: * Add a set of files to be deleted.
075: * @param set the FileSet to add.
076: */
077: public void addFileset(FileSet set) {
078: filesets.addElement(set);
079: }
080:
081: /**
082: * Set whether to fail on error.
083: * If false, note errors to the output but keep going.
084: * @param failonerror true or false.
085: */
086: public void setFailOnError(boolean failonerror) {
087: this .failonerror = failonerror;
088: }
089:
090: /**
091: * Set the source dir to find the image files.
092: * @param srcDir the directory in which the image files reside.
093: */
094: public void setSrcdir(File srcDir) {
095: this .srcDir = srcDir;
096: }
097:
098: /**
099: * Set the image encoding type. <a
100: * href="http://java.sun.com/products/java-media/jai/forDevelopers/jai1_0_1guide-unc/Encode.doc.html#56610">
101: * See this table in the JAI Programming Guide</a>.
102: * @param encoding the String image encoding.
103: */
104: public void setEncoding(String encoding) {
105: str_encoding = encoding;
106: }
107:
108: /**
109: * Set whether to overwrite a file if there is a naming conflict.
110: * @param overwrite whether to overwrite.
111: */
112: public void setOverwrite(boolean overwrite) {
113: this .overwrite = overwrite;
114: }
115:
116: /**
117: * Set whether to invoke Garbage Collection after each image processed.
118: * Defaults to false.
119: * @param gc whether to invoke the garbage collector.
120: */
121: public void setGc(boolean gc) {
122: garbage_collect = gc;
123: }
124:
125: /**
126: * Set the destination directory for manipulated images.
127: * @param destDir The destination directory.
128: */
129: public void setDestDir(File destDir) {
130: this .destDir = destDir;
131: }
132:
133: /**
134: * Add an ImageOperation to chain.
135: * @param instr The ImageOperation to append to the chain.
136: */
137: public void addImageOperation(ImageOperation instr) {
138: instructions.add(instr);
139: }
140:
141: /**
142: * Add a Rotate ImageOperation to the chain.
143: * @param instr The Rotate operation to add to the chain.
144: * @see org.apache.tools.ant.types.optional.image.Rotate
145: */
146: public void addRotate(Rotate instr) {
147: instructions.add(instr);
148: }
149:
150: /**
151: * Add a Scale ImageOperation to the chain.
152: * @param instr The Scale operation to add to the chain.
153: * @see org.apache.tools.ant.types.optional.image.Scale
154: */
155: public void addScale(Scale instr) {
156: instructions.add(instr);
157: }
158:
159: /**
160: * Add a Draw ImageOperation to the chain. DrawOperation
161: * DataType objects can be nested inside the Draw object.
162: * @param instr The Draw operation to add to the chain.
163: * @see org.apache.tools.ant.types.optional.image.Draw
164: * @see org.apache.tools.ant.types.optional.image.DrawOperation
165: */
166: public void addDraw(Draw instr) {
167: instructions.add(instr);
168: }
169:
170: /**
171: * Add an ImageOperation to chain.
172: * @param instr The ImageOperation to append to the chain.
173: * @since Ant 1.7
174: */
175: public void add(ImageOperation instr) {
176: addImageOperation(instr);
177: }
178:
179: /**
180: * Executes all the chained ImageOperations on the file
181: * specified.
182: * @param file The file to be processed.
183: */
184: public void processFile(File file) {
185: try {
186: log("Processing File: " + file.getAbsolutePath());
187: FileSeekableStream input = new FileSeekableStream(file);
188: PlanarImage image = JAI.create("stream", input);
189: for (int i = 0; i < instructions.size(); i++) {
190: Object instr = instructions.elementAt(i);
191: if (instr instanceof TransformOperation) {
192: image = ((TransformOperation) instr)
193: .executeTransformOperation(image);
194: } else {
195: log("Not a TransformOperation: " + instr);
196: }
197: }
198: input.close();
199:
200: if (str_encoding.toLowerCase().equals("jpg")) {
201: str_encoding = "JPEG";
202: } else if (str_encoding.toLowerCase().equals("tif")) {
203: str_encoding = "TIFF";
204: }
205: if (destDir == null) {
206: destDir = srcDir;
207: }
208: File newFile = new File(destDir, file.getName());
209:
210: if ((overwrite && newFile.exists())
211: && (!newFile.equals(file))) {
212: newFile.delete();
213: }
214: FileOutputStream stream = new FileOutputStream(newFile);
215:
216: JAI.create("encode", image, stream, str_encoding
217: .toUpperCase(), null);
218: stream.flush();
219: stream.close();
220: } catch (IOException err) {
221: if (!failonerror) {
222: log("Error processing file: " + err);
223: } else {
224: throw new BuildException(err);
225: }
226: } catch (java.lang.RuntimeException rerr) {
227: if (!failonerror) {
228: log("Error processing file: " + rerr);
229: } else {
230: throw new BuildException(rerr);
231: }
232: }
233: }
234:
235: /**
236: * Executes the Task.
237: * @throws BuildException on error.
238: */
239: public void execute() throws BuildException {
240:
241: validateAttributes();
242:
243: try {
244: DirectoryScanner ds = null;
245: String[] files = null;
246: ArrayList filesList = new ArrayList();
247:
248: // deal with specified srcDir
249: if (srcDir != null) {
250: ds = super .getDirectoryScanner(srcDir);
251:
252: files = ds.getIncludedFiles();
253: for (int i = 0; i < files.length; i++) {
254: filesList.add(new File(srcDir, files[i]));
255: }
256: }
257: // deal with the filesets
258: for (int i = 0; i < filesets.size(); i++) {
259: FileSet fs = (FileSet) filesets.elementAt(i);
260: ds = fs.getDirectoryScanner(getProject());
261: files = ds.getIncludedFiles();
262: File fromDir = fs.getDir(getProject());
263: for (int j = 0; j < files.length; j++) {
264: filesList.add(new File(fromDir, files[j]));
265: }
266: }
267: if (!overwrite) {
268: // remove any files that shouldn't be overwritten.
269: ArrayList filesToRemove = new ArrayList();
270: for (Iterator i = filesList.iterator(); i.hasNext();) {
271: File f = (File) i.next();
272: File newFile = new File(destDir, f.getName());
273: if (newFile.exists()) {
274: filesToRemove.add(f);
275: }
276: }
277: filesList.removeAll(filesToRemove);
278: }
279: // iterator through all the files and process them.
280: for (Iterator i = filesList.iterator(); i.hasNext();) {
281: File file = (File) i.next();
282:
283: processFile(file);
284: if (garbage_collect) {
285: System.gc();
286: }
287: }
288: } catch (Exception err) {
289: err.printStackTrace();
290: throw new BuildException(err.getMessage());
291: }
292: }
293:
294: /**
295: * Ensure we have a consistent and legal set of attributes, and set
296: * any internal flags necessary based on different combinations
297: * of attributes.
298: * @throws BuildException on error.
299: */
300: protected void validateAttributes() throws BuildException {
301: if (srcDir == null && filesets.size() == 0) {
302: throw new BuildException("Specify at least one source"
303: + "--a srcDir or a fileset.");
304: }
305: if (srcDir == null && destDir == null) {
306: throw new BuildException(
307: "Specify the destDir, or the srcDir.");
308: }
309: }
310: }
|