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>&lt;image&gt;</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>
+&lt;image srcdir="src" destdir="dest" includes="*.png"&gt;
+    &lt;scale proportions="width" width="40"/&gt;
+    &lt;globmapper from="*" to="scaled-*"/&gt;
+&lt;/image&gt;
+</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 {


Reply via email to