Merge commit 'hamnis/master'

Conflicts:
	imageio/imageio-batik/pom.xml
	imageio/imageio-core/pom.xml
	imageio/imageio-ico/pom.xml
	imageio/imageio-iff/pom.xml
	imageio/imageio-metadata/pom.xml
	imageio/imageio-pict/pom.xml
	imageio/imageio-psd/pom.xml
	imageio/imageio-reference/pom.xml
	imageio/imageio-thumbsdb/pom.xml
	twelvemonkeys-core/pom.xml
	twelvemonkeys-imageio/pom.xml
	twelvemonkeys-servlet/pom.xml
This commit is contained in:
Harald Kuhr
2010-02-07 20:43:44 +01:00
576 changed files with 440 additions and 439 deletions

View File

@@ -0,0 +1,56 @@
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.
Parts of this software is based on JVG/JIS.
See http://www.cs.hut.fi/~framling/JVG/index.html for more information.
Redistribution under BSD authorized by Kary Fr<46>mling:
Copyright (c) 2003, Kary Fr<46>mling
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 of the JIS/JVG 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.

View File

@@ -0,0 +1,27 @@
<?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>
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.0-SNAPSHOT</version>
</parent>
<artifactId>imageio-pict</artifactId>
<name>TwelveMonkeys ImageIO PICT plugin</name>
<description>ImageIO plugin for Apple Mac Paint Picture (PICT) format.</description>
<dependencies>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-core</artifactId>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-core</artifactId>
<classifier>tests</classifier>
</dependency>
</dependencies>
</project>

View File

@@ -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.pict;
import java.awt.*;
import java.awt.image.WritableRaster;
import java.awt.image.DataBufferByte;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
/**
* BitMapPattern
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: BitMapPattern.java,v 1.0 Mar 2, 2009 10:31:56 AM haraldk Exp$
*/
final class BitMapPattern extends Pattern {
BitMapPattern(final Paint pColor) {
super(pColor);
}
public BitMapPattern(final byte[] pPattern) {
this(create8x8Pattern(pPattern));
}
BitMapPattern(final int pPattern) {
this(create8x8Pattern(pPattern));
}
private static TexturePaint create8x8Pattern(final int pPattern) {
// TODO: Creating a special purpose Pattern might be faster than piggy-backing on TexturePaint
WritableRaster raster = QuickDraw.MONOCHROME.createCompatibleWritableRaster(8, 8);
byte[] data = ((DataBufferByte) raster.getDataBuffer()).getData();
for (int i = 0; i < data.length; i += 4) {
data[i ] = (byte) ((pPattern >> 24) & 0xFF);
data[i + 1] = (byte) ((pPattern >> 16) & 0xFF);
data[i + 2] = (byte) ((pPattern >> 8) & 0xFF);
data[i + 3] = (byte) ((pPattern ) & 0xFF);
}
BufferedImage img = new BufferedImage(QuickDraw.MONOCHROME, raster, false, null);
return new TexturePaint(img, new Rectangle(8, 8));
}
private static TexturePaint create8x8Pattern(final byte[] pPattern) {
WritableRaster raster = Raster.createPackedRaster(new DataBufferByte(pPattern, 8), 8, 8, 1, new Point());
BufferedImage img = new BufferedImage(QuickDraw.MONOCHROME, raster, false, null);
return new TexturePaint(img, new Rectangle(8, 8));
}
}

View File

@@ -0,0 +1,178 @@
/*
* 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.pict;
/**
* PICT format constants.
* <p/>
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: PICT.java,v 1.0 06.apr.2006 12:53:17 haku Exp$
*/
interface PICT {
/** PICT V1 identifier, two bytes, mask with 0xffff0000 */
int MAGIC_V1 = 0x11010000;
/** PICT V2 identifier, four bytes */
int MAGIC_V2 = 0x001102ff;
int PICT_NULL_HEADER_SIZE = 512;
// V2 Header, -1 (int)
int HEADER_V2 = 0xffffffff;
// V2 Extended header, -2 (short) + reserved (short)
int HEADER_V2_EXT = 0xfffe0000;
// PICT/QuickDraw uses 16 bit precision per color component internally
int COLOR_COMP_SIZE = 2;
/** Default Apple Macintosh DPI setting (72 DPI). */
int MAC_DEFAULT_DPI = 72;
/**
* PICT opcodes.
*/
int OP_HEADER_OP = 0x0C00;
int NOP = 0x00;
int OP_CLIP_RGN = 0x01;
int OP_BK_PAT = 0x02;
int OP_TX_FONT = 0x03;
int OP_TX_FACE = 0x04;
int OP_TX_MODE = 0x05;
int OP_SP_EXTRA = 0x06;
int OP_PN_SIZE = 0x07;
int OP_PN_MODE = 0x08;
int OP_PN_PAT = 0x09;
int OP_FILL_PAT = 0x0A;
int OP_OV_SIZE = 0x0B;
int OP_ORIGIN = 0x0C;
int OP_TX_SIZE = 0x0D;
int OP_FG_COLOR = 0x0E;
int OP_BK_COLOR = 0x0F;
int OP_TX_RATIO = 0x10;
int OP_VERSION = 0x11;
/* Not implemented */
int OP_BK_PIX_PAT = 0x12;
int OP_PN_PIX_PAT = 0x13;
int OP_FILL_PIX_PAT = 0x14;
int OP_PN_LOC_H_FRAC = 0x15;
int OP_CH_EXTRA = 0x16;
int OP_RGB_FG_COL = 0x1A;
int OP_RGB_BK_COL = 0x1B;
int OP_HILITE_MODE = 0x1C;
int OP_HILITE_COLOR = 0x1D;
int OP_DEF_HILITE = 0x1E;
int OP_OP_COLOR = 0x1F;
int OP_LINE = 0x20;
int OP_LINE_FROM = 0x21;
int OP_SHORT_LINE = 0x22;
int OP_SHORT_LINE_FROM = 0x23;
int OP_LONG_TEXT = 0x28;
int OP_DH_TEXT = 0x29;
int OP_DV_TEXT = 0x2A;
int OP_DHDV_TEXT = 0x2B;
int OP_FONT_NAME = 0x2C;
int OP_LINE_JUSTIFY = 0x2D;
int OP_GLYPH_STATE = 0x2E;
int OP_FRAME_RECT = 0x30;
int OP_PAINT_RECT = 0x31;
int OP_ERASE_RECT = 0x32;
int OP_INVERT_RECT = 0x33;
int OP_FILL_RECT = 0x34;
int OP_FRAME_SAME_RECT = 0x38;
int OP_PAINT_SAME_RECT = 0x39;
int OP_ERASE_SAME_RECT = 0x3A;
int OP_INVERT_SAME_RECT = 0x3B;
int OP_FILL_SAME_RECT = 0x3C;
int OP_FRAME_R_RECT = 0x40;
int OP_PAINT_R_RECT = 0x41;
int OP_ERASE_R_RECT = 0x42;
int OP_INVERT_R_RECT = 0x43;
int OP_FILL_R_RECT = 0x44;
int OP_FRAME_SAME_R_RECT = 0x48;
int OP_PAINT_SAME_R_RECT = 0x49;
int OP_ERASE_SAME_R_RECT = 0x4A;
int OP_INVERT_SAME_R_RECT = 0x4B;
int OP_FILL_SAME_R_RECT = 0x4C;
int OP_FRAME_OVAL = 0x50;
int OP_PAINT_OVAL = 0x51;
int OP_ERASE_OVAL = 0x52;
int OP_INVERT_OVAL = 0x53;
int OP_FILL_OVAL = 0x54;
int OP_FRAME_SAME_OVAL = 0x58;
int OP_PAINT_SAME_OVAL = 0x59;
int OP_ERASE_SAME_OVAL = 0x5A;
int OP_INVERT_SAME_OVAL = 0x5B;
int OP_FILL_SAME_OVAL = 0x5C;
int OP_FRAME_ARC = 0x60;
int OP_PAINT_ARC = 0x61;
int OP_ERASE_ARC = 0x62;
int OP_INVERT_ARC = 0x63;
int OP_FILL_ARC = 0x64;
int OP_FRAME_SAME_ARC = 0x68;
int OP_PAINT_SAME_ARC = 0x69;
int OP_ERASE_SAME_ARC = 0x6A;
int OP_INVERT_SAME_ARC = 0x6B;
int OP_FILL_SAME_ARC = 0x6C;
int OP_FRAME_POLY = 0x70;
int OP_PAINT_POLY = 0x71;
int OP_ERASE_POLY = 0x72;
int OP_INVERT_POLY = 0x73;
int OP_FILL_POLY = 0x74;
int OP_FRAME_SAME_POLY = 0x78;
int OP_PAINT_SAME_POLY = 0x79;
int OP_ERASE_SAME_POLY = 0x7A;
int OP_INVERT_SAME_POLY = 0x7B;
int OP_FILL_SAME_POLY = 0x7C;
int OP_FRAME_RGN = 0x80;
int OP_PAINT_RGN = 0x81;
int OP_ERASE_RGN = 0x82;
int OP_INVERT_RGN = 0x83;
int OP_FILL_RGN = 0x84;
int OP_FRAME_SAME_RGN = 0x88;
int OP_PAINT_SAME_RGN = 0x89;
int OP_ERASE_SAME_RGN = 0x8A;
int OP_INVERT_SAME_RGN = 0x8B;
int OP_FILL_SAME_RGN = 0x8C;
/* Not implemented */
int OP_BITS_RECT = 0x90;
int OP_BITS_RGN = 0x91;
int OP_PACK_BITS_RECT = 0x98;
int OP_PACK_BITS_RGN = 0x99;
int OP_DIRECT_BITS_RECT = 0x9A;
/* Not implemented */
int OP_DIRECT_BITS_RGN = 0x9B;
int OP_SHORT_COMMENT = 0xA0;
int OP_LONG_COMMENT = 0xA1;
int OP_END_OF_PICTURE = 0xFF;
int OP_VERSION_2 = 0x2FF;
int OP_COMPRESSED_QUICKTIME = 0x8200;
int OP_UNCOMPRESSED_QUICKTIME = 0x8201;
String APPLE_USE_RESERVED_FIELD = "Reserved for Apple use.";
}

