It all works

This commit is contained in:
Erlend Hamnaberg
2009-11-08 19:52:30 +01:00
parent b8faa6e36f
commit 0786949c1c
319 changed files with 0 additions and 0 deletions
@@ -0,0 +1,574 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.svg;
import com.twelvemonkeys.image.ImageUtil;
import com.twelvemonkeys.imageio.ImageReaderBase;
import com.twelvemonkeys.imageio.util.IIOUtil;
import org.apache.batik.bridge.*;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.dom.svg.SVGOMDocument;
import org.apache.batik.dom.util.DOMUtilities;
import org.apache.batik.ext.awt.image.GraphicsUtil;
import org.apache.batik.gvt.CanvasGraphicsNode;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.gvt.renderer.ConcreteImageRendererFactory;
import org.apache.batik.gvt.renderer.ImageRenderer;
import org.apache.batik.gvt.renderer.ImageRendererFactory;
import org.apache.batik.transcoder.*;
import org.apache.batik.transcoder.image.ImageTranscoder;
import org.apache.batik.util.ParsedURL;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.svg.SVGSVGElement;
import javax.imageio.IIOException;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.spi.ImageReaderSpi;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Dimension2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
/**
* Image reader for SVG document fragments.
* <p/>
*
* @author Harald Kuhr
* @author Inpspired by code from the Batik Team
* @version $Id: $
* @see <A href="http://www.mail-archive.com/batik-dev@xml.apache.org/msg00992.html">batik-dev</A>
*/
public class SVGImageReader extends ImageReaderBase {
private Rasterizer mRasterizer = new Rasterizer();
/**
* Creates an {@code SVGImageReader}.
*
* @param pProvider the provider
*/
public SVGImageReader(ImageReaderSpi pProvider) {
super(pProvider);
}
protected void resetMembers() {
}
@Override
public void dispose() {
super.dispose();
mRasterizer = null;
}
@Override
public void setInput(Object pInput, boolean pSeekForwardOnly, boolean pIgnoreMetadata) {
super.setInput(pInput, pSeekForwardOnly, pIgnoreMetadata);
if (mImageInput != null) {
TranscoderInput input = new TranscoderInput(IIOUtil.createStreamAdapter(mImageInput));
mRasterizer.setInput(input);
}
}
public BufferedImage read(int pIndex, ImageReadParam pParam) throws IOException {
checkBounds(pIndex);
String baseURI = null;
if (pParam instanceof SVGReadParam) {
SVGReadParam svgParam = (SVGReadParam) pParam;
// Set IIOParams as hints
// Note: The cast to Map invokes a different method that preserves
// unset defaults, DO NOT REMOVE!
mRasterizer.setTranscodingHints((Map) paramsToHints(svgParam));
// Get the base URI (not a hint)
baseURI = svgParam.getBaseURI();
}
Dimension size;
if (pParam != null && (size = pParam.getSourceRenderSize()) != null) {
// Use size...
}
else {
size = new Dimension(getWidth(pIndex), getHeight(pIndex));
}
BufferedImage destination = getDestination(pParam, getImageTypes(pIndex), size.width, size.height);
// Read in the image, using the Batik Transcoder
try {
processImageStarted(pIndex);
mRasterizer.mTranscoderInput.setURI(baseURI);
BufferedImage image = mRasterizer.getImage();
Graphics2D g = destination.createGraphics();
try {
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
g.drawImage(image, 0, 0, null); // TODO: Dest offset?
}
finally {
g.dispose();
}
processImageComplete();
return destination;
}
catch (TranscoderException e) {
throw new IIOException(e.getMessage(), e);
}
}
private TranscodingHints paramsToHints(SVGReadParam pParam) throws IOException {
TranscodingHints hints = new TranscodingHints();
// Note: We must allow generic ImageReadParams, so converting to
// TanscodingHints should be done outside the SVGReadParam class.
// Set dimensions
Dimension size = pParam.getSourceRenderSize();
Dimension origSize = new Dimension(getWidth(0), getHeight(0));
if (size == null) {
// SVG is not a pixel based format, but we'll scale it, according to
// the subsampling for compatibility
size = getSourceRenderSizeFromSubsamping(pParam, origSize);
}
if (size != null) {
hints.put(ImageTranscoder.KEY_WIDTH, new Float(size.getWidth()));
hints.put(ImageTranscoder.KEY_HEIGHT, new Float(size.getHeight()));
}
// Set area of interest
Rectangle region = pParam.getSourceRegion();
if (region != null) {
hints.put(ImageTranscoder.KEY_AOI, region);
// Avoid that the batik transcoder scales the AOI up to original image size
if (size == null) {
hints.put(ImageTranscoder.KEY_WIDTH, new Float(region.getWidth()));
hints.put(ImageTranscoder.KEY_HEIGHT, new Float(region.getHeight()));
}
else {
// Need to resize here...
double xScale = size.getWidth() / origSize.getWidth();
double yScale = size.getHeight() / origSize.getHeight();
hints.put(ImageTranscoder.KEY_WIDTH, new Float(region.getWidth() * xScale));
hints.put(ImageTranscoder.KEY_HEIGHT, new Float(region.getHeight() * yScale));
}
}
else if (size != null) {
// Allow non-uniform scaling
hints.put(ImageTranscoder.KEY_AOI, new Rectangle(origSize));
}
// Background color
Paint bg = pParam.getBackgroundColor();
if (bg != null) {
hints.put(ImageTranscoder.KEY_BACKGROUND_COLOR, bg);
}
return hints;
}
private Dimension getSourceRenderSizeFromSubsamping(ImageReadParam pParam, Dimension pOrigSize) {
if (pParam.getSourceXSubsampling() > 1 || pParam.getSourceYSubsampling() > 1) {
return new Dimension((int) (pOrigSize.width / (float) pParam.getSourceXSubsampling()),
(int) (pOrigSize.height / (float) pParam.getSourceYSubsampling()));
}
return null;
}
public ImageReadParam getDefaultReadParam() {
return new SVGReadParam();
}
public int getWidth(int pIndex) throws IOException {
checkBounds(pIndex);
try {
return mRasterizer.getDefaultWidth();
}
catch (TranscoderException e) {
throw new IIOException(e.getMessage(), e);
}
}
public int getHeight(int pIndex) throws IOException {
checkBounds(pIndex);
try {
return mRasterizer.getDefaultHeight();
}
catch (TranscoderException e) {
throw new IIOException(e.getMessage(), e);
}
}
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException {
return Collections.singleton(ImageTypeSpecifier.createFromRenderedImage(mRasterizer.createImage(1, 1))).iterator();
}
/**
* An image transcoder that stores the resulting image.
* <p/>
* NOTE: This class includes a lot of copy and paste code from the Batik classes
* and needs major refactoring!
*/
private class Rasterizer extends SVGAbstractTranscoder /*ImageTranscoder*/ {
BufferedImage mImage = null;
private TranscoderInput mTranscoderInput;
private float mDefaultWidth;
private float mDefaultHeight;
private boolean mInit = false;
private SVGOMDocument mDocument;
private String mURI;
private GraphicsNode mGVTRoot;
private TranscoderException mException;
private BridgeContext mContext;
public BufferedImage createImage(int w, int h) {
return ImageUtil.createTransparent(w, h);//, BufferedImage.TYPE_INT_ARGB);
}
// This is cheating... We don't fully transcode after all
protected void transcode(Document document, String uri, TranscoderOutput output) throws TranscoderException {
// Sets up root, curTxf & curAoi
// ----
if ((document != null) &&
!(document.getImplementation() instanceof SVGDOMImplementation)) {
DOMImplementation impl;
impl = (DOMImplementation) hints.get(KEY_DOM_IMPLEMENTATION);
// impl = ExtensibleSVGDOMImplementation.getDOMImplementation();
document = DOMUtilities.deepCloneDocument(document, impl);
if (uri != null) {
try {
URL url = new URL(uri);
((SVGOMDocument) document).setURLObject(url);
}
catch (MalformedURLException ignore) {
}
}
}
ctx = createBridgeContext();
SVGOMDocument svgDoc = (SVGOMDocument) document;
//SVGSVGElement root = svgDoc.getRootElement();
// build the GVT tree
builder = new GVTBuilder();
// flag that indicates if the document is dynamic
boolean isDynamic =
(hints.containsKey(KEY_EXECUTE_ONLOAD) &&
(Boolean) hints.get(KEY_EXECUTE_ONLOAD) &&
BaseScriptingEnvironment.isDynamicDocument(ctx, svgDoc));
if (isDynamic) {
ctx.setDynamicState(BridgeContext.DYNAMIC);
}
// Modified code below:
GraphicsNode root = null;
try {
root = builder.build(ctx, svgDoc);
}
catch (BridgeException ex) {
// Note: This might fail, but we STILL have the dimensions we need
// However, we need to reparse later...
//throw new TranscoderException(ex);
mException = new TranscoderException(ex);
}
// ----
// get the 'width' and 'height' attributes of the SVG document
Dimension2D docSize = ctx.getDocumentSize();
if (docSize != null) {
mDefaultWidth = (float) docSize.getWidth();
mDefaultHeight = (float) docSize.getHeight();
}
else {
mDefaultWidth = 200;
mDefaultHeight = 200;
}
// Hack to work around exception above
if (root != null) {
mGVTRoot = root;
}
mDocument = svgDoc;
mURI = uri;
//ctx.dispose();
// Hack to avoid the transcode method wacking my context...
mContext = ctx;
ctx = null;
}
private BufferedImage readImage() throws TranscoderException {
init();
if (abortRequested()) {
processReadAborted();
return null;
}
processImageProgress(10f);
// Hacky workaround below...
if (mGVTRoot == null) {
// Try to reparse, if we had no URI last time...
if (mURI != mTranscoderInput.getURI()) {
try {
mContext.dispose();
mDocument.setURLObject(new URL(mTranscoderInput.getURI()));
transcode(mDocument, mTranscoderInput.getURI(), null);
}
catch (MalformedURLException ignore) {
// Ignored
}
}
if (mGVTRoot == null) {
throw mException;
}
}
ctx = mContext;
// /Hacky
if (abortRequested()) {
processReadAborted();
return null;
}
processImageProgress(20f);
// -- --
SVGSVGElement root = mDocument.getRootElement();
// ----
// ----
setImageSize(mDefaultWidth, mDefaultHeight);
if (abortRequested()) {
processReadAborted();
return null;
}
processImageProgress(40f);
// compute the preserveAspectRatio matrix
AffineTransform Px;
String ref = new ParsedURL(mURI).getRef();
try {
Px = ViewBox.getViewTransform(ref, root, width, height);
}
catch (BridgeException ex) {
throw new TranscoderException(ex);
}
if (Px.isIdentity() && (width != mDefaultWidth || height != mDefaultHeight)) {
// The document has no viewBox, we need to resize it by hand.
// we want to keep the document size ratio
float xscale, yscale;
xscale = width / mDefaultWidth;
yscale = height / mDefaultHeight;
float scale = Math.min(xscale, yscale);
Px = AffineTransform.getScaleInstance(scale, scale);
}
// take the AOI into account if any
if (hints.containsKey(KEY_AOI)) {
Rectangle2D aoi = (Rectangle2D) hints.get(KEY_AOI);
// transform the AOI into the image's coordinate system
aoi = Px.createTransformedShape(aoi).getBounds2D();
AffineTransform Mx = new AffineTransform();
double sx = width / aoi.getWidth();
double sy = height / aoi.getHeight();
Mx.scale(sx, sy);
double tx = -aoi.getX();
double ty = -aoi.getY();
Mx.translate(tx, ty);
// take the AOI transformation matrix into account
// we apply first the preserveAspectRatio matrix
Px.preConcatenate(Mx);
curAOI = aoi;
}
else {
curAOI = new Rectangle2D.Float(0, 0, width, height);
}
if (abortRequested()) {
processReadAborted();
return null;
}
processImageProgress(50f);
CanvasGraphicsNode cgn = getCanvasGraphicsNode(mGVTRoot);
if (cgn != null) {
cgn.setViewingTransform(Px);
curTxf = new AffineTransform();
}
else {
curTxf = Px;
}
try {
// dispatch an 'onload' event if needed
if (ctx.isDynamic()) {
BaseScriptingEnvironment se;
se = new BaseScriptingEnvironment(ctx);
se.loadScripts();
se.dispatchSVGLoadEvent();
}
}
catch (BridgeException ex) {
throw new TranscoderException(ex);
}
this.root = mGVTRoot;
// ----
// NOTE: The code below is copied and pasted from the Batik
// ImageTranscoder class' transcode() method:
// prepare the image to be painted
int w = (int) (width + 0.5);
int h = (int) (height + 0.5);
// paint the SVG document using the bridge package
// create the appropriate renderer
ImageRendererFactory rendFactory = new ConcreteImageRendererFactory();
// ImageRenderer renderer = rendFactory.createDynamicImageRenderer();
ImageRenderer renderer = rendFactory.createStaticImageRenderer();
renderer.updateOffScreen(w, h);
renderer.setTransform(curTxf);
renderer.setTree(this.root);
this.root = null; // We're done with it...
if (abortRequested()) {
processReadAborted();
return null;
}
processImageProgress(75f);
try {
// now we are sure that the aoi is the image size
Shape raoi = new Rectangle2D.Float(0, 0, width, height);
// Warning: the renderer's AOI must be in user space
renderer.repaint(curTxf.createInverse().
createTransformedShape(raoi));
// NOTE: repaint above cause nullpointer exception with fonts..???
BufferedImage rend = renderer.getOffScreen();
renderer = null; // We're done with it...
BufferedImage dest = createImage(w, h);
Graphics2D g2d = GraphicsUtil.createGraphics(dest);
try {
if (hints.containsKey(ImageTranscoder.KEY_BACKGROUND_COLOR)) {
Paint bgcolor = (Paint) hints.get(ImageTranscoder.KEY_BACKGROUND_COLOR);
g2d.setComposite(AlphaComposite.SrcOver);
g2d.setPaint(bgcolor);
g2d.fillRect(0, 0, w, h);
}
if (rend != null) { // might be null if the svg document is empty
g2d.drawRenderedImage(rend, new AffineTransform());
}
}
finally {
if (g2d != null) {
g2d.dispose();
}
}
if (abortRequested()) {
processReadAborted();
return null;
}
processImageProgress(99f);
return dest;
//writeImage(dest, output);
}
catch (Exception ex) {
throw new TranscoderException(ex.getMessage(), ex);
}
finally {
if (mContext != null) {
mContext.dispose();
}
}
}
private synchronized void init() throws TranscoderException {
if (!mInit) {
if (mTranscoderInput == null) {
throw new IllegalStateException("input == null");
}
mInit = true;
super.transcode(mTranscoderInput, null);
}
}
private BufferedImage getImage() throws TranscoderException {
if (mImage == null) {
mImage = readImage();
}
return mImage;
}
protected int getDefaultWidth() throws TranscoderException {
init();
return (int) (mDefaultWidth + 0.5);
}
protected int getDefaultHeight() throws TranscoderException {
init();
return (int) (mDefaultHeight + 0.5);
}
public void setInput(TranscoderInput pInput) {
mTranscoderInput = pInput;
}
}
}
@@ -0,0 +1,174 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.svg;
import com.twelvemonkeys.imageio.spi.ProviderInfo;
import com.twelvemonkeys.lang.SystemUtil;
import com.twelvemonkeys.imageio.util.IIOUtil;
import javax.imageio.ImageReader;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.spi.ServiceRegistry;
import javax.imageio.stream.ImageInputStream;
import java.io.IOException;
import java.util.Locale;
/**
* SVGImageReaderSpi
* <p/>
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: SVGImageReaderSpi.java,v 1.1 2003/12/02 16:45:00 haku Exp $
*/
public class SVGImageReaderSpi extends ImageReaderSpi {
private final static boolean SVG_READER_AVAILABLE = SystemUtil.isClassAvailable("com.twelvemonkeys.imageio.plugins.svg.SVGImageReader");
/**
* Creates an {@code SVGImageReaderSpi}.
*/
public SVGImageReaderSpi() {
this(IIOUtil.getProviderInfo(SVGImageReaderSpi.class));
}
private SVGImageReaderSpi(final ProviderInfo pProviderInfo) {
super(
pProviderInfo.getVendorName(), // Vendor name
pProviderInfo.getVersion(), // Version
SVG_READER_AVAILABLE ? new String[]{"svg", "SVG"} : new String[]{""}, // Names
SVG_READER_AVAILABLE ? new String[]{"svg"} : null, // Suffixes
SVG_READER_AVAILABLE ? new String[]{"image/svg", "image/x-svg", "image/svg+xml", "image/svg-xml"} : null, // Mime-types
"com.twelvemonkeys.imageio.plugins.svg.SVGImageReader", // Reader class name
ImageReaderSpi.STANDARD_INPUT_TYPE, // Output types
null, // Writer SPI names
true, // Supports standard stream metadata format
null, // Native stream metadata format name
null, // Native stream metadata format class name
null, // Extra stream metadata format names
null, // Extra stream metadata format class names
true, // Supports standard image metadata format
null, // Native image metadata format name
null, // Native image metadata format class name
null, // Extra image metadata format names
null // Extra image metadata format class names
);
}
public boolean canDecodeInput(Object pSource) throws IOException {
return pSource instanceof ImageInputStream && SVG_READER_AVAILABLE && canDecode((ImageInputStream) pSource);
}
private static boolean canDecode(ImageInputStream pInput) throws IOException {
// NOTE: This test is quite quick as it does not involve any parsing,
// however it requires the doctype to be "svg", which may not be correct
// in all cases...
try {
pInput.mark();
// TODO: This is may not be ok for non-UTF/iso-latin encodings...
// TODO: Use an XML (encoding) aware Reader instance instead
// Need to figure out pretty fast if this is XML or not
int b;
while (Character.isWhitespace((char) (b = pInput.read()))) {
// Skip over leading WS
}
if (!((b == '<') && (pInput.read() == '?') && (pInput.read() == 'x') && (pInput.read() == 'm')
&& (pInput.read() == 'l'))) {
return false;
}
// Okay, we have XML. But, is it really SVG?
boolean docTypeFound = false;
while (!docTypeFound) {
while (pInput.read() != '<') {
// Skip over, until begin tag
}
// If this is not a comment, or the DOCTYPE declaration, the doc
// has no DOCTYPE and it can't be svg
if (pInput.read() != '!') {
return false;
}
// There might be comments before the doctype, unfortunately...
// If next is "--", this is a comment
if ((b = pInput.read()) == '-' && pInput.read() == '-') {
while (!(pInput.read() == '-' && pInput.read() == '-' && pInput.read() == '>')) {
// Skip until end of comment
}
}
// If we are lucky, this is DOCTYPE declaration
if (b == 'D' && pInput.read() == 'O' && pInput.read() == 'C'
&& pInput.read() == 'T' && pInput.read() == 'Y' && pInput.read() == 'P'
&& pInput.read() == 'E') {
docTypeFound = true;
while (Character.isWhitespace((char) (b = pInput.read()))) {
// Skip over WS
}
if (b == 's' && pInput.read() == 'v' && pInput.read() == 'g') {
//System.out.println("It's svg!");
return true;
}
}
}
return false;
}
finally {
pInput.reset();
}
}
public ImageReader createReaderInstance(Object extension) throws IOException {
return new SVGImageReader(this);
}
public String getDescription(Locale locale) {
return "Scaleable Vector Graphics (SVG) format image reader";
}
@SuppressWarnings({"deprecation"})
@Override
public void onRegistration(ServiceRegistry registry, Class<?> category) {
if (!SVG_READER_AVAILABLE) {
try {
// NOTE: This will break, but it gives us some useful debug info
new SVGImageReader(this);
}
catch (Throwable t) {
System.err.println("Could not instantiate SVGImageReader (missing support classes).");
t.printStackTrace();
}
IIOUtil.deregisterProvider(registry, this, category);
}
}}
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.svg;
import javax.imageio.ImageReadParam;
import java.awt.*;
/**
* Implementation of {@code IamgeReadParam} for SVG images.
* SVG images allows for different source render sizes.
*
*/
public class SVGReadParam extends ImageReadParam {
private Paint mBackground;
private String mBaseURI;
public Paint getBackgroundColor() {
return mBackground;
}
public void setBackgroundColor(Paint pColor) {
mBackground = pColor;
}
public String getBaseURI() {
return mBaseURI;
}
public void setBaseURI(String pBaseURI) {
mBaseURI = pBaseURI;
}
@Override
public boolean canSetSourceRenderSize() {
return true;
}
}
@@ -0,0 +1,189 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.tiff;
import com.twelvemonkeys.image.ImageUtil;
import com.twelvemonkeys.imageio.ImageReaderBase;
import org.apache.batik.ext.awt.image.codec.SeekableStream;
import org.apache.batik.ext.awt.image.codec.tiff.TIFFDecodeParam;
import org.apache.batik.ext.awt.image.codec.tiff.TIFFImageDecoder;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.spi.ImageReaderSpi;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* TIFFImageReader class description.
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haku $
* @version $Id: TIFFImageReader.java,v 1.0 29.jul.2004 12:52:33 haku Exp $
*/
// TODO: Massive clean-up
// TODO: Support raster decoding...
public class TIFFImageReader extends ImageReaderBase {
private TIFFImageDecoder mDecoder = null;
private List<RenderedImage> mImages = new ArrayList<RenderedImage>();
protected TIFFImageReader(final ImageReaderSpi pOriginatingProvider) {
super(pOriginatingProvider);
}
protected void resetMembers() {
mDecoder = null;
}
public BufferedImage read(int pIndex, ImageReadParam pParam) throws IOException {
// Decode image, convert and return as BufferedImage
RenderedImage image = readAsRenderedImage(pIndex, pParam);
return ImageUtil.toBuffered(image);
}
public RenderedImage readAsRenderedImage(int pIndex, ImageReadParam pParam) throws IOException {
init(pIndex);
processImageStarted(pIndex);
if (pParam == null) {
// Cache image for use by getWidth and getHeight methods
RenderedImage image;
if (mImages.size() > pIndex && mImages.get(pIndex) != null) {
image = mImages.get(pIndex);
}
else {
// Decode
image = mDecoder.decodeAsRenderedImage(pIndex);
// Make room
for (int i = mImages.size(); i < pIndex; i++) {
mImages.add(pIndex, null);
}
mImages.add(pIndex, image);
}
if (abortRequested()) {
processReadAborted();
return image;
}
processImageComplete();
return image;
}
else {
// TODO: Parameter conversion
mDecoder.setParam(new TIFFDecodeParam());
RenderedImage image = mDecoder.decodeAsRenderedImage(pIndex);
// Subsample and apply AOI
if (pParam.getSourceRegion() != null) {
image = fakeAOI(ImageUtil.toBuffered(image), pParam);
}
if (pParam.getSourceXSubsampling() > 1 || pParam.getSourceYSubsampling() > 1) {
image = ImageUtil.toBuffered(fakeSubsampling(ImageUtil.toBuffered(image), pParam));
}
processImageComplete();
return image;
}
}
private void init(int pIndex) throws IOException {
init();
checkBounds(pIndex);
}
protected void checkBounds(int pIndex) throws IOException {
if (pIndex < getMinIndex()){
throw new IndexOutOfBoundsException("index < minIndex");
}
else if (pIndex >= getNumImages(true)) {
throw new IndexOutOfBoundsException("index > numImages");
}
}
private synchronized void init() {
if (mDecoder == null) {
if (mImageInput == null) {
throw new IllegalStateException("input == null");
}
mDecoder = new TIFFImageDecoder(new SeekableStream() {
public int read() throws IOException {
return mImageInput.read();
}
public int read(final byte[] pBytes, final int pStart, final int pLength) throws IOException {
return mImageInput.read(pBytes, pStart, pLength);
}
public long getFilePointer() throws IOException {
return mImageInput.getStreamPosition();
}
public void seek(final long pPos) throws IOException {
mImageInput.seek(pPos);
}
}, null);
}
}
public int getWidth(int pIndex) throws IOException {
init(pIndex);
// TODO: Use cache...
return mDecoder.decodeAsRenderedImage(pIndex).getWidth();
}
public int getHeight(int pIndex) throws IOException {
init(pIndex);
// TODO: Use cache...
return mDecoder.decodeAsRenderedImage(pIndex).getHeight();
}
public Iterator<ImageTypeSpecifier> getImageTypes(final int imageIndex) throws IOException {
throw new UnsupportedOperationException("Method getImageTypes not implemented");// TODO: Implement
}
public int getNumImages(boolean pAllowSearch) throws IOException {
init();
if (pAllowSearch) {
return mDecoder.getNumPages();
}
return -1;
}
}
@@ -0,0 +1,125 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.tiff;
import com.twelvemonkeys.imageio.spi.ProviderInfo;
import com.twelvemonkeys.lang.SystemUtil;
import com.twelvemonkeys.imageio.util.IIOUtil;
import javax.imageio.ImageReader;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.spi.ServiceRegistry;
import javax.imageio.stream.ImageInputStream;
import java.io.IOException;
import java.util.Locale;
/**
* TIFFImageReaderSpi
* <p/>
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: TIFFImageReaderSpi.java,v 1.1 2003/12/02 16:45:00 wmhakur Exp $
*/
public class TIFFImageReaderSpi extends ImageReaderSpi {
final static boolean TIFF_CLASSES_AVAILABLE = SystemUtil.isClassAvailable("com.twelvemonkeys.imageio.plugins.tiff.TIFFImageReader");
/**
* Creates a {@code TIFFImageReaderSpi}.
*/
public TIFFImageReaderSpi() {
this(IIOUtil.getProviderInfo(TIFFImageReaderSpi.class));
}
private TIFFImageReaderSpi(final ProviderInfo pProviderInfo) {
super(
pProviderInfo.getVendorName(), // Vendor name
pProviderInfo.getVersion(), // Version
TIFF_CLASSES_AVAILABLE ? new String[]{"tiff", "TIFF"} : new String[] {""}, // Names
TIFF_CLASSES_AVAILABLE ? new String[]{"tiff", "tif"} : null, // Suffixes
TIFF_CLASSES_AVAILABLE ? new String[]{"image/tiff", "image/x-tiff"} : null, // Mime-types
"com.twelvemonkeys.imageio.plugins.tiff.TIFFImageReader", // Writer class name..?
ImageReaderSpi.STANDARD_INPUT_TYPE, // Output types
new String[]{"com.twelvemonkeys.imageio.plugins.tiff.TIFFImageWriterSpi"}, // Writer SPI names
true, // Supports standard stream metadata format
null, // Native stream metadata format name
null, // Native stream metadata format class name
null, // Extra stream metadata format names
null, // Extra stream metadata format class names
true, // Supports standard image metadata format
null, // Native image metadata format name
null, // Native image metadata format class name
null, // Extra image metadata format names
null // Extra image metadata format class names
);
}
public boolean canDecodeInput(Object source) throws IOException {
return source instanceof ImageInputStream && TIFF_CLASSES_AVAILABLE && canDecode((ImageInputStream) source);
}
static boolean canDecode(ImageInputStream pInput) throws IOException {
try {
pInput.mark();
int byte0 = pInput.read(); // Byte order 1 (M or I)
int byte1 = pInput.read(); // Byte order 2 (always same as 1)
int byte2 = pInput.read(); // Version number 1 (M: 0, I: 42)
int byte3 = pInput.read(); // Version number 2 (M: 42, I: 0)
// Test for Motorola or Intel byte order, and version number == 42
if ((byte0 == 'M' && byte1 == 'M' && byte2 == 0 && byte3 == 42)
|| (byte0 == 'I' && byte1 == 'I' && byte2 == 42 && byte3 == 0)) {
return true;
}
}
finally {
pInput.reset();
}
return false;
}
public ImageReader createReaderInstance(Object extension) throws IOException {
return new TIFFImageReader(this);
}
public String getDescription(Locale locale) {
return "Tagged Image File Format (TIFF) image reader";
}
@SuppressWarnings({"deprecation"})
@Override
public void onRegistration(ServiceRegistry registry, Class<?> category) {
if (!TIFF_CLASSES_AVAILABLE) {
IIOUtil.deregisterProvider(registry, this, category);
}
}
}
@@ -0,0 +1,145 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.tiff;
import com.twelvemonkeys.image.ImageUtil;
import com.twelvemonkeys.imageio.ImageWriterBase;
import com.twelvemonkeys.imageio.util.IIOUtil;
import org.apache.batik.ext.awt.image.codec.ImageEncodeParam;
import org.apache.batik.ext.awt.image.codec.tiff.TIFFEncodeParam;
import org.apache.batik.ext.awt.image.codec.tiff.TIFFImageEncoder;
import javax.imageio.IIOImage;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.ImageWriterSpi;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.IOException;
/**
* TIFFImageWriter class description.
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haku $
* @version $Id: TIFFImageWriter.java,v 1.0 29.jul.2004 12:52:54 haku Exp $
*/
public class TIFFImageWriter extends ImageWriterBase {
private TIFFImageEncoder mEncoder = null;
protected TIFFImageWriter(final ImageWriterSpi pProvider) {
super(pProvider);
}
@Override
public void setOutput(final Object pOutput) {
mEncoder = null;
super.setOutput(pOutput);
}
public IIOMetadata getDefaultImageMetadata(final ImageTypeSpecifier imageType, final ImageWriteParam param) {
throw new UnsupportedOperationException("Method getDefaultImageMetadata not implemented");// TODO: Implement
}
public IIOMetadata convertImageMetadata(final IIOMetadata inData, final ImageTypeSpecifier imageType, final ImageWriteParam param) {
throw new UnsupportedOperationException("Method convertImageMetadata not implemented");// TODO: Implement
}
public void write(final IIOMetadata pStreamMetadata, final IIOImage pImage, final ImageWriteParam pParam) throws IOException {
RenderedImage renderedImage = pImage.getRenderedImage();
init();
ImageEncodeParam param;
if (pParam != null) {
param = new TIFFEncodeParam();
// TODO: Convert params
mEncoder.setParam(param);
}
BufferedImage image;
// FIX: TIFFEnocder chokes on a any of the TYPE_INT_* types...
// (The TIFFEncoder expects int types to have 1 sample of size 32
// while there actually is 4 samples of size 8, according to the
// SampleModel...)
if (renderedImage instanceof BufferedImage && (
((BufferedImage) renderedImage).getType() == BufferedImage.TYPE_INT_ARGB
|| ((BufferedImage) renderedImage).getType() == BufferedImage.TYPE_INT_ARGB_PRE)) {
image = ImageUtil.toBuffered(renderedImage, BufferedImage.TYPE_4BYTE_ABGR);
}
else if (renderedImage instanceof BufferedImage && (
((BufferedImage) renderedImage).getType() == BufferedImage.TYPE_INT_BGR
|| ((BufferedImage) renderedImage).getType() == BufferedImage.TYPE_INT_RGB)) {
image = ImageUtil.toBuffered(renderedImage, BufferedImage.TYPE_3BYTE_BGR);
}
else {
image = ImageUtil.toBuffered(renderedImage);
}
image = fakeAOI(image, pParam);
image = ImageUtil.toBuffered(fakeSubsampling(image, pParam));
/*
System.out.println("Image: " + pImage);
SampleModel sampleModel = pImage.getSampleModel();
System.out.println("SampleModel: " + sampleModel);
int sampleSize[] = sampleModel.getSampleSize();
System.out.println("Samples: " + sampleSize.length);
for (int i = 0; i < sampleSize.length; i++) {
System.out.println("SampleSize[" + i + "]: " + sampleSize[i]);
}
int dataType = sampleModel.getDataType();
System.out.println("DataType: " + dataType);
*/
processImageStarted(0);
mEncoder.encode(image);
mImageOutput.flush();
processImageComplete();
}
public void dispose() {
super.dispose();
mEncoder = null;
}
private synchronized void init() {
if (mEncoder == null) {
if (mImageOutput == null) {
throw new IllegalStateException("output == null");
}
mEncoder = new TIFFImageEncoder(IIOUtil.createStreamAdapter(mImageOutput), null);
}
}
}
@@ -0,0 +1,107 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.tiff;
import com.twelvemonkeys.imageio.spi.ProviderInfo;
import com.twelvemonkeys.imageio.util.IIOUtil;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriter;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.spi.ServiceRegistry;
import java.io.IOException;
import java.util.Locale;
/**
* TIFFmageWriterSpi
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: TIFFImageWriterSpi.java,v 1.2 2004/01/14 15:21:44 wmhakur Exp $
*/
public class TIFFImageWriterSpi extends ImageWriterSpi {
/**
* Creates a {@code TIFFImageWriterSpi}.
*/
public TIFFImageWriterSpi() {
this(IIOUtil.getProviderInfo(TIFFImageWriterSpi.class));
}
private TIFFImageWriterSpi(final ProviderInfo pProviderInfo) {
super(
pProviderInfo.getVendorName(), // Vendor name
pProviderInfo.getVersion(), // Version
new String[]{"tiff", "TIFF"}, // Names
new String[]{"tif", "tiff"}, // Suffixes
new String[]{"image/tiff", "image/x-tiff"}, // Mime-types
"com.twelvemonkeys.imageio.plugins.tiff.TIFFImageWriter", // Writer class name..?
STANDARD_OUTPUT_TYPE, // Output types
new String[]{"com.twelvemonkeys.imageio.plugins.tiff.TIFFImageReaderSpi"}, // Reader SPI names
true, // Supports standard stream metadata format
null, // Native stream metadata format name
null, // Native stream metadata format class name
null, // Extra stream metadata format names
null, // Extra stream metadata format class names
true, // Supports standard image metadata format
null, // Native image metadata format name
null, // Native image metadata format class name
null, // Extra image metadata format names
null // Extra image metadata format class names
);
}
public boolean canEncodeImage(ImageTypeSpecifier type) {
return true;
}
public ImageWriter createWriterInstance(Object extension) throws IOException {
try {
return new TIFFImageWriter(this);
}
catch (Throwable t) {
// Wrap in IOException if the writer can't be instantiated.
// This makes the IIORegistry deregister this service provider
IOException exception = new IOException(t.getMessage());
exception.initCause(t);
throw exception;
}
}
public String getDescription(Locale locale) {
return "Tagged Image File Format (TIFF) image writer";
}
@SuppressWarnings({"deprecation"})
@Override
public void onRegistration(ServiceRegistry registry, Class<?> category) {
if (!TIFFImageReaderSpi.TIFF_CLASSES_AVAILABLE) {
IIOUtil.deregisterProvider(registry, this, category);
}
}
}
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.wmf;
/**
* WMF
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: WMF.java,v 1.0 Feb 17, 2008 5:46:59 PM haraldk Exp$
*/
interface WMF {
static byte[] HEADER = new byte[] {
(byte) 0xd7, (byte) 0xcd, (byte) 0xc6, (byte) 0x9a, (byte) 0x00,
(byte) 0x00, //(byte) 0x7a, (byte) 0xf3, (byte) 0xa6, (byte) 0xfe,
//(byte) 0xf5, (byte) 0x06, (byte) 0x1c, (byte) 0x01, (byte) 0xe8,
//(byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
//(byte) 0xcc,
};
}
@@ -0,0 +1,137 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.wmf;
import com.twelvemonkeys.imageio.ImageReaderBase;
import com.twelvemonkeys.imageio.plugins.svg.SVGImageReader;
import com.twelvemonkeys.imageio.plugins.svg.SVGReadParam;
import com.twelvemonkeys.imageio.util.IIOUtil;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.wmf.tosvg.WMFTranscoder;
import javax.imageio.IIOException;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.spi.ImageReaderSpi;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Iterator;
/**
* WMFImageReader class description.
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haku $
* @version $Id: WMFImageReader.java,v 1.0 29.jul.2004 13:00:59 haku Exp $
*/
// TODO: Probably possible to do less wrapping/unwrapping of data...
// TODO: Consider using temp file instead of in-memory stream
public class WMFImageReader extends ImageReaderBase {
private SVGImageReader mReader = null;
public WMFImageReader(final ImageReaderSpi pProvider) {
super(pProvider);
}
protected void resetMembers() {
if (mReader != null) {
mReader.dispose();
}
mReader = null;
}
public BufferedImage read(int pIndex, ImageReadParam pParam) throws IOException {
init();
processImageStarted(pIndex);
BufferedImage image = mReader.read(pIndex, pParam);
if (abortRequested()) {
processReadAborted();
return image;
}
processImageComplete();
return image;
}
private synchronized void init() throws IOException {
// Need the extra test, to avoid throwing an IOException from the Transcoder
if (mImageInput == null) {
throw new IllegalStateException("input == null");
}
if (mReader == null) {
WMFTranscoder transcoder = new WMFTranscoder();
ByteArrayOutputStream output = new ByteArrayOutputStream();
Writer writer = new OutputStreamWriter(output, "UTF8");
try {
TranscoderInput in = new TranscoderInput(IIOUtil.createStreamAdapter(mImageInput));
TranscoderOutput out = new TranscoderOutput(writer);
// TODO: Transcodinghints?
transcoder.transcode(in, out);
}
catch (TranscoderException e) {
throw new IIOException(e.getMessage(), e);
}
mReader = new SVGImageReader(getOriginatingProvider());
mReader.setInput(ImageIO.createImageInputStream(new ByteArrayInputStream(output.toByteArray())));
}
}
@Override
public ImageReadParam getDefaultReadParam() {
return new SVGReadParam();
}
public int getWidth(int pIndex) throws IOException {
init();
return mReader.getWidth(pIndex);
}
public int getHeight(int pIndex) throws IOException {
init();
return mReader.getHeight(pIndex);
}
public Iterator<ImageTypeSpecifier> getImageTypes(final int pImageIndex) throws IOException {
init();
return mReader.getImageTypes(pImageIndex);
}
}
@@ -0,0 +1,128 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.wmf;
import com.twelvemonkeys.imageio.spi.ProviderInfo;
import com.twelvemonkeys.lang.SystemUtil;
import com.twelvemonkeys.imageio.util.IIOUtil;
import javax.imageio.ImageReader;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.spi.ServiceRegistry;
import javax.imageio.stream.ImageInputStream;
import java.io.IOException;
import java.util.Locale;
/**
* WMFImageReaderSpi
* <p/>
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: WMFImageReaderSpi.java,v 1.1 2003/12/02 16:45:00 wmhakur Exp $
*/
public class WMFImageReaderSpi extends ImageReaderSpi {
// This is correct, as we rely on the SVG reader
private final static boolean WMF_READER_AVAILABLE = SystemUtil.isClassAvailable("com.twelvemonkeys.imageio.plugins.svg.SVGImageReader");
/**
* Creates a {@code WMFImageReaderSpi}.
*/
public WMFImageReaderSpi() {
this(IIOUtil.getProviderInfo(WMFImageReaderSpi.class));
}
private WMFImageReaderSpi(final ProviderInfo pProviderInfo) {
super(
pProviderInfo.getVendorName(), // Vendor name
pProviderInfo.getVersion(), // Version
WMF_READER_AVAILABLE ? new String[]{"wmf", "WMF"} : new String[]{""}, // Names
WMF_READER_AVAILABLE ? new String[]{"wmf", "emf"} : null, // Suffixes
WMF_READER_AVAILABLE ? new String[]{"application/x-msmetafile", "image/x-wmf"} : null, // Mime-types
WMFImageReader.class.getName(), // Reader class name..?
ImageReaderSpi.STANDARD_INPUT_TYPE, // Output types
null, // Writer SPI names
true, // Supports standard stream metadata format
null, // Native stream metadata format name
null, // Native stream metadata format class name
null, // Extra stream metadata format names
null, // Extra stream metadata format class names
true, // Supports standard image metadata format
null, // Native image metadata format name
null, // Native image metadata format class name
null, // Extra image metadata format names
null // Extra image metadata format class names
);
}
public boolean canDecodeInput(Object source) throws IOException {
return source instanceof ImageInputStream && WMF_READER_AVAILABLE && canDecode((ImageInputStream) source);
}
public static boolean canDecode(ImageInputStream pInput) throws IOException {
if (pInput == null) {
throw new IllegalArgumentException("input == null");
}
try {
pInput.mark();
for (byte header : WMF.HEADER) {
int read = (byte) pInput.read();
if (header != read) {
// System.out.println("--> " + i + ": " + read + " (expected " + header + ")");
return false;
}
}
return true;
}
finally {
pInput.reset();
}
}
public ImageReader createReaderInstance(Object extension) throws IOException {
return new WMFImageReader(this);
}
public String getDescription(Locale locale) {
return "Windows Meta File (WMF) image reader";
}
@SuppressWarnings({"deprecation"})
@Override
public void onRegistration(ServiceRegistry registry, Class<?> category) {
if (!WMF_READER_AVAILABLE) {
IIOUtil.deregisterProvider(registry, this, category);
}
}
}
@@ -0,0 +1,3 @@
com.twelvemonkeys.imageio.plugins.svg.SVGImageReaderSpi
com.twelvemonkeys.imageio.plugins.wmf.WMFImageReaderSpi
#com.twelvemonkeys.imageio.plugins.tiff.TIFFImageReaderSpi
@@ -0,0 +1 @@
#com.twelvemonkeys.imageio.plugins.tiff.TIFFImageWriterSpi