Browse Source

Add mapper support to <image>. PR 23243. Submitted by Rob Oxspring

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@807633 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 16 years ago
parent
commit
541157c5de
5 changed files with 207 additions and 57 deletions
  1. +6
    -0
      WHATSNEW
  2. +22
    -0
      docs/manual/OptionalTasks/image.html
  3. +7
    -0
      src/etc/testcases/taskdefs/optional/image/image.xml
  4. +164
    -57
      src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java
  5. +8
    -0
      src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageTest.java

+ 6
- 0
WHATSNEW View File

@@ -150,6 +150,12 @@ Changes that could break older environments:
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:
-----------



+ 22
- 0
docs/manual/OptionalTasks/image.html View File

@@ -200,6 +200,19 @@ nested inside the Draw object.</p>
</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>
@@ -228,6 +241,15 @@ and stores the <i>src</i>.</p>
</pre></blockquote>
<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>



+ 7
- 0
src/etc/testcases/taskdefs/optional/image/image.xml View File

@@ -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>

+ 164
- 57
src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java View File

@@ -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";
}
}
}


+ 8
- 0
src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageTest.java View File

@@ -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 {


Loading…
Cancel
Save