View File

@@ -0,0 +1,130 @@
/*
* 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.pict;
import com.twelvemonkeys.imageio.spi.ProviderInfo;
import com.twelvemonkeys.imageio.util.IIOUtil;
import javax.imageio.ImageReader;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;
import java.io.IOException;
import java.io.EOFException;
import java.util.Locale;
/**
* PICTImageReaderSpi
* <p/>
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: PICTImageReaderSpi.java,v 1.0 28.feb.2006 19:21:05 haku Exp$
*/
public class PICTImageReaderSpi extends ImageReaderSpi {
/**
* Creates a {@code PICTImageReaderSpi}.
*/
public PICTImageReaderSpi() {
this(IIOUtil.getProviderInfo(PICTImageReaderSpi.class));
}
private PICTImageReaderSpi(final ProviderInfo pProviderInfo) {
super(
pProviderInfo.getVendorName(),
pProviderInfo.getVersion(),
new String[]{"pct", "PCT", "pict", "PICT"},
new String[]{"pct", "pict"},
new String[]{"image/pict", "image/x-pict"},
"com.twelvemkonkeys.imageio.plugins.pict.PICTImageReader",
STANDARD_INPUT_TYPE,
new String[]{"com.twelvemkonkeys.imageio.plugins.pict.PICTImageWriterSpi"},
true, null, null, null, null,
true, null, null, null, null
);
}
public boolean canDecodeInput(final Object pSource) throws IOException {
if (!(pSource instanceof ImageInputStream)) {
return false;
}
ImageInputStream stream = (ImageInputStream) pSource;
stream.mark();
try {
if (isPICT(stream)) {
// If PICT Clipping format, return true immediately
return true;
}
else {
// Skip header 512 bytes for file-based streams
stream.reset();
PICTImageReader.skipNullHeader(stream);
}
return isPICT(stream);
}
catch (EOFException ignore) {
return false;
}
finally {
stream.reset();
}
}
private boolean isPICT(final ImageInputStream pStream) throws IOException {
// Size may be 0, so we can't use this for validation...
pStream.readUnsignedShort();
// Sanity check bounding box
int y1 = pStream.readUnsignedShort();
int x1 = pStream.readUnsignedShort();
// TODO: Figure out if frame can ever start at negative bounds...
// if (x1 != 0 || y1 != 0) {
// return false;
// }
int y2 = pStream.readUnsignedShort();
int x2 = pStream.readUnsignedShort();
if (x2 - x1 < 0 || y2 - y1 < 0) {
return false;
}
int magic = pStream.readInt();
return (magic & 0xffff0000) == PICT.MAGIC_V1 || magic == PICT.MAGIC_V2;
}
public ImageReader createReaderInstance(final Object pExtension) throws IOException {
return new PICTImageReader(this);
}
public String getDescription(final Locale pLocale) {
return "Apple Mac Paint Picture (PICT) image reader";
}
}

View File

