Adding the twelvemonkeys-imageio sub-project
25
twelvemonkeys-imageio/batik/license.txt
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
Copyright (c) 2009, 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.
|
68
twelvemonkeys-imageio/batik/pom.xml
Executable file
@@ -0,0 +1,68 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>twelvemonkeys-imageio-batik</artifactId>
|
||||||
|
<version>2.1</version>
|
||||||
|
<name>TwelveMonkeys ImageIO Batik Plugin</name>
|
||||||
|
<description>
|
||||||
|
<![CDATA[
|
||||||
|
ImageIO wrapper for the Batik SVG Toolkit, enabling Scalable Vector Graphics (SVG) support.
|
||||||
|
See the <a href="http://xmlgraphics.apache.org/batik/">Batik Home page</a>
|
||||||
|
for more information.]]>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<artifactId>twelvemonkeys-imageio</artifactId>
|
||||||
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
|
<version>2.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>twelvemonkeys-imageio-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>twelvemonkeys-imageio-core</artifactId>
|
||||||
|
<classifier>tests</classifier>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>batik</groupId>
|
||||||
|
<artifactId>batik-rasterizer-ext</artifactId>
|
||||||
|
<version>1.6-1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>batik</groupId>
|
||||||
|
<artifactId>batik-svggen</artifactId>
|
||||||
|
<version>1.6-1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>batik</groupId>
|
||||||
|
<artifactId>batik-transcoder</artifactId>
|
||||||
|
<version>1.6-1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
There seems to be some weirdness in the
|
||||||
|
Batik/FOP poms (Batik depends on FOP 0.20-5) that screws things up,
|
||||||
|
making everything end up depending on Batik 1.5, not 1.6
|
||||||
|
-->
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>fop</groupId>
|
||||||
|
<artifactId>fop</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@@ -0,0 +1,553 @@
|
|||||||
|
/*
|
||||||
|
* 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.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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read in the image, using the Batik Transcoder
|
||||||
|
try {
|
||||||
|
processImageStarted(pIndex);
|
||||||
|
|
||||||
|
mRasterizer.mTranscoderInput.setURI(baseURI);
|
||||||
|
BufferedImage image = mRasterizer.getImage();
|
||||||
|
|
||||||
|
processImageComplete();
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
throw new UnsupportedOperationException("Method getImageTypes not implemented");// TODO: Implement
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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,159 @@
|
|||||||
|
/*
|
||||||
|
* 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.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 SVGImageReaderSpi
|
||||||
|
*/
|
||||||
|
public SVGImageReaderSpi() {
|
||||||
|
super(
|
||||||
|
"TwelveMonkeys", // Vendor name
|
||||||
|
"2.0", // 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";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRegistration(ServiceRegistry registry, Class<?> category) {
|
||||||
|
if (!SVG_READER_AVAILABLE) {
|
||||||
|
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,119 @@
|
|||||||
|
/*
|
||||||
|
* 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.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 an SVGImageReaderSpi
|
||||||
|
*/
|
||||||
|
public TIFFImageReaderSpi() {
|
||||||
|
super(
|
||||||
|
"TwelveMonkeys", // Vendor name
|
||||||
|
"2.0", // 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";
|
||||||
|
}
|
||||||
|
|
||||||
|
@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,100 @@
|
|||||||
|
/*
|
||||||
|
* 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.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 TIFFImageWriterSpi.
|
||||||
|
*/
|
||||||
|
public TIFFImageWriterSpi() {
|
||||||
|
super(
|
||||||
|
"TwelveMonkeys", // Vendor name
|
||||||
|
"2.0", // 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";
|
||||||
|
}
|
||||||
|
|
||||||
|
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,136 @@
|
|||||||
|
/*
|
||||||
|
* 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 imageIndex) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Method getImageTypes not implemented");// TODO: Implement
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* 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.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 an SVGImageReaderSpi
|
||||||
|
*/
|
||||||
|
public WMFImageReaderSpi() {
|
||||||
|
super(
|
||||||
|
"TwelveMonkeys", // Vendor name
|
||||||
|
"2.0", // 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";
|
||||||
|
}
|
||||||
|
|
||||||
|
@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
|
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* 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.util.ImageReaderAbstractTestCase;
|
||||||
|
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SVGImageReaderTestCase
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: SVGImageReaderTestCase.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public class SVGImageReaderTestCase extends ImageReaderAbstractTestCase<SVGImageReader> {
|
||||||
|
private SVGImageReaderSpi mSVGImageReaderSpi = new SVGImageReaderSpi();
|
||||||
|
|
||||||
|
protected List<TestData> getTestData() {
|
||||||
|
return Arrays.asList(
|
||||||
|
new TestData(getClassLoaderResource("/svg/batikLogo.svg"), new Dimension(450, 500))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ImageReaderSpi createProvider() {
|
||||||
|
return mSVGImageReaderSpi;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SVGImageReader createReader() {
|
||||||
|
return new SVGImageReader(createProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class<SVGImageReader> getReaderClass() {
|
||||||
|
return SVGImageReader.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getFormatNames() {
|
||||||
|
return Arrays.asList("svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getSuffixes() {
|
||||||
|
return Arrays.asList("svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getMIMETypes() {
|
||||||
|
return Arrays.asList("image/svg+xml");
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* 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.util.ImageReaderAbstractTestCase;
|
||||||
|
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SVGImageReaderTestCase
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: SVGImageReaderTestCase.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public class WMFImageReaderTestCase extends ImageReaderAbstractTestCase<WMFImageReader> {
|
||||||
|
private WMFImageReaderSpi mSVGImageReaderSpi = new WMFImageReaderSpi();
|
||||||
|
|
||||||
|
protected List<TestData> getTestData() {
|
||||||
|
return Arrays.asList(
|
||||||
|
// TODO: Dimensions does not look right...
|
||||||
|
new TestData(getClassLoaderResource("/wmf/test.wmf"), new Dimension(841, 673))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ImageReaderSpi createProvider() {
|
||||||
|
return mSVGImageReaderSpi;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WMFImageReader createReader() {
|
||||||
|
return new WMFImageReader(createProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class<WMFImageReader> getReaderClass() {
|
||||||
|
return WMFImageReader.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getFormatNames() {
|
||||||
|
return Arrays.asList("wmf");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getSuffixes() {
|
||||||
|
return Arrays.asList("wmf", "emf");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getMIMETypes() {
|
||||||
|
return Arrays.asList("image/x-wmf", "application/x-msmetafile");
|
||||||
|
}
|
||||||
|
}
|
218
twelvemonkeys-imageio/batik/src/test/resources/svg/batikLogo.svg
Executable file
@@ -0,0 +1,218 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
============================================================================
|
||||||
|
The Apache Software License, Version 1.1
|
||||||
|
============================================================================
|
||||||
|
|
||||||
|
Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modifica-
|
||||||
|
tion, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. 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.
|
||||||
|
|
||||||
|
3. The end-user documentation included with the redistribution, if any, must
|
||||||
|
include the following acknowledgment: "This product includes software
|
||||||
|
developed by the Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
Alternately, this acknowledgment may appear in the software itself, if
|
||||||
|
and wherever such third-party acknowledgments normally appear.
|
||||||
|
|
||||||
|
4. The names "Batik" and "Apache Software Foundation" must not be
|
||||||
|
used to endorse or promote products derived from this software without
|
||||||
|
prior written permission. For written permission, please contact
|
||||||
|
apache@apache.org.
|
||||||
|
|
||||||
|
5. Products derived from this software may not be called "Apache", nor may
|
||||||
|
"Apache" appear in their name, without prior written permission of the
|
||||||
|
Apache Software Foundation.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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
|
||||||
|
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||||
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
|
||||||
|
DING, 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.
|
||||||
|
|
||||||
|
This software consists of voluntary contributions made by many individuals
|
||||||
|
on behalf of the Apache Software Foundation. For more information on the
|
||||||
|
Apache Software Foundation, please see <http://www.apache.org/>.
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- ====================================================================== -->
|
||||||
|
<!-- Defines the Batik Logo using an SVG font. -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- @author vhardy@apache.org -->
|
||||||
|
<!-- @author thomas.deweese@kodak.com -->
|
||||||
|
<!-- @author bella.robinson@cmis.csiro.au -->
|
||||||
|
<!-- @version $Id: batikLogo.svg,v 1.13 2003/08/08 11:39:29 vhardy Exp $ -->
|
||||||
|
<!-- ====================================================================== -->
|
||||||
|
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="body" width="450" height="500" viewBox="0 0 450 500">
|
||||||
|
<title>Batik Logo</title>
|
||||||
|
<g id="content">
|
||||||
|
<defs>
|
||||||
|
<symbol id="Batik_Squiggle" stroke="none" viewBox="0 0 540 570">
|
||||||
|
<path id="Batik_Squiggle_Blue" fill="#6666FF"
|
||||||
|
d="M172,44C137,60,31,135,11,199c-8,27,22,48,44,33
|
||||||
|
C14,306-1,332,0,356c0,14,13,42,44,27c8-4,35-25,52-41
|
||||||
|
c14-1,24-11,42-28c17,14,36,10,52-7c22,2,82-78,44-108
|
||||||
|
c-3-24-30-37-53-18c-6-2-13-1-18,1c22-35,43-82,49-105
|
||||||
|
C219,47,188,36,172,44z"/>
|
||||||
|
<path id="Batik_Squiggle_Red" fill="#FF0000"
|
||||||
|
d="M400,0c-18,3-49,31-49,31c-29,23-43,58-28,95
|
||||||
|
c-13,14-29,44-29,67c0,28,20,52,50,29c7,8,21,16,37,5
|
||||||
|
c-5,29,3,48,26,49c1,10,13,31,36,17c16-10,58-39,79-56
|
||||||
|
c25-23,25-94-18-89c33-59-3-96-27-84c-10,4-46,25-52,30
|
||||||
|
c-1-7-5-12-11-14C436,45,436-5,401,0z"/>
|
||||||
|
<path id="Batik_Squiggle_Green" fill="#33CC33"
|
||||||
|
d="M275,353c-46,12-88,43-114,91c-9,16,6,37,25,33
|
||||||
|
c-14,24-40,67-15,81c28,16,52-8,60-15c18,21,50,10,81-17
|
||||||
|
c41,14,68-2,103-53c8-12,30-43,30-65c0-16-15-30-35-21
|
||||||
|
c-1-12-9-38-53-19c-10-6-31-5-54,17
|
||||||
|
C308,375,300,347,275,353z"/>
|
||||||
|
</symbol>
|
||||||
|
|
||||||
|
<!-- ============================= -->
|
||||||
|
<!-- Batik SVG Font Definition -->
|
||||||
|
<!-- ============================= -->
|
||||||
|
|
||||||
|
<font horiz-adv-x="150" id="Batik">
|
||||||
|
<font-face
|
||||||
|
font-family="Batik SVGFont"
|
||||||
|
units-per-em="240"
|
||||||
|
ascent="190"
|
||||||
|
descent="50"
|
||||||
|
alphabetic="0"/>
|
||||||
|
|
||||||
|
<missing-glyph horiz-adv-x="150" d="M20 0 V240 H100 V0 z"/>
|
||||||
|
|
||||||
|
|
||||||
|
<glyph unicode=" " glyph-name=" " horiz-adv-x="100"/>
|
||||||
|
|
||||||
|
<glyph id="B" unicode="B" glyph-name="B" horiz-adv-x="130">
|
||||||
|
<g transform="scale(1,-1)translate(0,-170)">
|
||||||
|
<path d="M21.244,141.963V40.831c0-6.188-0.57-10.773-1.707-13.754c-1.137-2.977-3.066-5.461-5.793-7.449c-1.137-0.766-2.367-1.395-3.695-1.891s-3.012-0.938-5.055-1.32c-2.125-0.371-3.488-0.781-4.094-1.23s-0.906-1.121-0.906-2.02
|
||||||
|
c0-1.195,0.32-2.035,0.969-2.52c0.645-0.484,1.953-0.73,3.93-0.73c0.758,0,3.816,0.211,9.176,0.625c5.355,0.418,10.387,0.625,15.098,0.625c2.961,0,7.883-0.207,14.758-0.625c6.875-0.414,12.324-0.625,16.352-0.625c16.711,0,29.762,3.461,39.145,10.379
|
||||||
|
s14.074,16.574,14.074,28.965c0,7.148-1.793,13.418-5.375,18.816c-3.586,5.398-9,9.996-16.242,13.797v2.18c11.574,2.051,20.445,6.547,26.613,13.492s9.254,15.879,9.254,26.805c0,15.406-5.184,27.645-15.551,36.715s-24.473,13.602-42.316,13.602
|
||||||
|
c-6.078,0-13.367-0.293-21.871-0.875c-8.508-0.586-13.898-0.875-16.172-0.875c-6.762,0-13.863,0.348-21.301,1.043c-1.824,0.137-2.965,0.207-3.418,0.207c-0.609,0-1.199-0.344-1.77-1.027s-0.852-1.406-0.852-2.172c0-1.598,1.355-2.93,4.074-3.996l0.113-0.055
|
||||||
|
c1.809-0.836,3.223-1.574,4.242-2.223c1.02-0.645,1.906-1.387,2.66-2.223c2.039-2.047,3.492-4.516,4.359-7.402s1.301-7.254,1.301-13.105z M39.244,73.209c0,3.648,0.453,5.93,1.367,6.84c0.914,0.914,2.816,1.367,5.711,1.367h16.555
|
||||||
|
c12.023,0,20.758-2.031,26.203-6.098c5.441-4.066,8.164-10.508,8.164-19.324c0-10.945-4.188-20.027-12.559-27.246c-8.375-7.219-18.914-10.832-31.625-10.832c-5.711,0-9.441,0.855-11.191,2.566s-2.625,5.148-2.625,10.316v42.41z M39.244,150.737
|
||||||
|
c0,6.539,1.789,10.953,5.371,13.242c3.578,2.293,11.16,3.438,22.746,3.438c14.172,0,24.82-3.031,31.945-9.094s10.688-15.156,10.688-27.281c0-13.031-4.234-23.188-12.695-30.461s-20.316-10.914-35.563-10.914H47.463c-3.578,0-5.84,0.477-6.793,1.426
|
||||||
|
s-1.426,3.285-1.426,7.004v52.641z"/>
|
||||||
|
<!-- Put the Squiggle in the B -->
|
||||||
|
<use xlink:href="#Batik_Squiggle" width="54" height="57"
|
||||||
|
transform="translate(45,103)" />
|
||||||
|
</g>
|
||||||
|
</glyph>
|
||||||
|
|
||||||
|
<glyph id="a" unicode="a" glyph-name="a" horiz-adv-x="105">
|
||||||
|
<path transform="scale(1,-1)translate(-125, -170)"
|
||||||
|
d="M194.825,161.952c-5.238,4.766-10.891,8.285-16.961,10.559c-6.07,2.27-12.863,3.406-20.375,3.406c-7.363,0-12.98-1.922-16.848-5.762c-3.871-3.844-5.805-9.414-5.805-16.719c0-9.359,4.266-16.758,12.805-22.195
|
||||||
|
c8.535-5.438,23.766-10.215,45.695-14.324v-15.789c0-7.09-2.16-12.523-6.477-16.297s-10.523-5.664-18.625-5.664c-6.891,0-11.758,0.992-14.598,2.977s-4.258,5.336-4.258,10.063c0,1.984,0.281,4.27,0.852,6.863s0.855,4.156,0.855,4.688
|
||||||
|
c0,1.07-0.516,1.945-1.547,2.633s-2.352,1.027-3.953,1.027c-3.055,0-5.652-0.816-7.793-2.449s-3.207-3.664-3.207-6.098c0-6.605,3.664-12.625,11-18.055c7.332-5.43,15.977-8.148,25.93-8.148c13.906,0,23.727,2.621,29.465,7.855
|
||||||
|
c5.734,5.238,8.605,14.535,8.605,27.891v42.844c0,6.516,0.621,10.715,1.867,12.594s3.609,2.816,7.086,2.816c0.602,0,1.434-0.035,2.492-0.113c1.055-0.078,1.773-0.117,2.152-0.117c0.527,0,1.02,0.246,1.473,0.73c0.453,0.488,0.68,1.07,0.68,1.742
|
||||||
|
c0,1.574-1.273,2.887-3.816,3.934s-5.785,1.574-9.73,1.574c-4.176,0-7.668-1.039-10.477-3.117s-4.973-5.191-6.488-9.348z M193.037,122.167c-16.43,3.43-27.789,7.273-34.074,11.535c-6.285,4.266-9.426,9.973-9.426,17.129c0,5.559,1.512,9.879,4.543,12.961
|
||||||
|
c3.027,3.086,7.27,4.625,12.723,4.625c7.492,0,13.738-1.941,18.738-5.832c4.996-3.887,7.496-8.813,7.496-14.777v-25.641z"/>
|
||||||
|
</glyph>
|
||||||
|
|
||||||
|
<glyph id="ti" unicode="ti" glyph-name="ti" horiz-adv-x="100">
|
||||||
|
<g style="fill:#FF0000;" transform="scale(1,-1)translate(-215,-170)">
|
||||||
|
<path d="M311.259,168.69c-0.684-0.531-2.199-0.871-4.551-1.023c-1.441,0-2.711-0.113-3.813-0.34s-2.105-0.57-3.012-1.027c-3.035-1.594-5.102-3.586-6.203-5.98c-1.102-2.391-1.648-6.625-1.648-12.703v-35.543c0-11.688,0.188-23.227,0.566-34.617
|
||||||
|
c0.078-2.047,0.117-3.227,0.117-3.531c0-1.594-0.191-2.617-0.57-3.074c-0.383-0.453-1.066-0.684-2.059-0.684c-1.066,0-9.44,3.681-11.451,4.196s-6.655,1.804-11.209,1.804h-20.266V55.045c0-1.148-0.117-1.918-0.344-2.301s-0.684-0.578-1.363-0.578
|
||||||
|
c-1.219,0-3.059,2.172-5.527,6.516s-4.727,7.617-6.777,9.824c-2.887,3.199-5.98,6.246-9.285,9.141s-4.953,4.609-4.953,5.141c0,0.609,0.375,1.203,1.129,1.773s1.434,0.855,2.035,0.855h8.586v59.84c0,11.266,2.051,19.273,6.16,24.027
|
||||||
|
c4.105,4.754,10.875,7.133,20.305,7.133c5.724,0,11.038-1.066,15.948-3.17c4.26-0.381,8.633-0.58,13.126-0.58c4.328,0,8.957,0.211,13.895,0.625c4.934,0.414,7.668,0.625,8.199,0.625c1.141,0,2.09-0.266,2.848-0.793c0.758-0.531,1.141-1.176,1.141-1.934
|
||||||
|
c0-1.137-0.344-1.969-1.023-2.5z M251.317,163.288c-2.773-2.922-4.156-7.227-4.156-12.914v-64.957c0,0,12.812,0.543,13.215,0.57c1.194,0.081,2.965,0.184,5.164,0.184c3.867,0,6.23,1.637,7.637,3.914c1.402,2.281,2.105,7.367,2.105,15.266v42.039
|
||||||
|
c0,4.781-0.285,8.273-0.848,10.477c-0.566,2.203-1.563,4.211-2.992,6.031c-0.758,0.836-1.961,1.863-3.617,3.074c-0.292,0.169-0.532,0.312-0.731,0.434c-1.229,0.172-2.446,0.261-3.651,0.261c-5.313,0-9.355-1.457-12.125-4.379z"/>
|
||||||
|
<path d="M284.067,48.667c1.969,0,4.207-1.535,6.711-4.605c2.5-3.07,3.754-5.555,3.754-7.453c0-1.969-1.309-4.453-3.926-7.449c-2.617-2.992-4.648-4.492-6.086-4.492c-1.594,0-3.695,1.555-6.313,4.664s-3.926,5.766-3.926,7.961c0,2.352,1.137,4.836,3.41,7.453s4.398,3.922,6.375,3.922z"/>
|
||||||
|
</g>
|
||||||
|
</glyph>
|
||||||
|
|
||||||
|
|
||||||
|
<glyph id="k" unicode="k" glyph-name="k" horiz-adv-x="120">
|
||||||
|
<path transform="scale(1,-1)translate(-310, -170)"
|
||||||
|
d="M331.507,147.307V35.413c0-8.078-0.68-13.219-2.031-15.43s-3.906-3.316-7.664-3.316h-1.805c-1.387,0-2.465-0.242-3.23-0.734c-0.77-0.492-1.191-1.188-1.27-2.094c0-1.656,1.977-2.941,5.93-3.848l0.23-0.074
|
||||||
|
c1.824-0.301,3.516-0.68,5.074-1.133s3.098-0.984,4.617-1.594c2.66-1.059,5.586-2.535,8.781-4.43c3.191-1.895,5.246-2.844,6.16-2.844c0.984,0,1.746,0.383,2.277,1.141s0.801,1.859,0.801,3.301c0,0.305-0.039,1.082-0.113,2.332
|
||||||
|
c-0.078,1.254-0.113,2.375-0.113,3.359c-0.383,5.391-0.668,10.684-0.859,15.883s-0.285,10.531-0.285,15.996v80.641l33.148-30.207c1.434-1.367,2.566-2.715,3.398-4.047c0.832-1.328,1.25-2.527,1.25-3.594c0-1.289-1.324-2.316-3.969-3.078
|
||||||
|
c-0.305-0.074-0.566-0.148-0.793-0.227c-1.891-0.375-3.215-0.828-3.969-1.359c-0.758-0.527-1.133-1.242-1.133-2.148c0-0.68,0.453-1.262,1.359-1.754s2.004-0.738,3.289-0.738c0.301,0,2.305,0.211,6.008,0.625c3.703,0.418,7.297,0.625,10.773,0.625
|
||||||
|
c2.871,0,6.141-0.207,9.809-0.625c3.664-0.414,5.875-0.625,6.633-0.625c1.438,0,2.496,0.227,3.176,0.68s1.02,1.133,1.02,2.039c0,1.734-1.285,2.828-3.855,3.281h-0.113c-1.133,0.152-2.27,0.379-3.402,0.684s-2.305,0.723-3.516,1.254
|
||||||
|
c-7.332,2.891-13.758,7.07-19.273,12.543c-0.605,0.684-1.059,1.141-1.359,1.367l-19.73,17.781c10.66,14.914,19.223,26.215,25.688,33.902s11.59,12.672,15.371,14.953c3.023,1.75,6.879,2.969,11.566,3.652c0.375,0.078,0.641,0.113,0.793,0.113
|
||||||
|
c2.191,0.152,3.609,0.438,4.254,0.852c0.641,0.414,1,1.113,1.078,2.094c0,1.133-0.512,1.922-1.535,2.375s-3.012,0.68-5.965,0.68h-19.277c-5,0-15.23-10.113-30.684-30.34c-5.609-7.375-10.117-13.227-13.523-17.563l-6.516,6.156v15.617
|
||||||
|
c0,6.852,0.531,11.344,1.602,13.477c1.066,2.133,3.086,3.883,6.059,5.25c1.219,0.535,3.121,0.992,5.715,1.371c0.078,0.023,0.152,0.031,0.23,0.031c2.133,0.152,3.523,0.492,4.172,1.023s0.973,1.363,0.973,2.5c0,0.836-0.344,1.496-1.027,1.988
|
||||||
|
s-1.594,0.738-2.734,0.738c-0.305,0-2.758-0.211-7.355-0.625c-4.602-0.414-8.992-0.625-13.172-0.625c-6.309,0-12.313,0.375-18.016,1.125c-0.914,0.082-1.445,0.125-1.594,0.125c-0.836,0-1.523-0.25-2.055-0.746s-0.797-1.09-0.797-1.777
|
||||||
|
c0-0.766,0.262-1.473,0.789-2.121c0.523-0.648,1.613-1.434,3.27-2.355c0.375-0.227,0.789-0.492,1.242-0.797c1.273-0.758,2.215-1.445,2.816-2.055c1.277-1.367,2.16-3.074,2.648-5.129c0.488-2.051,0.734-5.926,0.734-11.629z"/>
|
||||||
|
</glyph>
|
||||||
|
|
||||||
|
<glyph unicode="*" glyph-name="*" horiz-adv-x="120">
|
||||||
|
<g transform="scale(1, -1)">
|
||||||
|
<use xlink:href="#Batik_Squiggle" width="108" height="114"
|
||||||
|
transform="translate(0,-130)" />
|
||||||
|
</g>
|
||||||
|
</glyph>
|
||||||
|
|
||||||
|
<hkern g1="B" g2="a" k="5"/>
|
||||||
|
<hkern g1="a" g2="t" k="14"/>
|
||||||
|
<hkern g1="a" g2="ti" k="14"/>
|
||||||
|
<hkern g1="i" g2="k" k="6"/>
|
||||||
|
<hkern g1="ti" g2="k" k="6"/>
|
||||||
|
</font>
|
||||||
|
|
||||||
|
<g id="Batik_Logo_Underline" transform="scale(.75,.75)" >
|
||||||
|
<path d="M37.886,60c-0.018,0.1-0.377,1.375-0.439,1.492c-0.15,0.285-1.382,2.046-1.598,2.291c0.206-0.233,0.428-0.452,0.65-0.67c-6.851,6.751-0.262,0.713,0.893-0.499c1.893-1.986-2.124,1.712,0.112-0.08
|
||||||
|
c0.604-0.484,1.242-0.925,1.886-1.355c-2.574,1.719,0.458-0.228,1.417-0.868c-2.634,1.761-1.231,0.788-0.605,0.423c1.799-1.049,3.686-1.946,5.591-2.783c0.978-0.43,1.97-0.828,2.964-1.217c1.844-0.723-1.918,0.683-0.003,0.012
|
||||||
|
c0.706-0.264,1.412-0.528,2.117-0.792c-1.224,0.456-1.388,0.521-0.491,0.195c2.531-0.908,5.102-1.708,7.683-2.461c5.73-1.672,11.556-3.013,17.401-4.216c30.689-6.315,61.555-8.765,92.723-10.467c35.225-1.924,70.559-2.313,105.819-1.278
|
||||||
|
c27.375,0.803,55.137,2.029,82.154,6.813c1.854,0.328,3.702,0.69,5.545,1.079c-2.182-0.459,0.632,0.149,1.102,0.26c0.785,0.185,1.566,0.383,2.347,0.585c2.714,0.705,5.407,1.537,7.987,2.642c0.676-4.98,1.351-9.959,2.026-14.939
|
||||||
|
c-29.001,20.428-70.184,18.783-104.484,20.881c-37.85,2.314-78.422,7.341-105.371,37.024c-3.142,3.46-5.693,10.35-0.21,12.998c8.018,3.873,16.683,5.137,25.266,7.166c7.149,1.69,13.362,4.381,16.934,11.121c4.934,9.311,2.75,18.519-0.175,28.003
|
||||||
|
c-3.217,10.428-5.508,20.886-0.692,31.219c4.219,9.05,19.441-3.641,15.823-11.611c-4.234-9.326,1.407-19.828,3.653-28.997c2.667-10.888,1.908-22.401-3.872-32.224c-9.76-16.588-31.066-13.848-46.449-21.271c-0.07,4.333-0.14,8.666-0.21,12.998
|
||||||
|
c10.537-11.719,25.017-18.668,40.974-22.714c18.159-4.604,37.034-5.719,55.666-6.747c37.146-2.049,77.822-2.405,109.506-24.634c4.136-2.902,8.771-12.048,2.026-14.939c-7.868-3.373-16.687-4.781-25.083-6.132c-12.447-2.004-25.032-3.156-37.6-4.075
|
||||||
|
c-33.215-2.427-66.599-2.839-99.887-2.247c-34.872,0.621-69.791,2.496-104.432,6.637c-24.317,2.907-50.972,6.112-73.187,17.171c-4.951,2.465-9.505,5.587-13.309,9.623c-1.027,1.089-2.19,2.464-2.986,3.643c0.137-0.203-3.419,6.639-1.518,3.165
|
||||||
|
c-0.205,0.374-0.38,0.762-0.549,1.151c-1.126,2.59-2.056,5.322-2.196,8.168c-0.222,4.484,4.48,3.091,6.917,1.551c3.856-2.437,7.345-6.516,8.167-11.093z"/>
|
||||||
|
</g> <!-- End Batik_Logo_Underline -->
|
||||||
|
|
||||||
|
<filter id="dropShadow" filterUnits="objectBoundingBox"
|
||||||
|
filterRes="200" width="1.4" height="1.4">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="4" />
|
||||||
|
<feOffset dx="8" dy="8" />
|
||||||
|
<feComponentTransfer result="shadow">
|
||||||
|
<feFuncA type="linear" slope=".5" intercept="0" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feComposite in2="shadow" in="SourceGraphic"/>
|
||||||
|
</filter>
|
||||||
|
|
||||||
|
<g id="Batik_Logo_Shadow" filter="url(#dropShadow)">
|
||||||
|
<g id="Batik_Logo">
|
||||||
|
<text id="text" x="0" y="0" font-family="Batik SVGFont"
|
||||||
|
font-size="180">Batik</text>
|
||||||
|
<use xlink:href="#Batik_Logo_Underline"/>
|
||||||
|
</g> <!-- End Batik_Logo -->
|
||||||
|
</g> <!-- End Batik_Logo_Shadow -->
|
||||||
|
|
||||||
|
<g id="Batik_Tag_Box" >
|
||||||
|
<rect x="1" y="1" width="446" height="496"
|
||||||
|
style="fill:none; stroke:black" />
|
||||||
|
<use xlink:href="#Batik_Squiggle" width="27" height="28"
|
||||||
|
transform="translate(418,467)" />
|
||||||
|
</g> <!-- End Batik_Tag_Box -->
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<use x="65" y="233" xlink:href="#Batik_Logo_Shadow" />
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- ============================================================= -->
|
||||||
|
<!-- Batik sample mark -->
|
||||||
|
<!-- ============================================================= -->
|
||||||
|
<use xlink:href="#Batik_Tag_Box" />
|
||||||
|
</svg>
|
BIN
twelvemonkeys-imageio/batik/src/test/resources/wmf/test.wmf
Executable file
25
twelvemonkeys-imageio/core/license.txt
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
Copyright (c) 2009, 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.
|
16
twelvemonkeys-imageio/core/pom.xml
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>twelvemonkeys-imageio-core</artifactId>
|
||||||
|
<version>2.1</version>
|
||||||
|
<name>TwelveMonkeys ImageIO Core</name>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<artifactId>twelvemonkeys-imageio</artifactId>
|
||||||
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
|
<version>2.1</version>
|
||||||
|
</parent>
|
||||||
|
</project>
|
@@ -0,0 +1,381 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.image.BufferedImageIcon;
|
||||||
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.imageio.ImageReadParam;
|
||||||
|
import javax.imageio.ImageReader;
|
||||||
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.MouseAdapter;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ImageReaderBase
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: ImageReaderBase.java,v 1.0 Sep 20, 2007 5:28:37 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public abstract class ImageReaderBase extends ImageReader {
|
||||||
|
/**
|
||||||
|
* For convenience. Only set if the input is an {@code ImageInputStream}.
|
||||||
|
* @see #setInput(Object, boolean, boolean)
|
||||||
|
*/
|
||||||
|
protected ImageInputStream mImageInput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an {@code ImageReader} and sets its
|
||||||
|
* {@code originatingProvider} field to the supplied value.
|
||||||
|
* <p/>
|
||||||
|
* <p> Subclasses that make use of extensions should provide a
|
||||||
|
* constructor with signature {@code (ImageReaderSpi,
|
||||||
|
* Object)} in order to retrieve the extension object. If
|
||||||
|
* the extension object is unsuitable, an
|
||||||
|
* {@code IllegalArgumentException} should be thrown.
|
||||||
|
*
|
||||||
|
* @param pOriginatingProvider the {@code ImageReaderSpi} that is
|
||||||
|
* invoking this constructor, or {@code null}.
|
||||||
|
*/
|
||||||
|
protected ImageReaderBase(final ImageReaderSpi pOriginatingProvider) {
|
||||||
|
super(pOriginatingProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides {@code setInput}, to allow easy access to the input, in case
|
||||||
|
* it is an {@code ImageInputStream}.
|
||||||
|
*
|
||||||
|
* @param pInput the {@code ImageInputStream} or other
|
||||||
|
* {@code Object} to use for future decoding.
|
||||||
|
* @param pSeekForwardOnly if {@code true}, images and metadata
|
||||||
|
* may only be read in ascending order from this input source.
|
||||||
|
* @param pIgnoreMetadata if {@code true}, metadata
|
||||||
|
* may be ignored during reads.
|
||||||
|
*
|
||||||
|
* @exception IllegalArgumentException if {@code input} is
|
||||||
|
* not an instance of one of the classes returned by the
|
||||||
|
* originating service provider's {@code getInputTypes}
|
||||||
|
* method, or is not an {@code ImageInputStream}.
|
||||||
|
*
|
||||||
|
* @see ImageInputStream
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setInput(Object pInput, boolean pSeekForwardOnly, boolean pIgnoreMetadata) {
|
||||||
|
resetMembers();
|
||||||
|
super.setInput(pInput, pSeekForwardOnly, pIgnoreMetadata);
|
||||||
|
if (pInput instanceof ImageInputStream) {
|
||||||
|
mImageInput = (ImageInputStream) pInput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
resetMembers();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
resetMembers();
|
||||||
|
super.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets all member variables. This method is by default invoked from:
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link #setInput(Object, boolean, boolean)}</li>
|
||||||
|
* <li>{@link #dispose()}</li>
|
||||||
|
* <li>{@link #reset()}</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected abstract void resetMembers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defaul implementation that always return {@code null}.
|
||||||
|
*
|
||||||
|
* @param pImageIndex ignored, unless overriden
|
||||||
|
* @return {@code null}, unless overriden
|
||||||
|
* @throws IOException never, unless overriden.
|
||||||
|
*/
|
||||||
|
public IIOMetadata getImageMetadata(int pImageIndex) throws IOException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defaul implementation that always return {@code null}.
|
||||||
|
*
|
||||||
|
* @return {@code null}, unless overriden
|
||||||
|
* @throws IOException never, unless overriden.
|
||||||
|
*/
|
||||||
|
public IIOMetadata getStreamMetadata() throws IOException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation that always returns {@code 1}.
|
||||||
|
*
|
||||||
|
* @param pAllowSearch ignored, unless overriden
|
||||||
|
* @return {@code 1}, unless overriden
|
||||||
|
* @throws IOException never, unless overriden
|
||||||
|
*/
|
||||||
|
public int getNumImages(boolean pAllowSearch) throws IOException {
|
||||||
|
assertInput();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method to make sure image index is within bounds.
|
||||||
|
*
|
||||||
|
* @param pIndex the image index
|
||||||
|
*
|
||||||
|
* @throws java.io.IOException if an error occurs during reading
|
||||||
|
* @throws IndexOutOfBoundsException if not
|
||||||
|
* <tt>minIndex <= pIndex < numImages</tt>
|
||||||
|
*/
|
||||||
|
protected void checkBounds(int pIndex) throws IOException {
|
||||||
|
assertInput();
|
||||||
|
if (pIndex < getMinIndex()) {
|
||||||
|
throw new IndexOutOfBoundsException("index < minIndex");
|
||||||
|
}
|
||||||
|
else if (getNumImages(false) != -1 && pIndex >= getNumImages(false)) {
|
||||||
|
throw new IndexOutOfBoundsException("index >= numImages (" + pIndex + " >= " + getNumImages(false) + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes sure input is set.
|
||||||
|
*
|
||||||
|
* @throws IllegalStateException if {@code getInput() == null}.
|
||||||
|
*/
|
||||||
|
protected void assertInput() {
|
||||||
|
if (getInput() == null) {
|
||||||
|
throw new IllegalStateException("getInput() == null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility method for getting the area of interest (AOI) of an image.
|
||||||
|
* The AOI is defined by the {@link javax.imageio.IIOParam#setSourceRegion(java.awt.Rectangle)}
|
||||||
|
* method.
|
||||||
|
* <p/>
|
||||||
|
* Note: If it is possible for the reader to read the AOI directly, such a
|
||||||
|
* method should be used instead, for efficiency.
|
||||||
|
*
|
||||||
|
* @param pImage the image to get AOI from
|
||||||
|
* @param pParam the param optionally specifying the AOI
|
||||||
|
*
|
||||||
|
* @return a {@code BufferedImage} containing the area of interest (source
|
||||||
|
* region), or the original image, if no source region was set, or
|
||||||
|
* {@code pParam} was {@code null}
|
||||||
|
*/
|
||||||
|
protected static BufferedImage fakeAOI(BufferedImage pImage, ImageReadParam pParam) {
|
||||||
|
return IIOUtil.fakeAOI(pImage, getSourceRegion(pParam, pImage.getWidth(), pImage.getHeight()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility method for getting the subsampled image.
|
||||||
|
* The subsampling is defined by the
|
||||||
|
* {@link javax.imageio.IIOParam#setSourceSubsampling(int, int, int, int)}
|
||||||
|
* method.
|
||||||
|
* <p/>
|
||||||
|
* NOTE: This method does not take the subsampling offsets into
|
||||||
|
* consideration.
|
||||||
|
* <p/>
|
||||||
|
* Note: If it is possible for the reader to subsample directly, such a
|
||||||
|
* method should be used instead, for efficiency.
|
||||||
|
*
|
||||||
|
* @param pImage the image to subsample
|
||||||
|
* @param pParam the param optionally specifying subsampling
|
||||||
|
*
|
||||||
|
* @return an {@code Image} containing the subsampled image, or the
|
||||||
|
* original image, if no subsampling was specified, or
|
||||||
|
* {@code pParam} was {@code null}
|
||||||
|
*/
|
||||||
|
protected static Image fakeSubsampling(Image pImage, ImageReadParam pParam) {
|
||||||
|
return IIOUtil.fakeSubsampling(pImage, pParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] pArgs) throws IOException {
|
||||||
|
BufferedImage image = ImageIO.read(new File(pArgs[0]));
|
||||||
|
showIt(image, pArgs[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void showIt(final BufferedImage pImage, final String pTitle) {
|
||||||
|
try {
|
||||||
|
SwingUtilities.invokeAndWait(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
JFrame frame = new JFrame(pTitle);
|
||||||
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
frame.setLocationByPlatform(true);
|
||||||
|
JPanel pane = new JPanel(new BorderLayout());
|
||||||
|
JScrollPane scroll = new JScrollPane(new ImageLabel(pImage));
|
||||||
|
scroll.setBorder(null);
|
||||||
|
pane.add(scroll);
|
||||||
|
frame.setContentPane(pane);
|
||||||
|
frame.pack();
|
||||||
|
frame.setVisible(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
catch (InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ImageLabel extends JLabel {
|
||||||
|
Paint mBackground;
|
||||||
|
|
||||||
|
public ImageLabel(BufferedImage pImage) {
|
||||||
|
super(new BufferedImageIcon(pImage));
|
||||||
|
setOpaque(false);
|
||||||
|
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
|
||||||
|
|
||||||
|
mBackground = createTexture();
|
||||||
|
|
||||||
|
JPopupMenu popup = createBackgroundPopup();
|
||||||
|
|
||||||
|
setComponentPopupMenu(popup);
|
||||||
|
addMouseListener(new MouseAdapter() {
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(MouseEvent e) {
|
||||||
|
if (e.isPopupTrigger()) {
|
||||||
|
getComponentPopupMenu().show(ImageLabel.this, e.getX(), e.getY());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private JPopupMenu createBackgroundPopup() {
|
||||||
|
JPopupMenu popup = new JPopupMenu();
|
||||||
|
ButtonGroup group = new ButtonGroup();
|
||||||
|
addCheckBoxItem(new ChangeBackgroundAction("Default", mBackground), popup, group);
|
||||||
|
popup.addSeparator();
|
||||||
|
addCheckBoxItem(new ChangeBackgroundAction("White", Color.WHITE), popup, group);
|
||||||
|
addCheckBoxItem(new ChangeBackgroundAction("Light", Color.LIGHT_GRAY), popup, group);
|
||||||
|
addCheckBoxItem(new ChangeBackgroundAction("Gray", Color.GRAY), popup, group);
|
||||||
|
addCheckBoxItem(new ChangeBackgroundAction("Dark", Color.DARK_GRAY), popup, group);
|
||||||
|
addCheckBoxItem(new ChangeBackgroundAction("Black", Color.BLACK), popup, group);
|
||||||
|
popup.addSeparator();
|
||||||
|
addCheckBoxItem(new ChooseBackgroundAction("Choose...", Color.BLUE), popup, group);
|
||||||
|
return popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCheckBoxItem(final Action pAction, final JPopupMenu pPopup, final ButtonGroup pGroup) {
|
||||||
|
JCheckBoxMenuItem item = new JCheckBoxMenuItem(pAction);
|
||||||
|
pGroup.add(item);
|
||||||
|
pPopup.add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Paint createTexture() {
|
||||||
|
GraphicsConfiguration graphicsConfiguration = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
|
||||||
|
BufferedImage pattern = graphicsConfiguration.createCompatibleImage(20, 20);
|
||||||
|
Graphics2D g = pattern.createGraphics();
|
||||||
|
try {
|
||||||
|
g.setColor(Color.LIGHT_GRAY);
|
||||||
|
g.fillRect(0, 0, pattern.getWidth(), pattern.getHeight());
|
||||||
|
g.setColor(Color.GRAY);
|
||||||
|
g.fillRect(0, 0, pattern.getWidth() / 2, pattern.getHeight() / 2);
|
||||||
|
g.fillRect(pattern.getWidth() / 2, pattern.getHeight() / 2, pattern.getWidth() / 2, pattern.getHeight() / 2);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
g.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TexturePaint(pattern, new Rectangle(pattern.getWidth(), pattern.getHeight()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintComponent(Graphics g) {
|
||||||
|
Graphics2D gr = (Graphics2D) g;
|
||||||
|
gr.setPaint(mBackground);
|
||||||
|
gr.fillRect(0, 0, getWidth(), getHeight());
|
||||||
|
super.paintComponent(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ChangeBackgroundAction extends AbstractAction {
|
||||||
|
protected Paint mPaint;
|
||||||
|
|
||||||
|
public ChangeBackgroundAction(final String pName, final Paint pPaint) {
|
||||||
|
super(pName);
|
||||||
|
mPaint = pPaint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
mBackground = mPaint;
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ChooseBackgroundAction extends ChangeBackgroundAction {
|
||||||
|
public ChooseBackgroundAction(final String pName, final Color pColor) {
|
||||||
|
super(pName, pColor);
|
||||||
|
putValue(Action.SMALL_ICON, new Icon() {
|
||||||
|
public void paintIcon(Component c, Graphics pGraphics, int x, int y) {
|
||||||
|
Graphics g = pGraphics.create();
|
||||||
|
g.setColor((Color) mPaint);
|
||||||
|
g.fillRect(x, y, 16, 16);
|
||||||
|
g.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIconWidth() {
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIconHeight() {
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
Color selected = JColorChooser.showDialog(ImageLabel.this, "Choose background", (Color) mPaint);
|
||||||
|
if (selected != null) {
|
||||||
|
mPaint = selected;
|
||||||
|
super.actionPerformed(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
|
|
||||||
|
import javax.imageio.ImageWriteParam;
|
||||||
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
|
import javax.imageio.spi.ImageWriterSpi;
|
||||||
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ImageWriterBase
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: ImageWriterBase.java,v 1.0 Sep 24, 2007 12:22:28 AM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public abstract class ImageWriterBase extends javax.imageio.ImageWriter {
|
||||||
|
protected ImageOutputStream mImageOutput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an {@code ImageWriter} and sets its
|
||||||
|
* {@code originatingProvider} instance variable to the
|
||||||
|
* supplied value.
|
||||||
|
* <p/>
|
||||||
|
* <p> Subclasses that make use of extensions should provide a
|
||||||
|
* constructor with signature {@code (ImageWriterSpi,
|
||||||
|
* Object)} in order to retrieve the extension object. If
|
||||||
|
* the extension object is unsuitable, an
|
||||||
|
* {@code IllegalArgumentException} should be thrown.
|
||||||
|
*
|
||||||
|
* @param pProvider the {@code ImageWriterSpi} that
|
||||||
|
* is constructing this object, or {@code null}.
|
||||||
|
*/
|
||||||
|
protected ImageWriterBase(final ImageWriterSpi pProvider) {
|
||||||
|
super(pProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFormatName() throws IOException {
|
||||||
|
return getOriginatingProvider().getFormatNames()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOutput(Object pOutput) {
|
||||||
|
super.setOutput(pOutput);
|
||||||
|
if (pOutput instanceof ImageOutputStream) {
|
||||||
|
mImageOutput = (ImageOutputStream) pOutput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes sure output is set.
|
||||||
|
*
|
||||||
|
* @throws IllegalStateException if {@code getOutput() == null}.
|
||||||
|
*/
|
||||||
|
protected void assertOutput() {
|
||||||
|
if (getOutput() == null) {
|
||||||
|
throw new IllegalStateException("getOutput() == null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code null}
|
||||||
|
*
|
||||||
|
* @param pParam igonred.
|
||||||
|
* @return {@code null}.
|
||||||
|
*/
|
||||||
|
public IIOMetadata getDefaultStreamMetadata(javax.imageio.ImageWriteParam pParam) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code null}
|
||||||
|
*
|
||||||
|
* @param pInData ignored.
|
||||||
|
* @param pParam igonred.
|
||||||
|
* @return {@code null}.
|
||||||
|
*/
|
||||||
|
public IIOMetadata convertStreamMetadata(IIOMetadata pInData, ImageWriteParam pParam) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Rectangle getSourceRegion(ImageWriteParam pParam, int pWidth, int pHeight) {
|
||||||
|
return IIOUtil.getSourceRegion(pParam, pWidth, pHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility method for getting the area of interest (AOI) of an image.
|
||||||
|
* The AOI is defined by the {@link IIOParam#setSourceRegion(java.awt.Rectangle)}
|
||||||
|
* method.
|
||||||
|
* <p/>
|
||||||
|
* Note: If it is possible for the reader to read the AOI directly, such a
|
||||||
|
* method should be used instead, for efficiency.
|
||||||
|
*
|
||||||
|
* @param pImage the image to get AOI from
|
||||||
|
* @param pParam the param optionally specifying the AOI
|
||||||
|
*
|
||||||
|
* @return a {@code BufferedImage} containing the area of interest (source
|
||||||
|
* region), or the original image, if no source region was set, or
|
||||||
|
* {@code pParam} was {@code null}
|
||||||
|
*/
|
||||||
|
protected static BufferedImage fakeAOI(BufferedImage pImage, ImageWriteParam pParam) {
|
||||||
|
return IIOUtil.fakeAOI(pImage, getSourceRegion(pParam, pImage.getWidth(), pImage.getHeight()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility method for getting the subsampled image.
|
||||||
|
* The subsampling is defined by the
|
||||||
|
* {@link IIOParam#setSourceSubsampling(int, int, int, int)}
|
||||||
|
* method.
|
||||||
|
* <p/>
|
||||||
|
* NOTE: This method does not take the subsampling offsets into
|
||||||
|
* consideration.
|
||||||
|
* <p/>
|
||||||
|
* Note: If it is possible for the reader to subsample directly, such a
|
||||||
|
* method should be used instead, for efficiency.
|
||||||
|
*
|
||||||
|
* @param pImage the image to subsample
|
||||||
|
* @param pParam the param optionally specifying subsampling
|
||||||
|
*
|
||||||
|
* @return an {@code Image} containing the subsampled image, or the
|
||||||
|
* original image, if no subsampling was specified, or
|
||||||
|
* {@code pParam} was {@code null}
|
||||||
|
*/
|
||||||
|
protected static Image fakeSubsampling(Image pImage, ImageWriteParam pParam) {
|
||||||
|
return IIOUtil.fakeSubsampling(pImage, pParam);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,171 @@
|
|||||||
|
package com.twelvemonkeys.imageio.stream;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import javax.imageio.stream.ImageInputStreamImpl;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BufferedFileImageInputStream
|
||||||
|
* Experimental - seems to be effective for FileImageInputStream and FileCacheImageInputStream.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: BufferedFileImageInputStream.java,v 1.0 May 15, 2008 4:36:49 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
// TODO: Create a provider for this (wrapping the FileIIS and FileCacheIIS classes), and disable the Sun built-in spis?
|
||||||
|
public final class BufferedImageInputStream extends ImageInputStreamImpl implements ImageInputStream {
|
||||||
|
|
||||||
|
static final int DEFAULT_BUFFER_SIZE = 8192;
|
||||||
|
|
||||||
|
private ImageInputStream mStream;
|
||||||
|
|
||||||
|
private byte[] mBuffer;
|
||||||
|
private long mBufferStart = 0;
|
||||||
|
private int mBufferPos = 0;
|
||||||
|
private int mBufferLength = 0;
|
||||||
|
|
||||||
|
public BufferedImageInputStream(final ImageInputStream pStream) {
|
||||||
|
this(pStream, DEFAULT_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedImageInputStream(final ImageInputStream pStream, final int pBufferSize) {
|
||||||
|
Validate.notNull(pStream, "stream");
|
||||||
|
|
||||||
|
mStream = pStream;
|
||||||
|
mBuffer = new byte[pBufferSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillBuffer() throws IOException {
|
||||||
|
mBufferStart = streamPos;
|
||||||
|
mBufferLength = mStream.read(mBuffer, 0, mBuffer.length);
|
||||||
|
mBufferPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBufferValid() throws IOException {
|
||||||
|
return mBufferPos < mBufferLength && mBufferStart == mStream.getStreamPosition() - mBufferLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
if (!isBufferValid()) {
|
||||||
|
fillBuffer();
|
||||||
|
}
|
||||||
|
if (mBufferLength <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitOffset = 0;
|
||||||
|
streamPos++;
|
||||||
|
|
||||||
|
return mBuffer[mBufferPos++] & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(final byte[] pBuffer, final int pOffset, final int pLength) throws IOException {
|
||||||
|
bitOffset = 0;
|
||||||
|
|
||||||
|
boolean bypassBuffer = false;
|
||||||
|
|
||||||
|
if (!isBufferValid()) {
|
||||||
|
// Bypass cache if cache is empty for reads longer than buffer
|
||||||
|
if (pLength >= mBuffer.length) {
|
||||||
|
bypassBuffer = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fillBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bypassBuffer && mBufferLength <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read as much as possible from buffer
|
||||||
|
int length = bypassBuffer ? 0 : Math.min(mBufferLength - mBufferPos, pLength);
|
||||||
|
|
||||||
|
if (length > 0) {
|
||||||
|
System.arraycopy(mBuffer, mBufferPos, pBuffer, pOffset, length);
|
||||||
|
mBufferPos += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read rest directly from stream, if longer than buffer
|
||||||
|
if (pLength - length >= mBuffer.length) {
|
||||||
|
int read = mStream.read(pBuffer, pOffset + length, pLength - length);
|
||||||
|
|
||||||
|
if (read > 0) {
|
||||||
|
length += read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
streamPos += length;
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void seek(long pPosition) throws IOException {
|
||||||
|
// TODO: Could probably be optimized to not invalidate buffer if new pos is within current buffer
|
||||||
|
mStream.seek(pPosition);
|
||||||
|
mBufferLength = 0; // Will invalidate buffer
|
||||||
|
streamPos = mStream.getStreamPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flushBefore(long pos) throws IOException {
|
||||||
|
mStream.flushBefore(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getFlushedPosition() {
|
||||||
|
return mStream.getFlushedPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCached() {
|
||||||
|
return mStream.isCached();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCachedMemory() {
|
||||||
|
return mStream.isCachedMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCachedFile() {
|
||||||
|
return mStream.isCachedFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
if (mStream != null) {
|
||||||
|
mStream.close();
|
||||||
|
mStream = null;
|
||||||
|
mBuffer = null;
|
||||||
|
}
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
super.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long length() {
|
||||||
|
// WTF?! This method is allowed to throw IOException in the interface...
|
||||||
|
try {
|
||||||
|
return mStream.length();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw unchecked(e, RuntimeException.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked", "UnusedDeclaration"})
|
||||||
|
private <T extends Throwable> T unchecked(IOException pExcption, Class<T> pClass) {
|
||||||
|
// Ugly hack to fool the compiler..
|
||||||
|
return (T) pExcption;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,56 @@
|
|||||||
|
package com.twelvemonkeys.imageio.stream;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
|
import javax.imageio.stream.ImageInputStreamImpl;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Experimental
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: ByteArrayImageInputStream.java,v 1.0 May 15, 2008 2:12:12 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public final class ByteArrayImageInputStream extends ImageInputStreamImpl {
|
||||||
|
private final byte[] mData;
|
||||||
|
|
||||||
|
public ByteArrayImageInputStream(final byte[] pData) {
|
||||||
|
Validate.notNull(pData, "data");
|
||||||
|
mData = pData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read() throws IOException {
|
||||||
|
if (streamPos >= mData.length) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
bitOffset = 0;
|
||||||
|
return mData[((int) streamPos++)] & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read(byte[] pBuffer, int pOffset, int pLength) throws IOException {
|
||||||
|
if (streamPos >= mData.length) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int length = (int) Math.min(mData.length - streamPos, pLength);
|
||||||
|
bitOffset = 0;
|
||||||
|
System.arraycopy(mData, (int) streamPos, pBuffer, pOffset, length);
|
||||||
|
streamPos += length;
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long length() {
|
||||||
|
return mData.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCached() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCachedMemory() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,36 @@
|
|||||||
|
package com.twelvemonkeys.imageio.stream;
|
||||||
|
|
||||||
|
import javax.imageio.spi.ImageInputStreamSpi;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ByteArrayImageInputStreamSpi
|
||||||
|
* Experimental
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: ByteArrayImageInputStreamSpi.java,v 1.0 May 15, 2008 2:12:12 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public class ByteArrayImageInputStreamSpi extends ImageInputStreamSpi {
|
||||||
|
|
||||||
|
public ByteArrayImageInputStreamSpi() {
|
||||||
|
super("TwelveMonkeys", "1.0 BETA", byte[].class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageInputStream createInputStreamInstance(Object pInput, boolean pUseCache, File pCacheDir) throws IOException {
|
||||||
|
if (pInput instanceof byte[]) {
|
||||||
|
return new ByteArrayImageInputStream((byte[]) pInput);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException("Expected input of type byte[]: " + pInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription(Locale pLocale) {
|
||||||
|
return "Service provider that instantiates an ImageInputStream from a byte array";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,84 @@
|
|||||||
|
package com.twelvemonkeys.imageio.stream;
|
||||||
|
|
||||||
|
import javax.imageio.spi.ImageInputStreamSpi;
|
||||||
|
import javax.imageio.stream.FileCacheImageInputStream;
|
||||||
|
import javax.imageio.stream.FileImageInputStream;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import javax.imageio.stream.MemoryCacheImageInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URLImageInputStreamSpi
|
||||||
|
* Experimental
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: URLImageInputStreamSpi.java,v 1.0 May 15, 2008 2:14:59 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
// TODO: URI instead of URL?
|
||||||
|
public class URLImageInputStreamSpi extends ImageInputStreamSpi {
|
||||||
|
public URLImageInputStreamSpi() {
|
||||||
|
super("TwelveMonkeys", "1.0 BETA", URL.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Create a URI or URLImageInputStream class, with a getUR[I|L] method, to allow for multiple file formats
|
||||||
|
// The good thing with that is that it does not clash with the built-in Sun-stuff or other people's hacks
|
||||||
|
// The bad thing is that most people don't expect there to be an UR[I|L]ImageInputStreamSpi..
|
||||||
|
public ImageInputStream createInputStreamInstance(final Object pInput, final boolean pUseCache, final File pCacheDir) throws IOException {
|
||||||
|
if (pInput instanceof URL) {
|
||||||
|
URL url = (URL) pInput;
|
||||||
|
|
||||||
|
// Special case for file protocol, a lot faster than FileCacheImageInputStream
|
||||||
|
if ("file".equals(url.getProtocol())) {
|
||||||
|
try {
|
||||||
|
return new BufferedImageInputStream(new FileImageInputStream(new File(url.toURI())));
|
||||||
|
// return new FileImageInputStream(new File(url.toURI()));
|
||||||
|
}
|
||||||
|
catch (URISyntaxException ignore) {
|
||||||
|
ignore.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise revert to cached
|
||||||
|
final InputStream stream = url.openStream();
|
||||||
|
if (pUseCache) {
|
||||||
|
return new BufferedImageInputStream(new FileCacheImageInputStream(stream, pCacheDir) {
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
try {
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
stream.close(); // NOTE: If this line throws IOE, it will shadow the original..
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new MemoryCacheImageInputStream(stream) {
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
try {
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
stream.close(); // NOTE: If this line throws IOE, it will shadow the original..
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException("Expected input of type URL: " + pInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription(final Locale pLocale) {
|
||||||
|
return "Service provider that instantiates an ImageInputStream from a URL";
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IIOInputStreamAdapter
|
||||||
|
* <p/>
|
||||||
|
* Note: You should always wrap this stream in a {@code BufferedInputStream}.
|
||||||
|
* If not, performance may degrade significantly.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: IIOInputStreamAdapter.java,v 1.0 Sep 26, 2007 11:35:59 AM haraldk Exp$
|
||||||
|
*/
|
||||||
|
class IIOInputStreamAdapter extends InputStream {
|
||||||
|
private ImageInputStream mInput;
|
||||||
|
private final boolean mHasLength;
|
||||||
|
private long mLeft;
|
||||||
|
private long mMarkPosition;
|
||||||
|
|
||||||
|
// TODO: Enforce stream boundaries!
|
||||||
|
// TODO: Stream start position....
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an {@code InputStream} that reads from the given {@code ImageInputStream}.
|
||||||
|
* The input stream will read from the current stream position, until the end of the
|
||||||
|
* underlying stream.
|
||||||
|
*
|
||||||
|
* @param pInput the {@code ImageInputStream} to read from.
|
||||||
|
*/
|
||||||
|
public IIOInputStreamAdapter(final ImageInputStream pInput) {
|
||||||
|
this(pInput, -1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an {@code InputStream} that reads from the given {@code ImageInputStream}.
|
||||||
|
* The input stream will read from the current stream position, until at most
|
||||||
|
* {@code pLength} bytes has been read.
|
||||||
|
*
|
||||||
|
* @param pInput the {@code ImageInputStream} to read from.
|
||||||
|
* @param pLength the length of the stream
|
||||||
|
*/
|
||||||
|
public IIOInputStreamAdapter(final ImageInputStream pInput, final long pLength) {
|
||||||
|
this(pInput, pLength, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IIOInputStreamAdapter(ImageInputStream pInput, long pLength, boolean pHasLength) {
|
||||||
|
if (pInput == null) {
|
||||||
|
throw new IllegalArgumentException("stream == null");
|
||||||
|
}
|
||||||
|
if (pHasLength && pLength < 0) {
|
||||||
|
throw new IllegalArgumentException("length < 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
mInput = pInput;
|
||||||
|
mHasLength = pHasLength;
|
||||||
|
mLeft = pLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks this stream as closed.
|
||||||
|
* This implementation does <em>not</em> close the underlying stream.
|
||||||
|
*/
|
||||||
|
public void close() throws IOException {
|
||||||
|
if (mHasLength) {
|
||||||
|
mInput.seek(mInput.getStreamPosition() + mLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
mLeft = 0;
|
||||||
|
mInput = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int available() throws IOException {
|
||||||
|
if (mHasLength) {
|
||||||
|
return mLeft > 0 ? (int) Math.min(Integer.MAX_VALUE, mLeft) : 0;
|
||||||
|
}
|
||||||
|
return 0; // We don't really know, so we say 0 to be safe.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean markSupported() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mark(int pReadLimit) {
|
||||||
|
try {
|
||||||
|
mMarkPosition = mInput.getStreamPosition();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
// Let's hope this never happens, because it's not possible to reset then...
|
||||||
|
throw new IllegalStateException("Could not read stream position: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() throws IOException {
|
||||||
|
long diff = mInput.getStreamPosition() - mMarkPosition;
|
||||||
|
mInput.seek(mMarkPosition);
|
||||||
|
mLeft += diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read() throws IOException {
|
||||||
|
if (mHasLength && mLeft-- <= 0) {
|
||||||
|
mLeft = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return mInput.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int read(byte[] pBytes) throws IOException {
|
||||||
|
return read(pBytes, 0, pBytes.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read(final byte[] pBytes, final int pOffset, final int pLength) throws IOException {
|
||||||
|
if (mHasLength && mLeft <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read = mInput.read(pBytes, pOffset, (int) findMaxLen(pLength));
|
||||||
|
if (mHasLength) {
|
||||||
|
mLeft = read < 0 ? 0 : mLeft - read;
|
||||||
|
}
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the maximum number of bytes we can read or skip, from this stream.
|
||||||
|
* The number will be in the range {@code [0 ... bytes left]}.
|
||||||
|
*
|
||||||
|
* @param pLength the requested length
|
||||||
|
* @return the maximum number of bytes to read
|
||||||
|
*/
|
||||||
|
private long findMaxLen(long pLength) {
|
||||||
|
if (mHasLength && mLeft < pLength) {
|
||||||
|
return Math.max(mLeft, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Math.max(pLength, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long skip(long pLength) throws IOException {
|
||||||
|
long skipped = mInput.skipBytes(findMaxLen(pLength)); // Skips 0 or more, never -1
|
||||||
|
mLeft -= skipped;
|
||||||
|
return skipped;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IIOOutputStreamAdapter
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: IIOOutputStreamAdapter.java,v 1.0 Sep 26, 2007 11:50:38 AM haraldk Exp$
|
||||||
|
*/
|
||||||
|
class IIOOutputStreamAdapter extends OutputStream {
|
||||||
|
private ImageOutputStream mOutput;
|
||||||
|
|
||||||
|
public IIOOutputStreamAdapter(final ImageOutputStream pOutput) {
|
||||||
|
mOutput = pOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(final byte[] pBytes) throws IOException {
|
||||||
|
mOutput.write(pBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(final byte[] pBytes, final int pOffset, final int pLength) throws IOException {
|
||||||
|
mOutput.write(pBytes, pOffset, pLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(final int pByte) throws IOException {
|
||||||
|
mOutput.write(pByte);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() throws IOException {
|
||||||
|
mOutput.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
mOutput = null;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,131 @@
|
|||||||
|
package com.twelvemonkeys.imageio.util;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.image.ImageUtil;
|
||||||
|
|
||||||
|
import javax.imageio.IIOParam;
|
||||||
|
import javax.imageio.spi.IIOServiceProvider;
|
||||||
|
import javax.imageio.spi.ServiceRegistry;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IIOUtil
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: IIOUtil.java,v 1.0 May 8, 2008 3:04:54 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public final class IIOUtil {
|
||||||
|
private IIOUtil() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an {@code InputStream} adapter that reads from an underlying {@code ImageInputStream}.
|
||||||
|
* The input stream will read until the end of {@code pStream}.
|
||||||
|
*
|
||||||
|
* @param pStream the stream to read from.
|
||||||
|
* @return an {@code InputStream} reading from {@code pStream}.
|
||||||
|
*/
|
||||||
|
public static InputStream createStreamAdapter(final ImageInputStream pStream) {
|
||||||
|
// TODO: Include stream start pos?
|
||||||
|
// TODO: Skip buffering for known in-memory implementations?
|
||||||
|
return new BufferedInputStream(new IIOInputStreamAdapter(pStream));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an {@code InputStream} adapter that reads from an underlying {@code ImageInputStream}.
|
||||||
|
* The input stream will read until the end of {@code pStream}, or at most {@code pLength} bytes has been read.
|
||||||
|
*
|
||||||
|
* @param pStream the stream to read from.
|
||||||
|
* @param pLength the maximum number of bytes that can be read from {@code pStream}.
|
||||||
|
* @return an {@code InputStream} reading from {@code pStream}.
|
||||||
|
*/
|
||||||
|
public static InputStream createStreamAdapter(final ImageInputStream pStream, final long pLength) {
|
||||||
|
// TODO: Include stream start pos?
|
||||||
|
// TODO: Skip buffering for known in-memory implementations?
|
||||||
|
return new BufferedInputStream(new IIOInputStreamAdapter(pStream, pLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an {@code OutputStream} adapter that writes to an underlying {@code ImageOutputStream}.
|
||||||
|
*
|
||||||
|
* @param pStream the stream to write to.
|
||||||
|
* @return an {@code OutputSteam} writing to {@code pStream}.
|
||||||
|
*/
|
||||||
|
public static OutputStream createStreamAdapter(final ImageOutputStream pStream) {
|
||||||
|
return new BufferedOutputStream(new IIOOutputStreamAdapter(pStream));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* THIS METHOD WILL ME MOVED/RENAMED, DO NOT USE.
|
||||||
|
*/
|
||||||
|
public static <T> void deregisterProvider(final ServiceRegistry pRegistry, final IIOServiceProvider pProvider, final Class<T> pCategory) {
|
||||||
|
// http://www.ibm.com/developerworks/java/library/j-jtp04298.html
|
||||||
|
// TODO: Consider placing this method in a ImageReaderSpiBase class or similar
|
||||||
|
pRegistry.deregisterServiceProvider(pCategory.cast(pProvider), pCategory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Image fakeSubsampling(final Image pImage, final IIOParam pParam) {
|
||||||
|
if (pImage == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pParam != null) {
|
||||||
|
int x = pParam.getSourceXSubsampling();
|
||||||
|
int y = pParam.getSourceYSubsampling();
|
||||||
|
|
||||||
|
// 1 is default
|
||||||
|
if (x > 1 || y > 1) {
|
||||||
|
int w = (ImageUtil.getWidth(pImage) + x - 1) / x;
|
||||||
|
int h = (ImageUtil.getHeight(pImage) + y - 1) / y;
|
||||||
|
|
||||||
|
// Fake subsampling by scaling fast
|
||||||
|
return pImage.getScaledInstance(w, h, Image.SCALE_FAST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rectangle getSourceRegion(final IIOParam pParam, final int pSrcWidth, final int pSrcHeight) {
|
||||||
|
Rectangle sourceRegion = new Rectangle(pSrcWidth, pSrcHeight);
|
||||||
|
|
||||||
|
// If param is present, calculate region
|
||||||
|
if (pParam != null) {
|
||||||
|
// Get intersection with source region
|
||||||
|
Rectangle region = pParam.getSourceRegion();
|
||||||
|
if (region != null) {
|
||||||
|
sourceRegion = sourceRegion.intersection(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale according to subsampling offsets
|
||||||
|
int subsampleXOffset = pParam.getSubsamplingXOffset();
|
||||||
|
int subsampleYOffset = pParam.getSubsamplingYOffset();
|
||||||
|
sourceRegion.x += subsampleXOffset;
|
||||||
|
sourceRegion.y += subsampleYOffset;
|
||||||
|
sourceRegion.width -= subsampleXOffset;
|
||||||
|
sourceRegion.height -= subsampleYOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceRegion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BufferedImage fakeAOI(final BufferedImage pImage, final Rectangle pSourceRegion) {
|
||||||
|
if (pImage == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pSourceRegion != null) {
|
||||||
|
if (pSourceRegion.x != 0 || pSourceRegion.y != 0 || pSourceRegion.width != pImage.getWidth() || pSourceRegion.height != pImage.getHeight()) {
|
||||||
|
return pImage.getSubimage(pSourceRegion.x, pSourceRegion.y, pSourceRegion.width, pSourceRegion.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pImage;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,41 @@
|
|||||||
|
package com.twelvemonkeys.imageio.util;
|
||||||
|
|
||||||
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
|
import java.awt.image.IndexColorModel;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.WritableRaster;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IndexedImageTypeSpecifier
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: IndexedImageTypeSpecifier.java,v 1.0 May 19, 2008 11:04:28 AM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public class IndexedImageTypeSpecifier extends ImageTypeSpecifier {
|
||||||
|
IndexedImageTypeSpecifier(IndexColorModel pColorModel) {
|
||||||
|
// For some reason, we need a sample model
|
||||||
|
super(pColorModel, pColorModel.createCompatibleSampleModel(1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ImageTypeSpecifier createFromIndexColorModel(final IndexColorModel pColorModel) {
|
||||||
|
return new IndexedImageTypeSpecifier(pColorModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final BufferedImage createBufferedImage(int pWidth, int pHeight) {
|
||||||
|
try {
|
||||||
|
// This is a fix for the super-method, that first creates a sample model, and then
|
||||||
|
// creates a raster from it, using Raster.createWritableRaster. The problem with
|
||||||
|
// that approach, is that it always creates a TYPE_CUSTOM BufferedImage for indexed images.
|
||||||
|
WritableRaster raster = colorModel.createCompatibleWritableRaster(pWidth, pHeight);
|
||||||
|
return new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), new Hashtable());
|
||||||
|
}
|
||||||
|
catch (NegativeArraySizeException e) {
|
||||||
|
// Exception most likely thrown from a DataBuffer constructor
|
||||||
|
throw new IllegalArgumentException("Array size > Integer.MAX_VALUE!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import javax.imageio.ImageReader;
|
||||||
|
import javax.imageio.ImageWriter;
|
||||||
|
import javax.imageio.event.IIOReadProgressListener;
|
||||||
|
import javax.imageio.event.IIOWriteProgressListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ProgressListenerBase
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: ProgressListenerBase.java,v 1.0 26.aug.2005 14:29:42 haku Exp$
|
||||||
|
*/
|
||||||
|
public abstract class ProgressListenerBase implements IIOReadProgressListener, IIOWriteProgressListener {
|
||||||
|
protected ProgressListenerBase() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void imageComplete(ImageReader pSource) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void imageProgress(ImageReader pSource, float pPercentageDone) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void imageStarted(ImageReader pSource, int pImageIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readAborted(ImageReader pSource) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sequenceComplete(ImageReader pSource) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sequenceStarted(ImageReader pSource, int pMinIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void thumbnailComplete(ImageReader pSource) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void thumbnailProgress(ImageReader pSource, float pPercentageDone) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void thumbnailStarted(ImageReader pSource, int pImageIndex, int pThumbnailIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void imageComplete(ImageWriter pSource) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void imageProgress(ImageWriter pSource, float pPercentageDone) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void imageStarted(ImageWriter pSource, int pImageIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void thumbnailComplete(ImageWriter pSource) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void thumbnailProgress(ImageWriter pSource, float pPercentageDone) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void thumbnailStarted(ImageWriter pSource, int pImageIndex, int pThumbnailIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeAborted(ImageWriter pSource) {
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.io.FileUtil;
|
||||||
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.swing.filechooser.FileFilter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ReaderFileSuffixFilter
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haku$
|
||||||
|
* @version $Id: ReaderFileSuffixFilter.java,v 1.0 11.okt.2006 20:05:36 haku Exp$
|
||||||
|
*/
|
||||||
|
public final class ReaderFileSuffixFilter extends FileFilter implements java.io.FileFilter {
|
||||||
|
private final String mDescription;
|
||||||
|
private final Map<String, Boolean> mKnownSuffixes = new HashMap<String, Boolean>(32);
|
||||||
|
|
||||||
|
public ReaderFileSuffixFilter() {
|
||||||
|
this("Images (all supported input formats)");
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReaderFileSuffixFilter(String pDescription) {
|
||||||
|
mDescription = pDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean accept(File pFile) {
|
||||||
|
// Directories are always supported
|
||||||
|
if (pFile.isDirectory()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if we have an ImageReader for this suffix
|
||||||
|
String suffix = FileUtil.getExtension(pFile);
|
||||||
|
|
||||||
|
return !StringUtil.isEmpty(suffix) && hasReaderForSuffix(suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasReaderForSuffix(String pSuffix) {
|
||||||
|
if (mKnownSuffixes.get(pSuffix) == Boolean.TRUE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Cahce lookup
|
||||||
|
Iterator iterator = ImageIO.getImageReadersBySuffix(pSuffix);
|
||||||
|
if (iterator.hasNext()) {
|
||||||
|
mKnownSuffixes.put(pSuffix, Boolean.TRUE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mKnownSuffixes.put(pSuffix, Boolean.FALSE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException iae) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return mDescription;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.io.FileUtil;
|
||||||
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.swing.filechooser.FileFilter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WriterFileSuffixFilter
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haku$
|
||||||
|
* @version $Id: WriterFileSuffixFilter.java,v 1.0 11.okt.2006 20:05:36 haku Exp$
|
||||||
|
*/
|
||||||
|
public final class WriterFileSuffixFilter extends FileFilter implements java.io.FileFilter {
|
||||||
|
private final String mDescription;
|
||||||
|
private Map<String, Boolean>mKnownSuffixes = new HashMap<String, Boolean>(32);
|
||||||
|
|
||||||
|
public WriterFileSuffixFilter() {
|
||||||
|
this("Images (all supported output formats)");
|
||||||
|
}
|
||||||
|
|
||||||
|
public WriterFileSuffixFilter(String pDescription) {
|
||||||
|
mDescription = pDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean accept(File pFile) {
|
||||||
|
// Directories are always supported
|
||||||
|
if (pFile.isDirectory()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if we have an ImageWriter for this suffix
|
||||||
|
String suffix = FileUtil.getExtension(pFile);
|
||||||
|
return !StringUtil.isEmpty(suffix) && hasWriterForSuffix(suffix);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasWriterForSuffix(String pSuffix) {
|
||||||
|
if (mKnownSuffixes.get(pSuffix) == Boolean.TRUE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Cahce lookup
|
||||||
|
Iterator iterator = ImageIO.getImageWritersBySuffix(pSuffix);
|
||||||
|
if (iterator.hasNext()) {
|
||||||
|
mKnownSuffixes.put(pSuffix, Boolean.TRUE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mKnownSuffixes.put(pSuffix, Boolean.FALSE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException iae) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return mDescription;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,116 @@
|
|||||||
|
package com.twelvemonkeys.imageio.stream;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.io.ole2.CompoundDocument;
|
||||||
|
import com.twelvemonkeys.io.ole2.Entry;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import javax.imageio.stream.MemoryCacheImageInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BufferedImageInputStreamTestCase
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: BufferedImageInputStreamTestCase.java,v 1.0 Jun 30, 2008 3:07:42 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public class BufferedImageInputStreamTestCase extends TestCase{
|
||||||
|
protected final Random mRandom = new Random();
|
||||||
|
|
||||||
|
public void testCreate() {
|
||||||
|
new BufferedImageInputStream(new ByteArrayImageInputStream(new byte[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateNull() {
|
||||||
|
try {
|
||||||
|
new BufferedImageInputStream(null);
|
||||||
|
fail("Expected IllegalArgumentException");
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException expected) {
|
||||||
|
assertNotNull("Null exception message", expected.getMessage());
|
||||||
|
String message = expected.getMessage().toLowerCase();
|
||||||
|
assertTrue("Exception message does not contain parameter name", message.contains("stream"));
|
||||||
|
assertTrue("Exception message does not contain null", message.contains("null"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Write other tests
|
||||||
|
|
||||||
|
// TODO: Create test that exposes read += -1 (eof) bug
|
||||||
|
|
||||||
|
public void testArrayIndexOutOfBoundsBufferedReadBug() throws IOException {
|
||||||
|
// TODO: Create a more straight forward way to prove correctness, for now this is good enough to avoid regression
|
||||||
|
ImageInputStream input = new BufferedImageInputStream(new MemoryCacheImageInputStream(getClass().getResourceAsStream("/Thumbs-camera.db")));
|
||||||
|
input.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
Entry root = new CompoundDocument(input).getRootEntry();
|
||||||
|
|
||||||
|
Entry child = root.getChildEntry("Catalog");
|
||||||
|
|
||||||
|
assertNotNull("Input stream can never be null", child.getInputStream());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReadResetReadDirectBufferBug() throws IOException {
|
||||||
|
// Make sure we use the exact size of the buffer
|
||||||
|
final int size = BufferedImageInputStream.DEFAULT_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// Fill bytes
|
||||||
|
byte[] bytes = new byte[size * 2];
|
||||||
|
mRandom.nextBytes(bytes);
|
||||||
|
|
||||||
|
// Create wrapper stream
|
||||||
|
BufferedImageInputStream stream = new BufferedImageInputStream(new ByteArrayImageInputStream(bytes));
|
||||||
|
|
||||||
|
// Read to fill the buffer, then reset
|
||||||
|
stream.readLong();
|
||||||
|
stream.seek(0);
|
||||||
|
|
||||||
|
// Read fully and compare
|
||||||
|
byte[] result = new byte[size];
|
||||||
|
stream.readFully(result);
|
||||||
|
assertTrue(rangeEquals(bytes, 0, result, 0, size));
|
||||||
|
|
||||||
|
stream.readFully(result);
|
||||||
|
assertTrue(rangeEquals(bytes, size, result, 0, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test two arrays for range equality. That is, they contain the same elements for some specified range.
|
||||||
|
*
|
||||||
|
* @param pFirst one array to test for equality
|
||||||
|
* @param pFirstOffset the offset into the first array to start testing for equality
|
||||||
|
* @param pSecond the other array to test for equality
|
||||||
|
* @param pSecondOffset the offset into the second array to start testing for equality
|
||||||
|
* @param pLength the length of the range to check for equality
|
||||||
|
*
|
||||||
|
* @return {@code true} if both arrays are non-{@code null}
|
||||||
|
* and have at least {@code offset + pLength} elements
|
||||||
|
* and all elements in the range from the first array is equal to the elements from the second array,
|
||||||
|
* or if {@code pFirst == pSecond} (including both arrays being {@code null})
|
||||||
|
* and {@code pFirstOffset == pSecondOffset}.
|
||||||
|
* Otherwise {@code false}.
|
||||||
|
*/
|
||||||
|
static boolean rangeEquals(byte[] pFirst, int pFirstOffset, byte[] pSecond, int pSecondOffset, int pLength) {
|
||||||
|
if (pFirst == pSecond && pFirstOffset == pSecondOffset) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pFirst == null || pSecond == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pFirst.length < pFirstOffset + pLength || pSecond.length < pSecondOffset + pLength) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < pLength; i++) {
|
||||||
|
if (pFirst[pFirstOffset + i] != pSecond[pSecondOffset + i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,102 @@
|
|||||||
|
package com.twelvemonkeys.imageio.stream;
|
||||||
|
|
||||||
|
import static com.twelvemonkeys.imageio.stream.BufferedImageInputStreamTestCase.rangeEquals;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ByteArrayImageInputStreamTestCase
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: ByteArrayImageInputStreamTestCase.java,v 1.0 Apr 21, 2009 10:58:48 AM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public class ByteArrayImageInputStreamTestCase extends TestCase {
|
||||||
|
protected final Random mRandom = new Random();
|
||||||
|
|
||||||
|
public void testCreate() {
|
||||||
|
ByteArrayImageInputStream stream = new ByteArrayImageInputStream(new byte[0]);
|
||||||
|
assertEquals("Data length should be same as stream length", 0, stream.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateNull() {
|
||||||
|
try {
|
||||||
|
new ByteArrayImageInputStream(null);
|
||||||
|
fail("Expected IllegalArgumentException");
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException expected) {
|
||||||
|
assertNotNull("Null exception message", expected.getMessage());
|
||||||
|
String message = expected.getMessage().toLowerCase();
|
||||||
|
assertTrue("Exception message does not contain parameter name", message.contains("data"));
|
||||||
|
assertTrue("Exception message does not contain null", message.contains("null"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testRead() throws IOException {
|
||||||
|
byte[] data = new byte[1024 * 1024];
|
||||||
|
mRandom.nextBytes(data);
|
||||||
|
|
||||||
|
ByteArrayImageInputStream stream = new ByteArrayImageInputStream(data);
|
||||||
|
|
||||||
|
assertEquals("Data length should be same as stream length", data.length, stream.length());
|
||||||
|
|
||||||
|
for (byte b : data) {
|
||||||
|
assertEquals("Wrong data read", b & 0xff, stream.read());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReadArray() throws IOException {
|
||||||
|
byte[] data = new byte[1024 * 1024];
|
||||||
|
mRandom.nextBytes(data);
|
||||||
|
|
||||||
|
ByteArrayImageInputStream stream = new ByteArrayImageInputStream(data);
|
||||||
|
|
||||||
|
assertEquals("Data length should be same as stream length", data.length, stream.length());
|
||||||
|
|
||||||
|
byte[] result = new byte[1024];
|
||||||
|
|
||||||
|
for (int i = 0; i < data.length / result.length; i++) {
|
||||||
|
stream.readFully(result);
|
||||||
|
assertTrue("Wrong data read: " + i, rangeEquals(data, i * result.length, result, 0, result.length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReadSkip() throws IOException {
|
||||||
|
byte[] data = new byte[1024 * 14];
|
||||||
|
mRandom.nextBytes(data);
|
||||||
|
|
||||||
|
ByteArrayImageInputStream stream = new ByteArrayImageInputStream(data);
|
||||||
|
|
||||||
|
assertEquals("Data length should be same as stream length", data.length, stream.length());
|
||||||
|
|
||||||
|
byte[] result = new byte[7];
|
||||||
|
|
||||||
|
for (int i = 0; i < data.length / result.length; i += 2) {
|
||||||
|
stream.readFully(result);
|
||||||
|
stream.skipBytes(result.length);
|
||||||
|
assertTrue("Wrong data read: " + i, rangeEquals(data, i * result.length, result, 0, result.length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReadSeek() throws IOException {
|
||||||
|
byte[] data = new byte[1024 * 18];
|
||||||
|
mRandom.nextBytes(data);
|
||||||
|
|
||||||
|
ByteArrayImageInputStream stream = new ByteArrayImageInputStream(data);
|
||||||
|
|
||||||
|
assertEquals("Data length should be same as stream length", data.length, stream.length());
|
||||||
|
|
||||||
|
byte[] result = new byte[9];
|
||||||
|
|
||||||
|
for (int i = 0; i < data.length / result.length; i++) {
|
||||||
|
// Read backwards
|
||||||
|
long newPos = stream.length() - result.length - i * result.length;
|
||||||
|
stream.seek(newPos);
|
||||||
|
assertEquals("Wrong stream position", newPos, stream.getStreamPosition());
|
||||||
|
stream.readFully(result);
|
||||||
|
assertTrue("Wrong data read: " + i, rangeEquals(data, (int) newPos, result, 0, result.length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.io.InputStreamAbstractTestCase;
|
||||||
|
|
||||||
|
import javax.imageio.stream.MemoryCacheImageInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IIOInputStreamAdapter
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: IIOInputStreamAdapter.java,v 1.0 Apr 11, 2008 1:04:42 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public class IIOInputStreamAdapterTestCase extends InputStreamAbstractTestCase {
|
||||||
|
public IIOInputStreamAdapterTestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected InputStream makeInputStream(byte[] pBytes) {
|
||||||
|
return new IIOInputStreamAdapter(new MemoryCacheImageInputStream(new ByteArrayInputStream(pBytes)), pBytes.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReadSubstreamOpenEnd() throws IOException {
|
||||||
|
byte[] bytes = new byte[20];
|
||||||
|
|
||||||
|
MemoryCacheImageInputStream input = new MemoryCacheImageInputStream(new ByteArrayInputStream(bytes));
|
||||||
|
|
||||||
|
input.seek(10);
|
||||||
|
assertEquals(10, input.getStreamPosition());
|
||||||
|
|
||||||
|
IIOInputStreamAdapter stream = new IIOInputStreamAdapter(input);
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
assertTrue("Unexpected end of stream", -1 != stream.read());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("Read value after end of stream", -1, stream.read());
|
||||||
|
assertEquals("Read value after end of stream", -1, stream.read());
|
||||||
|
|
||||||
|
// Make sure underlying stream is positioned at end of substream after close
|
||||||
|
stream.close();
|
||||||
|
assertEquals(20, input.getStreamPosition());
|
||||||
|
|
||||||
|
input.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReadSubstream() throws IOException {
|
||||||
|
byte[] bytes = new byte[20];
|
||||||
|
|
||||||
|
MemoryCacheImageInputStream input = new MemoryCacheImageInputStream(new ByteArrayInputStream(bytes));
|
||||||
|
IIOInputStreamAdapter stream = new IIOInputStreamAdapter(input, 9);
|
||||||
|
for (int i = 0; i < 9; i++) {
|
||||||
|
assertTrue("Unexpected end of stream", -1 != stream.read());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("Read value after end of stream", -1, stream.read());
|
||||||
|
assertEquals("Read value after end of stream", -1, stream.read());
|
||||||
|
|
||||||
|
// Make sure we don't read outside stream boundaries
|
||||||
|
assertTrue(input.getStreamPosition() <= 9);
|
||||||
|
|
||||||
|
input.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReadSubstreamRepositionOnClose() throws IOException {
|
||||||
|
byte[] bytes = new byte[20];
|
||||||
|
|
||||||
|
MemoryCacheImageInputStream input = new MemoryCacheImageInputStream(new ByteArrayInputStream(bytes));
|
||||||
|
IIOInputStreamAdapter stream = new IIOInputStreamAdapter(input, 10);
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
assertTrue("Unexpected end of stream", -1 != stream.read());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we don't read outside stream boundaries
|
||||||
|
assertTrue(input.getStreamPosition() <= 7);
|
||||||
|
|
||||||
|
// Make sure underlying stream is positioned at end of substream after close
|
||||||
|
stream.close();
|
||||||
|
assertEquals(10, input.getStreamPosition());
|
||||||
|
|
||||||
|
input.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSeekBeforeStreamNoEnd() throws IOException {
|
||||||
|
byte[] bytes = new byte[20];
|
||||||
|
|
||||||
|
MemoryCacheImageInputStream input = new MemoryCacheImageInputStream(new ByteArrayInputStream(bytes));
|
||||||
|
|
||||||
|
input.seek(10);
|
||||||
|
assertEquals(10, input.getStreamPosition());
|
||||||
|
|
||||||
|
IIOInputStreamAdapter stream = new IIOInputStreamAdapter(input);
|
||||||
|
assertEquals("Should not skip backwards", 0, stream.skip(-5));
|
||||||
|
assertEquals(10, input.getStreamPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSeekBeforeStream() throws IOException {
|
||||||
|
byte[] bytes = new byte[20];
|
||||||
|
|
||||||
|
MemoryCacheImageInputStream input = new MemoryCacheImageInputStream(new ByteArrayInputStream(bytes));
|
||||||
|
|
||||||
|
input.seek(10);
|
||||||
|
assertEquals(10, input.getStreamPosition());
|
||||||
|
|
||||||
|
IIOInputStreamAdapter stream = new IIOInputStreamAdapter(input, 9);
|
||||||
|
assertEquals("Should not skip backwards", 0, stream.skip(-5));
|
||||||
|
assertEquals(10, input.getStreamPosition());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import org.jmock.Mock;
|
||||||
|
import org.jmock.cglib.MockObjectTestCase;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.imageio.ImageWriteParam;
|
||||||
|
import javax.imageio.ImageWriter;
|
||||||
|
import javax.imageio.event.IIOWriteProgressListener;
|
||||||
|
import java.awt.image.RenderedImage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ImageReaderAbstractTestCase class description.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haku $
|
||||||
|
* @version $Id: ImageReaderAbstractTestCase.java,v 1.0 18.nov.2004 17:38:33 haku Exp $
|
||||||
|
*/
|
||||||
|
public abstract class ImageWriterAbstractTestCase extends MockObjectTestCase {
|
||||||
|
|
||||||
|
protected abstract ImageWriter createImageWriter();
|
||||||
|
|
||||||
|
protected abstract RenderedImage getTestData();
|
||||||
|
|
||||||
|
public void testSetOutput() throws IOException {
|
||||||
|
// Should just pass with no exceptions
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
assertNotNull(writer);
|
||||||
|
writer.setOutput(ImageIO.createImageOutputStream(new ByteArrayOutputStream()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSetOutputNull() {
|
||||||
|
// Should just pass with no exceptions
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
assertNotNull(writer);
|
||||||
|
writer.setOutput(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWrite() throws IOException {
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
||||||
|
try {
|
||||||
|
writer.write(getTestData());
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
assertTrue("No image data written", buffer.size() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWrite2() {
|
||||||
|
// Note: There's a difference between new ImageOutputStreamImpl and
|
||||||
|
// ImageIO.createImageOutputStream... Make sure writers handle both
|
||||||
|
// cases
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
||||||
|
writer.write(getTestData());
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue("No image data written", buffer.size() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWriteNull() throws IOException {
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
||||||
|
try {
|
||||||
|
writer.write((RenderedImage) null);
|
||||||
|
}
|
||||||
|
catch(IllegalArgumentException ignore) {
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
assertTrue("Image data written", buffer.size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWriteNoOutput() {
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
try {
|
||||||
|
writer.write(getTestData());
|
||||||
|
}
|
||||||
|
catch (IllegalStateException ignore) {
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetDefaultWriteParam() {
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
ImageWriteParam param = writer.getDefaultWriteParam();
|
||||||
|
assertNotNull("Default ImageWriteParam is null", param);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Test writing with params
|
||||||
|
// TODO: Source region and subsampling at least
|
||||||
|
|
||||||
|
public void testAddIIOWriteProgressListener() {
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
Mock mockListener = new Mock(IIOWriteProgressListener.class);
|
||||||
|
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListener.proxy());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAddIIOWriteProgressListenerNull() {
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
writer.addIIOWriteProgressListener(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAddIIOWriteProgressListenerCallbacks() throws IOException {
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
||||||
|
|
||||||
|
Mock mockListener = new Mock(IIOWriteProgressListener.class);
|
||||||
|
String started = "Started";
|
||||||
|
mockListener.expects(once()).method("imageStarted").withAnyArguments().id(started);
|
||||||
|
mockListener.stubs().method("imageProgress").withAnyArguments().after(started);
|
||||||
|
mockListener.expects(once()).method("imageComplete").withAnyArguments().after(started);
|
||||||
|
|
||||||
|
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListener.proxy());
|
||||||
|
|
||||||
|
try {
|
||||||
|
writer.write(getTestData());
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
fail("Could not write image");
|
||||||
|
}
|
||||||
|
|
||||||
|
// At least imageStarted and imageComplete, plus any number of imageProgress
|
||||||
|
mockListener.verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultipleAddIIOWriteProgressListenerCallbacks() throws IOException {
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
||||||
|
|
||||||
|
Mock mockListener = new Mock(IIOWriteProgressListener.class);
|
||||||
|
String started = "Started";
|
||||||
|
mockListener.expects(once()).method("imageStarted").withAnyArguments().id(started);
|
||||||
|
mockListener.stubs().method("imageProgress").withAnyArguments().after(started);
|
||||||
|
mockListener.expects(once()).method("imageComplete").withAnyArguments().after(started);
|
||||||
|
|
||||||
|
Mock mockListenerToo = new Mock(IIOWriteProgressListener.class);
|
||||||
|
String startedToo = "Started Two";
|
||||||
|
mockListenerToo.expects(once()).method("imageStarted").withAnyArguments().id(startedToo);
|
||||||
|
mockListenerToo.stubs().method("imageProgress").withAnyArguments().after(startedToo);
|
||||||
|
mockListenerToo.expects(once()).method("imageComplete").withAnyArguments().after(startedToo);
|
||||||
|
|
||||||
|
Mock mockListenerThree = new Mock(IIOWriteProgressListener.class);
|
||||||
|
String startedThree = "Started Three";
|
||||||
|
mockListenerThree.expects(once()).method("imageStarted").withAnyArguments().id(startedThree);
|
||||||
|
mockListenerThree.stubs().method("imageProgress").withAnyArguments().after(startedThree);
|
||||||
|
mockListenerThree.expects(once()).method("imageComplete").withAnyArguments().after(startedThree);
|
||||||
|
|
||||||
|
|
||||||
|
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListener.proxy());
|
||||||
|
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListenerToo.proxy());
|
||||||
|
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListenerThree.proxy());
|
||||||
|
|
||||||
|
try {
|
||||||
|
writer.write(getTestData());
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
fail("Could not write image");
|
||||||
|
}
|
||||||
|
|
||||||
|
// At least imageStarted and imageComplete, plus any number of imageProgress
|
||||||
|
mockListener.verify();
|
||||||
|
mockListenerToo.verify();
|
||||||
|
mockListenerThree.verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testRemoveIIOWriteProgressListenerNull() {
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
writer.removeIIOWriteProgressListener(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testRemoveIIOWriteProgressListenerNone() {
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
Mock mockListener = new Mock(IIOWriteProgressListener.class);
|
||||||
|
writer.removeIIOWriteProgressListener((IIOWriteProgressListener) mockListener.proxy());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testRemoveIIOWriteProgressListener() throws IOException {
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
||||||
|
|
||||||
|
Mock mockListener = new Mock(IIOWriteProgressListener.class);
|
||||||
|
IIOWriteProgressListener listener = (IIOWriteProgressListener) mockListener.proxy();
|
||||||
|
writer.addIIOWriteProgressListener(listener);
|
||||||
|
writer.removeIIOWriteProgressListener(listener);
|
||||||
|
|
||||||
|
try {
|
||||||
|
writer.write(getTestData());
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
fail("Could not write image");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should not have called any methods...
|
||||||
|
mockListener.verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testRemoveIIOWriteProgressListenerMultiple() throws IOException {
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
||||||
|
|
||||||
|
|
||||||
|
Mock mockListener = new Mock(IIOWriteProgressListener.class);
|
||||||
|
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListener.proxy());
|
||||||
|
|
||||||
|
Mock mockListenerToo = new Mock(IIOWriteProgressListener.class);
|
||||||
|
mockListenerToo.stubs().method("imageStarted").withAnyArguments();
|
||||||
|
mockListenerToo.stubs().method("imageProgress").withAnyArguments();
|
||||||
|
mockListenerToo.stubs().method("imageComplete").withAnyArguments();
|
||||||
|
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListenerToo.proxy());
|
||||||
|
|
||||||
|
writer.removeIIOWriteProgressListener((IIOWriteProgressListener) mockListener.proxy());
|
||||||
|
|
||||||
|
try {
|
||||||
|
writer.write(getTestData());
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
fail("Could not write image");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should not have called any methods...
|
||||||
|
mockListener.verify();
|
||||||
|
mockListenerToo.verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testRemoveAllIIOWriteProgressListeners() throws IOException {
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
||||||
|
|
||||||
|
|
||||||
|
Mock mockListener = new Mock(IIOWriteProgressListener.class);
|
||||||
|
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListener.proxy());
|
||||||
|
|
||||||
|
writer.removeAllIIOWriteProgressListeners();
|
||||||
|
|
||||||
|
try {
|
||||||
|
writer.write(getTestData());
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
fail("Could not write image");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should not have called any methods...
|
||||||
|
mockListener.verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testRemoveAllIIOWriteProgressListenersMultiple() throws IOException {
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
||||||
|
|
||||||
|
|
||||||
|
Mock mockListener = new Mock(IIOWriteProgressListener.class);
|
||||||
|
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListener.proxy());
|
||||||
|
|
||||||
|
Mock mockListenerToo = new Mock(IIOWriteProgressListener.class);
|
||||||
|
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListenerToo.proxy());
|
||||||
|
|
||||||
|
writer.removeAllIIOWriteProgressListeners();
|
||||||
|
|
||||||
|
try {
|
||||||
|
writer.write(getTestData());
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
fail("Could not write image");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should not have called any methods...
|
||||||
|
mockListener.verify();
|
||||||
|
mockListenerToo.verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,28 @@
|
|||||||
|
package com.twelvemonkeys.imageio.util;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import java.awt.image.DataBuffer;
|
||||||
|
import java.awt.image.IndexColorModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IndexedImageTypeSpecifierTestCase
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: IndexedImageTypeSpecifierTestCase.java,v 1.0 Jun 9, 2008 2:42:03 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public class IndexedImageTypeSpecifierTestCase extends TestCase {
|
||||||
|
public void testEquals() {
|
||||||
|
IndexColorModel cm = new IndexColorModel(1, 2, new int[]{0xffffff, 0x00}, 0, false, -1, DataBuffer.TYPE_BYTE);
|
||||||
|
|
||||||
|
IndexedImageTypeSpecifier spec = new IndexedImageTypeSpecifier(cm);
|
||||||
|
IndexedImageTypeSpecifier other = new IndexedImageTypeSpecifier(cm);
|
||||||
|
|
||||||
|
assertEquals(spec, other);
|
||||||
|
assertEquals(other, spec);
|
||||||
|
|
||||||
|
assertTrue(spec.equals(other));
|
||||||
|
assertTrue(other.equals(spec));
|
||||||
|
}
|
||||||
|
}
|
BIN
twelvemonkeys-imageio/core/src/test/resources/Thumbs-camera.db
Executable file
8
twelvemonkeys-imageio/core/todo.txt
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
- Rename to imageio-common?
|
||||||
|
- Separate modules for more for more plugins
|
||||||
|
- The BMP reader spports some special formats not supported by Sun reader
|
||||||
|
- PNM package is pretty complete, but useless, as it's provided by Sun? Licencse?
|
||||||
|
- WBMP?
|
||||||
|
- XBM?
|
||||||
|
DONE:
|
||||||
|
- Split up into separate plugins (modules), to allow easier configuration
|
25
twelvemonkeys-imageio/ico/license.txt
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
Copyright (c) 2009, 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.
|
29
twelvemonkeys-imageio/ico/pom.xml
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>twelvemonkeys-imageio-ico</artifactId>
|
||||||
|
<version>2.1</version>
|
||||||
|
<name>TwelveMonkeys ImageIO ICO plugin</name>
|
||||||
|
<description>ImageIO plugin for Windows Icon (ICO) and Cursor (CUR) format.</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<artifactId>twelvemonkeys-imageio</artifactId>
|
||||||
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
|
<version>2.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>twelvemonkeys-imageio-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>twelvemonkeys-imageio-core</artifactId>
|
||||||
|
<classifier>tests</classifier>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ico;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes a bitmap structure.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: Bitmap.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||||
|
*/
|
||||||
|
abstract class BitmapDescriptor {
|
||||||
|
protected final DirectoryEntry mEntry;
|
||||||
|
protected final DIBHeader mHeader;
|
||||||
|
|
||||||
|
protected BufferedImage mImage;
|
||||||
|
|
||||||
|
public BitmapDescriptor(final DirectoryEntry pEntry, final DIBHeader pHeader) {
|
||||||
|
Validate.notNull(pEntry, "entry");
|
||||||
|
Validate.notNull(pHeader, "header");
|
||||||
|
|
||||||
|
mEntry = pEntry;
|
||||||
|
mHeader = pHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public BufferedImage getImage();
|
||||||
|
|
||||||
|
public final int getWidth() {
|
||||||
|
return mEntry.getWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getHeight() {
|
||||||
|
return mEntry.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final int getColorCount() {
|
||||||
|
return mEntry.getColorCount() != 0 ? mEntry.getColorCount() : 1 << getBitCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final int getBitCount() {
|
||||||
|
return mEntry.getBitCount() != 0 ? mEntry.getBitCount() : mHeader.getBitCount();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ico;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.image.InverseColorMapIndexColorModel;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.DataBuffer;
|
||||||
|
import java.awt.image.IndexColorModel;
|
||||||
|
import java.awt.image.WritableRaster;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes an indexed bitmap structure (1, 4, or 8 bits per pixes).
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: BitmapIndexed.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||||
|
*/
|
||||||
|
class BitmapIndexed extends BitmapDescriptor {
|
||||||
|
protected final int[] mBits;
|
||||||
|
protected final int[] mColors;
|
||||||
|
|
||||||
|
private BitmapMask mMask;
|
||||||
|
|
||||||
|
public BitmapIndexed(final DirectoryEntry pEntry, final DIBHeader pHeader) {
|
||||||
|
super(pEntry, pHeader);
|
||||||
|
mBits = new int[getWidth() * getHeight()];
|
||||||
|
|
||||||
|
// NOTE: We're adding space for one extra color, for transparency
|
||||||
|
mColors = new int[getColorCount() + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedImage createImageIndexed() {
|
||||||
|
// TODO: This is very stupid, maybe we need a TYPE_CUSTOM image, with separate alphaRaster?!
|
||||||
|
// As ICO has a separate bitmask, not related to palette index (allows 256 colors + trans) :-P
|
||||||
|
|
||||||
|
IndexColorModel icm = createColorModel();
|
||||||
|
|
||||||
|
// This is slightly obscure, and should probably be moved..
|
||||||
|
Hashtable<String, Object> properties = null;
|
||||||
|
if (mEntry instanceof DirectoryEntry.CUREntry) {
|
||||||
|
DirectoryEntry.CUREntry entry = (DirectoryEntry.CUREntry) mEntry;
|
||||||
|
properties = new Hashtable<String, Object>(1);
|
||||||
|
properties.put("cursor_hotspot", entry.getHotspot());
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferedImage image = new BufferedImage(
|
||||||
|
icm,
|
||||||
|
icm.createCompatibleWritableRaster(getWidth(), getHeight()),
|
||||||
|
icm.isAlphaPremultiplied(), properties
|
||||||
|
);
|
||||||
|
|
||||||
|
WritableRaster raster = image.getRaster();
|
||||||
|
|
||||||
|
// Make pixels transparant according to mask
|
||||||
|
final int trans = icm.getTransparentPixel();
|
||||||
|
for (int y = 0; y < getHeight(); y++) {
|
||||||
|
for (int x = 0; x < getWidth(); x++) {
|
||||||
|
if (mMask.isTransparent(x, y)) {
|
||||||
|
mBits[x + getWidth() * y] = trans;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
raster.setSamples(0, 0, getWidth(), getHeight(), 0, mBits);
|
||||||
|
|
||||||
|
//System.out.println("Image: " + image);
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Color model created from color palette in entry
|
||||||
|
*/
|
||||||
|
IndexColorModel createColorModel() {
|
||||||
|
// NOTE: This is a hack to make room for transparent pixel for mask
|
||||||
|
int bits = getBitCount();
|
||||||
|
|
||||||
|
int colors = mColors.length;
|
||||||
|
int trans = -1;
|
||||||
|
|
||||||
|
// Try to avoid USHORT transfertype, as it results in BufferedImage TYPE_CUSTOM
|
||||||
|
// NOTE: This code assumes icons are small, and is NOT optimized for performance...
|
||||||
|
if (colors > (1 << getBitCount())) {
|
||||||
|
int index = BitmapIndexed.findTransIndexMaybeRemap(mColors, mBits);
|
||||||
|
|
||||||
|
if (index == -1) {
|
||||||
|
// No duplicate found, increase bitcount
|
||||||
|
bits++;
|
||||||
|
trans = mColors.length - 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Found a duplicate, use it as trans
|
||||||
|
trans = index;
|
||||||
|
colors--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Setting hasAlpha to true, makes things work on 1.2
|
||||||
|
return new InverseColorMapIndexColorModel(
|
||||||
|
bits, colors, mColors, 0, true, trans,
|
||||||
|
bits <= 8 ? DataBuffer.TYPE_BYTE : DataBuffer.TYPE_USHORT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int findTransIndexMaybeRemap(final int[] pColors, final int[] pBits) {
|
||||||
|
// Look for unused colors, to use as transparent
|
||||||
|
final boolean[] used = new boolean[pColors.length - 1];
|
||||||
|
for (int pBit : pBits) {
|
||||||
|
if (!used[pBit]) {
|
||||||
|
used[pBit] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < used.length; i++) {
|
||||||
|
if (!used[i]) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find duplicates in colormap, and remap
|
||||||
|
int trans = -1;
|
||||||
|
int duplicate = -1;
|
||||||
|
for (int i = 0; trans == -1 && i < pColors.length - 1; i++) {
|
||||||
|
for (int j = i + 1; j < pColors.length - 1; j++) {
|
||||||
|
if (pColors[i] == pColors[j]) {
|
||||||
|
trans = j;
|
||||||
|
duplicate = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trans != -1) {
|
||||||
|
// Remap duplicate
|
||||||
|
for (int i = 0; i < pBits.length; i++) {
|
||||||
|
if (pBits[i] == trans) {
|
||||||
|
pBits[i] = duplicate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return trans;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedImage getImage() {
|
||||||
|
if (mImage == null) {
|
||||||
|
mImage = createImageIndexed();
|
||||||
|
}
|
||||||
|
return mImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMask(final BitmapMask pMask) {
|
||||||
|
mMask = pMask;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ico;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes a transparency mask structure (1 bit).
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: BitmapMask.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||||
|
*/
|
||||||
|
class BitmapMask extends BitmapDescriptor {
|
||||||
|
protected final BitmapIndexed mMask;
|
||||||
|
|
||||||
|
public BitmapMask(final DirectoryEntry pParent, final DIBHeader pHeader) {
|
||||||
|
super(pParent, pHeader);
|
||||||
|
mMask = new BitmapIndexed(pParent, pHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isTransparent(final int pX, final int pY) {
|
||||||
|
// NOTE: 1: Fully transparent, 0: Opaque...
|
||||||
|
return mMask.mBits[pX + pY * getWidth()] != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedImage getImage() {
|
||||||
|
return mMask.getImage();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ico;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes an RGB/true color bitmap structure (16, 24 and 32 bits per pixel).
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: BitmapRGB.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||||
|
*/
|
||||||
|
class BitmapRGB extends BitmapDescriptor {
|
||||||
|
|
||||||
|
public BitmapRGB(final DirectoryEntry pEntry, final DIBHeader pHeader) {
|
||||||
|
super(pEntry, pHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedImage getImage() {
|
||||||
|
return mImage;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ico;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents bitmap structures we can't read.
|
||||||
|
* Allows for deferred exception handling, and allowing clients to read all images that can be read.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: BitmapUnsupported.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||||
|
*/
|
||||||
|
class BitmapUnsupported extends BitmapDescriptor {
|
||||||
|
private String mMessage;
|
||||||
|
|
||||||
|
public BitmapUnsupported(final DirectoryEntry pEntry, final String pMessage) {
|
||||||
|
super(pEntry, null);
|
||||||
|
|
||||||
|
mMessage = pMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedImage getImage() {
|
||||||
|
throw new IllegalStateException(mMessage);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ico;
|
||||||
|
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ImageReader for Microsoft Windows CUR (cursor) format.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: CURImageReader.java,v 1.0 Apr 20, 2009 11:54:28 AM haraldk Exp$
|
||||||
|
*
|
||||||
|
* @see com.twelvemonkeys.imageio.plugins.ico.ICOImageReader
|
||||||
|
*/
|
||||||
|
public class CURImageReader extends ICOImageReader {
|
||||||
|
// NOTE: All implementation is part of the ICOImageReader
|
||||||
|
|
||||||
|
public CURImageReader() {
|
||||||
|
super(DIB.TYPE_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CURImageReader(final ImageReaderSpi pProvider) {
|
||||||
|
super(pProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hotspot location for the cursor.
|
||||||
|
*
|
||||||
|
* @param pImageIndex the index of the cursor in the current input.
|
||||||
|
* @return the hotspot location for the cursor
|
||||||
|
*
|
||||||
|
* @throws IOException if an I/O exception occurs during reading of image meta data
|
||||||
|
* @throws IndexOutOfBoundsException if {@code pImageIndex} is less than {@code 0} or greater than/equal to
|
||||||
|
* the number of cursors in the file
|
||||||
|
*/
|
||||||
|
public final Point getHotSpot(final int pImageIndex) throws IOException {
|
||||||
|
DirectoryEntry.CUREntry entry = (DirectoryEntry.CUREntry) getEntry(pImageIndex);
|
||||||
|
return entry.getHotspot();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ico;
|
||||||
|
|
||||||
|
import javax.imageio.ImageReader;
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CURImageReaderSpi
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: CURImageReaderSpi.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||||
|
*/
|
||||||
|
public class CURImageReaderSpi extends ImageReaderSpi {
|
||||||
|
|
||||||
|
public CURImageReaderSpi() {
|
||||||
|
super(
|
||||||
|
"TwelveMonkeys",
|
||||||
|
"2.1",
|
||||||
|
new String[]{"cur", "CUR"},
|
||||||
|
new String[]{"cur"},
|
||||||
|
new String[]{
|
||||||
|
"image/vnd.microsoft.cursor", // Official IANA MIME
|
||||||
|
"image/x-cursor", // Common extension MIME
|
||||||
|
"image/cursor" // Unofficial, but common
|
||||||
|
},
|
||||||
|
"com.twelvemonkeys.imageio.plugins.ico.CURImageReader",
|
||||||
|
STANDARD_INPUT_TYPE,
|
||||||
|
null,
|
||||||
|
true, null, null, null, null,
|
||||||
|
true,
|
||||||
|
null, null,
|
||||||
|
null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canDecodeInput(final Object pSource) throws IOException {
|
||||||
|
return pSource instanceof ImageInputStream && ICOImageReaderSpi.canDecode((ImageInputStream) pSource, DIB.TYPE_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageReader createReaderInstance(final Object pExtension) throws IOException {
|
||||||
|
return new CURImageReader(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription(final Locale pLocale) {
|
||||||
|
return "Windows Cursor Format (CUR) Reader";
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ico;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DIB
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: DIB.java,v 1.0 Apr 8, 2008 1:43:04 PM haraldk Exp$
|
||||||
|
*
|
||||||
|
* @see <a href="http://en.wikipedia.org/wiki/BMP_file_format">BMP file format (Wikipedia)</a>
|
||||||
|
* @see <a href="http://en.wikipedia.org/wiki/ICO_(icon_image_file_format)">ICO file format (Wikipedia)</a>
|
||||||
|
*/
|
||||||
|
interface DIB {
|
||||||
|
int TYPE_UNKNOWN = 0;
|
||||||
|
int TYPE_ICO = 1;
|
||||||
|
int TYPE_CUR = 2;
|
||||||
|
|
||||||
|
/** BITMAPCOREHEADER size, OS/2 V1 */
|
||||||
|
int OS2_V1_HEADER_SIZE = 12;
|
||||||
|
|
||||||
|
/** BITMAPCOREHEADER size, OS/2 V2 */
|
||||||
|
int OS2_V2_HEADER_SIZE = 64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BITMAPINFOHEADER size, Windows 3.0 and later.
|
||||||
|
* This is the most commonly used header for persistent bitmaps
|
||||||
|
*/
|
||||||
|
int WINDOWS_V3_HEADER_SIZE = 40;
|
||||||
|
|
||||||
|
/** BITMAPV4HEADER size, Windows 95/NT4 and later */
|
||||||
|
int WINDOWS_V4_HEADER_SIZE = 108;
|
||||||
|
|
||||||
|
/** BITMAPV5HEADER size, Windows 98/2000 and later */
|
||||||
|
int WINDOWS_V5_HEADER_SIZE = 124;
|
||||||
|
|
||||||
|
/** PNG "magic" identifier */
|
||||||
|
long PNG_MAGIC = 0x89l << 56 | (long) 'P' << 48 | (long) 'N' << 40 | (long) 'G' << 32 | 0x0dl << 24 | 0x0al << 16 | 0x1al << 8 | 0x0al;
|
||||||
|
}
|
@@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ico;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the DIB (Device Independent Bitmap) Information header structure.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: DIBHeader.java,v 1.0 May 5, 2009 10:45:31 AM haraldk Exp$
|
||||||
|
* @see <a href="http://en.wikipedia.org/wiki/BMP_file_format">BMP file format (Wikipedia)</a>
|
||||||
|
*/
|
||||||
|
abstract class DIBHeader {
|
||||||
|
protected int mSize;
|
||||||
|
|
||||||
|
protected int mWidth;
|
||||||
|
|
||||||
|
// NOTE: If a bitmask is present, this value includes the height of the mask
|
||||||
|
// (so often header.height = entry.height * 2)
|
||||||
|
protected int mHeight;
|
||||||
|
|
||||||
|
protected int mPlanes;
|
||||||
|
protected int mBitCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 0 = BI_RGB: No compression
|
||||||
|
* 1 = BI_RLE8: 8 bit RLE Compression (8 bit only)
|
||||||
|
* 2 = BI_RLE4: 4 bit RLE Compression (4 bit only)
|
||||||
|
* 3 = BI_BITFIELDS: No compression (16 & 32 bit only)
|
||||||
|
*/
|
||||||
|
protected int mCompression;
|
||||||
|
|
||||||
|
// May be 0 if not known
|
||||||
|
protected int mImageSize;
|
||||||
|
|
||||||
|
protected int mXPixelsPerMeter;
|
||||||
|
protected int mYPixelsPerMeter;
|
||||||
|
|
||||||
|
protected int mColorsUsed;
|
||||||
|
|
||||||
|
// 0 means all colors are important
|
||||||
|
protected int mColorsImportant;
|
||||||
|
|
||||||
|
protected DIBHeader() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DIBHeader read(final DataInput pStream) throws IOException {
|
||||||
|
int size = pStream.readInt();
|
||||||
|
|
||||||
|
// ICO always uses the Microsoft Windows V3 DIB header, which is 40 bytes
|
||||||
|
DIBHeader header = createHeader(size);
|
||||||
|
header.read(size, pStream);
|
||||||
|
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DIBHeader createHeader(final int pSize) throws IOException {
|
||||||
|
switch (pSize) {
|
||||||
|
case DIB.OS2_V1_HEADER_SIZE:
|
||||||
|
case DIB.OS2_V2_HEADER_SIZE:
|
||||||
|
throw new IIOException(String.format("OS/2 Bitmap Information Header (size: %s) not supported", pSize));
|
||||||
|
case DIB.WINDOWS_V3_HEADER_SIZE:
|
||||||
|
return new WindowsV3DIBHeader();
|
||||||
|
case DIB.WINDOWS_V4_HEADER_SIZE:
|
||||||
|
case DIB.WINDOWS_V5_HEADER_SIZE:
|
||||||
|
throw new IIOException(String.format("Windows Bitmap Information Header (size: %s) not supported", pSize));
|
||||||
|
default:
|
||||||
|
throw new IIOException(String.format("Unknown Bitmap Information Header (size: %s)", pSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void read(int pSize, DataInput pStream) throws IOException;
|
||||||
|
|
||||||
|
public final int getSize() {
|
||||||
|
return mSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getWidth() {
|
||||||
|
return mWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getHeight() {
|
||||||
|
return mHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getPlanes() {
|
||||||
|
return mPlanes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getBitCount() {
|
||||||
|
return mBitCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCompression() {
|
||||||
|
return mCompression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getImageSize() {
|
||||||
|
return mImageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getXPixelsPerMeter() {
|
||||||
|
return mXPixelsPerMeter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getYPixelsPerMeter() {
|
||||||
|
return mYPixelsPerMeter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColorsUsed() {
|
||||||
|
return mColorsUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColorsImportant() {
|
||||||
|
return mColorsImportant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"%s: size: %d bytes, " +
|
||||||
|
"width: %d, height: %d, planes: %d, bit count: %d, compression: %d, " +
|
||||||
|
"image size: %d%s, " +
|
||||||
|
"X pixels per m: %d, Y pixels per m: %d, " +
|
||||||
|
"colors used: %d, colors important: %d%s",
|
||||||
|
getClass().getSimpleName(),
|
||||||
|
getSize(), getWidth(), getHeight(), getPlanes(), getBitCount(), getCompression(),
|
||||||
|
getImageSize(), (getImageSize() == 0 ? " (unknown)" : ""),
|
||||||
|
getXPixelsPerMeter(), getYPixelsPerMeter(),
|
||||||
|
getColorsUsed(), getColorsImportant(), (getColorsImportant() == 0 ? " (all)" : "")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the DIB (Device Independent Bitmap) Windows V3 Bitmap Information header structure.
|
||||||
|
* This is the common format for persistent DIB structures, even if Windows
|
||||||
|
* may use the later versions at run-time.
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: DIBHeader.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||||
|
* @see <a href="http://en.wikipedia.org/wiki/BMP_file_format">BMP file format (Wikipedia)</a>
|
||||||
|
*/
|
||||||
|
static final class WindowsV3DIBHeader extends DIBHeader {
|
||||||
|
protected void read(final int pSize, final DataInput pStream) throws IOException {
|
||||||
|
if (pSize != DIB.WINDOWS_V3_HEADER_SIZE) {
|
||||||
|
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.WINDOWS_V3_HEADER_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
mSize = pSize;
|
||||||
|
|
||||||
|
mWidth = pStream.readInt();
|
||||||
|
mHeight = pStream.readInt();
|
||||||
|
|
||||||
|
mPlanes = pStream.readUnsignedShort();
|
||||||
|
mBitCount = pStream.readUnsignedShort();
|
||||||
|
mCompression = pStream.readInt();
|
||||||
|
|
||||||
|
mImageSize = pStream.readInt();
|
||||||
|
|
||||||
|
mXPixelsPerMeter = pStream.readInt();
|
||||||
|
mYPixelsPerMeter = pStream.readInt();
|
||||||
|
|
||||||
|
mColorsUsed = pStream.readInt();
|
||||||
|
mColorsImportant = pStream.readInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ico;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directory
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: Directory.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||||
|
*/
|
||||||
|
class Directory {
|
||||||
|
private final List<DirectoryEntry> mEntries;
|
||||||
|
|
||||||
|
private Directory(int pImageCount) {
|
||||||
|
mEntries = Arrays.asList(new DirectoryEntry[pImageCount]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Directory read(final int pType, final int pImageCount, final DataInput pStream) throws IOException {
|
||||||
|
Directory directory = new Directory(pImageCount);
|
||||||
|
directory.readEntries(pType, pStream);
|
||||||
|
return directory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readEntries(final int pType, final DataInput pStream) throws IOException {
|
||||||
|
for (int i = 0; i < mEntries.size(); i++) {
|
||||||
|
mEntries.set(i, DirectoryEntry.read(pType, pStream));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DirectoryEntry getEntry(final int pEntryIndex) {
|
||||||
|
return mEntries.get(pEntryIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int count() {
|
||||||
|
return mEntries.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("%s%s", getClass().getSimpleName(), mEntries);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ico;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DirectoryEntry
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: DirectoryEntry.java,v 1.0 Apr 4, 2009 4:29:53 PM haraldk Exp$
|
||||||
|
* @see <a href="http://en.wikipedia.org/wiki/ICO_(icon_image_file_format)#Directory">Wikipedia</a>
|
||||||
|
*/
|
||||||
|
abstract class DirectoryEntry {
|
||||||
|
private int mWidth;
|
||||||
|
private int mHeight;
|
||||||
|
private int mColorCount;
|
||||||
|
int mPlanes;
|
||||||
|
int mBitCount;
|
||||||
|
private int mSize;
|
||||||
|
private int mOffset;
|
||||||
|
|
||||||
|
private DirectoryEntry() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DirectoryEntry read(final int pType, final DataInput pStream) throws IOException {
|
||||||
|
DirectoryEntry entry = createEntry(pType);
|
||||||
|
entry.read(pStream);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DirectoryEntry createEntry(int pType) throws IIOException {
|
||||||
|
switch (pType) {
|
||||||
|
case DIB.TYPE_ICO:
|
||||||
|
return new ICOEntry();
|
||||||
|
case DIB.TYPE_CUR:
|
||||||
|
return new CUREntry();
|
||||||
|
default:
|
||||||
|
throw new IIOException(
|
||||||
|
String.format(
|
||||||
|
"Unknown DIB type: %s, expected: %s (ICO) or %s (CUR)",
|
||||||
|
pType, DIB.TYPE_ICO, DIB.TYPE_CUR
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void read(final DataInput pStream) throws IOException {
|
||||||
|
// Width/height = 0, means 256
|
||||||
|
int w = pStream.readUnsignedByte();
|
||||||
|
mWidth = w == 0 ? 256 : w;
|
||||||
|
int h = pStream.readUnsignedByte();
|
||||||
|
mHeight = h == 0 ? 256 : h;
|
||||||
|
|
||||||
|
// Color count = 0, means 256 or more colors
|
||||||
|
mColorCount = pStream.readUnsignedByte();
|
||||||
|
|
||||||
|
// Ignore. Should be 0, but .NET (System.Drawing.Icon.Save) sets this value to 255, according to Wikipedia
|
||||||
|
pStream.readUnsignedByte();
|
||||||
|
|
||||||
|
mPlanes = pStream.readUnsignedShort(); // Should be 0 or 1 for ICO, x hotspot for CUR
|
||||||
|
mBitCount = pStream.readUnsignedShort(); // bit count for ICO, y hotspot for CUR
|
||||||
|
|
||||||
|
// Size of bitmap in bytes
|
||||||
|
mSize = pStream.readInt();
|
||||||
|
mOffset = pStream.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"%s: width: %d, height: %d, colors: %d, planes: %d, bit count: %d, size: %d, offset: %d",
|
||||||
|
getClass().getSimpleName(),
|
||||||
|
mWidth, mHeight, mColorCount, mPlanes, mBitCount, mSize, mOffset
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBitCount() {
|
||||||
|
return mBitCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColorCount() {
|
||||||
|
return mColorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight() {
|
||||||
|
return mHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOffset() {
|
||||||
|
return mOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPlanes() {
|
||||||
|
return mPlanes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
return mSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWidth() {
|
||||||
|
return mWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cursor directory entry.
|
||||||
|
*/
|
||||||
|
static class CUREntry extends DirectoryEntry {
|
||||||
|
private int mXHotspot;
|
||||||
|
private int mYHotspot;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void read(final DataInput pStream) throws IOException {
|
||||||
|
super.read(pStream);
|
||||||
|
|
||||||
|
// NOTE: This is a hack...
|
||||||
|
mXHotspot = mPlanes;
|
||||||
|
mYHotspot = mBitCount;
|
||||||
|
|
||||||
|
mPlanes = 1; // Always 1 for all BMP types
|
||||||
|
mBitCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getHotspot() {
|
||||||
|
return new Point(mXHotspot, mYHotspot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Icon directory entry.
|
||||||
|
*/
|
||||||
|
static final class ICOEntry extends DirectoryEntry {
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,709 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ico;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.image.ImageUtil;
|
||||||
|
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||||
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
|
import com.twelvemonkeys.imageio.util.IndexedImageTypeSpecifier;
|
||||||
|
import com.twelvemonkeys.util.WeakWeakMap;
|
||||||
|
|
||||||
|
import javax.imageio.*;
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.color.ColorSpace;
|
||||||
|
import java.awt.event.WindowAdapter;
|
||||||
|
import java.awt.event.WindowEvent;
|
||||||
|
import java.awt.image.*;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ImageReader for Microsoft Windows ICO (icon) format.
|
||||||
|
* 1, 4, 8 bit palette support with bitmask transparency, and 16, 24 and 32 bit
|
||||||
|
* true color support with alpha. Also supports Windows Vista PNG ecoded icons.
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: ICOImageReader.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||||
|
*
|
||||||
|
* @see <a href="http://en.wikipedia.org/wiki/BMP_file_format">BMP file format (Wikipedia)</a>
|
||||||
|
* @see <a href="http://en.wikipedia.org/wiki/ICO_(icon_image_file_format)">ICO file format (Wikipedia)</a>
|
||||||
|
*/
|
||||||
|
// SEE http://en.wikipedia.org/wiki/ICO_(icon_image_file_format)
|
||||||
|
// TODO: Decide wether DirectoryEntry or DIBHeader should be primary source for color count/bit count
|
||||||
|
// TODO: Support loading icons from DLLs, see
|
||||||
|
// <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwui/html/msdn_icons.asp">MSDN</a>
|
||||||
|
// Known issue: 256x256 PNG encoded icons does not have IndexColorModel even if stated in DirectoryEntry (seem impossible as the PNGs are all true color)
|
||||||
|
public class ICOImageReader extends ImageReaderBase {
|
||||||
|
// TODO: Consider moving the reading to inner classes (subclasses of BitmapDescriptor)
|
||||||
|
private Directory mDirectory;
|
||||||
|
|
||||||
|
// TODO: Review these, make sure we don't have a memory leak
|
||||||
|
private Map<DirectoryEntry, DIBHeader> mHeaders = new WeakHashMap<DirectoryEntry, DIBHeader>();
|
||||||
|
private Map<DirectoryEntry, BitmapDescriptor> mDescriptors = new WeakWeakMap<DirectoryEntry, BitmapDescriptor>();
|
||||||
|
|
||||||
|
private ImageReader mPNGImageReader;
|
||||||
|
|
||||||
|
public ICOImageReader() {
|
||||||
|
this(DIB.TYPE_ICO);
|
||||||
|
}
|
||||||
|
|
||||||
|
ICOImageReader(final int pType) {
|
||||||
|
this(createProviderForConstructor(pType));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ICOImageReader(final ImageReaderSpi pProvider) {
|
||||||
|
super(pProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ImageReaderSpi createProviderForConstructor(final int pType) {
|
||||||
|
switch (pType) {
|
||||||
|
case DIB.TYPE_ICO:
|
||||||
|
return new ICOImageReaderSpi();
|
||||||
|
case DIB.TYPE_CUR:
|
||||||
|
return new CURImageReaderSpi();
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(String.format("Unsupported ICO/CUR type: %d", pType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void resetMembers() {
|
||||||
|
mDirectory = null;
|
||||||
|
|
||||||
|
mHeaders.clear();
|
||||||
|
mDescriptors.clear();
|
||||||
|
|
||||||
|
if (mPNGImageReader != null) {
|
||||||
|
mPNGImageReader.dispose();
|
||||||
|
mPNGImageReader = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<ImageTypeSpecifier> getImageTypes(final int pImageIndex) throws IOException {
|
||||||
|
DirectoryEntry entry = getEntry(pImageIndex);
|
||||||
|
|
||||||
|
// NOTE: Delegate to PNG reader
|
||||||
|
if (isPNG(entry)) {
|
||||||
|
return getImageTypesPNG(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ImageTypeSpecifier> types = new ArrayList<ImageTypeSpecifier>();
|
||||||
|
DIBHeader header = getHeader(entry);
|
||||||
|
|
||||||
|
// Use data from header to create specifier
|
||||||
|
ImageTypeSpecifier specifier;
|
||||||
|
switch (header.getBitCount()) {
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 4:
|
||||||
|
case 8:
|
||||||
|
// TODO: This is slightly QnD...
|
||||||
|
int offset = entry.getOffset() + header.getSize();
|
||||||
|
if (offset != mImageInput.getStreamPosition()) {
|
||||||
|
mImageInput.seek(offset);
|
||||||
|
}
|
||||||
|
BitmapIndexed indexed = new BitmapIndexed(entry, header);
|
||||||
|
readColorMap(indexed);
|
||||||
|
specifier = IndexedImageTypeSpecifier.createFromIndexColorModel(indexed.createColorModel());
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
specifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_USHORT_555_RGB);
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
specifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR);
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
specifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IIOException(String.format("Unknown bit depth: %d", header.getBitCount()));
|
||||||
|
}
|
||||||
|
|
||||||
|
types.add(specifier);
|
||||||
|
|
||||||
|
return types.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumImages(final boolean pAllowSearch) throws IOException {
|
||||||
|
return getDirectory().count();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWidth(final int pImageIndex) throws IOException {
|
||||||
|
return getEntry(pImageIndex).getWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight(final int pImageIndex) throws IOException {
|
||||||
|
return getEntry(pImageIndex).getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedImage read(final int pImageIndex, final ImageReadParam pParam) throws IOException {
|
||||||
|
checkBounds(pImageIndex);
|
||||||
|
|
||||||
|
processImageStarted(pImageIndex);
|
||||||
|
|
||||||
|
DirectoryEntry entry = getEntry(pImageIndex);
|
||||||
|
|
||||||
|
BufferedImage destination;
|
||||||
|
|
||||||
|
if (isPNG(entry)) {
|
||||||
|
// NOTE: Special case for Windows Vista, 256x256 PNG encoded images, with no DIB header...
|
||||||
|
destination = readPNG(entry, pParam);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// NOTE: If param does not have explicit destination, we'll try to create a BufferedImage later,
|
||||||
|
// to allow for storing the cursor hotspot for CUR images
|
||||||
|
destination = hasExplicitDestination(pParam) ?
|
||||||
|
getDestination(pParam, getImageTypes(pImageIndex), getWidth(pImageIndex), getHeight(pImageIndex)) :
|
||||||
|
null;
|
||||||
|
|
||||||
|
BufferedImage image = readBitmap(entry);
|
||||||
|
|
||||||
|
// TODO: Handle AOI and subsampling inline, probably not of big importance...
|
||||||
|
if (pParam != null) {
|
||||||
|
image = fakeAOI(image, pParam);
|
||||||
|
image = ImageUtil.toBuffered(fakeSubsampling(image, pParam));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (destination == null) {
|
||||||
|
// This is okay, as long as the client did not request explicit destination image/type
|
||||||
|
destination = image;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Graphics2D g = destination.createGraphics();
|
||||||
|
try {
|
||||||
|
g.setComposite(AlphaComposite.Src);
|
||||||
|
g.drawImage(image, 0, 0, null);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
g.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processImageProgress(100);
|
||||||
|
processImageComplete();
|
||||||
|
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasExplicitDestination(final ImageReadParam pParam) {
|
||||||
|
return (pParam != null && (pParam.getDestination() != null || pParam.getDestinationType() != null || pParam.getDestinationOffset() != null));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPNG(final DirectoryEntry pEntry) throws IOException {
|
||||||
|
long magic;
|
||||||
|
|
||||||
|
mImageInput.seek(pEntry.getOffset());
|
||||||
|
mImageInput.setByteOrder(ByteOrder.BIG_ENDIAN);
|
||||||
|
|
||||||
|
try {
|
||||||
|
magic = mImageInput.readLong();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
mImageInput.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
return magic == DIB.PNG_MAGIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedImage readPNG(final DirectoryEntry pEntry, final ImageReadParam pParam) throws IOException {
|
||||||
|
// TODO: Consider delegating listener calls
|
||||||
|
return initPNGReader(pEntry).read(0, pParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Iterator<ImageTypeSpecifier> getImageTypesPNG(final DirectoryEntry pEntry) throws IOException {
|
||||||
|
return initPNGReader(pEntry).getImageTypes(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImageReader initPNGReader(final DirectoryEntry pEntry) throws IOException {
|
||||||
|
ImageReader pngReader = getPNGReader();
|
||||||
|
|
||||||
|
mImageInput.seek(pEntry.getOffset());
|
||||||
|
InputStream inputStream = IIOUtil.createStreamAdapter(mImageInput, pEntry.getSize());
|
||||||
|
ImageInputStream stream = ImageIO.createImageInputStream(inputStream);
|
||||||
|
|
||||||
|
// NOTE: Will throw IOException on later reads if input is not PNG
|
||||||
|
pngReader.setInput(stream);
|
||||||
|
|
||||||
|
return pngReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImageReader getPNGReader() throws IIOException {
|
||||||
|
// TODO: Prefer Sun's std JDK PNGImagerReader, because it has known behaviour?
|
||||||
|
if (mPNGImageReader == null) {
|
||||||
|
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("PNG");
|
||||||
|
|
||||||
|
if (readers.hasNext()) {
|
||||||
|
mPNGImageReader = readers.next();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IIOException("No PNGImageReader found using ImageIO, can't read PNG encoded ICO format.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mPNGImageReader.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mPNGImageReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DIBHeader getHeader(final DirectoryEntry pEntry) throws IOException {
|
||||||
|
if (!mHeaders.containsKey(pEntry)) {
|
||||||
|
mImageInput.seek(pEntry.getOffset());
|
||||||
|
DIBHeader header = DIBHeader.read(mImageInput);
|
||||||
|
mHeaders.put(pEntry, header);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mHeaders.get(pEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedImage readBitmap(final DirectoryEntry pEntry) throws IOException {
|
||||||
|
// TODO: Currently, we have a memory leak, as the values refer to the keys...
|
||||||
|
BitmapDescriptor descriptor = mDescriptors.get(pEntry);
|
||||||
|
|
||||||
|
if (!mDescriptors.containsKey(pEntry)) {
|
||||||
|
DIBHeader header = getHeader(pEntry);
|
||||||
|
|
||||||
|
int offset = pEntry.getOffset() + header.getSize();
|
||||||
|
if (offset != mImageInput.getStreamPosition()) {
|
||||||
|
mImageInput.seek(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Support this, it's already in the BMP reader, spec allows RLE4 and RLE8
|
||||||
|
if (header.getCompression() != 0) {
|
||||||
|
descriptor = new BitmapUnsupported(pEntry, String.format("Unsupported compression: %d", header.getCompression()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int bitCount = header.getBitCount();
|
||||||
|
|
||||||
|
switch (bitCount) {
|
||||||
|
// Palette style
|
||||||
|
case 1:
|
||||||
|
case 4:
|
||||||
|
case 8:
|
||||||
|
descriptor = new BitmapIndexed(pEntry, header);
|
||||||
|
readBitmapIndexed((BitmapIndexed) descriptor);
|
||||||
|
break;
|
||||||
|
// RGB style
|
||||||
|
case 16:
|
||||||
|
descriptor = new BitmapRGB(pEntry, header);
|
||||||
|
readBitmap16(descriptor);
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
descriptor = new BitmapRGB(pEntry, header);
|
||||||
|
readBitmap24(descriptor);
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
descriptor = new BitmapRGB(pEntry, header);
|
||||||
|
readBitmap32(descriptor);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
descriptor = new BitmapUnsupported(pEntry, String.format("Unsupported bit count %d", bitCount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mDescriptors.put(pEntry, descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return descriptor.getImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readBitmapIndexed(final BitmapIndexed pBitmap) throws IOException {
|
||||||
|
readColorMap(pBitmap);
|
||||||
|
|
||||||
|
switch (pBitmap.getBitCount()) {
|
||||||
|
case 1:
|
||||||
|
readBitmapIndexed1(pBitmap, false);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
readBitmapIndexed4(pBitmap);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
readBitmapIndexed8(pBitmap);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BitmapMask mask = new BitmapMask(pBitmap.mEntry, pBitmap.mHeader);
|
||||||
|
readBitmapIndexed1(mask.mMask, true);
|
||||||
|
pBitmap.setMask(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readColorMap(final BitmapIndexed pBitmap) throws IOException {
|
||||||
|
int colorCount = pBitmap.getColorCount();
|
||||||
|
|
||||||
|
for (int i = 0; i < colorCount; i++) {
|
||||||
|
// aRGB (a is "Reserved")
|
||||||
|
pBitmap.mColors[i] = (mImageInput.readInt() & 0xffffff) | 0xff000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readBitmapIndexed1(final BitmapIndexed pBitmap, final boolean pAsMask) throws IOException {
|
||||||
|
int width = adjustToPadding(pBitmap.getWidth() >> 3);
|
||||||
|
byte[] row = new byte[width];
|
||||||
|
|
||||||
|
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
||||||
|
mImageInput.readFully(row, 0, width);
|
||||||
|
int rowPos = 0;
|
||||||
|
int xOrVal = 0x80;
|
||||||
|
int pos = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
|
||||||
|
|
||||||
|
for (int x = 0; x < pBitmap.getWidth(); x++) {
|
||||||
|
pBitmap.mBits[pos++] = ((row[rowPos] & xOrVal) / xOrVal) & 0xFF;
|
||||||
|
|
||||||
|
if (xOrVal == 1) {
|
||||||
|
xOrVal = 0x80;
|
||||||
|
rowPos++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
xOrVal >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: If we are reading the mask, we don't abort or progress
|
||||||
|
if (!pAsMask) {
|
||||||
|
if (abortRequested()) {
|
||||||
|
processReadAborted();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readBitmapIndexed4(final BitmapIndexed pBitmap) throws IOException {
|
||||||
|
int width = adjustToPadding(pBitmap.getWidth() >> 1);
|
||||||
|
byte[] row = new byte[width];
|
||||||
|
|
||||||
|
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
||||||
|
mImageInput.readFully(row, 0, width);
|
||||||
|
int rowPos = 0;
|
||||||
|
boolean high4 = true;
|
||||||
|
int pos = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
|
||||||
|
|
||||||
|
for (int x = 0; x < pBitmap.getWidth(); x++) {
|
||||||
|
int value;
|
||||||
|
|
||||||
|
if (high4) {
|
||||||
|
value = (row[rowPos] & 0xF0) >> 4;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
value = row[rowPos] & 0x0F;
|
||||||
|
rowPos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
pBitmap.mBits[pos++] = value & 0xFF;
|
||||||
|
high4 = !high4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abortRequested()) {
|
||||||
|
processReadAborted();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readBitmapIndexed8(final BitmapIndexed pBitmap) throws IOException {
|
||||||
|
int width = adjustToPadding(pBitmap.getWidth());
|
||||||
|
|
||||||
|
byte[] row = new byte[width];
|
||||||
|
|
||||||
|
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
||||||
|
mImageInput.readFully(row, 0, width);
|
||||||
|
int rowPos = 0;
|
||||||
|
int pos = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
|
||||||
|
|
||||||
|
for (int x = 0; x < pBitmap.getWidth(); x++) {
|
||||||
|
pBitmap.mBits[pos++] = row[rowPos++] & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abortRequested()) {
|
||||||
|
processReadAborted();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param pWidth Bytes per scan line (i.e., 1BPP, width = 9 -> bytes = 1)
|
||||||
|
* @return padded width
|
||||||
|
*/
|
||||||
|
private static int adjustToPadding(final int pWidth) {
|
||||||
|
if ((pWidth & 0x03) != 0) {
|
||||||
|
return (pWidth & ~0x03) + 4;
|
||||||
|
}
|
||||||
|
return pWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readBitmap16(final BitmapDescriptor pBitmap) throws IOException {
|
||||||
|
// TODO: No idea if this actually works..
|
||||||
|
short[] pixels = new short[pBitmap.getWidth() * pBitmap.getHeight()];
|
||||||
|
|
||||||
|
// Will create TYPE_USHORT_555;
|
||||||
|
DirectColorModel cm = new DirectColorModel(16, 0x7C00, 0x03E0, 0x001F);
|
||||||
|
DataBuffer buffer = new DataBufferShort(pixels, pixels.length);
|
||||||
|
WritableRaster raster = Raster.createPackedRaster(
|
||||||
|
buffer, pBitmap.getWidth(), pBitmap.getHeight(), pBitmap.getWidth(), cm.getMasks(), null
|
||||||
|
);
|
||||||
|
pBitmap.mImage = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||||
|
|
||||||
|
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
||||||
|
int offset = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
|
||||||
|
mImageInput.readFully(pixels, offset, pBitmap.getWidth());
|
||||||
|
|
||||||
|
|
||||||
|
// Skip to 32 bit boundary
|
||||||
|
if (pBitmap.getWidth() % 2 != 0) {
|
||||||
|
mImageInput.readShort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abortRequested()) {
|
||||||
|
processReadAborted();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readBitmap24(final BitmapDescriptor pBitmap) throws IOException {
|
||||||
|
byte[] pixels = new byte[pBitmap.getWidth() * pBitmap.getHeight() * 3];
|
||||||
|
|
||||||
|
// Create TYPE_3BYTE_BGR
|
||||||
|
DataBuffer buffer = new DataBufferByte(pixels, pixels.length);
|
||||||
|
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
|
||||||
|
int[] nBits = {8, 8, 8};
|
||||||
|
int[] bOffs = {2, 1, 0};
|
||||||
|
ComponentColorModel cm = new ComponentColorModel(
|
||||||
|
cs, nBits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE
|
||||||
|
);
|
||||||
|
|
||||||
|
WritableRaster raster = Raster.createInterleavedRaster(
|
||||||
|
buffer, pBitmap.getWidth(), pBitmap.getHeight(), pBitmap.getWidth(), 3, bOffs, null
|
||||||
|
);
|
||||||
|
pBitmap.mImage = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||||
|
|
||||||
|
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
||||||
|
int offset = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
|
||||||
|
mImageInput.readFully(pixels, offset, pBitmap.getWidth() * 3);
|
||||||
|
|
||||||
|
// TODO: Possibly read padding byte here!
|
||||||
|
|
||||||
|
if (abortRequested()) {
|
||||||
|
processReadAborted();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readBitmap32(final BitmapDescriptor pBitmap) throws IOException {
|
||||||
|
int[] pixels = new int[pBitmap.getWidth() * pBitmap.getHeight()];
|
||||||
|
|
||||||
|
// Will create TYPE_INT_ARGB
|
||||||
|
DirectColorModel cm = (DirectColorModel) ColorModel.getRGBdefault();
|
||||||
|
DataBuffer buffer = new DataBufferInt(pixels, pixels.length);
|
||||||
|
WritableRaster raster = Raster.createPackedRaster(
|
||||||
|
buffer, pBitmap.getWidth(), pBitmap.getHeight(), pBitmap.getWidth(), cm.getMasks(), null
|
||||||
|
);
|
||||||
|
pBitmap.mImage = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||||
|
|
||||||
|
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
||||||
|
int offset = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
|
||||||
|
mImageInput.readFully(pixels, offset, pBitmap.getWidth());
|
||||||
|
|
||||||
|
if (abortRequested()) {
|
||||||
|
processReadAborted();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Directory getDirectory() throws IOException {
|
||||||
|
assertInput();
|
||||||
|
|
||||||
|
if (mDirectory == null) {
|
||||||
|
readFileHeader();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readFileHeader() throws IOException {
|
||||||
|
mImageInput.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
|
// Read file header
|
||||||
|
mImageInput.readUnsignedShort(); // Reserved
|
||||||
|
|
||||||
|
// Should be same as type as the provider
|
||||||
|
int type = mImageInput.readUnsignedShort();
|
||||||
|
int imageCount = mImageInput.readUnsignedShort();
|
||||||
|
|
||||||
|
// Read directory
|
||||||
|
mDirectory = Directory.read(type, imageCount, mImageInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
final DirectoryEntry getEntry(final int pImageIndex) throws IOException {
|
||||||
|
Directory directory = getDirectory();
|
||||||
|
if (pImageIndex < 0 || pImageIndex >= directory.count()) {
|
||||||
|
throw new IndexOutOfBoundsException(String.format("Index: %d, ImageCount: %d", pImageIndex, directory.count()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return directory.getEntry(pImageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test code below, ignore.. :-)
|
||||||
|
public static void main(final String[] pArgs) throws IOException {
|
||||||
|
if (pArgs.length == 0) {
|
||||||
|
System.err.println("Please specify the icon file name");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
String title = new File(pArgs[0]).getName();
|
||||||
|
JFrame frame = createWindow(title);
|
||||||
|
JPanel root = new JPanel(new FlowLayout());
|
||||||
|
JScrollPane scroll =
|
||||||
|
new JScrollPane(root, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||||
|
scroll.setBorder(BorderFactory.createEmptyBorder());
|
||||||
|
frame.setContentPane(scroll);
|
||||||
|
|
||||||
|
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("ico");
|
||||||
|
if (!readers.hasNext()) {
|
||||||
|
System.err.println("No reader for format 'ico' found");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageReader reader = readers.next();
|
||||||
|
|
||||||
|
for (String arg : pArgs) {
|
||||||
|
JPanel panel = new JPanel(null);
|
||||||
|
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
|
||||||
|
readImagesInFile(arg, reader, panel);
|
||||||
|
root.add(panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.pack();
|
||||||
|
frame.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void readImagesInFile(String pFileName, ImageReader pReader, final Container pContainer) throws IOException {
|
||||||
|
File file = new File(pFileName);
|
||||||
|
if (!file.isFile()) {
|
||||||
|
System.err.println(pFileName + " not found, or is no file");
|
||||||
|
}
|
||||||
|
|
||||||
|
pReader.setInput(ImageIO.createImageInputStream(file));
|
||||||
|
int imageCount = pReader.getNumImages(true);
|
||||||
|
for (int i = 0; i < imageCount; i++) {
|
||||||
|
try {
|
||||||
|
addImage(pContainer, pReader, i);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
System.err.println("FileName: " + pFileName);
|
||||||
|
System.err.println("Icon: " + i);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JFrame createWindow(final String pTitle) {
|
||||||
|
JFrame frame = new JFrame(pTitle);
|
||||||
|
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||||
|
frame.addWindowListener(new WindowAdapter() {
|
||||||
|
public void windowClosed(WindowEvent e) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addImage(final Container pParent, final ImageReader pReader, final int pImageNo) throws IOException {
|
||||||
|
final JButton button = new JButton();
|
||||||
|
BufferedImage image = pReader.read(pImageNo);
|
||||||
|
button.setIcon(new ImageIcon(image) {
|
||||||
|
TexturePaint mTexture;
|
||||||
|
|
||||||
|
private void createTexture(final GraphicsConfiguration pGraphicsConfiguration) {
|
||||||
|
BufferedImage pattern = pGraphicsConfiguration.createCompatibleImage(20, 20);
|
||||||
|
Graphics2D g = pattern.createGraphics();
|
||||||
|
try {
|
||||||
|
g.setColor(Color.LIGHT_GRAY);
|
||||||
|
g.fillRect(0, 0, pattern.getWidth(), pattern.getHeight());
|
||||||
|
g.setColor(Color.GRAY);
|
||||||
|
g.fillRect(0, 0, pattern.getWidth() / 2, pattern.getHeight() / 2);
|
||||||
|
g.fillRect(pattern.getWidth() / 2, pattern.getHeight() / 2, pattern.getWidth() / 2, pattern.getHeight() / 2);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
g.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
mTexture = new TexturePaint(pattern, new Rectangle(pattern.getWidth(), pattern.getHeight()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paintIcon(Component c, Graphics g, int x, int y) {
|
||||||
|
if (mTexture == null) {
|
||||||
|
createTexture(c.getGraphicsConfiguration());
|
||||||
|
}
|
||||||
|
Graphics2D gr = (Graphics2D) g;
|
||||||
|
gr.setPaint(mTexture);
|
||||||
|
gr.fillRect(x, y, getIconWidth(), getIconHeight());
|
||||||
|
super.paintIcon(c, g, x, y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
button.setText("" + image.getWidth() + "x" +
|
||||||
|
image.getHeight() + ": "
|
||||||
|
+ ((image.getColorModel() instanceof IndexColorModel) ?
|
||||||
|
"" + ((IndexColorModel) image.getColorModel()).getMapSize() :
|
||||||
|
"TrueColor"));
|
||||||
|
pParent.add(button);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 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.ico;
|
||||||
|
|
||||||
|
import javax.imageio.ImageReader;
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ICOImageReaderSpi
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: ICOImageReaderSpi.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||||
|
*/
|
||||||
|
public class ICOImageReaderSpi extends ImageReaderSpi {
|
||||||
|
|
||||||
|
public ICOImageReaderSpi() {
|
||||||
|
super(
|
||||||
|
"TwelveMonkeys",
|
||||||
|
"2.1",
|
||||||
|
new String[]{"ico", "ICO"},
|
||||||
|
new String[]{"ico"},
|
||||||
|
new String[]{
|
||||||
|
"image/vnd.microsoft.icon", // Official IANA MIME
|
||||||
|
"image/x-icon", // Common extension MIME
|
||||||
|
"image/ico" // Unofficial, but common
|
||||||
|
},
|
||||||
|
"com.twelvemonkeys.imageio.plugins.ico.ICOImageReader",
|
||||||
|
STANDARD_INPUT_TYPE,
|
||||||
|
null,
|
||||||
|
true, null, null, null, null,
|
||||||
|
true,
|
||||||
|
null, null,
|
||||||
|
null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canDecodeInput(final Object pSource) throws IOException {
|
||||||
|
return pSource instanceof ImageInputStream && canDecode((ImageInputStream) pSource, DIB.TYPE_ICO);
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean canDecode(final ImageInputStream pInput, final int pType) throws IOException {
|
||||||
|
byte[] signature = new byte[4];
|
||||||
|
|
||||||
|
try {
|
||||||
|
pInput.mark();
|
||||||
|
pInput.readFully(signature);
|
||||||
|
|
||||||
|
int count = pInput.readByte() + (pInput.readByte() << 8);
|
||||||
|
|
||||||
|
return (signature[0] == 0x0 && signature[1] == 0x0 && signature[2] == pType
|
||||||
|
&& signature[3] == 0x0 && count > 0);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
pInput.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageReader createReaderInstance(final Object pExtension) throws IOException {
|
||||||
|
return new ICOImageReader(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription(final Locale pLocale) {
|
||||||
|
return "Windows Icon Format (ICO) Reader";
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,2 @@
|
|||||||
|
com.twelvemonkeys.imageio.plugins.ico.ICOImageReaderSpi
|
||||||
|
com.twelvemonkeys.imageio.plugins.ico.CURImageReaderSpi
|
@@ -0,0 +1,103 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.ico;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTestCase;
|
||||||
|
|
||||||
|
import javax.imageio.ImageReadParam;
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CURImageReaderTestCase
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: CURImageReaderTestCase.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public class CURImageReaderTestCase extends ImageReaderAbstractTestCase<CURImageReader> {
|
||||||
|
protected List<TestData> getTestData() {
|
||||||
|
return Arrays.asList(
|
||||||
|
new TestData(getClassLoaderResource("/cur/hand.cur"), new Dimension(32, 32)),
|
||||||
|
new TestData(getClassLoaderResource("/cur/zoom.cur"), new Dimension(32, 32))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ImageReaderSpi createProvider() {
|
||||||
|
return new CURImageReaderSpi();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CURImageReader createReader() {
|
||||||
|
return new CURImageReader();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class<CURImageReader> getReaderClass() {
|
||||||
|
return CURImageReader.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getFormatNames() {
|
||||||
|
return Arrays.asList("cur");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getSuffixes() {
|
||||||
|
return Arrays.asList("cur");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getMIMETypes() {
|
||||||
|
return Arrays.asList("image/vnd.microsoft.cursor", "image/cursor", "image/x-cursor");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertHotSpot(final TestData pTestData, final ImageReadParam pParam, final Point pExpected) throws IOException {
|
||||||
|
CURImageReader reader = createReader();
|
||||||
|
reader.setInput(pTestData.getInputStream());
|
||||||
|
|
||||||
|
BufferedImage image = reader.read(0, pParam);
|
||||||
|
Object hotspot = image.getProperty("cursor_hotspot");
|
||||||
|
|
||||||
|
if (hotspot == Image.UndefinedProperty) {
|
||||||
|
hotspot = reader.getHotSpot(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Typically never happens, because of weirdness
|
||||||
|
assertNotNull("Hotspot for cursor not present", hotspot);
|
||||||
|
|
||||||
|
// Image weirdness
|
||||||
|
assertTrue("Hotspot for cursor undefined (java.awt.Image.UndefinedProperty)", Image.UndefinedProperty != hotspot);
|
||||||
|
|
||||||
|
assertTrue(String.format("Hotspot not a java.awt.Point: %s", hotspot.getClass()), hotspot instanceof Point);
|
||||||
|
assertEquals(pExpected, hotspot);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testHandHotspot() throws IOException {
|
||||||
|
assertHotSpot(getTestData().get(0), null, new Point(15, 15));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testZoomHotspot() throws IOException {
|
||||||
|
assertHotSpot(getTestData().get(1), null, new Point(13, 11));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testHandHotspotWithParam() throws IOException {
|
||||||
|
ImageReadParam param = new ImageReadParam();
|
||||||
|
assertHotSpot(getTestData().get(0), param, new Point(15, 15));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testHandHotspotExplicitDestination() throws IOException {
|
||||||
|
CURImageReader reader = createReader();
|
||||||
|
reader.setInput(getTestData().get(0).getInputStream());
|
||||||
|
BufferedImage image = reader.read(0);
|
||||||
|
|
||||||
|
// Create dest image with same data, except properties...
|
||||||
|
BufferedImage dest = new BufferedImage(
|
||||||
|
image.getColorModel(), image.getRaster(), image.getColorModel().isAlphaPremultiplied(), null
|
||||||
|
);
|
||||||
|
ImageReadParam param = new ImageReadParam();
|
||||||
|
param.setDestination(dest);
|
||||||
|
|
||||||
|
assertHotSpot(getTestData().get(0), param, new Point(15, 15));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Test cursor is transparent
|
||||||
|
}
|
@@ -0,0 +1,66 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.ico;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTestCase;
|
||||||
|
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ICOImageReaderTestCase
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: ICOImageReaderTestCase.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public class ICOImageReaderTestCase extends ImageReaderAbstractTestCase<ICOImageReader> {
|
||||||
|
protected List<TestData> getTestData() {
|
||||||
|
return Arrays.asList(
|
||||||
|
new TestData(
|
||||||
|
getClassLoaderResource("/ico/JavaCup.ico"),
|
||||||
|
new Dimension(48, 48), new Dimension(32, 32), new Dimension(16, 16),
|
||||||
|
new Dimension(48, 48), new Dimension(32, 32), new Dimension(16, 16),
|
||||||
|
new Dimension(48, 48), new Dimension(32, 32), new Dimension(16, 16)
|
||||||
|
),
|
||||||
|
new TestData(getClassLoaderResource("/ico/favicon.ico"), new Dimension(32, 32)),
|
||||||
|
new TestData(
|
||||||
|
getClassLoaderResource("/ico/joypad.ico"),
|
||||||
|
new Dimension(16, 16), new Dimension(24, 24), new Dimension(32, 32), new Dimension(48, 48),
|
||||||
|
new Dimension(16, 16), new Dimension(24, 24), new Dimension(32, 32), new Dimension(48, 48)
|
||||||
|
),
|
||||||
|
// Windows Vista icon, PNG encoded for 256x256 sizes
|
||||||
|
new TestData(
|
||||||
|
getClassLoaderResource("/ico/down.ico"),
|
||||||
|
new Dimension(16, 16), new Dimension(16, 16), new Dimension(32, 32), new Dimension(32, 32),
|
||||||
|
new Dimension(48, 48), new Dimension(48, 48), new Dimension(256, 256), new Dimension(256, 256),
|
||||||
|
new Dimension(16, 16), new Dimension(32, 32), new Dimension(48, 48), new Dimension(256, 256)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ImageReaderSpi createProvider() {
|
||||||
|
return new ICOImageReaderSpi();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ICOImageReader createReader() {
|
||||||
|
return new ICOImageReader();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class<ICOImageReader> getReaderClass() {
|
||||||
|
return ICOImageReader.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getFormatNames() {
|
||||||
|
return Arrays.asList("ico");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getSuffixes() {
|
||||||
|
return Arrays.asList("ico");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getMIMETypes() {
|
||||||
|
return Arrays.asList("image/vnd.microsoft.icon", "image/ico", "image/x-icon");
|
||||||
|
}
|
||||||
|
}
|
BIN
twelvemonkeys-imageio/ico/src/test/resources/cur/hand.cur
Executable file
After Width: | Height: | Size: 326 B |
BIN
twelvemonkeys-imageio/ico/src/test/resources/cur/zoom.cur
Executable file
After Width: | Height: | Size: 326 B |
BIN
twelvemonkeys-imageio/ico/src/test/resources/ico/JavaCup.ico
Executable file
After Width: | Height: | Size: 25 KiB |
BIN
twelvemonkeys-imageio/ico/src/test/resources/ico/colors.ico
Executable file
After Width: | Height: | Size: 113 KiB |
BIN
twelvemonkeys-imageio/ico/src/test/resources/ico/down.ico
Executable file
After Width: | Height: | Size: 149 KiB |
BIN
twelvemonkeys-imageio/ico/src/test/resources/ico/favicon.ico
Executable file
After Width: | Height: | Size: 766 B |
BIN
twelvemonkeys-imageio/ico/src/test/resources/ico/joypad.ico
Executable file
After Width: | Height: | Size: 26 KiB |
1
twelvemonkeys-imageio/ico/todo.txt
Executable file
@@ -0,0 +1 @@
|
|||||||
|
- Support all DIB formats?
|
25
twelvemonkeys-imageio/iff/license.txt
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
Copyright (c) 2009, 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.
|
32
twelvemonkeys-imageio/iff/pom.xml
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>twelvemonkeys-imageio-iff</artifactId>
|
||||||
|
<version>2.1</version>
|
||||||
|
<name>TwelveMonkeys ImageIO IFF plugin</name>
|
||||||
|
<description>
|
||||||
|
ImageIO plugin for Amiga/Electronic Arts Interchange Filed Format (IFF)
|
||||||
|
type ILBM and PBM format.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<artifactId>twelvemonkeys-imageio</artifactId>
|
||||||
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
|
<version>2.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>twelvemonkeys-imageio-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>twelvemonkeys-imageio-core</artifactId>
|
||||||
|
<classifier>tests</classifier>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* 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.iff;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BMHDChunk
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: BMHDChunk.java,v 1.0 28.feb.2006 00:04:32 haku Exp$
|
||||||
|
*/
|
||||||
|
class BMHDChunk extends IFFChunk {
|
||||||
|
//
|
||||||
|
// typedef UBYTE Masking; /* Choice of masking technique. */
|
||||||
|
//
|
||||||
|
// #define mskNone 0
|
||||||
|
// #define mskHasMask 1
|
||||||
|
// #define mskHasTransparentColor 2
|
||||||
|
// #define mskLasso 3
|
||||||
|
//
|
||||||
|
// typedef UBYTE Compression; /* Choice of compression algorithm
|
||||||
|
// applied to the rows of all source and mask planes. "cmpByteRun1"
|
||||||
|
// is the byte run encoding described in Appendix C. Do not compress
|
||||||
|
// across rows! */
|
||||||
|
// #define cmpNone 0
|
||||||
|
// #define cmpByteRun1 1
|
||||||
|
//
|
||||||
|
// typedef struct {
|
||||||
|
// UWORD w, h; /* raster width & height in pixels */
|
||||||
|
// WORD x, y; /* pixel position for this image */
|
||||||
|
// UBYTE nPlanes; /* # source bitplanes */
|
||||||
|
// Masking masking;
|
||||||
|
// Compression compression;
|
||||||
|
// UBYTE pad1; /* unused; ignore on read, write as 0 */
|
||||||
|
// UWORD transparentColor; /* transparent "color number" (sort of) */
|
||||||
|
// UBYTE xAspect, yAspect; /* pixel aspect, a ratio width : height */
|
||||||
|
// WORD pageWidth, pageHeight; /* source "page" size in pixels */
|
||||||
|
// } BitMapHeader;*/
|
||||||
|
|
||||||
|
static final int MASK_NONE = 0;
|
||||||
|
static final int MASK_HAS_MASK = 1;
|
||||||
|
static final int MASK_TRANSPARENT_COLOR = 2;
|
||||||
|
static final int MASK_LASSO = 3;
|
||||||
|
|
||||||
|
static final int COMPRESSION_NONE = 0;
|
||||||
|
// RLE
|
||||||
|
static final int COMPRESSION_BYTE_RUN = 1;
|
||||||
|
|
||||||
|
// NOTE: Each row of the image is stored in an integral number of 16 bit
|
||||||
|
// words. The number of words per row is words=((w+15)/16)
|
||||||
|
|
||||||
|
// Dimensions of raster
|
||||||
|
int mWidth;
|
||||||
|
int mHeight;
|
||||||
|
|
||||||
|
// Source offsets
|
||||||
|
// Hmm.. Consider making these Image.properties?
|
||||||
|
int mXPos;
|
||||||
|
int mYPos;
|
||||||
|
|
||||||
|
// The number of source bitplanes in the BODY chunk (see below) is stored in
|
||||||
|
// nPlanes. An ILBM with a CMAP but no BODY and nPlanes = 0 is the
|
||||||
|
// recommended way to store a color map.
|
||||||
|
int mBitplanes;
|
||||||
|
|
||||||
|
int mMaskType;
|
||||||
|
int mCompressionType;
|
||||||
|
|
||||||
|
int mTransparentIndex;
|
||||||
|
|
||||||
|
// NOTE: Typical values are 10:11 (320 x 200)
|
||||||
|
int mXAspect;
|
||||||
|
int mYAspect;
|
||||||
|
|
||||||
|
// Source page dimension
|
||||||
|
// NOTE: The image may be larger than the page, probably ignore these
|
||||||
|
int mPageWidth;
|
||||||
|
int mPageHeight;
|
||||||
|
|
||||||
|
protected BMHDChunk(int pChunkLength) {
|
||||||
|
super(IFF.CHUNK_BMHD, pChunkLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected BMHDChunk(int pWidth, int pHeight, int pBitplanes,
|
||||||
|
int pMaskType, int pCompressionType,
|
||||||
|
int pTransparentIndex) {
|
||||||
|
super(IFF.CHUNK_BMHD, 20);
|
||||||
|
mWidth = pWidth;
|
||||||
|
mHeight = pHeight;
|
||||||
|
mXPos = 0;
|
||||||
|
mYPos = 0;
|
||||||
|
mBitplanes = pBitplanes;
|
||||||
|
mMaskType = pMaskType;
|
||||||
|
mCompressionType = pCompressionType;
|
||||||
|
mTransparentIndex = pTransparentIndex;
|
||||||
|
mXAspect = 1;
|
||||||
|
mYAspect = 1;
|
||||||
|
mPageWidth = Math.min(pWidth, Short.MAX_VALUE); // For some reason, these are signed?
|
||||||
|
mPageHeight = Math.min(pHeight, Short.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void readChunk(DataInput pInput) throws IOException {
|
||||||
|
if (mChunkLength != 20) {
|
||||||
|
throw new IIOException("Unknown BMHD chunk length: " + mChunkLength);
|
||||||
|
}
|
||||||
|
mWidth = pInput.readUnsignedShort();
|
||||||
|
mHeight = pInput.readUnsignedShort();
|
||||||
|
mXPos = pInput.readShort();
|
||||||
|
mYPos = pInput.readShort();
|
||||||
|
mBitplanes = pInput.readUnsignedByte();
|
||||||
|
mMaskType = pInput.readUnsignedByte();
|
||||||
|
mCompressionType = pInput.readUnsignedByte();
|
||||||
|
pInput.readByte(); // PAD
|
||||||
|
mTransparentIndex = pInput.readUnsignedShort();
|
||||||
|
mXAspect = pInput.readUnsignedByte();
|
||||||
|
mYAspect = pInput.readUnsignedByte();
|
||||||
|
mPageWidth = pInput.readShort();
|
||||||
|
mPageHeight = pInput.readShort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeChunk(DataOutput pOutput) throws IOException {
|
||||||
|
pOutput.writeInt(mChunkId);
|
||||||
|
pOutput.writeInt(mChunkLength);
|
||||||
|
|
||||||
|
pOutput.writeShort(mWidth);
|
||||||
|
pOutput.writeShort(mHeight);
|
||||||
|
pOutput.writeShort(mXPos);
|
||||||
|
pOutput.writeShort(mYPos);
|
||||||
|
pOutput.writeByte(mBitplanes);
|
||||||
|
pOutput.writeByte(mMaskType);
|
||||||
|
pOutput.writeByte(mCompressionType);
|
||||||
|
pOutput.writeByte(0); // PAD
|
||||||
|
pOutput.writeShort(mTransparentIndex);
|
||||||
|
pOutput.writeByte(mXAspect);
|
||||||
|
pOutput.writeByte(mYAspect);
|
||||||
|
pOutput.writeShort(mPageWidth);
|
||||||
|
pOutput.writeShort(mPageHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return super.toString()
|
||||||
|
+ " {w=" + mWidth + ", h=" + mHeight
|
||||||
|
+ ", x=" + mXPos + ", y=" + mYPos
|
||||||
|
+ ", planes=" + mBitplanes + ", mask=" + mMaskType
|
||||||
|
+ ", compression=" + mCompressionType + ", trans=" + mTransparentIndex
|
||||||
|
+ ", xAspect=" + mXAspect + ", yAspect=" + mYAspect
|
||||||
|
+ ", pageWidth=" + mPageWidth + ", pageHeight=" + mPageHeight + "}";
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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.iff;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BODYChunk
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: BODYChunk.java,v 1.0 28.feb.2006 01:25:49 haku Exp$
|
||||||
|
*/
|
||||||
|
class BODYChunk extends IFFChunk {
|
||||||
|
|
||||||
|
protected BODYChunk(int pChunkLength) {
|
||||||
|
super(IFF.CHUNK_BODY, pChunkLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void readChunk(DataInput pInput) throws IOException {
|
||||||
|
throw new InternalError("BODY chunk should only be read from IFFImageReader");
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeChunk(DataOutput pOutput) throws IOException {
|
||||||
|
throw new InternalError("BODY chunk should only be written from IFFImageWriter");
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* 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.iff;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CAMGChunk
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: CAMGChunk.java,v 1.0 28.feb.2006 02:10:07 haku Exp$
|
||||||
|
*/
|
||||||
|
class CAMGChunk extends IFFChunk {
|
||||||
|
|
||||||
|
// #define CAMG_HAM 0x800 /* hold and modify */
|
||||||
|
// #define CAMG_EHB 0x80 /* extra halfbrite */
|
||||||
|
|
||||||
|
private int mCAMG;
|
||||||
|
|
||||||
|
public CAMGChunk(int pLength) {
|
||||||
|
super(IFF.CHUNK_CAMG, pLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void readChunk(DataInput pInput) throws IOException {
|
||||||
|
if (mChunkLength != 4) {
|
||||||
|
throw new IIOException("Unknown CAMG chunk length: " + mChunkLength);
|
||||||
|
}
|
||||||
|
mCAMG = pInput.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeChunk(DataOutput pOutput) throws IOException {
|
||||||
|
throw new InternalError("Not implemented: writeChunk()");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isHAM() {
|
||||||
|
return (mCAMG & 0x800) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isEHB() {
|
||||||
|
return (mCAMG & 0x80) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + " {mode=" + (isHAM() ? "HAM" : isEHB() ? "EHB" : "Normal") + "}";
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* 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.iff;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.image.InverseColorMapIndexColorModel;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.IndexColorModel;
|
||||||
|
import java.awt.image.WritableRaster;
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CMAPChunk
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: CMAPChunk.java,v 1.0 28.feb.2006 00:38:05 haku Exp$
|
||||||
|
*/
|
||||||
|
class CMAPChunk extends IFFChunk {
|
||||||
|
|
||||||
|
// typedef struct {
|
||||||
|
// UBYTE red, green, blue; /* color intensities 0..255 */
|
||||||
|
// } ColorRegister; /* size = 3 bytes */
|
||||||
|
//
|
||||||
|
// typedef ColorRegister ColorMap[n]; /* size = 3n bytes */
|
||||||
|
|
||||||
|
|
||||||
|
byte[] mReds;
|
||||||
|
byte[] mGreens;
|
||||||
|
byte[] mBlues;
|
||||||
|
|
||||||
|
boolean mEHB;
|
||||||
|
|
||||||
|
final private BMHDChunk mHeader;
|
||||||
|
final private CAMGChunk mCamg;
|
||||||
|
private IndexColorModel mModel;
|
||||||
|
|
||||||
|
protected CMAPChunk(int pChunkLength, BMHDChunk pHeader, CAMGChunk pCamg) {
|
||||||
|
super(IFF.CHUNK_CMAP, pChunkLength);
|
||||||
|
mHeader = pHeader;
|
||||||
|
mCamg = pCamg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CMAPChunk(IndexColorModel pModel) {
|
||||||
|
super(IFF.CHUNK_CMAP, pModel.getMapSize() * 3);
|
||||||
|
mModel = pModel;
|
||||||
|
mHeader = null;
|
||||||
|
mCamg = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void readChunk(DataInput pInput) throws IOException {
|
||||||
|
int numColors = mChunkLength / 3;
|
||||||
|
int paletteSize = numColors;
|
||||||
|
|
||||||
|
boolean isEHB = mCamg != null && mCamg.isEHB();
|
||||||
|
if (isEHB) {
|
||||||
|
if (numColors == 32) {
|
||||||
|
paletteSize = 64;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IIOException("Unknown number of colors for EHB: " + numColors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mReds = new byte[paletteSize];
|
||||||
|
mGreens = mReds.clone();
|
||||||
|
mBlues = mReds.clone();
|
||||||
|
|
||||||
|
for (int i = 0; i < numColors; i++) {
|
||||||
|
mReds[i] = pInput.readByte();
|
||||||
|
mGreens[i] = pInput.readByte();
|
||||||
|
mBlues[i] = pInput.readByte();
|
||||||
|
}
|
||||||
|
if (isEHB) {
|
||||||
|
for (int i = 0; i < numColors; i++) {
|
||||||
|
mReds[i + numColors] = (byte) ((mReds[i] & 0xff) / 2);
|
||||||
|
mGreens[i + numColors] = (byte) ((mGreens[i] & 0xff) / 2);
|
||||||
|
mBlues[i + numColors] = (byte) ((mBlues[i] & 0xff) / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: When reading in a CMAP for 8-bit-per-gun display or
|
||||||
|
// manipulation, you may want to assume that any CMAP which has 0 values
|
||||||
|
// for the low bits of all guns for all registers was stored shifted
|
||||||
|
// rather than scaled, and provide your own scaling.
|
||||||
|
// Use defaults if the color map is absent or has fewer color registers
|
||||||
|
// than you need. Ignore any extra color registers.
|
||||||
|
|
||||||
|
// R8 := (Rn x 255 ) / maxColor
|
||||||
|
|
||||||
|
// All chunks are WORD aligned (even sized), may need to read pad...
|
||||||
|
if (mChunkLength % 2 != 0) {
|
||||||
|
pInput.readByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Bitmask transparency
|
||||||
|
// Would it work to double to numbers of colors, and create an indexcolormodel,
|
||||||
|
// with alpha, where all colors above the original color is all transparent?
|
||||||
|
// This is a waste of time and space, of course...
|
||||||
|
int trans = mHeader.mMaskType == BMHDChunk.MASK_TRANSPARENT_COLOR ? mHeader.mTransparentIndex : -1;
|
||||||
|
mModel = new InverseColorMapIndexColorModel(mHeader.mBitplanes, mReds.length, mReds, mGreens, mBlues, trans);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeChunk(DataOutput pOutput) throws IOException {
|
||||||
|
pOutput.writeInt(mChunkId);
|
||||||
|
pOutput.writeInt(mChunkLength);
|
||||||
|
|
||||||
|
final int length = mModel.getMapSize();
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
pOutput.writeByte(mModel.getRed(i));
|
||||||
|
pOutput.writeByte(mModel.getGreen(i));
|
||||||
|
pOutput.writeByte(mModel.getBlue(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mChunkLength % 2 != 0) {
|
||||||
|
pOutput.writeByte(0); // PAD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + " {colorMap=" + mModel + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexColorModel getIndexColorModel() {
|
||||||
|
return mModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedImage createPaletteImage() {
|
||||||
|
// Create a 1 x colors.length image
|
||||||
|
IndexColorModel cm = getIndexColorModel();
|
||||||
|
WritableRaster raster = cm.createCompatibleWritableRaster(cm.getMapSize(), 1);
|
||||||
|
byte[] pixel = null;
|
||||||
|
for (int x = 0; x < cm.getMapSize(); x++) {
|
||||||
|
pixel = (byte[]) cm.getDataElements(cm.getRGB(x), pixel);
|
||||||
|
raster.setDataElements(x, 0, pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* 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.iff;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.geom.Point2D;
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GRABChunk
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: GRABChunk.java,v 1.0 28.feb.2006 01:55:05 haku Exp$
|
||||||
|
*/
|
||||||
|
class GRABChunk extends IFFChunk {
|
||||||
|
// typedef struct {
|
||||||
|
// WORD x, y; /* relative coordinates (pixels) */
|
||||||
|
// } Point2D;
|
||||||
|
|
||||||
|
Point2D mPoint;
|
||||||
|
|
||||||
|
protected GRABChunk(int pChunkLength) {
|
||||||
|
super(IFF.CHUNK_GRAB, pChunkLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected GRABChunk(Point2D pPoint) {
|
||||||
|
super(IFF.CHUNK_GRAB, 4);
|
||||||
|
mPoint = pPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
void readChunk(DataInput pInput) throws IOException {
|
||||||
|
if (mChunkLength != 4) {
|
||||||
|
throw new IIOException("Unknown GRAB chunk size: " + mChunkLength);
|
||||||
|
}
|
||||||
|
mPoint = new Point(pInput.readShort(), pInput.readShort());
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeChunk(DataOutput pOutput) throws IOException {
|
||||||
|
pOutput.writeShort((int) mPoint.getX());
|
||||||
|
pOutput.writeShort((int) mPoint.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + " {point=" + mPoint + "}";
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 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.iff;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UnknownChunk
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: UnknownChunk.java,v 1.0 28.feb.2006 00:53:47 haku Exp$
|
||||||
|
*/
|
||||||
|
class GenericChunk extends IFFChunk {
|
||||||
|
|
||||||
|
byte[] mData;
|
||||||
|
|
||||||
|
protected GenericChunk(int pChunkId, int pChunkLength) {
|
||||||
|
super(pChunkId, pChunkLength);
|
||||||
|
mData = new byte[pChunkLength <= 50 ? pChunkLength : 47];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected GenericChunk(int pChunkId, byte[] pChunkData) {
|
||||||
|
super(pChunkId, pChunkData.length);
|
||||||
|
mData = pChunkData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void readChunk(DataInput pInput) throws IOException {
|
||||||
|
pInput.readFully(mData, 0, mData.length);
|
||||||
|
|
||||||
|
int toSkip = mChunkLength - mData.length;
|
||||||
|
while (toSkip > 0) {
|
||||||
|
toSkip -= pInput.skipBytes(toSkip);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read pad
|
||||||
|
if (mChunkLength % 2 != 0) {
|
||||||
|
pInput.readByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeChunk(DataOutput pOutput) throws IOException {
|
||||||
|
pOutput.writeInt(mChunkId);
|
||||||
|
pOutput.writeInt(mChunkLength);
|
||||||
|
pOutput.write(mData, 0, mData.length);
|
||||||
|
|
||||||
|
if (mData.length % 2 != 0) {
|
||||||
|
pOutput.writeByte(0); // PAD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + " {value=\""
|
||||||
|
+ new String(mData, 0, mData.length <= 50 ? mData.length : 47)
|
||||||
|
+ (mChunkLength <= 50 ? "" : "...") + "\"}";
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* 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.iff;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IFF format constants.
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: IFF.java,v 1.0 07.mar.2006 15:31:48 haku Exp$
|
||||||
|
*/
|
||||||
|
interface IFF {
|
||||||
|
/** IFF FORM group chunk */
|
||||||
|
int CHUNK_FORM = ('F' << 24) + ('O' << 16) + ('R' << 8) + 'M';
|
||||||
|
|
||||||
|
/** IFF ILBM form type */
|
||||||
|
int TYPE_ILBM = ('I' << 24) + ('L' << 16) + ('B' << 8) + 'M';
|
||||||
|
|
||||||
|
/** IFF PBM form type */
|
||||||
|
int TYPE_PBM = ('P' << 24) + ('B' << 16) + ('M' << 8) + ' ';
|
||||||
|
|
||||||
|
/** Bitmap Header chunk */
|
||||||
|
int CHUNK_BMHD = ('B' << 24) + ('M' << 16) + ('H' << 8) + 'D';
|
||||||
|
|
||||||
|
/** Color map chunk */
|
||||||
|
int CHUNK_CMAP = ('C' << 24) + ('M' << 16) + ('A' << 8) + 'P';
|
||||||
|
|
||||||
|
/** Hotspot chunk (cursors, brushes) */
|
||||||
|
int CHUNK_GRAB = ('G' << 24) + ('R' << 16) + ('A' << 8) + 'B';
|
||||||
|
|
||||||
|
/** Destination merge data chunk */
|
||||||
|
int CHUNK_DEST = ('D' << 24) + ('E' << 16) + ('S' << 8) + 'T';
|
||||||
|
|
||||||
|
/** Sprite information chunk */
|
||||||
|
int CHUNK_SPRT = ('S' << 24) + ('P' << 16) + ('R' << 8) + 'T';
|
||||||
|
|
||||||
|
/** Commodore Amiga viewport mode chunk (used to determine HAM and EHB modes) */
|
||||||
|
int CHUNK_CAMG = ('C' << 24) + ('A' << 16) + ('M' << 8) + 'G';
|
||||||
|
|
||||||
|
/** Main data (body) chunk */
|
||||||
|
int CHUNK_BODY = ('B' << 24) + ('O' << 16) + ('D' << 8) + 'Y';
|
||||||
|
}
|
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* 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.iff;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IFFChunk
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: IFFChunk.java,v 1.0 28.feb.2006 00:00:45 haku Exp$
|
||||||
|
*/
|
||||||
|
abstract class IFFChunk {
|
||||||
|
int mChunkId;
|
||||||
|
int mChunkLength;
|
||||||
|
|
||||||
|
protected IFFChunk(int pChunkId, int pChunkLength) {
|
||||||
|
mChunkId = pChunkId;
|
||||||
|
mChunkLength = pChunkLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract void readChunk(DataInput pInput) throws IOException;
|
||||||
|
|
||||||
|
abstract void writeChunk(DataOutput pOutput) throws IOException;
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return IFFUtil.toChunkStr(mChunkId) + " chunk (" + mChunkLength + " bytes)";
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,693 @@
|
|||||||
|
/*
|
||||||
|
* 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.iff;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||||
|
import com.twelvemonkeys.imageio.stream.BufferedImageInputStream;
|
||||||
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
|
import com.twelvemonkeys.imageio.util.IndexedImageTypeSpecifier;
|
||||||
|
import com.twelvemonkeys.io.enc.DecoderStream;
|
||||||
|
import com.twelvemonkeys.io.enc.PackBitsDecoder;
|
||||||
|
|
||||||
|
import javax.imageio.*;
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.color.ColorSpace;
|
||||||
|
import java.awt.image.*;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reader for Amiga (Electronic Arts) IFF ILBM (InterLeaved BitMap) and PBM
|
||||||
|
* format (Packed BitMap).
|
||||||
|
* The IFF format (Interchange File Format) is the standard file format
|
||||||
|
* supported by allmost all image software for the Amiga computer.
|
||||||
|
* <p/>
|
||||||
|
* This reader supports the original palette-based 1-8 bit formats, including
|
||||||
|
* EHB (Extra Halfbright), HAM (Hold and Modify), and the more recent "deep"
|
||||||
|
* formats, 8 bit gray, 24 bit RGB and 32 bit ARGB.
|
||||||
|
* Uncompressed and ByteRun1 compressed (run lenght encoding) files are
|
||||||
|
* supported.
|
||||||
|
* <p/>
|
||||||
|
* Palette based images are read as {@code BufferedImage} of
|
||||||
|
* {@link BufferedImage#TYPE_BYTE_INDEXED TYPE_BYTE_INDEXED} or
|
||||||
|
* {@link BufferedImage#TYPE_BYTE_BINARY BufferedImage#}
|
||||||
|
* depending on the bit depth.
|
||||||
|
* Gray images are read as
|
||||||
|
* {@link BufferedImage#TYPE_BYTE_GRAY TYPE_BYTE_GRAY}.
|
||||||
|
* 24 bit true-color images are read as
|
||||||
|
* {@link BufferedImage#TYPE_3BYTE_BGR TYPE_3BYTE_BGR}.
|
||||||
|
* 32 bit true-color images are read as
|
||||||
|
* {@link BufferedImage#TYPE_4BYTE_ABGR TYPE_4BYTE_ABGR}.
|
||||||
|
* <p/>
|
||||||
|
* Issues: HAM and HAM8 (Hold and Modify) formats are converted to RGB (24 bit),
|
||||||
|
* as it seems to be very hard to create an {@code IndexColorModel} subclass
|
||||||
|
* that would correctly describe these formats.
|
||||||
|
* These formats utilizes the special display hardware in the Amiga computers.
|
||||||
|
* HAM (6 bits) needs 12 bits storage/pixel, if unpacked to RGB (4 bits/gun).
|
||||||
|
* HAM8 (8 bits) needs 18 bits storage/pixel, if unpacked to RGB (6 bits/gun).
|
||||||
|
* See <a href="http://en.wikipedia.org/wiki/Hold_And_Modify">Wikipedia: HAM</a>
|
||||||
|
* for more information.
|
||||||
|
* <br/>
|
||||||
|
* EHB palette is expanded to an {@link IndexColorModel} with 64 entries.
|
||||||
|
* See <a href="http://en.wikipedia.org/wiki/Extra_Half-Brite">Wikipedia: EHB</a>
|
||||||
|
* for more information.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haku $
|
||||||
|
* @version $Id: IFFImageReader.java,v 1.0 29.aug.2004 20:26:58 haku Exp $
|
||||||
|
* @see <a href="http://en.wikipedia.org/wiki/Interchange_File_Format">Wikipedia: IFF</a>
|
||||||
|
* @see <a href="http://en.wikipedia.org/wiki/ILBM">Wikipedia: IFF ILBM</a>
|
||||||
|
*/
|
||||||
|
public class IFFImageReader extends ImageReaderBase {
|
||||||
|
|
||||||
|
private BMHDChunk mHeader;
|
||||||
|
private CMAPChunk mColorMap;
|
||||||
|
private BODYChunk mBody;
|
||||||
|
private GRABChunk mGrab;
|
||||||
|
private CAMGChunk mViewPort;
|
||||||
|
private int mFormType;
|
||||||
|
private long mBodyStart;
|
||||||
|
|
||||||
|
private BufferedImage mImage;
|
||||||
|
private DataInputStream mByteRunStream;
|
||||||
|
|
||||||
|
public IFFImageReader() {
|
||||||
|
super(IFFImageReaderSpi.sharedProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IFFImageReader(ImageReaderSpi pProvider) {
|
||||||
|
super(pProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init(int pIndex) throws IOException {
|
||||||
|
checkBounds(pIndex);
|
||||||
|
|
||||||
|
if (mHeader == null) {
|
||||||
|
readMeta();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void resetMembers() {
|
||||||
|
mHeader = null;
|
||||||
|
mColorMap = null;
|
||||||
|
mBody = null;
|
||||||
|
mViewPort = null;
|
||||||
|
mFormType = 0;
|
||||||
|
|
||||||
|
mImage = null;
|
||||||
|
mByteRunStream = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readMeta() throws IOException {
|
||||||
|
if (mImageInput.readInt() != IFF.CHUNK_FORM) {
|
||||||
|
throw new IIOException("Unknown file format for IFFImageReader");
|
||||||
|
}
|
||||||
|
|
||||||
|
int remaining = mImageInput.readInt() - 4; // We'll read 4 more in a sec
|
||||||
|
|
||||||
|
mFormType = mImageInput.readInt();
|
||||||
|
if (mFormType != IFF.TYPE_ILBM && mFormType != IFF.TYPE_PBM) {
|
||||||
|
throw new IIOException("Only IFF (FORM) type ILBM and PBM supported: " + IFFUtil.toChunkStr(mFormType));
|
||||||
|
}
|
||||||
|
|
||||||
|
//System.out.println("IFF type FORM " + toChunkStr(type));
|
||||||
|
|
||||||
|
mGrab = null;
|
||||||
|
mViewPort = null;
|
||||||
|
|
||||||
|
while (remaining > 0) {
|
||||||
|
int chunkId = mImageInput.readInt();
|
||||||
|
int length = mImageInput.readInt();
|
||||||
|
|
||||||
|
remaining -= 8;
|
||||||
|
remaining -= length % 2 == 0 ? length : length + 1;
|
||||||
|
|
||||||
|
//System.out.println("Next chunk: " + toChunkStr(chunkId) + " lenght: " + length);
|
||||||
|
//System.out.println("Remaining bytes after chunk: " + remaining);
|
||||||
|
|
||||||
|
switch (chunkId) {
|
||||||
|
case IFF.CHUNK_BMHD:
|
||||||
|
if (mHeader != null) {
|
||||||
|
throw new IIOException("Multiple BMHD chunks not allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
mHeader = new BMHDChunk(length);
|
||||||
|
mHeader.readChunk(mImageInput);
|
||||||
|
|
||||||
|
//System.out.println(mHeader);
|
||||||
|
break;
|
||||||
|
case IFF.CHUNK_CMAP:
|
||||||
|
if (mColorMap != null) {
|
||||||
|
throw new IIOException("Multiple CMAP chunks not allowed");
|
||||||
|
}
|
||||||
|
mColorMap = new CMAPChunk(length, mHeader, mViewPort);
|
||||||
|
mColorMap.readChunk(mImageInput);
|
||||||
|
|
||||||
|
//System.out.println(mColorMap);
|
||||||
|
break;
|
||||||
|
case IFF.CHUNK_GRAB:
|
||||||
|
if (mGrab != null) {
|
||||||
|
throw new IIOException("Multiple GRAB chunks not allowed");
|
||||||
|
}
|
||||||
|
mGrab = new GRABChunk(length);
|
||||||
|
mGrab.readChunk(mImageInput);
|
||||||
|
|
||||||
|
//System.out.println(mGrab);
|
||||||
|
break;
|
||||||
|
case IFF.CHUNK_CAMG:
|
||||||
|
if (mViewPort != null) {
|
||||||
|
throw new IIOException("Multiple CAMG chunks not allowed");
|
||||||
|
}
|
||||||
|
mViewPort = new CAMGChunk(length);
|
||||||
|
mViewPort.readChunk(mImageInput);
|
||||||
|
|
||||||
|
//System.out.println(mViewPort);
|
||||||
|
break;
|
||||||
|
case IFF.CHUNK_BODY:
|
||||||
|
if (mBody != null) {
|
||||||
|
throw new IIOException("Multiple BODY chunks not allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
mBody = new BODYChunk(length);
|
||||||
|
mBodyStart = mImageInput.getStreamPosition();
|
||||||
|
|
||||||
|
// NOTE: We don't read the body here, it's done later in the
|
||||||
|
// read(int, ImageReadParam) method
|
||||||
|
|
||||||
|
// Done reading meta
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
// TODO: We probably want to store anno chunks as Metadata
|
||||||
|
// ANNO, DEST, SPRT and more
|
||||||
|
IFFChunk generic = new GenericChunk(chunkId, length);
|
||||||
|
generic.readChunk(mImageInput);
|
||||||
|
|
||||||
|
//System.out.println(generic);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedImage read(int pIndex, ImageReadParam pParam) throws IOException {
|
||||||
|
init(pIndex);
|
||||||
|
|
||||||
|
processImageStarted(pIndex);
|
||||||
|
|
||||||
|
mImage = getDestination(pParam, getImageTypes(pIndex), mHeader.mWidth, mHeader.mHeight);
|
||||||
|
//System.out.println(mBody);
|
||||||
|
if (mBody != null) {
|
||||||
|
//System.out.println("Read body");
|
||||||
|
readBody(pParam);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// In the rare case of an ILBM containing nothing but a CMAP
|
||||||
|
//System.out.println(mColorMap);
|
||||||
|
if (mColorMap != null) {
|
||||||
|
//System.out.println("Creating palette!");
|
||||||
|
mImage = mColorMap.createPaletteImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferedImage result = mImage;
|
||||||
|
|
||||||
|
processImageComplete();
|
||||||
|
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWidth(int pIndex) throws IOException {
|
||||||
|
init(pIndex);
|
||||||
|
return mHeader.mWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight(int pIndex) throws IOException {
|
||||||
|
init(pIndex);
|
||||||
|
return mHeader.mHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<ImageTypeSpecifier> getImageTypes(int pIndex) throws IOException {
|
||||||
|
init(pIndex);
|
||||||
|
|
||||||
|
List<ImageTypeSpecifier> types = Arrays.asList(
|
||||||
|
getRawImageType(pIndex),
|
||||||
|
ImageTypeSpecifier.createFromBufferedImageType(mHeader.mBitplanes == 32 ? BufferedImage.TYPE_4BYTE_ABGR : BufferedImage.TYPE_3BYTE_BGR)
|
||||||
|
// TODO: ImageTypeSpecifier.createFromBufferedImageType(mHeader.mBitplanes == 32 ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB),
|
||||||
|
// TODO: Allow 32 bit always. Allow RGB and discard alpha, if present?
|
||||||
|
);
|
||||||
|
return types.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImageTypeSpecifier getRawImageType(int pIndex) throws IOException {
|
||||||
|
init(pIndex);
|
||||||
|
// TODO: Stay DRY...
|
||||||
|
// TODO: Use this for creating the Image/Buffer in the read code below...
|
||||||
|
// NOTE: mColorMap may be null for 8 bit (gray), 24 bit or 32 bit only
|
||||||
|
ImageTypeSpecifier specifier;
|
||||||
|
switch (mHeader.mBitplanes) {
|
||||||
|
case 1:
|
||||||
|
// 1 bit
|
||||||
|
case 2:
|
||||||
|
// 2 bit
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
// 4 bit
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
// May be HAM6
|
||||||
|
// May be EHB
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
// 8 bit
|
||||||
|
// May be HAM8
|
||||||
|
if (!isHAM()) {
|
||||||
|
IndexColorModel cm = mColorMap.getIndexColorModel();
|
||||||
|
if (cm != null) {
|
||||||
|
specifier = IndexedImageTypeSpecifier.createFromIndexColorModel(cm);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
specifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 24:
|
||||||
|
// 24 bit RGB
|
||||||
|
specifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR);
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
// 32 bit ARGB
|
||||||
|
specifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IIOException("Bit depth not implemented: " + mHeader.mBitplanes);
|
||||||
|
}
|
||||||
|
return specifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readBody(ImageReadParam pParam) throws IOException {
|
||||||
|
mImageInput.seek(mBodyStart); // 8 for the header before length in stream
|
||||||
|
mByteRunStream = null;
|
||||||
|
|
||||||
|
// NOTE: mColorMap may be null for 8 bit (gray), 24 bit or 32 bit only
|
||||||
|
if (mColorMap != null) {
|
||||||
|
IndexColorModel cm = mColorMap.getIndexColorModel();
|
||||||
|
readIndexed(pParam, mImageInput, cm);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
readTrueColor(pParam, mImageInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readIndexed(ImageReadParam pParam, final ImageInputStream pInput, final IndexColorModel pModel) throws IOException {
|
||||||
|
final int width = mHeader.mWidth;
|
||||||
|
final int height = mHeader.mHeight;
|
||||||
|
|
||||||
|
final Rectangle aoi = getSourceRegion(pParam, width, height);
|
||||||
|
final Point offset = pParam == null ? new Point(0, 0) : pParam.getDestinationOffset();
|
||||||
|
|
||||||
|
// Set everything to default values
|
||||||
|
int sourceXSubsampling = 1;
|
||||||
|
int sourceYSubsampling = 1;
|
||||||
|
int[] sourceBands = null;
|
||||||
|
int[] destinationBands = null;
|
||||||
|
|
||||||
|
// Get values from the ImageReadParam, if any
|
||||||
|
if (pParam != null) {
|
||||||
|
sourceXSubsampling = pParam.getSourceXSubsampling();
|
||||||
|
sourceYSubsampling = pParam.getSourceYSubsampling();
|
||||||
|
|
||||||
|
sourceBands = pParam.getSourceBands();
|
||||||
|
destinationBands = pParam.getDestinationBands();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure band settings from param are compatible with images
|
||||||
|
checkReadParamBandSettings(pParam, isHAM() ? 3 : 1, mImage.getSampleModel().getNumBands());
|
||||||
|
|
||||||
|
WritableRaster destination = mImage.getRaster();
|
||||||
|
if (destinationBands != null || offset.x != 0 || offset.y != 0) {
|
||||||
|
destination = destination.createWritableChild(0, 0, destination.getWidth(), destination.getHeight(), offset.x, offset.y, destinationBands);
|
||||||
|
}
|
||||||
|
|
||||||
|
int planeWidth = (width + 7) / 8;
|
||||||
|
final byte[] planeData = new byte[8 * planeWidth];
|
||||||
|
|
||||||
|
ColorModel cm;
|
||||||
|
WritableRaster raster;
|
||||||
|
|
||||||
|
if (isHAM()) {
|
||||||
|
// TODO: If HAM6, use type USHORT_444_RGB or 2BYTE_444_RGB?
|
||||||
|
// Or create a HAMColorModel, if at all possible?
|
||||||
|
// TYPE_3BYTE_BGR
|
||||||
|
cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[]{8, 8, 8},
|
||||||
|
false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
|
||||||
|
// Create a byte raster with BGR order
|
||||||
|
raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, 1, width * 3, 3, new int[]{2, 1, 0}, null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED
|
||||||
|
cm = pModel;
|
||||||
|
raster = pModel.createCompatibleWritableRaster(width, 1);
|
||||||
|
}
|
||||||
|
Raster sourceRow = raster.createChild(aoi.x, 0, aoi.width, 1, 0, 0, sourceBands);
|
||||||
|
|
||||||
|
final byte[] row = new byte[width * 8];
|
||||||
|
|
||||||
|
//System.out.println("Data length: " + data.length);
|
||||||
|
//System.out.println("PlaneData length: " + planeData.length * planeData[0].length);
|
||||||
|
//System.out.println("Row length: " + row.length);
|
||||||
|
|
||||||
|
final byte[] data = ((DataBufferByte) raster.getDataBuffer()).getData();
|
||||||
|
|
||||||
|
final int planes = mHeader.mBitplanes;
|
||||||
|
|
||||||
|
Object dataElements = null;
|
||||||
|
Object outDataElements = null;
|
||||||
|
ColorConvertOp converter = null;
|
||||||
|
|
||||||
|
for (int srcY = 0; srcY < height; srcY++) {
|
||||||
|
|
||||||
|
for (int p = 0; p < planes; p++) {
|
||||||
|
try {
|
||||||
|
readPlaneData(pInput, planeData, p * planeWidth, planeWidth);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
// TODO: Add warning? Probbably a bug somewhere, should not catch!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip rows outside AOI
|
||||||
|
if (srcY < aoi.y || (srcY - aoi.y) % sourceYSubsampling != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (srcY >= (aoi.y + aoi.height)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mFormType == IFF.TYPE_ILBM) {
|
||||||
|
int pixelPos = 0;
|
||||||
|
int planePos = 0;
|
||||||
|
for (int i = 0; i < planeWidth; i++) {
|
||||||
|
IFFUtil.bitRotateCW(planeData, planePos, planeWidth, row, pixelPos, 1);
|
||||||
|
pixelPos += 8;
|
||||||
|
planePos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isHAM()) {
|
||||||
|
hamToRGB(row, pModel, data, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
raster.setDataElements(0, 0, width, 1, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /*if (mType == IFFImageReader.TYPE_PBM)*/ {
|
||||||
|
// TODO: Arraycopy might not be neccessary, if it's okay with row larger than width
|
||||||
|
System.arraycopy(planeData, 0, row, 0, mHeader.mBitplanes * planeWidth);
|
||||||
|
raster.setDataElements(0, 0, width, 1, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dstY = (srcY - aoi.y) / sourceYSubsampling;
|
||||||
|
// Handle non-converting raster as special case for performance
|
||||||
|
if (cm.isCompatibleRaster(destination)) {
|
||||||
|
// Rasters are compatible, just write to destinaiton
|
||||||
|
if (sourceXSubsampling == 1) {
|
||||||
|
destination.setRect(offset.x, dstY, sourceRow);
|
||||||
|
// dataElements = raster.getDataElements(aoi.x, 0, aoi.width, 1, dataElements);
|
||||||
|
// destination.setDataElements(offset.x, offset.y + (srcY - aoi.y) / sourceYSubsampling, aoi.width, 1, dataElements);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int srcX = 0; srcX < sourceRow.getWidth(); srcX += sourceXSubsampling) {
|
||||||
|
dataElements = sourceRow.getDataElements(srcX, 0, dataElements);
|
||||||
|
int dstX = /*offset.x +*/ srcX / sourceXSubsampling;
|
||||||
|
destination.setDataElements(dstX, dstY, dataElements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (cm instanceof IndexColorModel) {
|
||||||
|
// TODO: Optimize this thing... Maybe it's faster to just get the data indexed, and use drawImage?
|
||||||
|
IndexColorModel icm = (IndexColorModel) cm;
|
||||||
|
|
||||||
|
for (int srcX = 0; srcX < sourceRow.getWidth(); srcX += sourceXSubsampling) {
|
||||||
|
dataElements = sourceRow.getDataElements(srcX, 0, dataElements);
|
||||||
|
int rgb = icm.getRGB(dataElements);
|
||||||
|
outDataElements = mImage.getColorModel().getDataElements(rgb, outDataElements);
|
||||||
|
int dstX = srcX / sourceXSubsampling;
|
||||||
|
destination.setDataElements(dstX, dstY, outDataElements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// TODO: This branch is never tested, and is probably "dead"
|
||||||
|
// ColorConvertOp
|
||||||
|
if (converter == null) {
|
||||||
|
converter = new ColorConvertOp(cm.getColorSpace(), mImage.getColorModel().getColorSpace(), null);
|
||||||
|
}
|
||||||
|
converter.filter(
|
||||||
|
raster.createChild(aoi.x, 0, aoi.width, 1, 0, 0, null),
|
||||||
|
destination.createWritableChild(offset.x, offset.y + srcY - aoi.y, aoi.width, 1, 0, 0, null)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processImageProgress(srcY * 100f / mHeader.mWidth);
|
||||||
|
if (abortRequested()) {
|
||||||
|
processReadAborted();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// One row from each of the 24 bitplanes is written before moving to the
|
||||||
|
// next scanline. For each scanline, the red bitplane rows are stored first,
|
||||||
|
// followed by green and blue. The first plane holds the least significant
|
||||||
|
// bit of the red value for each pixel, and the last holds the most
|
||||||
|
// significant bit of the blue value.
|
||||||
|
private void readTrueColor(ImageReadParam pParam, final ImageInputStream pInput) throws IOException {
|
||||||
|
final int width = mHeader.mWidth;
|
||||||
|
final int height = mHeader.mHeight;
|
||||||
|
|
||||||
|
final Rectangle aoi = getSourceRegion(pParam, width, height);
|
||||||
|
final Point offset = pParam == null ? new Point(0, 0) : pParam.getDestinationOffset();
|
||||||
|
|
||||||
|
// Set everything to default values
|
||||||
|
int sourceXSubsampling = 1;
|
||||||
|
int sourceYSubsampling = 1;
|
||||||
|
int[] sourceBands = null;
|
||||||
|
int[] destinationBands = null;
|
||||||
|
|
||||||
|
// Get values from the ImageReadParam, if any
|
||||||
|
if (pParam != null) {
|
||||||
|
sourceXSubsampling = pParam.getSourceXSubsampling();
|
||||||
|
sourceYSubsampling = pParam.getSourceYSubsampling();
|
||||||
|
|
||||||
|
sourceBands = pParam.getSourceBands();
|
||||||
|
destinationBands = pParam.getDestinationBands();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure band settings from param are compatible with images
|
||||||
|
checkReadParamBandSettings(pParam, mHeader.mBitplanes / 8, mImage.getSampleModel().getNumBands());
|
||||||
|
|
||||||
|
int planeWidth = (width + 7) / 8;
|
||||||
|
|
||||||
|
final byte[] planeData = new byte[8 * planeWidth];
|
||||||
|
|
||||||
|
WritableRaster destination = mImage.getRaster();
|
||||||
|
if (destinationBands != null || offset.x != 0 || offset.y != 0) {
|
||||||
|
destination = destination.createWritableChild(0, 0, destination.getWidth(), destination.getHeight(), offset.x, offset.y, destinationBands);
|
||||||
|
}
|
||||||
|
WritableRaster raster = mImage.getRaster().createCompatibleWritableRaster(width, 1);
|
||||||
|
Raster sourceRow = raster.createChild(aoi.x, 0, aoi.width, 1, 0, 0, sourceBands);
|
||||||
|
|
||||||
|
final byte[] data = ((DataBufferByte) raster.getDataBuffer()).getData();
|
||||||
|
final int channels = (mHeader.mBitplanes + 7) / 8;
|
||||||
|
final int planesPerChannel = 8;
|
||||||
|
Object dataElements = null;
|
||||||
|
|
||||||
|
for (int srcY = 0; srcY < height; srcY++) {
|
||||||
|
for (int c = 0; c < channels; c++) {
|
||||||
|
|
||||||
|
for (int p = 0; p < planesPerChannel; p++) {
|
||||||
|
readPlaneData(pInput, planeData, p * planeWidth, planeWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip rows outside AOI
|
||||||
|
if (srcY < aoi.y || (srcY - aoi.y) % sourceYSubsampling != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (srcY >= (aoi.y + aoi.height)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mFormType == IFF.TYPE_ILBM) {
|
||||||
|
// NOTE: Using (channels - c - 1) instead of just c,
|
||||||
|
// effectively reverses the channel order from RGBA to ABGR
|
||||||
|
int off = (channels - c - 1);
|
||||||
|
|
||||||
|
int pixelPos = 0;
|
||||||
|
int planePos = 0;
|
||||||
|
for (int i = 0; i < planeWidth; i++) {
|
||||||
|
IFFUtil.bitRotateCW(planeData, planePos, planeWidth, data, off + pixelPos * channels, channels);
|
||||||
|
pixelPos += 8;
|
||||||
|
planePos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /*if (mType == IFFImageReader.TYPE_PBM)*/ {
|
||||||
|
System.arraycopy(planeData, 0, data, srcY * 8 * planeWidth, planeWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int dstY = (srcY - aoi.y) / sourceYSubsampling;
|
||||||
|
// TODO: Support conversion to INT (A)RGB rasters (maybe using ColorConvertOp?)
|
||||||
|
// TODO: Avoid createChild if no region?
|
||||||
|
if (sourceXSubsampling == 1) {
|
||||||
|
destination.setRect(0, dstY, sourceRow);
|
||||||
|
// dataElements = raster.getDataElements(aoi.x, 0, aoi.width, 1, dataElements);
|
||||||
|
// destination.setDataElements(offset.x, offset.y + (srcY - aoi.y) / sourceYSubsampling, aoi.width, 1, dataElements);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int srcX = 0; srcX < sourceRow.getWidth(); srcX += sourceXSubsampling) {
|
||||||
|
dataElements = sourceRow.getDataElements(srcX, 0, dataElements);
|
||||||
|
int dstX = srcX / sourceXSubsampling;
|
||||||
|
destination.setDataElements(dstX, dstY, dataElements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processImageProgress(srcY * 100f / mHeader.mWidth);
|
||||||
|
if (abortRequested()) {
|
||||||
|
processReadAborted();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readPlaneData(final ImageInputStream pInput, final byte[] pData, final int pOffset, final int pPlaneWidth)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
switch (mHeader.mCompressionType) {
|
||||||
|
case BMHDChunk.COMPRESSION_NONE:
|
||||||
|
pInput.readFully(pData, pOffset, pPlaneWidth);
|
||||||
|
// Uncompressed rows must have even number of bytes
|
||||||
|
if ((mHeader.mBitplanes * pPlaneWidth) % 2 != 0) {
|
||||||
|
pInput.readByte();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMHDChunk.COMPRESSION_BYTE_RUN:
|
||||||
|
if (mByteRunStream == null) {
|
||||||
|
mByteRunStream = new DataInputStream(new DecoderStream(
|
||||||
|
IIOUtil.createStreamAdapter(pInput, mBody.mChunkLength),
|
||||||
|
new PackBitsDecoder(true)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
mByteRunStream.readFully(pData, pOffset, pPlaneWidth);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IIOException("Unknown compression type: " + mHeader.mCompressionType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hamToRGB(final byte[] pIndexed, final IndexColorModel pModel,
|
||||||
|
final byte[] pDest, final int pDestOffset) {
|
||||||
|
final int bits = mHeader.mBitplanes;
|
||||||
|
final int width = mHeader.mWidth;
|
||||||
|
int lastRed = 0;
|
||||||
|
int lastGreen = 0;
|
||||||
|
int lastBlue = 0;
|
||||||
|
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
int pixel = pIndexed[x] & 0xff;
|
||||||
|
|
||||||
|
//System.out.println("--> ham" + bits);
|
||||||
|
int paletteIndex = bits == 6 ? pixel & 0x0f : pixel & 0x3f;
|
||||||
|
int indexShift = bits == 6 ? 4 : 2;
|
||||||
|
int colorMask = bits == 6 ? 0x0f : 0x03;
|
||||||
|
//System.out.println("palette index=" + paletteIndex);
|
||||||
|
|
||||||
|
// Get Hold and Modify bits
|
||||||
|
switch ((pixel >> (8 - indexShift)) & 0x03) {
|
||||||
|
case 0x00:// HOLD
|
||||||
|
lastRed = pModel.getRed(paletteIndex);
|
||||||
|
lastGreen = pModel.getGreen(paletteIndex);
|
||||||
|
lastBlue = pModel.getBlue(paletteIndex);
|
||||||
|
break;
|
||||||
|
case 0x01:// MODIFY BLUE
|
||||||
|
lastBlue = (lastBlue & colorMask) | (paletteIndex << indexShift);
|
||||||
|
break;
|
||||||
|
case 0x02:// MODIFY RED
|
||||||
|
lastRed = (lastRed & colorMask) | (paletteIndex << indexShift);
|
||||||
|
break;
|
||||||
|
case 0x03:// MODIFY GREEN
|
||||||
|
lastGreen = (lastGreen & colorMask) | (paletteIndex << indexShift);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int offset = (x * 3) + pDestOffset;
|
||||||
|
pDest[2 + offset] = (byte) lastRed;
|
||||||
|
pDest[1 + offset] = (byte) lastGreen;
|
||||||
|
pDest[offset] = (byte) lastBlue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isHAM() {
|
||||||
|
return mViewPort != null && mViewPort.isHAM();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] pArgs) throws IOException {
|
||||||
|
ImageReader reader = new IFFImageReader(new IFFImageReaderSpi());
|
||||||
|
|
||||||
|
// ImageInputStream input = ImageIO.createImageInputStream(new File(pArgs[0]));
|
||||||
|
ImageInputStream input = new BufferedImageInputStream(ImageIO.createImageInputStream(new File(pArgs[0])));
|
||||||
|
boolean canRead = reader.getOriginatingProvider().canDecodeInput(input);
|
||||||
|
|
||||||
|
System.out.println("Can read: " + canRead);
|
||||||
|
|
||||||
|
if (canRead) {
|
||||||
|
reader.setInput(input);
|
||||||
|
ImageReadParam param = reader.getDefaultReadParam();
|
||||||
|
// param.setSourceRegion(new Rectangle(0, 0, 160, 200));
|
||||||
|
// param.setSourceRegion(new Rectangle(160, 200, 160, 200));
|
||||||
|
// param.setSourceRegion(new Rectangle(80, 100, 160, 200));
|
||||||
|
// param.setDestinationOffset(new Point(80, 100));
|
||||||
|
// param.setSourceSubsampling(3, 3, 0, 0);
|
||||||
|
// param.setSourceBands(new int[]{0, 1, 2});
|
||||||
|
// param.setDestinationBands(new int[]{1, 0, 2});
|
||||||
|
BufferedImage image = reader.read(0, param);
|
||||||
|
System.out.println("image = " + image);
|
||||||
|
|
||||||
|
showIt(image, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* 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.iff;
|
||||||
|
|
||||||
|
import javax.imageio.ImageReader;
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IFFImageReaderSpi
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: IFFImageWriterSpi.java,v 1.0 28.feb.2006 19:21:05 haku Exp$
|
||||||
|
*/
|
||||||
|
public class IFFImageReaderSpi extends ImageReaderSpi {
|
||||||
|
|
||||||
|
static IFFImageReaderSpi mSharedInstance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an IFFImageReaderSpi
|
||||||
|
*/
|
||||||
|
public IFFImageReaderSpi() {
|
||||||
|
super(
|
||||||
|
"TwelveMonkeys",
|
||||||
|
"2.0",
|
||||||
|
new String[]{"iff", "IFF"},
|
||||||
|
new String[]{"iff", "lbm", "ham", "ham8", "ilbm"},
|
||||||
|
new String[]{"image/iff", "image/x-iff"},
|
||||||
|
"com.twelvemonkeys.imageio.plugins.iff.IFFImageReader",
|
||||||
|
STANDARD_INPUT_TYPE,
|
||||||
|
new String[]{"com.twelvemonkeys.imageio.plugins.iff.IFFImageWriterSpi"},
|
||||||
|
true, null, null, null, null,
|
||||||
|
true, null, null, null, null
|
||||||
|
);
|
||||||
|
|
||||||
|
if (mSharedInstance == null) {
|
||||||
|
mSharedInstance = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canDecodeInput(Object pSource) throws IOException {
|
||||||
|
return pSource instanceof ImageInputStream && canDecode((ImageInputStream) pSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean canDecode(ImageInputStream pInput) throws IOException {
|
||||||
|
pInput.mark();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Is it IFF
|
||||||
|
if (pInput.readInt() == IFF.CHUNK_FORM) {
|
||||||
|
pInput.readInt();// Skip length field
|
||||||
|
|
||||||
|
int type = pInput.readInt();
|
||||||
|
|
||||||
|
// Is it ILBM or PBM
|
||||||
|
if (type == IFF.TYPE_ILBM || type == IFF.TYPE_PBM) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
pInput.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ImageReader createReaderInstance(Object pExtension) throws IOException {
|
||||||
|
return new IFFImageReader(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription(Locale pLocale) {
|
||||||
|
return "Amiga (Electronic Arts) Image Interchange Format (IFF) image reader";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ImageReaderSpi sharedProvider() {
|
||||||
|
if (mSharedInstance == null) {
|
||||||
|
new IFFImageReaderSpi();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mSharedInstance;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,269 @@
|
|||||||
|
/*
|
||||||
|
* 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.iff;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.ImageWriterBase;
|
||||||
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
|
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
||||||
|
import com.twelvemonkeys.io.enc.EncoderStream;
|
||||||
|
import com.twelvemonkeys.io.enc.PackBitsEncoder;
|
||||||
|
|
||||||
|
import javax.imageio.*;
|
||||||
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
|
import javax.imageio.spi.ImageWriterSpi;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.*;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writer for Amiga (Electronic Arts) IFF ILBM (InterLeaved BitMap) format.
|
||||||
|
* The IFF format (Interchange File Format) is the standard file format
|
||||||
|
* supported by allmost all image software for the Amiga computer.
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: IFFImageWriter.java,v 1.0 02.mar.2006 13:32:30 haku Exp$
|
||||||
|
*
|
||||||
|
* @see <a href="http://en.wikipedia.org/wiki/Interchange_File_Format">Wikipedia: IFF</a>
|
||||||
|
* @see <a href="http://en.wikipedia.org/wiki/ILBM">Wikipedia: IFF ILBM</a>
|
||||||
|
*/
|
||||||
|
public class IFFImageWriter extends ImageWriterBase {
|
||||||
|
|
||||||
|
private static final byte[] ANNO_DATA = "Written by TwelveMonkeys IFFImageWriter 1.0 for Java (javax.imageio).".getBytes();
|
||||||
|
|
||||||
|
public IFFImageWriter() {
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IFFImageWriter(ImageWriterSpi pProvider) {
|
||||||
|
super(pProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param) {
|
||||||
|
throw new UnsupportedOperationException("Method getDefaultImageMetadata not implemented");// TODO: Implement
|
||||||
|
}
|
||||||
|
|
||||||
|
public IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param) {
|
||||||
|
throw new UnsupportedOperationException("Method convertImageMetadata not implemented");// TODO: Implement
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(IIOMetadata pStreamMetadata, IIOImage pImage, ImageWriteParam pParam) throws IOException {
|
||||||
|
assertOutput();
|
||||||
|
|
||||||
|
if (pImage.hasRaster()) {
|
||||||
|
throw new UnsupportedOperationException("Cannot write raster");
|
||||||
|
}
|
||||||
|
|
||||||
|
processImageStarted(0);
|
||||||
|
|
||||||
|
// Prepare image data to be written
|
||||||
|
ByteArrayOutputStream imageData = new FastByteArrayOutputStream(1024);
|
||||||
|
packImageData(imageData, pImage.getRenderedImage(), pParam);
|
||||||
|
|
||||||
|
//System.out.println("Image data: " + imageData.size());
|
||||||
|
|
||||||
|
// Write metadata
|
||||||
|
writeMeta(pImage.getRenderedImage(), imageData.size());
|
||||||
|
|
||||||
|
// Write image data
|
||||||
|
writeBody(imageData);
|
||||||
|
|
||||||
|
processImageComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeBody(ByteArrayOutputStream pImageData) throws IOException {
|
||||||
|
mImageOutput.writeInt(IFF.CHUNK_BODY);
|
||||||
|
mImageOutput.writeInt(pImageData.size());
|
||||||
|
|
||||||
|
// NOTE: This is much faster than mOutput.write(pImageData.toByteArray())
|
||||||
|
// as the data array is not duplicated
|
||||||
|
pImageData.writeTo(IIOUtil.createStreamAdapter(mImageOutput));
|
||||||
|
|
||||||
|
if (pImageData.size() % 2 == 0) {
|
||||||
|
mImageOutput.writeByte(0); // PAD
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Most progress is done in packImageData, however, as we need to
|
||||||
|
// buffer, to write correct size, we defer the last 10 percent until now.
|
||||||
|
processImageProgress(100f);
|
||||||
|
|
||||||
|
mImageOutput.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void packImageData(OutputStream pOutput, RenderedImage pImage, ImageWriteParam pParam) throws IOException {
|
||||||
|
// TODO: Allow param to dictate uncompressed
|
||||||
|
// TODO: Subsample/AOI
|
||||||
|
final boolean compress = shouldCompress(pImage);
|
||||||
|
final OutputStream output = compress ? new EncoderStream(pOutput, new PackBitsEncoder(), true) : pOutput;
|
||||||
|
final ColorModel model = pImage.getColorModel();
|
||||||
|
final Raster raster = pImage.getData();
|
||||||
|
|
||||||
|
final int width = pImage.getWidth();
|
||||||
|
final int height = pImage.getHeight();
|
||||||
|
|
||||||
|
// Store each row of pixels
|
||||||
|
// 0. Loop pr channel
|
||||||
|
// 1. Convert to planar
|
||||||
|
// 2. Perform byteRun1 compression for each plane separately
|
||||||
|
// 3. Write the plane data for each plane
|
||||||
|
|
||||||
|
final int planeWidth = (width + 7) / 8;
|
||||||
|
final byte[] planeData = new byte[8 * planeWidth];
|
||||||
|
final int channels = (model.getPixelSize() + 7) / 8;
|
||||||
|
final int planesPerChannel = channels == 1 ? model.getPixelSize() : 8;
|
||||||
|
int[] pixels = new int[8 * planeWidth];
|
||||||
|
|
||||||
|
// NOTE: I'm a little unsure if this is correct for 4 channel (RGBA)
|
||||||
|
// data, but it is at least consistent with the IFFImageReader for now...
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int c = 0; c < channels; c++) {
|
||||||
|
pixels = raster.getSamples(0, y, width, 1, c, pixels);
|
||||||
|
|
||||||
|
int pixelPos = 0;
|
||||||
|
int planePos = 0;
|
||||||
|
for (int i = 0; i < planeWidth; i++) {
|
||||||
|
IFFUtil.bitRotateCCW(pixels, pixelPos, 1,
|
||||||
|
planeData, planePos, planeWidth);
|
||||||
|
pixelPos += 8;
|
||||||
|
planePos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int p = 0; p < planesPerChannel; p++) {
|
||||||
|
output.write(planeData, p * planeWidth, planeWidth);
|
||||||
|
|
||||||
|
if (!compress && planeWidth % 2 != 0) {
|
||||||
|
output.write(0); // PAD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processImageProgress(y * 90f / height);
|
||||||
|
}
|
||||||
|
|
||||||
|
output.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeMeta(RenderedImage pImage, int pBodyLength) throws IOException {
|
||||||
|
// Annotation ANNO chunk, 8 + annoData.length bytes
|
||||||
|
GenericChunk anno = new GenericChunk(IFFUtil.toInt("ANNO".getBytes()), ANNO_DATA);
|
||||||
|
|
||||||
|
ColorModel cm = pImage.getColorModel();
|
||||||
|
IndexColorModel icm = null;
|
||||||
|
|
||||||
|
// Bitmap header BMHD chunk, 8 + 20 bytes
|
||||||
|
// By default, don't compress narrow images
|
||||||
|
int compression = shouldCompress(pImage) ? BMHDChunk.COMPRESSION_BYTE_RUN : BMHDChunk.COMPRESSION_NONE;
|
||||||
|
|
||||||
|
BMHDChunk header;
|
||||||
|
if (cm instanceof IndexColorModel) {
|
||||||
|
//System.out.println("IndexColorModel");
|
||||||
|
icm = (IndexColorModel) cm;
|
||||||
|
int trans = icm.getTransparency() == Transparency.BITMASK ? BMHDChunk.MASK_TRANSPARENT_COLOR : BMHDChunk.MASK_NONE;
|
||||||
|
int transPixel = icm.getTransparency() == Transparency.BITMASK ? icm.getTransparentPixel() : 0;
|
||||||
|
header = new BMHDChunk(pImage.getWidth(), pImage.getHeight(), icm.getPixelSize(),
|
||||||
|
trans, compression, transPixel);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//System.out.println(cm.getClass().getName());
|
||||||
|
header = new BMHDChunk(pImage.getWidth(), pImage.getHeight(), cm.getPixelSize(),
|
||||||
|
BMHDChunk.MASK_NONE, compression, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Colormap CMAP chunk, 8 + icm.getMapSize() * 3 bytes (+ 1 optional pad).
|
||||||
|
CMAPChunk cmap = null;
|
||||||
|
if (icm != null) {
|
||||||
|
//System.out.println("CMAP!");
|
||||||
|
cmap = new CMAPChunk(icm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ILBM(4) + anno(8+len) + header(8+20) + cmap(8+len)? + body(8+len);
|
||||||
|
int size = 4 + 8 + anno.mChunkLength + 28 + 8 + pBodyLength;
|
||||||
|
if (cmap != null) {
|
||||||
|
size += 8 + cmap.mChunkLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
mImageOutput.writeInt(IFF.CHUNK_FORM);
|
||||||
|
mImageOutput.writeInt(size);
|
||||||
|
|
||||||
|
mImageOutput.writeInt(IFF.TYPE_ILBM);
|
||||||
|
|
||||||
|
anno.writeChunk(mImageOutput);
|
||||||
|
header.writeChunk(mImageOutput);
|
||||||
|
if (cmap != null) {
|
||||||
|
//System.out.println("CMAP written");
|
||||||
|
cmap.writeChunk(mImageOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldCompress(RenderedImage pImage) {
|
||||||
|
return pImage.getWidth() >= 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] pArgs) throws IOException {
|
||||||
|
BufferedImage image = ImageIO.read(new File(pArgs[0]));
|
||||||
|
|
||||||
|
ImageWriter writer = new IFFImageWriter(new IFFImageWriterSpi());
|
||||||
|
writer.setOutput(ImageIO.createImageOutputStream(new File(pArgs[1])));
|
||||||
|
//writer.addIIOWriteProgressListener(new ProgressListenerBase() {
|
||||||
|
// int mCurrPct = 0;
|
||||||
|
//
|
||||||
|
// public void imageComplete(ImageWriter pSource) {
|
||||||
|
// mCurrPct = 100;
|
||||||
|
// printProgress(mCurrPct);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void imageProgress(ImageWriter pSource, float pPercentageDone) {
|
||||||
|
// if ((int) pPercentageDone > mCurrPct) {
|
||||||
|
// printProgress((int) pPercentageDone);
|
||||||
|
// mCurrPct = (int) pPercentageDone;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private void printProgress(int pCurrPct) {
|
||||||
|
// if (mCurrPct == 0) {
|
||||||
|
// System.out.print("[");
|
||||||
|
// }
|
||||||
|
// for (int i = mCurrPct / 2; i < pCurrPct / 2; i++) {
|
||||||
|
// System.out.print(".");
|
||||||
|
// }
|
||||||
|
// if (mCurrPct == 100) {
|
||||||
|
// System.out.println("]");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//});
|
||||||
|
|
||||||
|
//image = com.twelvemonkeys.image.ImageUtil.toBuffered(image, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
|
||||||
|
writer.write(image);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* 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.iff;
|
||||||
|
|
||||||
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
|
import javax.imageio.ImageWriter;
|
||||||
|
import javax.imageio.spi.ImageWriterSpi;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IFFImageWriterSpi
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version $Id: IFFImageWriterSpi.java,v 1.0 02.mar.2006 19:21:05 haku Exp$
|
||||||
|
*/
|
||||||
|
public class IFFImageWriterSpi extends ImageWriterSpi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an IFFImageWriterSpi
|
||||||
|
*/
|
||||||
|
public IFFImageWriterSpi() {
|
||||||
|
super(
|
||||||
|
"TwelveMonkeys",
|
||||||
|
"$Revision: 1.0 $",
|
||||||
|
new String[]{"iff", "IFF"},
|
||||||
|
new String[]{"iff", "lbm", "ham", "ham8", "ilbm"},
|
||||||
|
new String[]{"image/iff", "image/x-iff"},
|
||||||
|
"com.twelvemonkeys.imageio.plugins.iff.IFFImageWriter",
|
||||||
|
STANDARD_OUTPUT_TYPE,
|
||||||
|
new String[]{"com.twelvemonkeys.imageio.plugins.iff.IFFImageReaderSpi"},
|
||||||
|
true, null, null, null, null,
|
||||||
|
true, null, null, null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canEncodeImage(ImageTypeSpecifier pType) {
|
||||||
|
// TODO: Probably can't store 16 bit types etc...
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageWriter createWriterInstance(Object pExtension) throws IOException {
|
||||||
|
return new IFFImageWriter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription(Locale pLocale) {
|
||||||
|
return "Amiga (Electronic Arts) IFF image writer";
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,255 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Fast 90-degree bit rotation routines.
|
||||||
|
*
|
||||||
|
* Based on Sue-Ken Yap, "A Fast 90-Degree Bitmap Rotator," in GRAPHICS
|
||||||
|
* GEMS II, James Arvo ed., Academic Press, 1991, ISBN 0-12-064480-0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.twelvemonkeys.imageio.plugins.iff;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IFFUtil
|
||||||
|
* <p/>
|
||||||
|
* Bit rotate methods based on Sue-Ken Yap, "A Fast 90-Degree Bitmap Rotator,"
|
||||||
|
* in GRAPHICS GEMS II, James Arvo ed., Academic Press, 1991, ISBN 0-12-064480-0.
|
||||||
|
*
|
||||||
|
* @author Unascribed (C version)
|
||||||
|
* @author Harald Kuhr (Java port)
|
||||||
|
* @version $Id: IFFUtil.java,v 1.0 06.mar.2006 13:31:35 haku Exp$
|
||||||
|
*/
|
||||||
|
class IFFUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a rotation table
|
||||||
|
* @param n
|
||||||
|
*
|
||||||
|
* @return the rotation table
|
||||||
|
*/
|
||||||
|
static private long[] rtable(int n) {
|
||||||
|
return new long[]{
|
||||||
|
0x00000000l << n, 0x00000001l << n, 0x00000100l << n, 0x00000101l << n,
|
||||||
|
0x00010000l << n, 0x00010001l << n, 0x00010100l << n, 0x00010101l << n,
|
||||||
|
0x01000000l << n, 0x01000001l << n, 0x01000100l << n, 0x01000101l << n,
|
||||||
|
0x01010000l << n, 0x01010001l << n, 0x01010100l << n, 0x01010101l << n};
|
||||||
|
}
|
||||||
|
|
||||||
|
static private final long[][] RTABLE = {
|
||||||
|
rtable(0), rtable(1), rtable(2), rtable(3),
|
||||||
|
rtable(4), rtable(5), rtable(6), rtable(7)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate bits clockwise.
|
||||||
|
* The IFFImageReader uses this to convert pixel bits from planar to chunky.
|
||||||
|
* Bits from the source are rotated 90 degrees clockwise written to the
|
||||||
|
* destination.
|
||||||
|
*
|
||||||
|
* @param pSrc source pixel data
|
||||||
|
* @param pSrcPos starting index of 8 x 8 bit source tile
|
||||||
|
* @param pSrcStep byte offset between adjacent rows in source
|
||||||
|
* @param pDst destination pixel data
|
||||||
|
* @param pDstPos starting index of 8 x 8 bit destination tile
|
||||||
|
* @param pDstStep byte offset between adjacent rows in destination
|
||||||
|
*/
|
||||||
|
static void bitRotateCW(final byte[] pSrc, int pSrcPos, int pSrcStep,
|
||||||
|
final byte[] pDst, int pDstPos, int pDstStep) {
|
||||||
|
int idx = pSrcPos;
|
||||||
|
|
||||||
|
int lonyb;
|
||||||
|
int hinyb;
|
||||||
|
long lo = 0;
|
||||||
|
long hi = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
lonyb = pSrc[idx] & 0xF;
|
||||||
|
hinyb = (pSrc[idx] >> 4) & 0xF;
|
||||||
|
lo |= RTABLE[i][lonyb];
|
||||||
|
hi |= RTABLE[i][hinyb];
|
||||||
|
idx += pSrcStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = pDstPos;
|
||||||
|
|
||||||
|
pDst[idx] = (byte)((hi >> 24) & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
if (idx < pDst.length) {
|
||||||
|
pDst[idx] = (byte)((hi >> 16) & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
if (idx < pDst.length) {
|
||||||
|
pDst[idx] = (byte)((hi >> 8) & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
if (idx < pDst.length) {
|
||||||
|
pDst[idx] = (byte)(hi & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx < pDst.length) {
|
||||||
|
pDst[idx] = (byte)((lo >> 24) & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
if (idx < pDst.length) {
|
||||||
|
pDst[idx] = (byte)((lo >> 16) & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
if (idx < pDst.length) {
|
||||||
|
pDst[idx] = (byte)((lo >> 8) & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
if (idx < pDst.length) {
|
||||||
|
pDst[idx] = (byte)(lo & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate bits counterclockwise.
|
||||||
|
* The IFFImageWriter uses this to convert pixel bits from chunky to planar.
|
||||||
|
*
|
||||||
|
* @param pSrc source pixel data (only lower 8 bits used)
|
||||||
|
* @param pSrcPos starting index of 8 x 8 bit source tile
|
||||||
|
* @param pSrcStep byte offset between adjacent rows in source
|
||||||
|
* @param pDst destination pixel data
|
||||||
|
* @param pDstPos starting index of 8 x 8 bit destination tile
|
||||||
|
* @param pDstStep byte offset between adjacent rows in destination
|
||||||
|
*/
|
||||||
|
static void bitRotateCCW(final int[] pSrc, int pSrcPos, int pSrcStep,
|
||||||
|
final byte[] pDst, int pDstPos, int pDstStep) {
|
||||||
|
int idx = pSrcPos;
|
||||||
|
|
||||||
|
int lonyb;
|
||||||
|
int hinyb;
|
||||||
|
long lo = 0;
|
||||||
|
long hi = 0;
|
||||||
|
|
||||||
|
for (int i = 7; i >= 0; i--) {
|
||||||
|
lonyb = pSrc[idx] & 0xF;
|
||||||
|
hinyb = (pSrc[idx] >> 4) & 0xF;
|
||||||
|
lo |= RTABLE[i][lonyb];
|
||||||
|
hi |= RTABLE[i][hinyb];
|
||||||
|
idx += pSrcStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = pDstPos;
|
||||||
|
|
||||||
|
pDst[idx] = (byte)(lo & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
pDst[idx] = (byte)((lo >> 8) & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
pDst[idx] = (byte)((lo >> 16) & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
pDst[idx] = (byte)((lo >> 24) & 0xFF);
|
||||||
|
|
||||||
|
idx += pDstStep;
|
||||||
|
|
||||||
|
pDst[idx] = (byte)(hi & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
pDst[idx] = (byte)((hi >> 8) & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
pDst[idx] = (byte)((hi >> 16) & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
pDst[idx] = (byte)((hi >> 24) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate bits counterclockwise.
|
||||||
|
* The IFFImageWriter uses this to convert pixel bits from chunky to planar.
|
||||||
|
*
|
||||||
|
* @param pSrc source pixel data
|
||||||
|
* @param pSrcPos starting index of 8 x 8 bit source tile
|
||||||
|
* @param pSrcStep byte offset between adjacent rows in source
|
||||||
|
* @param pDst destination pixel data
|
||||||
|
* @param pDstPos starting index of 8 x 8 bit destination tile
|
||||||
|
* @param pDstStep byte offset between adjacent rows in destination
|
||||||
|
*/
|
||||||
|
static void bitRotateCCW(final byte[] pSrc, int pSrcPos, int pSrcStep,
|
||||||
|
final byte[] pDst, int pDstPos, int pDstStep) {
|
||||||
|
int idx = pSrcPos;
|
||||||
|
|
||||||
|
int lonyb;
|
||||||
|
int hinyb;
|
||||||
|
long lo = 0;
|
||||||
|
long hi = 0;
|
||||||
|
|
||||||
|
for (int i = 7; i >= 0; i--) {
|
||||||
|
lonyb = pSrc[idx] & 0xF;
|
||||||
|
hinyb = (pSrc[idx] >> 4) & 0xF;
|
||||||
|
lo |= RTABLE[i][lonyb];
|
||||||
|
hi |= IFFUtil.RTABLE[i][hinyb];
|
||||||
|
idx += pSrcStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = pDstPos;
|
||||||
|
|
||||||
|
pDst[idx] = (byte)(lo & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
pDst[idx] = (byte)((lo >> 8) & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
pDst[idx] = (byte)((lo >> 16) & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
pDst[idx] = (byte)((lo >> 24) & 0xFF);
|
||||||
|
|
||||||
|
idx += pDstStep;
|
||||||
|
|
||||||
|
pDst[idx] = (byte)(hi & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
pDst[idx] = (byte)((hi >> 8) & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
pDst[idx] = (byte)((hi >> 16) & 0xFF);
|
||||||
|
idx += pDstStep;
|
||||||
|
pDst[idx] = (byte)((hi >> 24) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a byte array to an int.
|
||||||
|
*
|
||||||
|
* @param pBytes a byte array of length 4
|
||||||
|
* @return the bytes converted to an int
|
||||||
|
*
|
||||||
|
* @throws ArrayIndexOutOfBoundsException if length is < 4
|
||||||
|
*/
|
||||||
|
static int toInt(final byte[] pBytes) {
|
||||||
|
return (pBytes[0] & 0xff) << 24 | (pBytes[1] & 0xff) << 16
|
||||||
|
| (pBytes[2] & 0xff) << 8 | (pBytes[3] & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an int to a four letter String.
|
||||||
|
*
|
||||||
|
* @param pChunkId
|
||||||
|
* @return a String
|
||||||
|
*/
|
||||||
|
static String toChunkStr(int pChunkId) {
|
||||||
|
return new String(new byte[] {(byte) ((pChunkId & 0xff000000) >> 24),
|
||||||
|
(byte) ((pChunkId & 0x00ff0000) >> 16),
|
||||||
|
(byte) ((pChunkId & 0x0000ff00) >> 8),
|
||||||
|
(byte) ((pChunkId & 0x000000ff))});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1 @@
|
|||||||
|
com.twelvemonkeys.imageio.plugins.iff.IFFImageReaderSpi
|
@@ -0,0 +1 @@
|
|||||||
|
com.twelvemonkeys.imageio.plugins.iff.IFFImageWriterSpi
|
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 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.iff;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTestCase;
|
||||||
|
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IFFImageReaderTestCase
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: IFFImageReaderTestCase.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public class IFFImageReaderTestCase extends ImageReaderAbstractTestCase<IFFImageReader> {
|
||||||
|
// TODO: Need test for IFF PBM
|
||||||
|
protected List<TestData> getTestData() {
|
||||||
|
return Arrays.asList(
|
||||||
|
// 32 bit - Ok
|
||||||
|
new TestData(getClassLoaderResource("/iff/test.iff"), new Dimension(300, 200)), // 32 bit
|
||||||
|
// 24 bit - Ok
|
||||||
|
new TestData(getClassLoaderResource("/iff/survivor.iff"), new Dimension(800, 600)), // 24 bit
|
||||||
|
// HAM6 - Ok (a lot of visual "fringe", would be interesting to see on a real HAM display)
|
||||||
|
new TestData(getClassLoaderResource("/iff/A4000T_HAM6.IFF"), new Dimension(320, 512)), // ham6
|
||||||
|
// HAM8 - Passes tests, but visuals are trashed. Have other HAM8 files that are ok
|
||||||
|
new TestData(getClassLoaderResource("/iff/A4000T_HAM8.IFF"), new Dimension(628, 512)), // ham8
|
||||||
|
// 8 color indexed - Passes tests, but trashed. Must be something special with these images
|
||||||
|
new TestData(getClassLoaderResource("/iff/AmigaBig.iff"), new Dimension(300, 200)), // 8 color
|
||||||
|
// 8 color indexed - Ok
|
||||||
|
new TestData(getClassLoaderResource("/iff/AmigaAmiga.iff"), new Dimension(200, 150)), // 8 color
|
||||||
|
// Breaks completely... Could be bug in the packbits decoder?
|
||||||
|
new TestData(getClassLoaderResource("/iff/Abyss.iff"), new Dimension(320, 400))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ImageReaderSpi createProvider() {
|
||||||
|
return new IFFImageReaderSpi();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class<IFFImageReader> getReaderClass() {
|
||||||
|
return IFFImageReader.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getFormatNames() {
|
||||||
|
return Arrays.asList("iff");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getSuffixes() {
|
||||||
|
return Arrays.asList("iff", "ilbm", "ham", "ham8", "lbm");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getMIMETypes() {
|
||||||
|
return Arrays.asList("image/iff", "image/x-iff");
|
||||||
|
}
|
||||||
|
}
|
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/A4000T_HAM6.IFF
Executable file
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/A4000T_HAM8.IFF
Executable file
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/Abyss.iff
Executable file
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/AmigaAmiga.iff
Executable file
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/AmigaBig.iff
Executable file
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/survivor.iff
Executable file
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/test.iff
Executable file
4
twelvemonkeys-imageio/iff/todo.txt
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
- Fix the crashes with "java.io.EOFException: Unexpected end of PackBits stream"
|
||||||
|
- Fix the bugs with trashed images
|
||||||
|
- Have a look at Werner Randelshofer's ANIM applet, maybe we can "borrow" the the ANIM support. :-)
|
||||||
|
DONE:
|
25
twelvemonkeys-imageio/jmagick/license.txt
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
Copyright (c) 2009, 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.
|
41
twelvemonkeys-imageio/jmagick/pom.xml
Executable file
@@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>twelvemonkeys-imageio-jmagick</artifactId>
|
||||||
|
<version>2.1</version>
|
||||||
|
<name>TwelveMonkeys ImageIO JMagick Plugin</name>
|
||||||
|
<description>
|
||||||
|
<![CDATA[
|
||||||
|
ImageIO wrapper for JMagick.
|
||||||
|
See the <a href="http://www.yeo.id.au/jmagick/">JMagick Home page</a>
|
||||||
|
for more information.]]>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<artifactId>twelvemonkeys-imageio</artifactId>
|
||||||
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
|
<version>2.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>twelvemonkeys-imageio-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>twelvemonkeys-imageio-core</artifactId>
|
||||||
|
<classifier>tests</classifier>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>jmagick</groupId>
|
||||||
|
<artifactId>jmagick</artifactId>
|
||||||
|
<version>6.2.4</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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.jmagick;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BMPImageReader
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: BMPImageReader.java,v 1.0 Dec 2, 2007 9:03:37 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public final class BMPImageReader extends JMagickReader {
|
||||||
|
public BMPImageReader(final BMPImageReaderSpi pProvider) {
|
||||||
|
super(pProvider);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* 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.jmagick;
|
||||||
|
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BMPImageReaderSpi
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haku $
|
||||||
|
* @version $Id: BMPImageReaderSpi.java,v 1.0 30.jul.2004 20:39:48 haku Exp $
|
||||||
|
*/
|
||||||
|
public class BMPImageReaderSpi extends JMagickImageReaderSpiSupport {
|
||||||
|
public BMPImageReaderSpi() {
|
||||||
|
super(
|
||||||
|
new String[]{"bmp", "BMP"},
|
||||||
|
new String[]{"bmp", "rle", "dib"},
|
||||||
|
new String[]{"image/bmp", "image/x-bmp", "image/x-windows-bmp", "image/x-ms-bmp"}, // http://en.wikipedia.org/wiki/Windows_Bitmap
|
||||||
|
BMPImageReader.class.getName(),
|
||||||
|
new String[]{"com.twelvemonkeys.imageio.plugins.jmagick.BMPImageWriterSpi"}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BMPImageReader createReaderImpl(Object pExtension) throws IOException {
|
||||||
|
return new BMPImageReader(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canDecode(ImageInputStream pSource) throws IOException {
|
||||||
|
//new byte[][] {new byte[] {'B', 'M'}, new byte[] {'M', 'B'}, }, // BMP
|
||||||
|
//new byte[][] {new byte[] {0x00, 0x00, 0x02, 0x00,
|
||||||
|
// 0x01, 0x00, 0x20, 0x20}}, // CUR
|
||||||
|
//new byte[][] {new byte[] {0x0, 0x0, 0x1, 0x0}}, // ICO (best guess)
|
||||||
|
byte[] magic = new byte[2];
|
||||||
|
pSource.readFully(magic);
|
||||||
|
|
||||||
|
return (magic[0] == 'B' && magic[1] == 'M') || (magic[0] == 'M' && magic[1] == 'B');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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.jmagick;
|
||||||
|
|
||||||
|
import javax.imageio.ImageWriteParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BMPImageWriter
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: BMPImageWriter.java,v 1.0 Dec 3, 2007 12:04:10 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public final class BMPImageWriter extends JMagickWriter {
|
||||||
|
protected BMPImageWriter(final BMPImageWriterSpi pProvider) {
|
||||||
|
super(pProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ImageWriteParam createDefaultWriteParam() {
|
||||||
|
return new ImageWriteParam(getLocale()) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canWriteCompressed() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCompressionLossless() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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.jmagick;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BMPImageWriterSpi
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haku $
|
||||||
|
* @version $Id: BMPImageWriterSpi.java,v 1.0 30.jul.2004 18:32:40 haku Exp $
|
||||||
|
*/
|
||||||
|
public class BMPImageWriterSpi extends JMagickImageWriterSpiSupport {
|
||||||
|
public BMPImageWriterSpi() {
|
||||||
|
super(
|
||||||
|
new String[]{"bmp", "BMP"},
|
||||||
|
new String[]{"bmp"},
|
||||||
|
new String[]{"image/bmp", "image/x-bmp", "image/x-windows-bmp", "image/x-ms-bmp"}, // http://en.wikipedia.org/wiki/Windows_Bitmap
|
||||||
|
BMPImageWriter.class.getName(),
|
||||||
|
new String[]{"com.twelvemonkeys.imageio.plugins.jmageick.BMPImageReaderSpi"}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BMPImageWriter createWriterImpl(Object pExtension) throws IOException {
|
||||||
|
return new BMPImageWriter(this);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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.jmagick;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GIFImageReader
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: GIFImageReader.java,v 1.0 Dec 3, 2007 12:53:44 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
public class GIFImageReader extends JMagickReader {
|
||||||
|
protected GIFImageReader(final GIFImageReaderSpi pProvider) {
|
||||||
|
super(pProvider);
|
||||||
|
}
|
||||||
|
}
|