From 541157c5de95bf1cb2ff9f47b8aadac0b3ee98e1 Mon Sep 17 00:00:00 2001 From: Stefan Bodewig Date: Tue, 25 Aug 2009 13:52:17 +0000 Subject: [PATCH] Add mapper support to . PR 23243. Submitted by Rob Oxspring git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@807633 13f79535-47bb-0310-9956-ffa450edef68 --- WHATSNEW | 6 + docs/manual/OptionalTasks/image.html | 22 ++ .../taskdefs/optional/image/image.xml | 7 + .../ant/taskdefs/optional/image/Image.java | 221 +++++++++++++----- .../taskdefs/optional/image/ImageTest.java | 8 + 5 files changed, 207 insertions(+), 57 deletions(-) diff --git a/WHATSNEW b/WHATSNEW index 535152da4..8e5452712 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -150,6 +150,12 @@ Changes that could break older environments: java.vm.version for the Created-By Manifest attribute. Bugzilla Report 47632. + * The 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: ----------- diff --git a/docs/manual/OptionalTasks/image.html b/docs/manual/OptionalTasks/image.html index 93614416c..3e5cd7f8e 100644 --- a/docs/manual/OptionalTasks/image.html +++ b/docs/manual/OptionalTasks/image.html @@ -200,6 +200,19 @@ nested inside the Draw object.

+

mapper

+

Since Ant 1.8.0

+ +

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

@@ -228,6 +241,15 @@ and stores the src.

Same as above but stores the result in dest.

+
+<image srcdir="src" destdir="dest" includes="*.png">
+    <scale proportions="width" width="40"/>
+    <globmapper from="*" to="scaled-*"/>
+</image>
+
+

Same as above but stores the resulting file names will be prefixed + by "scaled-".

+
 
diff --git a/src/etc/testcases/taskdefs/optional/image/image.xml b/src/etc/testcases/taskdefs/optional/image/image.xml index e30b3909a..bc93b0c40 100644 --- a/src/etc/testcases/taskdefs/optional/image/image.xml +++ b/src/etc/testcases/taskdefs/optional/image/image.xml @@ -66,4 +66,11 @@ + + + + + + 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 7779c0c21..b49f46642 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 @@ -20,13 +20,18 @@ 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.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 @@ public class Image extends MatchingTask { // CheckStyle:VisibilityModifier ON + private Mapper mapperElement = null; + /** * Add a set of files to be deleted. * @param set the FileSet to add. @@ -176,53 +183,158 @@ public class Image extends MatchingTask { 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. + * @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 @@ public class Image extends MatchingTask { 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])); - } - } - 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); + 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); } - // 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 @@ public class Image extends MatchingTask { 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"; + } } } diff --git a/src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageTest.java b/src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageTest.java index 25b42457d..5769345b7 100644 --- a/src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageTest.java +++ b/src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageTest.java @@ -91,6 +91,14 @@ public class ImageTest extends BuildFileTest { 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 {