@@ -0,0 +1,414 @@
/*
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.
Parts of this software is based on JVG/JIS.
See http://www.cs.hut.fi/~framling/JVG/index.html for more information.
Redistribution under BSD authorized by Kary Fr<46>mling:
Copyright (c) 2003, Kary Fr<46>mling
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 of the JIS/JVG 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.pict;
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 javax.imageio.stream.ImageOutputStream;
import java.awt.color.ColorSpace;
import java.awt.image.*;
import java.io.*;
/**
* Writer for Apple Mac Paint Picture (PICT) format.
* <p/>
* Images are stored using the "opDirectBitsRect" opcode, which directly
* stores RGB values (using PackBits run-length encoding).
*
* @author <a href="http://www.cs.hut.fi/~framling/JVG/">Kary Fr<46>mling</a>
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: PICTWriter.java,v 1.0 05.apr.2006 15:20:48 haku Exp$
*/
public class PICTImageWriter extends ImageWriterBase {
// TODO: Inline these?
private int mRowBytes;
private byte[] mScanlineBytes;
private int mScanWidthLeft;
public PICTImageWriter() {
this(null);
}
/**
* 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 PICTImageWriter(final ImageWriterSpi pProvider) {
super(pProvider);
}
private void writePICTHeader(RenderedImage pImage) throws IOException {
// TODO: Make 512 byte header optional
// Write empty 512-byte header
byte[] buf = new byte[PICT.PICT_NULL_HEADER_SIZE];
mImageOutput.write(buf);
// Write out the size, leave as 0, this is ok
mImageOutput.writeShort(0);
// Write image frame (same as image bounds)
mImageOutput.writeShort(0);
mImageOutput.writeShort(0);
mImageOutput.writeShort(pImage.getHeight());
mImageOutput.writeShort(pImage.getWidth());
// Write version, version 2
mImageOutput.writeShort(PICT.OP_VERSION);
mImageOutput.writeShort(PICT.OP_VERSION_2);
// Version 2 HEADER_OP, extended version.
mImageOutput.writeShort(PICT.OP_HEADER_OP);
mImageOutput.writeInt(PICT.HEADER_V2_EXT); // incl 2 bytes reseverd
// Image resolution, 72 dpi
mImageOutput.writeShort(PICT.MAC_DEFAULT_DPI);
mImageOutput.writeShort(0);
mImageOutput.writeShort(PICT.MAC_DEFAULT_DPI);
mImageOutput.writeShort(0);
// Optimal source rectangle (same as image bounds)
mImageOutput.writeShort(0);
mImageOutput.writeShort(0);
mImageOutput.writeShort(pImage.getHeight());
mImageOutput.writeShort(pImage.getWidth());
// Reserved (4 bytes)
mImageOutput.writeInt(0);
// TODO: The header really ends here...
// Highlight
mImageOutput.writeShort(PICT.OP_DEF_HILITE);
// Set the clip rectangle
mImageOutput.writeShort(PICT.OP_CLIP_RGN);
mImageOutput.writeShort(10);
mImageOutput.writeShort(0);
mImageOutput.writeShort(0);
mImageOutput.writeShort(pImage.getHeight());
mImageOutput.writeShort(pImage.getWidth());
// Pixmap operation
mImageOutput.writeShort(PICT.OP_DIRECT_BITS_RECT);
// PixMap pointer (always 0x000000FF);
mImageOutput.writeInt(0x000000ff);
// Write rowBytes, this is 4 times the width.
// Set the high bit, to indicate a PixMap.
mRowBytes = 4 * pImage.getWidth();
mImageOutput.writeShort(0x8000 | mRowBytes);
// Write bounds rectangle (same as image bounds)
mImageOutput.writeShort(0);
mImageOutput.writeShort(0);
mImageOutput.writeShort(pImage.getHeight()); // TODO: Handle overflow?
mImageOutput.writeShort(pImage.getWidth());
// PixMap record version
mImageOutput.writeShort(0);
// Packing format (always 4: PackBits)
mImageOutput.writeShort(4);
// Size of packed data (leave as 0)
mImageOutput.writeInt(0);
// Pixmap resolution, 72 dpi
mImageOutput.writeShort(PICT.MAC_DEFAULT_DPI);
mImageOutput.writeShort(0);
mImageOutput.writeShort(PICT.MAC_DEFAULT_DPI);
mImageOutput.writeShort(0);
// Pixel type, 16 is allright for direct pixels
mImageOutput.writeShort(16);
// Pixel size
mImageOutput.writeShort(32);
// TODO: Allow alpha? Allow 5 bit per pixel component (16 bit)?
// Pixel component count
mImageOutput.writeShort(3);
// Pixel component size
mImageOutput.writeShort(8);
// PlaneBytes, ignored for now
mImageOutput.writeInt(0);
// TODO: Allow IndexColorModel?
// ColorTable record (for RGB direct pixels, just write 0)
mImageOutput.writeInt(0);
// Reserved (4 bytes)
mImageOutput.writeInt(0);
// Source and dest rect (both are same as image bounds)
mImageOutput.writeShort(0);
mImageOutput.writeShort(0);
mImageOutput.writeShort(pImage.getHeight());
mImageOutput.writeShort(pImage.getWidth());
mImageOutput.writeShort(0);
mImageOutput.writeShort(0);
mImageOutput.writeShort(pImage.getHeight());
mImageOutput.writeShort(pImage.getWidth());
// Transfer mode
mImageOutput.writeShort(QuickDraw.SRC_COPY);
// TODO: Move to writePICTData?
// TODO: Alpha support
// Set up the buffers for storing scanline bytes
mScanlineBytes = new byte[3 * pImage.getWidth()];
mScanWidthLeft = pImage.getWidth();
}
private void writePICTData(int x, int y, int w, int h, ColorModel model,
byte[] pixels, int off, int scansize) throws IOException {
ByteArrayOutputStream bytes = new FastByteArrayOutputStream(mScanlineBytes.length / 2);
int components = model.getNumComponents();
// TODO: Clean up, as we only have complete scanlines
// Fill the scanline buffer. We get problems if ever we have several
// lines (h > 1) and (w < width). This should never be the case.
for (int i = 0; i < h; i++) {
// Reduce the counter of bytes left on the scanline.
mScanWidthLeft -= w;
// Treat the scanline.
for (int j = 0; j < w; j++) {
if (model instanceof ComponentColorModel && model.getColorSpace().getType() == ColorSpace.TYPE_RGB) {
// TODO: Component order?
// TODO: Alpha support
mScanlineBytes[x + j] = pixels[off + i * scansize * components + components * j + 2];
mScanlineBytes[x + w + j] = pixels[off + i * scansize * components + components * j + 1];
mScanlineBytes[x + 2 * w + j] = pixels[off + i * scansize * components + components * j];
}
else {
int rgb = model.getRGB(pixels[off + i * scansize + j] & 0xFF);
// Set red, green and blue components.
mScanlineBytes[x + j] = (byte) ((rgb >> 16) & 0xFF);
mScanlineBytes[x + w + j] = (byte) ((rgb >> 8) & 0xFF);
mScanlineBytes[x + 2 * w + j] = (byte) (rgb & 0xFF);
}
}
// If we have a complete scanline, then pack it and write it out.
if (mScanWidthLeft == 0) {
// Pack using PackBitsEncoder/EncoderStream
bytes.reset();
DataOutput packBits = new DataOutputStream(new EncoderStream(bytes, new PackBitsEncoder(), true));
packBits.write(mScanlineBytes);
if (mRowBytes > 250) {
mImageOutput.writeShort(bytes.size());
}
else {
mImageOutput.writeByte(bytes.size());
}
bytes.writeTo(IIOUtil.createStreamAdapter(mImageOutput));
mScanWidthLeft = w;
}
}
}
private void writePICTData(int x, int y, int w, int h, ColorModel model,
int[] pixels, int off, int scansize) throws IOException {
ByteArrayOutputStream bytes = new FastByteArrayOutputStream(mScanlineBytes.length / 2);
// TODO: Clean up, as we only have complete scanlines
// Fill the scanline buffer. We get problems if ever we have several
// lines (h > 1) and (w < width). This should never be the case.
for (int i = 0; i < h; i++) {
// Reduce the counter of bytes left on the scanline.
mScanWidthLeft -= w;
// Treat the scanline.
for (int j = 0; j < w; j++) {
int rgb = model.getRGB(pixels[off + i * scansize + j]);
// Set red, green and blue components.
mScanlineBytes[x + j] = (byte) ((rgb >> 16) & 0xFF);
mScanlineBytes[x + w + j] = (byte) ((rgb >> 8) & 0xFF);
mScanlineBytes[x + 2 * w + j] = (byte) (rgb & 0xFF);
}
// If we have a complete scanline, then pack it and write it out.
if (mScanWidthLeft == 0) {
// Pack using PackBitsEncoder/EncoderStream
bytes.reset();
DataOutput packBits = new DataOutputStream(new EncoderStream(bytes, new PackBitsEncoder(), true));
packBits.write(mScanlineBytes);
if (mRowBytes > 250) {
mImageOutput.writeShort(bytes.size());
}
else {
mImageOutput.writeByte(bytes.size());
}
bytes.writeTo(IIOUtil.createStreamAdapter(mImageOutput));
mScanWidthLeft = w;
}
}
}
private void writePICTTrailer() throws IOException {
// Write out end opcode. Be sure to be word-aligned.
long length = mImageOutput.length();
if (length == -1) {
throw new IIOException("Cannot write trailer without knowing length");
}
if ((length & 1) > 0) {
mImageOutput.writeByte(0);
}
mImageOutput.writeShort(PICT.OP_END_OF_PICTURE);
}
public void write(IIOMetadata pStreamMetadata, IIOImage pImage, ImageWriteParam pParam) throws IOException {
assertOutput();
if (pImage.hasRaster()) {
throw new UnsupportedOperationException("Cannot write raster");
}
processImageStarted(0);
RenderedImage image = pImage.getRenderedImage();
writePICTHeader(image);
// NOTE: getRaster is much faster than getData, as it does no copying
Raster raster = image instanceof BufferedImage ? ((BufferedImage) image).getRaster() : image.getData();
DataBuffer buf = raster.getDataBuffer();
if (buf instanceof DataBufferByte) {
writePICTData(0, 0, image.getWidth(), image.getHeight(),
image.getColorModel(), ((DataBufferByte) buf).getData(),
0, image.getWidth());
}
else if (buf instanceof DataBufferInt) {
writePICTData(0, 0, image.getWidth(), image.getHeight(),
image.getColorModel(), ((DataBufferInt) buf).getData(),
0, image.getWidth());
}
else {
throw new IIOException("DataBuffer type " + buf.getDataType() + " not supported");
}
// TODO: Support 16 bit USHORT type
writePICTTrailer();
processImageComplete();
}
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 static void main(String[] pArgs) throws IOException {
System.out.print("Reading image.. ");
BufferedImage image = ImageIO.read(new File(pArgs[0]));
System.out.println("image read");
System.out.println("image: " + image);
ImageWriter writer = new PICTImageWriter(null);
ImageOutputStream stream = ImageIO.createImageOutputStream(new File(pArgs[1]));
writer.setOutput(stream);
writer.write(image);
stream.close();
}
}

View File

@@ -0,0 +1,84 @@
/*
* 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.pict;
import com.twelvemonkeys.imageio.spi.ProviderInfo;
import com.twelvemonkeys.imageio.util.IIOUtil;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriter;
import javax.imageio.spi.ImageWriterSpi;
import java.io.IOException;
import java.util.Locale;
/**
* PICTImageWriterSpi
* <p/>
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: PICTImageWriterSpi.java,v 1.0 02.mar.2006 19:21:05 haku Exp$
*/
public class PICTImageWriterSpi extends ImageWriterSpi {
/**
* Creates a {@code PICTImageWriterSpi}.
*/
public PICTImageWriterSpi() {
this(IIOUtil.getProviderInfo(PICTImageWriterSpi.class));
}
private PICTImageWriterSpi(final ProviderInfo pProviderInfo) {
super(
pProviderInfo.getVendorName(),
pProviderInfo.getVersion(),
new String[]{"pct", "PCT",
"pict", "PICT"},
new String[]{"pct", "pict"},
new String[]{"image/pict", "image/x-pict"},
"com.twelvemonkeys.imageio.plugins.pict.PICTImageWriter",
STANDARD_OUTPUT_TYPE,
new String[]{"com.twelvemonkeys.imageio.plugins.pict.PICTImageReaderSpi"},
true, null, null, null, null,
true, null, null, null, null
);
}
public boolean canEncodeImage(ImageTypeSpecifier pType) {
// TODO: FixMe
return true;
}
public ImageWriter createWriterInstance(Object pExtension) throws IOException {
return new PICTImageWriter();
}
public String getDescription(Locale pLocale) {
return "Apple Mac Paint Picture (PICT) image writer";
}
}

View File

@@ -0,0 +1,264 @@
/*
* 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.pict;
import javax.imageio.IIOException;
import java.awt.*;
import java.awt.image.DataBuffer;
import java.awt.image.IndexColorModel;
import java.io.DataInput;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
/**
* PICTUtil
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: PICTUtil.java,v 1.0 Feb 16, 2009 8:46:27 PM haraldk Exp$
*/
final class PICTUtil {
private static final String ENC_MAC_ROMAN = "MacRoman";
public static final String ENCODING = initEncoding();
private static String initEncoding() {
try {
new String("\uF8FF".getBytes(), ENC_MAC_ROMAN);
return ENC_MAC_ROMAN;
}
catch (UnsupportedEncodingException e) {
return "ISO-8859-1";
}
}
/**
* Reads a fixed point number from the given stream.
*
* @param pStream the input stream
* @return the number as a {@code double}.
*
* @throws java.io.IOException if an I/O error occurs during read
*/
public static double readFixedPoint(final DataInput pStream) throws IOException {
return pStream.readInt() / (double) (1 << 16);
}
static String readIdString(final DataInput pStream) throws IOException {
byte[] bytes = new byte[4];
pStream.readFully(bytes);
return new String(bytes, "ASCII");
}
/**
* Reads a dimension from the given stream.
*
* @param pStream the input stream
* @return the dimension read
*
* @throws java.io.IOException if an I/O error occurs during read
*/
public static Dimension readDimension(final DataInput pStream) throws IOException {
final int h = pStream.readShort() ;
final int v = pStream.readShort() ;
return new Dimension(h,v);
}
/**
* Reads a 32 byte fixed length Pascal string from the given input.
* The input stream must be positioned at the length byte of the text,
* the text will be no longer than 31 characters long.
*
* @param pStream the input stream
* @return the text read
*
* @throws IOException if an I/O exception occurs during reading
*/
public static String readStr31(final DataInput pStream) throws IOException {
String text = readPascalString(pStream);
int length = 31 - text.length();
if (length < 0) {
throw new IOException("String length exceeds maximum (31): " + text.length());
}
pStream.skipBytes(length);
return text;
}
/**
* Reads a Pascal String from the given strean.
* The input stream must be positioned at the length byte of the text,
* which can thus be a maximum of 255 characters long.
*
* @param pStream the input stream
* @return the text read
*
* @throws IOException if an I/O exception occurs during reading
*/
public static String readPascalString(final DataInput pStream) throws IOException {
// Get as many bytes as indicated by byte count
int length = pStream.readUnsignedByte();
byte[] bytes = new byte[length];
pStream.readFully(bytes, 0, length);
return new String(bytes, ENCODING);
}
/**
* Reads a {@link Pattern pattern} from the given stream.
*
* @param pStream the input stream
* @return the pattern read
*
* @throws java.io.IOException if an I/O error occurs during read
*/
public static Pattern readPattern(final DataInput pStream) throws IOException {
// Get the data (8 bytes)
byte[] data = new byte[8];
pStream.readFully(data);
return new BitMapPattern(data);
}
/**
* Reads a variable width {@link Pattern color pattern} from the given stream
*
* @param pStream the input stream
* @return the pattern read
*
* @throws java.io.IOException if an I/O error occurs during read
*/
/*
http://developer.apple.com/DOCUMENTATION/mac/QuickDraw/QuickDraw-461.html#MARKER-9-243
IF patType = ditherPat
THEN
PatType: word; {pattern type = 2}
Pat1Data: Pattern; {old pattern data}
RGB: RGBColor; {desired RGB for pattern}
ELSE
PatType: word; {pattern type = 1}
Pat1Data: Pattern; {old pattern data}
PixMap: PixMap;
ColorTable: ColorTable;
PixData: PixData;
END;
*/
public static Pattern readColorPattern(final DataInput pStream) throws IOException {
short type = pStream.readShort();
Pattern pattern;
Pattern fallback = readPattern(pStream);
if (type == 1) {
// TODO: This is foobar...
// PixMap
// ColorTable
// PixData
throw new IIOException(String.format("QuickDraw pattern type '0x%04x' not implemented (yet)", type));
}
else if (type == 2) {
Color color = readRGBColor(pStream);
pattern = new PixMapPattern(color, fallback);
}
else {
throw new IIOException(String.format("Unknown QuickDraw pattern type '0x%04x'", type));
}
return pattern;
}
/**
* Reads an {@link RGBColor} record from the given stream.
*
* @param pStream the input stream
* @return the color read
*
* @throws java.io.IOException if an I/O error occurs during read
*/
/*
http://developer.apple.com/DOCUMENTATION/mac/QuickDraw/QuickDraw-269.html#HEADING269-11
RGBColor =
RECORD
red: Integer; {red component}
green: Integer; {green component}
blue: Integer; {blue component}
END;
*/
public static Color readRGBColor(final DataInput pStream) throws IOException {
short r = pStream.readShort();
short g = pStream.readShort();
short b = pStream.readShort();
return new RGBColor(r, g, b);
}
/**
* Reads a {@code ColorTable} data structure from the given stream.
*
* @param pStream the input stream
* @param pPixelSize the pixel size
* @return the indexed color model created from the {@code ColorSpec} records read.
*
* @throws java.io.IOException if an I/O error occurs during read
*/
/*
http://developer.apple.com/DOCUMENTATION/mac/QuickDraw/QuickDraw-269.html#HEADING269-11
ColorSpec =
RECORD
value: Integer; {index or other value}
rgb: RGBColor; {true color}
END;
ColorTable =
RECORD
ctSeed: LongInt; {unique identifier from table}
ctFlags: Integer; {contains flags describing the ctTable field; }
{ clear for a PixMap record}
ctSize: Integer; {number of entries in the next field minus 1}
ctTable: cSpecArray; {an array of ColorSpec records}
END;
*/
public static IndexColorModel readColorTable(final DataInput pStream, final int pPixelSize) throws IOException {
// TODO: Do we need to support these?
/*int seed = */pStream.readInt();
/*int flags = */pStream.readUnsignedShort();
int size = pStream.readUnsignedShort() + 1; // data is size - 1
int[] colors = new int[size];
for (int i = 0; i < size ; i++) {
// Read ColorSpec records
int index = pStream.readUnsignedShort();
Color color = readRGBColor(pStream);
colors[index] = color.getRGB();
}
return new IndexColorModel(pPixelSize, size, colors, 0, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
}
}

View File

@@ -0,0 +1,64 @@
/*
* 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.pict;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.geom.AffineTransform;
import java.awt.image.*;
import java.util.Collections;
/**
* Pattern
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: Pattern.java,v 1.0 Oct 9, 2007 1:21:38 AM haraldk Exp$
*/
abstract class Pattern implements Paint {
private final Paint mPaint;
Pattern(final Paint pPaint) {
mPaint = pPaint;
}
public PaintContext createContext(final ColorModel pModel, final Rectangle pDeviceBounds,
final Rectangle2D pUserBounds, final AffineTransform pTransform,
final RenderingHints pHints) {
return mPaint.createContext(
pModel, pDeviceBounds,
pUserBounds, pTransform,
pHints != null ? pHints : new RenderingHints(Collections.<RenderingHints.Key, Object>emptyMap())
);
}
public int getTransparency() {
return mPaint.getTransparency();
}
}

View File

@@ -0,0 +1,52 @@
/*
* 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.pict;
import java.awt.*;
/**
* PenState
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: PenState.java,v 1.0 Oct 9, 2007 1:56:33 AM haraldk Exp$
*/
class PenState {
public final Point mPenLocation; /* pen location */
public final Dimension mPenSize; /* pen size */
public final int mPenMode; /* pen's pattern mode */
public final Pattern mPenPattern; /* pen pattern */
public PenState(final Point pPenLocation, final int pPenMode, final Pattern pPenPattern, final Dimension pPenSize) {
mPenLocation = pPenLocation;
mPenMode = pPenMode;
mPenPattern = pPenPattern;
mPenSize = pPenSize;
}
}

View File

@@ -0,0 +1,54 @@
/*
* 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.pict;
import java.awt.*;
/**
* PixMapPattern
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: PixMapPattern.java,v 1.0 Mar 1, 2009 11:36:10 PM haraldk Exp$
*/
final class PixMapPattern extends Pattern {
private final Pattern mFallback;
PixMapPattern(final Paint pPaint, final Pattern pBitMapFallback) {
super(pPaint);
mFallback = pBitMapFallback;
}
/**
* @return the fallback B/W pattern
*/
public Pattern getPattern() {
return mFallback;
}
}

View File

@@ -0,0 +1,161 @@
/*
* 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.pict;
import com.twelvemonkeys.image.BufferedImageIcon;
import com.twelvemonkeys.image.ImageUtil;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.awt.*;
import java.lang.reflect.InvocationTargetException;
/**
* QDTest
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: QDTest.java,v 1.0 Oct 10, 2007 6:06:55 PM haraldk Exp$
*/
public class QDTest {
public static void main(String[] pArgs) {
BufferedImage image = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
// g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
QuickDrawContext context = new QuickDrawContext(g);
try {
// Fill background, as Xor don't work with transparent bg
context.fillRect(new Rectangle(200, 200), QuickDraw.WHITE);
context.moveTo(10, 10);
context.lineTo(10, 190);
context.lineTo(190, 190);
context.lineTo(190, 10);
context.lineTo(10, 10);
context.moveTo(10, 10);
context.lineTo(190, 190);
context.setPenSize(new Dimension(2, 2));
context.frameRect(new Rectangle(15, 15, 20, 20));
context.paintRect(new Rectangle(15, 45, 20, 20));
context.fillRect(new Rectangle(15, 75, 20, 20), QuickDraw.DARK_GRAY);
context.fillRect(new Rectangle(12, 102, 26, 26), new BitMapPattern(Color.GRAY));
context.eraseRect(new Rectangle(15, 105, 20, 20));
context.fillRect(new Rectangle(12, 132, 26, 8), QuickDraw.LIGT_GRAY);
context.fillRect(new Rectangle(12, 140, 26, 10), new BitMapPattern(Color.RED));
context.fillRect(new Rectangle(12, 150, 26, 8), QuickDraw.DARK_GRAY);
context.invertRect(new Rectangle(15, 135, 20, 20));
context.setPenSize(new Dimension(10, 10));
context.moveTo(80, 30);
context.line(80, 20);
context.move(20, 0);
context.line(0, -25);
context.setPenPattern(QuickDraw.GRAY);
context.moveTo(80, 70);
context.line(80, 20);
context.move(20, 0);
context.line(0, -25);
context.setPenPattern(new BitMapPattern(Color.GRAY));
context.moveTo(80, 110);
context.line(80, 20);
context.move(20, 0);
context.line(0, -25);
context.setPenPattern(new BitMapPattern(Color.RED));
context.moveTo(80, 150);
context.line(80, 20);
context.move(20, 0);
context.line(0, -25);
context.setPenPattern(new BitMapPattern(Color.ORANGE));
context.setPenSize(new Dimension(2, 2));
context.frameRoundRect(new Rectangle(45, 15, 20, 20), 4, 4);
context.setPenPattern(new BitMapPattern(Color.DARK_GRAY));
context.paintOval(new Rectangle(45, 45, 20, 20));
context.invertArc(new Rectangle(45 + 1, 45, 20, 20), 45, 90);
context.frameArc(new Rectangle(45 - 1, 75, 20, 20), 45, -270);
context.fillArc(new Rectangle(45 + 1, 75, 20, 20), 45, 90, new BitMapPattern(Color.RED));
context.invertPoly(new Polygon(new int[]{43, 55, 67}, new int[]{125, 103, 125}, 3));
context.setPenPattern(new BitMapPattern(Color.ORANGE));
Polygon star = new Polygon(
new int[]{43, 52, 55, 58, 68, 59, 63, 55, 47, 51},
new int[]{143, 143, 133, 143, 143, 148, 157, 152, 157, 148},
10
);
context.paintPoly(star);
context.setPenNormal();
context.framePoly(star);
// TODO: FixMe: Seems like rectangle should be INSIDE? Or at least, one pixel less than AWT thinks..
// context.frameRoundRect(new Rectangle(20, 10, 100, 165), 5, 4);
context.moveTo(15, 185);
context.drawString("Java QuickDraw test");
}
finally {
context.closePicture();
}
showIt(image, "QuickDraw Test");
}
public 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());
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
BufferedImageIcon icon = new BufferedImageIcon(ImageUtil.accelerate(pImage, gc));
JScrollPane scroll = new JScrollPane(new JLabel(icon));
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);
}
}
}

