/* * Copyright 2002,2004 The Apache Software Foundation * * Licensed 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 com.sun.media.jai.codec.FileSeekableStream; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.taskdefs.MatchingTask; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.optional.image.Draw; import org.apache.tools.ant.types.optional.image.ImageOperation; import org.apache.tools.ant.types.optional.image.Rotate; import org.apache.tools.ant.types.optional.image.Scale; import org.apache.tools.ant.types.optional.image.TransformOperation; import javax.media.jai.JAI; import javax.media.jai.PlanarImage; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.Vector; /** * A MatchingTask which relies on * JAI (Java Advanced Imaging) * to perform image manipulation operations on existing images. The * operations are represented as ImageOperation DataType objects. * The operations are arranged to conform to the Chaining Model * of JAI. * Check out the * * JAI Programming Guide * * @see org.apache.tools.ant.types.optional.image.ImageOperation * @see org.apache.tools.ant.types.DataType */ public class Image extends MatchingTask { protected Vector instructions = new Vector(); protected String str_encoding = "JPEG"; protected boolean overwrite = false; protected boolean garbage_collect = false; private boolean failonerror = true; protected Vector filesets = new Vector(); protected File srcDir = null; protected File destDir = null; /** * Adds a set of files to be deleted. */ public void addFileset(FileSet set) { filesets.addElement(set); } /** * If false, note errors to the output but keep going. * @param failonerror true or false */ public void setFailOnError(boolean failonerror) { this.failonerror = failonerror; } /** * Set the source dir to find the image files. */ public void setSrcdir(File srcDir) { this.srcDir = srcDir; } /** * Set the image encoding type. * * See this table in the JAI Programming Guide. */ public void setEncoding(String encoding) { str_encoding = encoding; } /** * Sets whether or not to overwrite a file if there is a naming conflict. */ public void setOverwrite(boolean overwrite) { this.overwrite = overwrite; } /** * Enables Garbage Collection after each image processed. Defaults to false. */ public void setGc(boolean gc) { garbage_collect = gc; } /** * Sets the destination directory for manipulated images. * @param destDir The destination directory */ public void setDestDir(File destDir) { this.destDir = destDir; } /** * Adds an ImageOperation to chain. * @param instr The ImageOperation to append to the chain */ public void addImageOperation(ImageOperation instr) { instructions.add(instr); } /** * Adds a Rotate ImageOperation to the chain * @param instr The Rotate operation to add to the chain * @see org.apache.tools.ant.types.optional.image.Rotate */ public void addRotate(Rotate instr) { instructions.add(instr); } /** * Adds a Scale ImageOperation to the chain * @param instr The Scale operation to add to the chain * @see org.apache.tools.ant.types.optional.image.Scale */ public void addScale(Scale instr) { instructions.add(instr); } /** * Adds 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 org.apache.tools.ant.types.optional.image.Draw * @see org.apache.tools.ant.types.optional.image.DrawOperation */ public void addDraw(Draw instr) { instructions.add(instr); } /** * Executes all the chained ImageOperations on the file * specified. * @param file The file to be processed */ public void processFile(File file) { try { log("Processing File: " + file.getAbsolutePath()); FileSeekableStream input = new FileSeekableStream(file); PlanarImage image = JAI.create("stream", input); for (int i = 0; i < instructions.size(); i++) { Object instr = instructions.elementAt(i); if (instr instanceof TransformOperation) { image = ((TransformOperation) instr).executeTransformOperation(image); } else { log("Not a TransformOperation: " + instr); } } input.close(); if (str_encoding.toLowerCase().equals("jpg")) { str_encoding = "JPEG"; } else if (str_encoding.toLowerCase().equals("tif")) { str_encoding = "TIFF"; } if (destDir == null) { destDir = srcDir; } File new_file = new File(destDir.getAbsolutePath() + File.separator + file.getName()); if ((overwrite && new_file.exists()) && (!new_file.equals(file))) { new_file.delete(); } FileOutputStream stream = new FileOutputStream(new_file); JAI.create("encode", image, stream, str_encoding.toUpperCase(), null); stream.flush(); stream.close(); } catch (IOException err) { if (!failonerror) { log("Error processing file: " + err); } else { throw new BuildException(err); } } catch (java.lang.RuntimeException rerr) { if (!failonerror) { log("Error processing file: " + rerr); } else { throw new BuildException(rerr); } } } /** * Executes the Task */ public void execute() throws BuildException { validateAttributes(); try { DirectoryScanner ds = null; String[] files = null; ArrayList filesList = new ArrayList(); // deal with specified srcDir if (srcDir != null) { ds = super.getDirectoryScanner(srcDir); files = ds.getIncludedFiles(); for (int i = 0; i < files.length; i++) { filesList.add(new File(srcDir.getAbsolutePath() + File.separator + files[i])); } } // deal with the filesets for (int i = 0; i < filesets.size(); i++) { FileSet fs = (FileSet) filesets.elementAt(i); ds = fs.getDirectoryScanner(getProject()); files = ds.getIncludedFiles(); File fromDir = fs.getDir(getProject()); for (int j = 0; j < files.length; j++) { filesList.add(new File(fromDir.getAbsolutePath() + File.separator + files[j])); } } if (!overwrite) { // remove any files that shouldn't be overwritten. ArrayList filesToRemove = new ArrayList(); for (Iterator i = filesList.iterator(); i.hasNext();) { File f = (File) i.next(); File new_file = new File(destDir.getAbsolutePath() + File.separator + f.getName()); if (new_file.exists()) { filesToRemove.add(f); } } filesList.removeAll(filesToRemove); } // iterator through all the files and process them. for (Iterator i = filesList.iterator(); i.hasNext();) { File file = (File) i.next(); processFile(file); if (garbage_collect) { System.gc(); } } } catch (Exception err) { err.printStackTrace(); 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. */ protected void validateAttributes() throws BuildException { if (srcDir == null && filesets.size() == 0) { 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."); } } }