Author: bodewig Date: Tue Aug 25 13:52:17 2009 New Revision: 807633 URL: http://svn.apache.org/viewvc?rev=807633&view=rev Log: Add mapper support to <image>. PR 23243. Submitted by Rob Oxspring
Modified: ant/core/trunk/WHATSNEW ant/core/trunk/docs/manual/OptionalTasks/image.html ant/core/trunk/src/etc/testcases/taskdefs/optional/image/image.xml ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java ant/core/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageTest.java Modified: ant/core/trunk/WHATSNEW URL: http://svn.apache.org/viewvc/ant/core/trunk/WHATSNEW?rev=807633&r1=807632&r2=807633&view=diff ============================================================================== --- ant/core/trunk/WHATSNEW (original) +++ ant/core/trunk/WHATSNEW Tue Aug 25 13:52:17 2009 @@ -150,6 +150,12 @@ java.vm.version for the Created-By Manifest attribute. Bugzilla Report 47632. + * The <image> task now supports a nested mapper. In order to + implement this, the Java API of the task had to change so any + custom subclass overriding the processFile method will need to + adapt (by overriding the new two-arg processFile method). + Bugzilla Report 23243. + Fixed bugs: ----------- Modified: ant/core/trunk/docs/manual/OptionalTasks/image.html URL: http://svn.apache.org/viewvc/ant/core/trunk/docs/manual/OptionalTasks/image.html?rev=807633&r1=807632&r2=807633&view=diff ============================================================================== --- ant/core/trunk/docs/manual/OptionalTasks/image.html (original) +++ ant/core/trunk/docs/manual/OptionalTasks/image.html Tue Aug 25 13:52:17 2009 @@ -200,6 +200,19 @@ </tr> </table> +<h4>mapper</h4> +<p><em>Since Ant 1.8.0</em></p> + +<p>You can define filename transformations by using a + nested <a href="../CoreTypes/mapper.html">mapper</a> element. The + default mapper used by + <code><image></code> is + the <a href="../CoreTypes/mapper.html#identity-mapper">identity + mapper</a>.</p> + +<p>You can also use a filenamemapper type in place of the mapper + element.</p> + <h3>Examples</h3> <blockquote><pre> @@ -229,6 +242,15 @@ <p>Same as above but stores the result in <i>dest</i>.</p> <blockquote><pre> +<image srcdir="src" destdir="dest" includes="*.png"> + <scale proportions="width" width="40"/> + <globmapper from="*" to="scaled-*"/> +</image> +</pre></blockquote> +<p>Same as above but stores the resulting file names will be prefixed + by "scaled-".</p> + +<blockquote><pre> </pre></blockquote> Modified: ant/core/trunk/src/etc/testcases/taskdefs/optional/image/image.xml URL: http://svn.apache.org/viewvc/ant/core/trunk/src/etc/testcases/taskdefs/optional/image/image.xml?rev=807633&r1=807632&r2=807633&view=diff ============================================================================== --- ant/core/trunk/src/etc/testcases/taskdefs/optional/image/image.xml (original) +++ ant/core/trunk/src/etc/testcases/taskdefs/optional/image/image.xml Tue Aug 25 13:52:17 2009 @@ -66,4 +66,11 @@ </image> </target> + <target name="testSimpleScaleWithMapper" depends="init"> + <image includes="*.jpg" srcdir="${src.dir}" + destdir="${dest.dir}" overwrite="no" failonerror="no"> + <scale width="300" proportions="width"/> + <globmapper from="*" to="scaled-*"/> + </image> + </target> </project> Modified: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java URL: http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java?rev=807633&r1=807632&r2=807633&view=diff ============================================================================== --- ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java (original) +++ ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java Tue Aug 25 13:52:17 2009 @@ -20,13 +20,18 @@ import com.sun.media.jai.codec.FileSeekableStream; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; +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.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 org.apache.tools.ant.util.FileNameMapper; +import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.util.IdentityMapper; import javax.media.jai.JAI; import javax.media.jai.PlanarImage; @@ -70,6 +75,8 @@ // CheckStyle:VisibilityModifier ON + private Mapper mapperElement = null; + /** * Add a set of files to be deleted. * @param set the FileSet to add. @@ -177,52 +184,157 @@ } /** + * 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. + * @since Ant 1.8.0 + */ + public int processDir(final File srcDir, final String srcNames[], + final File dstDir, final FileNameMapper mapper) { + int writeCount = 0; + + for (int i = 0; i < srcNames.length; ++i) { + final String srcName = srcNames[i]; + 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 (int j = 0; j < dstNames.length; ++j){ + + final String dstName = dstNames[j]; + 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 (garbage_collect) { + 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 */ 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) { 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); + + FileSeekableStream input = null; + PlanarImage image = null; + try { + input = new FileSeekableStream(file); + 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); + } } + } finally { + FileUtils.close(input); } - input.close(); - if (str_encoding.toLowerCase().equals("jpg")) { - str_encoding = "JPEG"; - } else if (str_encoding.toLowerCase().equals("tif")) { - str_encoding = "TIFF"; + File dstParent = newFile.getParentFile(); + if (!dstParent.isDirectory() && !dstParent.mkdirs()){ + throw new BuildException("Failed to create parent directory " + + dstParent); } - if (destDir == null) { - destDir = srcDir; - } - File newFile = new File(destDir, file.getName()); if ((overwrite && newFile.exists()) && (!newFile.equals(file))) { newFile.delete(); } - FileOutputStream stream = new FileOutputStream(newFile); - JAI.create("encode", image, stream, str_encoding.toUpperCase(), - null); - stream.flush(); - stream.close(); + FileOutputStream stream = null; + try { + stream = new FileOutputStream(newFile); + + JAI.create("encode", image, stream, str_encoding.toUpperCase(), + null); + stream.flush(); + } finally { + FileUtils.close(stream); + } } catch (IOException err) { + if (!file.equals(newFile)){ + newFile.delete(); + } if (!failonerror) { log("Error processing file: " + err); } else { throw new BuildException(err); } } catch (java.lang.RuntimeException rerr) { + if (!file.equals(newFile)){ + newFile.delete(); + } if (!failonerror) { log("Error processing file: " + rerr); } else { @@ -240,50 +352,40 @@ validateAttributes(); try { - DirectoryScanner ds = null; - String[] files = null; - ArrayList filesList = new ArrayList(); + File dest = destDir != null ? destDir : srcDir; + + int writeCount = 0; + + // build mapper + final FileNameMapper mapper; + if (mapperElement==null){ + mapper = new IdentityMapper(); + } else { + mapper = mapperElement.getImplementation(); + } // deal with specified srcDir if (srcDir != null) { - ds = super.getDirectoryScanner(srcDir); + final DirectoryScanner ds = super.getDirectoryScanner(srcDir); - files = ds.getIncludedFiles(); - for (int i = 0; i < files.length; i++) { - filesList.add(new File(srcDir, files[i])); - } + final String[] files = ds.getIncludedFiles(); + writeCount += processDir(srcDir, files, dest, mapper); } // 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, files[j])); - } + final FileSet fs = (FileSet) filesets.elementAt(i); + final DirectoryScanner ds = + fs.getDirectoryScanner(getProject()); + final String[] files = ds.getIncludedFiles(); + final File fromDir = fs.getDir(getProject()); + writeCount += processDir(fromDir, files, dest, mapper); } - 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 newFile = new File(destDir, f.getName()); - if (newFile.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(); - } + + if (writeCount>0){ + log("Processed " + writeCount + + (writeCount == 1 ? " image." : " images.")); } + } catch (Exception err) { err.printStackTrace(); throw new BuildException(err.getMessage()); @@ -304,6 +406,11 @@ if (srcDir == null && destDir == null) { throw new BuildException("Specify the destDir, or the srcDir."); } + if (str_encoding.toLowerCase().equals("jpg")) { + str_encoding = "JPEG"; + } else if (str_encoding.toLowerCase().equals("tif")) { + str_encoding = "TIFF"; + } } } Modified: ant/core/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageTest.java URL: http://svn.apache.org/viewvc/ant/core/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageTest.java?rev=807633&r1=807632&r2=807633&view=diff ============================================================================== --- ant/core/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageTest.java (original) +++ ant/core/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageTest.java Tue Aug 25 13:52:17 2009 @@ -91,6 +91,14 @@ lastModified == overwrittenLastModified); } + public void testSimpleScaleWithMapper() { + expectLogContaining("testSimpleScaleWithMapper", "Processing File"); + File f = createRelativeFile("/dest/scaled-" + LARGEIMAGE); + assertTrue( + "Did not create "+f.getAbsolutePath(), + f.exists()); + + } public void off_testFailOnError() { try {