View File

@@ -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.plugins.pict;
import com.twelvemonkeys.io.FastByteArrayOutputStream;
import com.twelvemonkeys.io.LittleEndianDataOutputStream;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
/**
* QTBMPDecompressor
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: QTBMPDecompressor.java,v 1.0 Feb 16, 2009 9:18:28 PM haraldk Exp$
*/
final class QTBMPDecompressor extends QTDecompressor {
public boolean canDecompress(final QuickTime.ImageDesc pDescription) {
return QuickTime.VENDOR_APPLE.equals(pDescription.compressorVendor) && "WRLE".equals(pDescription.compressorIdentifer)
&& "bmp ".equals(idString(pDescription.extraDesc, 4));
}
private static String idString(final byte[] pData, final int pOffset) {
try {
return new String(pData, pOffset, 4, "ASCII");
}
catch (UnsupportedEncodingException e) {
throw new Error("ASCII charset must always be supported", e);
}
}
public BufferedImage decompress(final QuickTime.ImageDesc pDescription, final InputStream pStream) throws IOException {
return ImageIO.read(new SequenceInputStream(fakeBMPHeader(pDescription), pStream));
}
private InputStream fakeBMPHeader(final QuickTime.ImageDesc pDescription) throws IOException {
int bmpHeaderSize = 14;
int dibHeaderSize = 12; // 12: OS/2 V1
ByteArrayOutputStream out = new FastByteArrayOutputStream(bmpHeaderSize + dibHeaderSize);
LittleEndianDataOutputStream stream = new LittleEndianDataOutputStream(out);
// BMP header
stream.writeByte('B');
stream.writeByte('M');
stream.writeInt(pDescription.dataSize + bmpHeaderSize + dibHeaderSize); // Data size + BMP header + DIB header
stream.writeShort(0x0); // Reserved
stream.writeShort(0x0); // Reserved
stream.writeInt(bmpHeaderSize + dibHeaderSize); // Image offset
// DIB header
stream.writeInt(dibHeaderSize); // DIB header size
stream.writeShort(pDescription.width);
stream.writeShort(pDescription.height);
stream.writeShort(1); // Planes, only legal value: 1
stream.writeShort(pDescription.depth); // Bit depth
return new ByteArrayInputStream(out.toByteArray());
}
}

