Skip to content

Commit

Permalink
Merge pull request #40 from trello/dlew/fix-codec
Browse files Browse the repository at this point in the history
Fix some codec issues
  • Loading branch information
dlew committed Mar 24, 2016
2 parents c5ba52a + 07e5250 commit 59bc752
Show file tree
Hide file tree
Showing 15 changed files with 5,655 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ cache:
directories:
- $HOME/.gradle

script: ./gradlew build test
script: ./gradlew build test
5 changes: 5 additions & 0 deletions victor/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ dependencies {
compile localGroovy()
}

// This makes it easier to figure out issues with Travis CI builds
test {
testLogging.showStandardStreams = true
}

apply plugin: 'maven'

repositories {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.batik.ext.awt.image.codec.imageio;

import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;

import org.apache.batik.ext.awt.image.GraphicsUtil;
import org.apache.batik.ext.awt.image.renderable.DeferRable;
import org.apache.batik.ext.awt.image.renderable.Filter;
import org.apache.batik.ext.awt.image.renderable.RedRable;
import org.apache.batik.ext.awt.image.rendered.Any2sRGBRed;
import org.apache.batik.ext.awt.image.rendered.CachableRed;
import org.apache.batik.ext.awt.image.rendered.FormatRed;
import org.apache.batik.ext.awt.image.spi.ImageTagRegistry;
import org.apache.batik.ext.awt.image.spi.MagicNumberRegistryEntry;
import org.apache.batik.util.ParsedURL;

/**
* This is the base class for all ImageIO-based RegistryEntry implementations. They
* have a slightly lower priority than the RegistryEntry implementations using the
* internal codecs, so these take precedence if they are available.
*
* @version $Id$
*/
public abstract class AbstractImageIORegistryEntry
extends MagicNumberRegistryEntry {

/**
* Constructor
* @param name Format Name
* @param exts Standard set of extensions
* @param magicNumbers array of magic numbers any of which can match.
*/
public AbstractImageIORegistryEntry(String name,
String [] exts,
String [] mimeTypes,
MagicNumber [] magicNumbers) {
super(name, PRIORITY + 100, exts, mimeTypes, magicNumbers);
}

/**
* Constructor, simplifies construction of entry when only
* one extension and one magic number is required.
* @param name Format Name
* @param ext Standard extension
* @param offset Offset of magic number
* @param magicNumber byte array to match.
*/
public AbstractImageIORegistryEntry(String name,
String ext,
String mimeType,
int offset, byte[] magicNumber) {
super(name, PRIORITY + 100, ext, mimeType, offset, magicNumber);
}

/**
* Decode the Stream into a RenderableImage
*
* @param inIS The input stream that contains the image.
* @param origURL The original URL, if any, for documentation
* purposes only. This may be null.
* @param needRawData If true the image returned should not have
* any default color correction the file may
* specify applied.
*/
public Filter handleStream(InputStream inIS,
ParsedURL origURL,
boolean needRawData) {
final DeferRable dr = new DeferRable();
final InputStream is = inIS;
final String errCode;
final Object [] errParam;
if (origURL != null) {
errCode = ERR_URL_FORMAT_UNREADABLE;
errParam = new Object[] {getFormatName(), origURL};
} else {
errCode = ERR_STREAM_FORMAT_UNREADABLE;
errParam = new Object[] {getFormatName()};
}

Thread t = new Thread() {
@Override
public void run() {
Filter filt;
try{
Iterator<ImageReader> iter = ImageIO.getImageReadersByMIMEType(
getMimeTypes().get(0).toString());
if (!iter.hasNext()) {
throw new UnsupportedOperationException(
"No image reader for "
+ getFormatName() + " available!");
}
ImageReader reader = iter.next();
ImageInputStream imageIn = ImageIO.createImageInputStream(is);
reader.setInput(imageIn, true);

int imageIndex = 0;
dr.setBounds(new Rectangle2D.Double
(0, 0,
reader.getWidth(imageIndex),
reader.getHeight(imageIndex)));
CachableRed cr;
//Naive approach possibly wasting lots of memory
//and ignoring the gamma correction done by PNGRed :-(
//Matches the code used by the former JPEGRegistryEntry, though.
BufferedImage bi = reader.read(imageIndex);
cr = GraphicsUtil.wrap(bi);
cr = new Any2sRGBRed(cr);
cr = new FormatRed(cr, GraphicsUtil.sRGB_Unpre);
WritableRaster wr = (WritableRaster)cr.getData();
ColorModel cm = cr.getColorModel();
BufferedImage image = new BufferedImage
(cm, wr, cm.isAlphaPremultiplied(), null);
cr = GraphicsUtil.wrap(image);
filt = new RedRable(cr);
} catch (IOException ioe) {
// Something bad happened here...
filt = ImageTagRegistry.getBrokenLinkImage
(AbstractImageIORegistryEntry.this,
errCode, errParam);
} catch (ThreadDeath td) {
filt = ImageTagRegistry.getBrokenLinkImage
(AbstractImageIORegistryEntry.this,
errCode, errParam);
dr.setSource(filt);
throw td;
} catch (Throwable t) {
filt = ImageTagRegistry.getBrokenLinkImage
(AbstractImageIORegistryEntry.this,
errCode, errParam);
}

dr.setSource(filt);
}
};
t.start();
return dr;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.batik.ext.awt.image.codec.imageio;

import java.awt.image.RenderedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.event.IIOWriteWarningListener;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.ImageOutputStream;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import org.apache.batik.ext.awt.image.spi.ImageWriter;
import org.apache.batik.ext.awt.image.spi.ImageWriterParams;

/**
* ImageWriter implementation that uses Image I/O to write images.
*
* @version $Id$
*/
public class ImageIOImageWriter implements ImageWriter, IIOWriteWarningListener {

private String targetMIME;

/**
* Main constructor.
* @param mime the MIME type of the image format
*/
public ImageIOImageWriter(String mime) {
this.targetMIME = mime;
}

/**
* @see ImageWriter#writeImage(RenderedImage, OutputStream)
*/
public void writeImage(RenderedImage image, OutputStream out) throws IOException {
writeImage(image, out, null);
}

/**
* @see ImageWriter#writeImage(RenderedImage, OutputStream, ImageWriterParams)
*/
public void writeImage(RenderedImage image, OutputStream out,
ImageWriterParams params)
throws IOException {
Iterator iter;
iter = ImageIO.getImageWritersByMIMEType(getMIMEType());
javax.imageio.ImageWriter iiowriter = null;
try {
iiowriter = (javax.imageio.ImageWriter)iter.next();
if (iiowriter != null) {
iiowriter.addIIOWriteWarningListener(this);

ImageOutputStream imgout = null;
try {
imgout = ImageIO.createImageOutputStream(out);
ImageWriteParam iwParam = getDefaultWriteParam(iiowriter, image, params);

ImageTypeSpecifier type;
if (iwParam.getDestinationType() != null) {
type = iwParam.getDestinationType();
} else {
type = ImageTypeSpecifier.createFromRenderedImage(image);
}

//Handle metadata
IIOMetadata meta = iiowriter.getDefaultImageMetadata(
type, iwParam);
//meta might be null for some JAI codecs as they don't support metadata
if (params != null && meta != null) {
meta = updateMetadata(meta, params);
}

//Write image
iiowriter.setOutput(imgout);
IIOImage iioimg = new IIOImage(image, null, meta);
iiowriter.write(null, iioimg, iwParam);
} finally {
if (imgout != null) {
imgout.close();
}
}
} else {
throw new UnsupportedOperationException("No ImageIO codec for writing "
+ getMIMEType() + " is available!");
}
} finally {
if (iiowriter != null) {
iiowriter.dispose();
}
}
}

/**
* Returns the default write parameters for encoding the image.
* @param iiowriter The IIO ImageWriter that will be used
* @param image the image to be encoded
* @param params the parameters for this writer instance
* @return the IIO ImageWriteParam instance
*/
protected ImageWriteParam getDefaultWriteParam(
javax.imageio.ImageWriter iiowriter, RenderedImage image,
ImageWriterParams params) {
ImageWriteParam param = iiowriter.getDefaultWriteParam();
if ((params != null) && (params.getCompressionMethod() != null)) {
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionType(params.getCompressionMethod());
}
return param;
}

/**
* Updates the metadata information based on the parameters to this writer.
* @param meta the metadata
* @param params the parameters
* @return the updated metadata
*/
protected IIOMetadata updateMetadata(IIOMetadata meta, ImageWriterParams params) {
final String stdmeta = "javax_imageio_1.0";
if (meta.isStandardMetadataFormatSupported()) {
IIOMetadataNode root = (IIOMetadataNode)meta.getAsTree(stdmeta);
IIOMetadataNode dim = getChildNode(root, "Dimension");
IIOMetadataNode child;
if (params.getResolution() != null) {
child = getChildNode(dim, "HorizontalPixelSize");
if (child == null) {
child = new IIOMetadataNode("HorizontalPixelSize");
dim.appendChild(child);
}
child.setAttribute("value",
Double.toString(params.getResolution().doubleValue() / 25.4));
child = getChildNode(dim, "VerticalPixelSize");
if (child == null) {
child = new IIOMetadataNode("VerticalPixelSize");
dim.appendChild(child);
}
child.setAttribute("value",
Double.toString(params.getResolution().doubleValue() / 25.4));
}
try {
meta.mergeTree(stdmeta, root);
} catch (IIOInvalidTreeException e) {
throw new RuntimeException("Cannot update image metadata: "
+ e.getMessage());
}
}
return meta;
}

/**
* Returns a specific metadata child node
* @param n the base node
* @param name the name of the child
* @return the requested child node
*/
protected static IIOMetadataNode getChildNode(Node n, String name) {
NodeList nodes = n.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
Node child = nodes.item(i);
if (name.equals(child.getNodeName())) {
return (IIOMetadataNode)child;
}
}
return null;
}

/**
* @see ImageWriter#getMIMEType()
*/
public String getMIMEType() {
return this.targetMIME;
}

/**
* @see IIOWriteWarningListener#warningOccurred(javax.imageio.ImageWriter, int, String)
*/
public void warningOccurred(javax.imageio.ImageWriter source,
int imageIndex, String warning) {
System.err.println("Problem while writing image using ImageI/O: "
+ warning);
}
}
Loading

0 comments on commit 59bc752

Please sign in to comment.