View File

@@ -0,0 +1,64 @@
/*
* 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.pict;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
/**
* Abstract base class for a stateless image decompressor, for use by {@link QuickTime}.
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: QTDecompressor.java,v 1.0 Feb 16, 2009 7:21:27 PM haraldk Exp$
*/
abstract class QTDecompressor {
/**
* Returns wether this decompressor is capable of decompressing the image
* data described by the given image description.
*
* @param pDescription the image description ({@code 'idsc'} Atom).
* @return {@code true} if this decompressor is capable of decompressing
* he data in the given image description, otherwise {@code false}.
*/
public abstract boolean canDecompress(QuickTime.ImageDesc pDescription);
/**
* Decompresses an image.
*
* @param pDescription the image description ({@code 'idsc'} Atom).
* @param pStream the image data stream
* @return the decompressed image
*
* @throws java.io.IOException if an I/O exception occurs during reading.
*/
public abstract BufferedImage decompress(QuickTime.ImageDesc pDescription, InputStream pStream) throws IOException;
}

View File

@@ -0,0 +1,51 @@
/*
* 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.pict;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
/**
* QTGenericDecompressor
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: QTGenericDecompressor.java,v 1.0 Feb 16, 2009 9:26:13 PM haraldk Exp$
*/
final class QTGenericDecompressor extends QTDecompressor {
public boolean canDecompress(final QuickTime.ImageDesc pDescription) {
return true;
}
public BufferedImage decompress(final QuickTime.ImageDesc pDescription, final InputStream pStream) throws IOException {
return ImageIO.read(pStream);
}
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.pict;
import javax.imageio.IIOException;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.*;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* QTRAWDecompressor
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: QTRAWDecompressor.java,v 1.0 Feb 16, 2009 9:29:18 PM haraldk Exp$
*/
final class QTRAWDecompressor extends QTDecompressor {
// TODO: Create a RAWImageReader for ImageIO to delegate to?
// - Would have to require a parameter controlling bit depth and pixel layout
// - Have a look at com.sun.media.imageio.stream.RawImageInputStream...
// TODO: Support different bit depths
public boolean canDecompress(final QuickTime.ImageDesc pDescription) {
return QuickTime.VENDOR_APPLE.equals(pDescription.compressorVendor)
&& "raw ".equals(pDescription.compressorIdentifer)
&& (pDescription.depth == 24 || pDescription.depth == 32);
}
public BufferedImage decompress(final QuickTime.ImageDesc pDescription, final InputStream pStream) throws IOException {
byte[] data = new byte[pDescription.dataSize];
DataInputStream stream = new DataInputStream(pStream);
try {
stream.readFully(data, 0, pDescription.dataSize);
}
finally {
stream.close();
}
DataBuffer buffer = new DataBufferByte(data, data.length);
WritableRaster raster;
// TODO: Depth parameter can be 1-32 (color) or 33-40 (gray scale)
switch (pDescription.depth) {
case 40: // 8 bit gray (untested)
raster = Raster.createInterleavedRaster(
buffer,
pDescription.width, pDescription.height,
pDescription.width, 1,
new int[] {0},
null
);
break;
case 24: // 24 bit RGB
raster = Raster.createInterleavedRaster(
buffer,
pDescription.width, pDescription.height,
pDescription.width * 3, 3,
new int[] {0, 1, 2},
null
);
break;
case 32: // 32 bit ARGB
// WORKAROUND: There is a bug in the way Java 2D interprets the band offsets in
// Raster.createInterleavedRaster (see below) before Java 6. So, instead of
// passing a correct offset array below, we swap channel 1 & 3 to make it ABGR...
for (int y = 0; y < pDescription.height; y++) {
for (int x = 0; x < pDescription.width; x++) {
int offset = 4 * y * pDescription.width + x * 4;
byte temp = data[offset + 1];
data[offset + 1] = data[offset + 3];
data[offset + 3] = temp;
}
}
raster = Raster.createInterleavedRaster(
buffer,
pDescription.width, pDescription.height,
pDescription.width * 4, 4,
new int[] {3, 2, 1, 0}, // B & R mixed up. {1, 2, 3, 0} is correct
null
);
break;
default:
throw new IIOException("Unsupported RAW depth: " + pDescription.depth);
}
ColorModel cm = new ComponentColorModel(
pDescription.depth <= 32 ? ColorSpace.getInstance(ColorSpace.CS_sRGB) : ColorSpace.getInstance(ColorSpace.CS_GRAY),
pDescription.depth == 32,
false,
pDescription.depth == 32 ? Transparency.TRANSLUCENT : Transparency.OPAQUE,
DataBuffer.TYPE_BYTE
);
return new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
}
}

View File

@@ -0,0 +1,108 @@
/*
* 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.pict;
import java.awt.image.*;
import java.awt.*;
/**
* QuickDraw constants.
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: QuickDraw.java,v 1.0 Oct 9, 2007 1:15:09 AM haraldk Exp$
*/
interface QuickDraw {
// Reversed from default BufferedImage.TYPE_BYTE_BINARY
IndexColorModel MONOCHROME = new IndexColorModel(1, 2, new int[] {0xffffff, 0x00000000}, 0, false, -1, DataBuffer.TYPE_BYTE);
/** QuickDraw {@code white} pattern */
Pattern WHITE = new BitMapPattern(Color.WHITE);
/** QuickDraw {@code black} pattern */
Pattern BLACK = new BitMapPattern(Color.BLACK);
/** QuickDraw {@code gray} pattern */
Pattern GRAY = new BitMapPattern(0xAA55AA55);
/** QuickDraw {@code ltGray} pattern */
Pattern LIGT_GRAY = new BitMapPattern(0x88228822);
/** QuickDraw {@code dkGray} pattern */
Pattern DARK_GRAY = new BitMapPattern(0x77DD77DD);
// Boolean Transfer modes.
// http://developer.apple.com/documentation/mac/quickdraw/QuickDraw-196.html#HEADING196-2
// http://developer.apple.com/documentation/mac/quickdraw/QuickDraw-269.html#HEADING269-2
// See http://developer.apple.com/documentation/mac/quickdraw/QuickDraw-199.html#HEADING199-76 for color!
int SRC_COPY = 0;
int SRC_OR = 1;
int SRC_XOR = 2;
int SRC_BIC = 3;
int NOT_SRC_COPY = 4;
int NOT_SRC_OR = 5;
int NOT_SRC_XOR = 6;
int NOT_SRC_BIC = 7;
int PAT_COPY = 8;
int PAT_OR = 9;
int PAT_XOR = 10;
int PAT_BIC = 11;
int NOT_PAT_COPY = 12;
int NOT_PAT_OR = 13;
int NOT_PAT_XOR = 14;
int NOT_PAT_BIC = 15;
int DITHER_COPY = 64; // Add to src mode for dither
int HILITE = 50; // Add to src or pattern mode for highlight
// Arithmetic Transfer Modes
// http://developer.apple.com/documentation/mac/quickdraw/QuickDraw-199.html#HEADING199-112
int BLEND = 32; // dest = source weight/65,535 + destination (1 - weight/65,535)
int ADD_PIN = 33;
int ADD_OVER = 34;
int SUB_PIN = 35;
int TRANSPARENT = 36;
int AD_MAX = 37;
int SUB_OVER = 38;
int AD_MIN = 39;
int GRAYISH_TEXT_OR = 49;
// int MASK = 64; // ?! From K<>ry's code..
/*
* Text face masks.
*/
int TX_BOLD_MASK = 1;
int TX_ITALIC_MASK = 2;
int TX_UNDERLINE_MASK = 4;
int TX_OUTLINE_MASK = 8;
int TX_SHADOWED_MASK = 16;
int TX_CONDENSED_MASK = 32;
int TX_EXTENDED_MASK = 64;
}

View File

@@ -0,0 +1,258 @@
/*
* 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.pict;
import com.twelvemonkeys.imageio.util.IIOUtil;
import javax.imageio.IIOException;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
import java.io.DataInput;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
/**
* QuickTime
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author <a href="mailto:matthias.wiesmann@a3.epfl.ch">Matthias Wiesmann</a> (original embedded QuickTime parsing)
* @author last modified by $Author: haraldk$
* @version $Id: QT.java,v 1.0 Feb 16, 2009 7:20:59 PM haraldk Exp$
*/
final class QuickTime {
public static final String VENDOR_APPLE = "appl";
// TODO: Consider SPI for this in the future, however not very likely
private static final List<QTDecompressor> sDecompressors = Arrays.asList(
new QTBMPDecompressor(),
new QTRAWDecompressor(),
// The GenericDecompressor must be the last in the list
new QTGenericDecompressor()
);
/*
Apple compressor id's (vendor 'appl'):
http://developer.apple.com/DOCUMENTATION/quicktime/Reference/QTRef_Constants/Reference/reference.html
kAnimationCodecType ='rle '
kAVRJPEGCodecType ='avr '
kBaseCodecType ='base'
kBMPCodecType ='WRLE' -> BMP without header, SUPPORTED
kCinepakCodecType ='cvid'
kCloudCodecType ='clou'
kCMYKCodecType ='cmyk' -> Is this raw CMYK data?
kComponentVideoCodecType ='yuv2'
kComponentVideoSigned ='yuvu'
kComponentVideoUnsigned ='yuvs'
kDVCNTSCCodecType ='dvc '
kDVCPALCodecType ='dvcp'
kDVCProNTSCCodecType ='dvpn'
kDVCProPALCodecType ='dvpp'
kFireCodecType ='fire'
kFLCCodecType ='flic'
k48RGBCodecType ='b48r' -> 48 bit (12 bpp) raw color data?
kGIFCodecType ='gif ' -> GIF, should work, but lacks test data
kGraphicsCodecType ='smc '
kH261CodecType ='h261'
kH263CodecType ='h263'
kIndeo4CodecType ='IV41'
kJPEGCodecType ='jpeg' -> JPEG, SUPPORTED
kMacPaintCodecType ='PNTG' -> Isn't this the PICT format itself? Does that make sense?! ;-)
kMicrosoftVideo1CodecType ='msvc'
kMotionJPEGACodecType ='mjpa'
kMotionJPEGBCodecType ='mjpb'
kMpegYUV420CodecType ='myuv'
kOpenDMLJPEGCodecType ='dmb1'
kPhotoCDCodecType ='kpcd' -> Could potentially use JMagick/JUI plugin
kPlanarRGBCodecType ='8BPS' -> Use (parts of) Photoshop plugin?
kPNGCodecType ='png ' -> PNG, SUPPORTED
kQuickDrawCodecType ='qdrw' -> QD?
kQuickDrawGXCodecType ='qdgx' -> QD?
kRawCodecType ='raw ' -> Raw (A)RGB pixel data
kSGICodecType ='.SGI'
k16GrayCodecType ='b16g' -> Raw 16 bit gray data?
k64ARGBCodecType ='b64a' -> Raw 64 bit (16 bpp) color data?
kSorensonCodecType ='SVQ1'
kSorensonYUV9CodecType ='syv9'
kTargaCodecType ='tga ' -> TGA, maybe create a plugin for that
k32AlphaGrayCodecType ='b32a' -> 16 bit gray + 16 bit alpha raw data?
kTIFFCodecType ='tiff' -> TIFF, SUPPORTED
kVectorCodecType ='path'
kVideoCodecType ='rpza'
kWaterRippleCodecType ='ripl'
kWindowsRawCodecType ='WRAW' -> Raw pixels with reverse byte order ((A)BGR vs (A)RGB)?
kYUV420CodecType ='y420'
*/
/**
* Gets a decompressor that can decompress the described data.
*
* @param pDescription the image description ({@code 'idsc'} Atom).
* @return a decompressor that can decompress data decribed by the given {@link ImageDesc description},
* or {@code null} if no decompressor is found
*/
private static QTDecompressor getDecompressor(final ImageDesc pDescription) {
for (QTDecompressor decompressor : sDecompressors) {
if (decompressor.canDecompress(pDescription)) {
return decompressor;
}
}
return null;
}
/**
* Decompresses the QuickTime image data from the given stream.
*
* @param pStream the image input stream
* @return a {@link BufferedImage} containing the image data, or {@code null} if no decompressor is capable of
* decompressing the image.
* @throws IOException if an I/O exception occurs during read
*/
public static BufferedImage decompress(final ImageInputStream pStream) throws IOException {
ImageDesc description = ImageDesc.read(pStream);
if (PICTImageReader.DEBUG) {
System.out.println(description);
}
QTDecompressor decompressor = getDecompressor(description);
if (decompressor == null) {
return null;
}
InputStream streamAdapter = IIOUtil.createStreamAdapter(pStream, description.dataSize);
try {
return decompressor.decompress(description, streamAdapter);
}
finally {
streamAdapter.close();
}
}
/**
* Class representing the {@code 'idsc'} QuickTime Atom.
*/
static final class ImageDesc /*extends QTAtom*/ {
private static final int SIZE = 86;
// 'idsc' Atom size
int size;
String compressorIdentifer;
short version;
short revision;
String compressorVendor;
int temporalQuality;
int spatialQuality;
int width;
int height;
double horizontalRes;
double verticalRes;
// Size of image data following 'idsc'
int dataSize;
int frameCount;
String compressorName;
short depth;
short colorLUTId;
byte[] extraDesc;
private ImageDesc() {}
public static ImageDesc read(final DataInput pStream) throws IOException {
// The following looks like the 'idsc' Atom (as described in the QuickTime File Format)
ImageDesc description = new ImageDesc();
description.size = pStream.readInt();
description.compressorIdentifer = PICTUtil.readIdString(pStream);
pStream.skipBytes(4); // Reserved, should be 0
pStream.skipBytes(2); // Reserved, should be 0
pStream.skipBytes(2); // Reserved, should be 0
description.version = pStream.readShort(); // Major version, 0 if not applicable
description.revision = pStream.readShort(); // Minor version, 0 if not applicable
description.compressorVendor = PICTUtil.readIdString(pStream);
description.temporalQuality = pStream.readInt(); // Temporal quality, 0 means "no temporal compression"
description.spatialQuality = pStream.readInt(); // Spatial quality, 0x0000 0200 is codecNormalQuality
description.width = pStream.readShort(); // Width (short)
description.height = pStream.readShort(); // Height (short)
description.horizontalRes = PICTUtil.readFixedPoint(pStream); // Horizontal resolution, FP, 0x0048 0000 means 72 DPI
description.verticalRes = PICTUtil.readFixedPoint(pStream); // Vertical resolution, FP, 0x0048 0000 means 72 DPI
// TODO: Handle 0 data size as unknown
description.dataSize = pStream.readInt(); // Data size, may be 0, if unknown
description.frameCount = pStream.readShort(); // Frame count
description.compressorName = PICTUtil.readStr31(pStream); // Compresor name, 32 byte null-terminated Pascal String
description.depth = pStream.readShort(); // Image bit depth
description.colorLUTId = pStream.readShort(); // Color Lookup Table Id, -1 means none
int extraDescSize = description.size - ImageDesc.SIZE;
if (extraDescSize < 0) {
throw new IIOException("Negative array size in 'idsc' Atom: " + extraDescSize);
}
description.extraDesc = new byte[extraDescSize];
pStream.readFully(description.extraDesc);
return description;
}
@Override
public String toString() {
return String.format("'idsc', size: %s, id: '%s', ver: %s, rev: %s, vendor: '%s', " +
// "tempQ: %s, spatQ: %s, " +
"w: %d, h: %d, " +
// "horiz: %s, vert: %s, " +
"data-size: %d, frame-count: %s, " +
"name: '%s', depth: %d, lut: %s, extra: %d",
size, compressorIdentifer, version, revision, compressorVendor,
// temporalQuality, spatialQuality,
width, height,
// horizontalRes, verticalRes,
dataSize, frameCount,
compressorName, depth,
colorLUTId, extraDesc != null ? extraDesc.length : 0
);
}
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.pict;
import java.awt.*;
/**
* RGBColor
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: RGBColor.java,v 1.0 Mar 2, 2009 10:39:24 AM haraldk Exp$
*/
class RGBColor extends Color {
// TODO: Is the 16 bit resolution ever significant?
public RGBColor(short r, short g, short b) {
super((r & 0xffff) / (float) 0xffff, (g & 0xffff) / (float) 0xffff, (b & 0xffff) / (float) 0xffff);
}
}

View File

@@ -0,0 +1,225 @@
package com.twelvemonkeys.imageio.plugins.pict;
import com.twelvemonkeys.image.BufferedImageIcon;
import com.twelvemonkeys.image.ImageUtil;
import com.twelvemonkeys.net.MIMEUtil;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.*;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* TestPICTClippingApp
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: TestPICTClippingApp.java,v 1.0 Feb 16, 2009 3:05:16 PM haraldk Exp$
*/
public class TestPICTClippingApp {
public static void main(final String[] pArgs) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception ignore) {
}
JFrame frame = new JFrame("PICTClipping test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel dropZone = new JLabel("Drop images here", JLabel.CENTER) {
@Override
public Dimension getPreferredSize() {
return new Dimension(320, 200);
}
};
dropZone.setTransferHandler(new ImageDropHandler(dropZone));
frame.add(dropZone);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
private static class ImageDropHandler extends TransferHandler {
private final JLabel mLabel;
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
public ImageDropHandler(JLabel pLabel) {
super(null);
mLabel = pLabel;
}
private DataFlavor getSupportedFlavor(final DataFlavor[] transferFlavors) {
for (DataFlavor flavor : transferFlavors) {
String type = MIMEUtil.bareMIME(flavor.getMimeType());
if (InputStream.class.isAssignableFrom(flavor.getDefaultRepresentationClass()) && ImageIO.getImageReadersByMIMEType(type).hasNext()) {
return flavor;
}
else if (flavor.equals(DataFlavor.javaFileListFlavor)) {
return flavor;
}
}
for (DataFlavor flavor : transferFlavors) {
System.err.printf("flavor: %s%n", flavor);
}
return null;
}
@Override
public boolean canImport(final JComponent comp, final DataFlavor[] transferFlavors) {
return getSupportedFlavor(transferFlavors) != null;
}
@Override
public boolean importData(JComponent comp, Transferable t) {
DataFlavor[] flavors = t.getTransferDataFlavors();
DataFlavor flavor = getSupportedFlavor(flavors);
if (flavor != null) {
try {
InputStream input;
if (DataFlavor.javaFileListFlavor.equals(flavor)) {
List files = (List) t.getTransferData(flavor);
if (files.isEmpty()) {
return false;
}
else {
input = new FileInputStream((File) files.get(0));
}
}
else {
Object data = t.getTransferData(flavor);
input = (InputStream) data;
}
final ImageInputStream stream = ImageIO.createImageInputStream(input);
Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);
if (!readers.hasNext()) {
String mimeType = MIMEUtil.bareMIME(flavor.getMimeType());
System.out.printf("Getting reader by MIME type (%s)...%n", mimeType);
readers = ImageIO.getImageReadersByMIMEType(mimeType);
}
if (readers.hasNext()) {
final ImageReader imageReader = readers.next();
mExecutor.execute(new Runnable() {
public void run() {
try {
readAndInstallImage(stream, imageReader);
}
catch (IOException e) {
e.printStackTrace();
}
}
});
return true;
}
else {
System.err.println("No reader found!");
}
}
catch (UnsupportedFlavorException ignore) {
ignore.printStackTrace();
}
catch (IOException ignore) {
ignore.printStackTrace();
}
catch (RuntimeException e) {
e.printStackTrace();
throw e;
}
}
return false;
}
private void readAndInstallImage(final ImageInputStream pStream, final ImageReader reader) throws IOException {
reader.setInput(pStream);
final int maxDimension = 200;
int w = reader.getWidth(0);
int h = reader.getHeight(0);
ImageReadParam param = null;
if (w > maxDimension && h > maxDimension) {
int sub = (int) Math.ceil((Math.max(w, h) / (double) maxDimension) / 3.0);
if (sub > 1) {
param = reader.getDefaultReadParam();
param.setSourceSubsampling(sub, sub, 0, 0);
}
}
System.out.printf("Reading %s format%s... ", reader.getFormatName(), (param != null ? ", sampling every " + param.getSourceXSubsampling() + "th pixel" : ""));
final BufferedImage image = reader.read(0, param);
System.out.printf("Done (%dx%d).%n", image.getWidth(), image.getHeight());
reader.dispose();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.out.print("Scaling image... ");
BufferedImage scaled = box(image, maxDimension);
System.out.printf("Done (%dx%d).%n", scaled.getWidth(), scaled.getHeight());
mLabel.setIcon(new BufferedImageIcon(scaled));
}
});
}
private BufferedImage box(final BufferedImage pImage, final int pMaxDimension) {
// TODO: ImageUtil.toRGB method? ColorConvertOp MUCH faster than ImageUtil.toBuffered(img, type)
BufferedImage image = pImage;
if (image.getType() == 0) {
try {
ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null);
image = op.filter(image, new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_4BYTE_ABGR_PRE));
}
catch (Exception e) {
e.printStackTrace();
image = ImageUtil.accelerate(image);
}
}
if (image.getWidth() > pMaxDimension || image.getHeight() > pMaxDimension) {
int w, h;
if (image.getWidth() > image.getHeight()) {
w = pMaxDimension;
h = (int) Math.round(w / (image.getWidth() / (double) image.getHeight()));
}
else {
h = pMaxDimension;
w = (int) Math.round(h * (image.getWidth() / (double) image.getHeight()));
}
return ImageUtil.createResampled(image, w, h, Image.SCALE_DEFAULT);
}
return image;
}
}
}

View File

@@ -0,0 +1,26 @@
package com.twelvemonkeys.imageio.plugins.pict;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
/**
* TestPICTEagerDetect
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: TestPICTEagerDetect.java,v 1.0 Aug 6, 2009 2:59:41 PM haraldk Exp$
*/
public class TestPICTEagerDetect {
public static void main(final String[] pArgs) throws IOException {
PICTImageReaderSpi provider = new PICTImageReaderSpi();
if (pArgs.length == 0) {
System.exit(1);
}
for (String arg : pArgs) {
boolean canDecode = provider.canDecodeInput(ImageIO.createImageInputStream(new File(arg)));
System.err.printf("canDecode %s: %s%n", arg, canDecode);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
com.twelvemonkeys.imageio.plugins.pict.PICTImageReaderSpi

View File

@@ -0,0 +1 @@
com.twelvemonkeys.imageio.plugins.pict.PICTImageWriterSpi

View File

@@ -0,0 +1,70 @@
package com.twelvemonkeys.imageio.plugins.pict;
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTestCase;
import javax.imageio.spi.ImageReaderSpi;
import java.awt.*;
import java.io.IOException;
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 PICTImageReaderTestCase extends ImageReaderAbstractTestCase<PICTImageReader> {
static ImageReaderSpi sProvider = new PICTImageReaderSpi();
// TODO: Should also test the clipboard format (without 512 byte header)
protected List<TestData> getTestData() {
return Arrays.asList(
new TestData(getClassLoaderResource("/pict/test.pct"), new Dimension(300, 200)),
new TestData(getClassLoaderResource("/pict/food.pct"), new Dimension(146, 194)),
new TestData(getClassLoaderResource("/pict/carte.pict"), new Dimension(782, 598)),
// Embedded QuickTime image... Should at least include the embedded fallback text
new TestData(getClassLoaderResource("/pict/u2.pict"), new Dimension(160, 159)),
// Obsolete V2 format with weird header
new TestData(getClassLoaderResource("/pict/FLAG_B24.PCT"), new Dimension(124, 124)),
// 1000 DPI with bounding box not matching DPI
new TestData(getClassLoaderResource("/pict/oom.pict"), new Dimension(1713, 1263))
);
}
protected ImageReaderSpi createProvider() {
return sProvider;
}
@Override
protected PICTImageReader createReader() {
return new PICTImageReader(sProvider);
}
protected Class<PICTImageReader> getReaderClass() {
return PICTImageReader.class;
}
protected List<String> getFormatNames() {
return Arrays.asList("pict");
}
protected List<String> getSuffixes() {
return Arrays.asList("pct", "pict");
}
protected List<String> getMIMETypes() {
return Arrays.asList("image/pict", "image/x-pict");
}
public void testProviderNotMatchJPEG() throws IOException {
// This JPEG contains PICT magic bytes at locations a PICT would normally have them.
// We should not claim to be able read it.
assertFalse(sProvider.canDecodeInput(new TestData(
getClassLoaderResource("/jpeg/R-7439-1151526181.jpeg"),
new Dimension(386, 396)
)));
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.