You are viewing a plain text version of this content. The canonical link for it is here.
Posted to sanselan-commits@incubator.apache.org by cm...@apache.org on 2008/07/27 21:34:37 UTC
svn commit: r680193 - in /incubator/sanselan/trunk: ./
src/main/java/org/apache/sanselan/ src/main/java/org/apache/sanselan/common/
src/main/java/org/apache/sanselan/formats/gif/
src/main/java/org/apache/sanselan/formats/png/ src/main/java/org/apache/s...
Author: cmchen
Date: Sun Jul 27 14:34:36 2008
New Revision: 680193
URL: http://svn.apache.org/viewvc?rev=680193&view=rev
Log:
* Added ability to embed XMP XML when writing the following formats: GIF, PNG, TIFF.
Added:
incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/xmp/XmpUpdateTest.java (with props)
Modified:
incubator/sanselan/trunk/RELEASE_NOTES
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/SanselanConstants.java
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibInflater.java
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/gif/GenericGIFBlock.java
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/gif/GifImageParser.java
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngConstants.java
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngWriter.java
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunkiCCP.java
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunkiTXt.java
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunkzTXt.java
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterBase.java
Modified: incubator/sanselan/trunk/RELEASE_NOTES
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/RELEASE_NOTES?rev=680193&r1=680192&r2=680193&view=diff
==============================================================================
--- incubator/sanselan/trunk/RELEASE_NOTES (original)
+++ incubator/sanselan/trunk/RELEASE_NOTES Sun Jul 27 14:34:36 2008
@@ -15,6 +15,7 @@
Release 0.95
------------
+ * Added ability to embed XMP XML when writing the following formats: GIF, PNG, TIFF.
* Improved handling of tEXt and zTXt PNG text blocks.
* Added XMP XML extraction for the following formats: GIF (untested), JPEG, TIFF, PNG, PSD.
* Added RELEASE_NOTES file (this file).
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/SanselanConstants.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/SanselanConstants.java?rev=680193&r1=680192&r2=680193&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/SanselanConstants.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/SanselanConstants.java Sun Jul 27 14:34:36 2008
@@ -22,67 +22,87 @@
public interface SanselanConstants
{
- /**
- * Parameter key. Applies to read and write operations.
+ /**
+ * Parameter key. Applies to read and write operations.
* <p>
* Valid values: Boolean.TRUE and Boolean.FALSE.
*/
public static final String PARAM_KEY_VERBOSE = "VERBOSE";
- /**
- * Parameter key. Used to hint the filename when reading from a byte array or InputStream.
- * The filename hint can help disambiguate what file the image format.
+ /**
+ * Parameter key. Used to hint the filename when reading from a byte array
+ * or InputStream. The filename hint can help disambiguate what file the
+ * image format.
* <p>
* Applies to read operations.
* <p>
* Valid values: filename as string
* <p>
+ *
* @see InputStream
*/
public static final String PARAM_KEY_FILENAME = "FILENAME";
- /**
- * Parameter key. Used in write operations to indicate desired image format.
+ /**
+ * Parameter key. Used in write operations to indicate desired image format.
* <p>
- * Valid values: Any format defined in ImageFormat, such as ImageFormat.IMAGE_FORMAT_PNG.
+ * Valid values: Any format defined in ImageFormat, such as
+ * ImageFormat.IMAGE_FORMAT_PNG.
* <p>
+ *
* @see ImageFormat
*/
public static final String PARAM_KEY_FORMAT = "FORMAT";
- /**
- * Parameter key. Used in write operations to indicate desired compression algorithm.
+ /**
+ * Parameter key. Used in write operations to indicate desired compression
+ * algorithm.
* <p>
* Currently only applies to writing TIFF image files.
* <p>
- * Valid values: TiffConstants.TIFF_COMPRESSION_UNCOMPRESSED, TiffConstants.TIFF_COMPRESSION_LZW, TiffConstants.TIFF_COMPRESSION_PACKBITS.
+ * Valid values: TiffConstants.TIFF_COMPRESSION_UNCOMPRESSED,
+ * TiffConstants.TIFF_COMPRESSION_LZW,
+ * TiffConstants.TIFF_COMPRESSION_PACKBITS.
* <p>
+ *
* @see TiffConstants
*/
public static final String PARAM_KEY_COMPRESSION = "COMPRESSION";
public static final String BUFFERED_IMAGE_FACTORY = "BUFFERED_IMAGE_FACTORY";
- /**
- * Parameter key. Indicates whether to read embedded thumbnails.
+ /**
+ * Parameter key. Indicates whether to read embedded thumbnails.
* <p>
* Only applies to read EXIF metadata from JPEG/JFIF files.
* <p>
* Valid values: Boolean.TRUE and Boolean.FALSE.
* <p>
+ *
* @see TiffConstants
*/
public static final String PARAM_KEY_READ_THUMBNAILS = "READ_THUMBNAILS";
- /**
- * Parameter key. Indicates whether to throw exceptions when parsing
- * invalid files, or whether to tolerate small problems.
+ /**
+ * Parameter key. Indicates whether to throw exceptions when parsing invalid
+ * files, or whether to tolerate small problems.
* <p>
- * Valid values: Boolean.TRUE and Boolean.FALSE.
- * Default value: Boolean.FALSE.
+ * Valid values: Boolean.TRUE and Boolean.FALSE. Default value:
+ * Boolean.FALSE.
* <p>
+ *
* @see TiffConstants
*/
public static final String PARAM_KEY_STRICT = "STRICT";
+ /**
+ * Parameter key.
+ *
+ * Only used when writing images.
+ * <p>
+ * Valid values: String of XMP XML.
+ * <p>
+ */
+ public static final String PARAM_KEY_XMP_XML = "XMP_XML";
+
}
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibInflater.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibInflater.java?rev=680193&r1=680192&r2=680193&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibInflater.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibInflater.java Sun Jul 27 14:34:36 2008
@@ -18,14 +18,14 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.util.zip.DeflaterInputStream;
import java.util.zip.InflaterInputStream;
import org.apache.sanselan.ImageReadException;
public class ZLibInflater extends BinaryFileFunctions
{
- public final byte[] zlibInflate(byte bytes[]) throws ImageReadException,
- IOException
+ public final byte[] inflate(byte bytes[]) throws IOException
// slow, probably.
{
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
@@ -33,4 +33,11 @@
return getStreamBytes(zIn);
}
+ public final byte[] deflate(byte bytes[]) throws IOException
+ {
+ ByteArrayInputStream in = new ByteArrayInputStream(bytes);
+ DeflaterInputStream zIn = new DeflaterInputStream(in);
+ return getStreamBytes(zIn);
+ }
+
}
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/gif/GenericGIFBlock.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/gif/GenericGIFBlock.java?rev=680193&r1=680192&r2=680193&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/gif/GenericGIFBlock.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/gif/GenericGIFBlock.java Sun Jul 27 14:34:36 2008
@@ -34,11 +34,18 @@
public byte[] appendSubBlocks() throws IOException
{
+ return appendSubBlocks(false);
+ }
+
+ public byte[] appendSubBlocks(boolean includeLengths) throws IOException
+ {
ByteArrayOutputStream out = new ByteArrayOutputStream();
for (int i = 0; i < subblocks.size(); i++)
{
byte subblock[] = (byte[]) subblocks.get(i);
+ if(includeLengths && i>0)
+ out.write(subblock.length);
out.write(subblock);
}
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/gif/GifImageParser.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/gif/GifImageParser.java?rev=680193&r1=680192&r2=680193&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/gif/GifImageParser.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/gif/GifImageParser.java Sun Jul 27 14:34:36 2008
@@ -42,6 +42,7 @@
import org.apache.sanselan.common.byteSources.ByteSource;
import org.apache.sanselan.common.mylzw.MyLZWCompressor;
import org.apache.sanselan.common.mylzw.MyLZWDecompressor;
+import org.apache.sanselan.formats.tiff.write.TiffOutputField;
import org.apache.sanselan.palette.Palette;
import org.apache.sanselan.palette.PaletteFactory;
import org.apache.sanselan.util.Debug;
@@ -203,7 +204,6 @@
protected GenericGIFBlock readGenericGIFBlock(InputStream is, int code,
byte first[]) throws ImageReadException, IOException
{
- byte bytes[] = null;
ArrayList subblocks = new ArrayList();
if (first != null)
@@ -211,7 +211,7 @@
while (true)
{
- bytes = readSubBlock(is);
+ byte bytes[] = readSubBlock(is);
if (bytes.length < 1)
break;
subblocks.add(bytes);
@@ -220,12 +220,16 @@
return new GenericGIFBlock(code, subblocks);
}
+ private final static int EXTENSION_CODE = 0x21;
private final static int IMAGE_SEPARATOR = 0x2C;
- private final static int GRAPHIC_CONTROL_EXTENSION = (0x2100 | 0xf9);
+ private final static int GRAPHIC_CONTROL_EXTENSION = (EXTENSION_CODE << 8) | 0xf9;
private final static int COMMENT_EXTENSION = 0xfe;
private final static int PLAIN_TEXT_EXTENSION = 0x01;
private final static int XMP_EXTENSION = 0xff;
private final static int TERMINATOR_BYTE = 0x3b;
+ private final static int APPLICATION_EXTENSION_LABEL = 0xff;
+ private final static int XMP_COMPLETE_CODE = (EXTENSION_CODE << 8)
+ | XMP_EXTENSION;
private ArrayList readBlocks(GIFHeaderInfo ghi, InputStream is,
boolean stopBeforeImageData, FormatCompliance formatCompliance)
@@ -236,7 +240,7 @@
while (true)
{
int code = is.read();
-// this.debugNumber("code: ", code);
+ // this.debugNumber("code: ", code);
switch (code)
{
@@ -247,43 +251,43 @@
ImageDescriptor id = readImageDescriptor(ghi, code, is,
stopBeforeImageData, formatCompliance);
result.add(id);
-// if(stopBeforeImageData)
-// return result;
+ // if(stopBeforeImageData)
+ // return result;
break;
- case 0x21: // extension
+ case EXTENSION_CODE: // extension
{
- int extension_code = is.read();
+ int extensionCode = is.read();
// this.debugNumber("extension_code: ", extension_code);
- int complete_code = ((0xff & code) << 8)
- | (0xff & extension_code);
+ int completeCode = ((0xff & code) << 8)
+ | (0xff & extensionCode);
- switch (extension_code)
+ switch (extensionCode)
{
case 0xf9:
GraphicControlExtension gce = readGraphicControlExtension(
- complete_code, is);
+ completeCode, is);
result.add(gce);
break;
case COMMENT_EXTENSION:
case PLAIN_TEXT_EXTENSION: {
GenericGIFBlock block = readGenericGIFBlock(is,
- complete_code);
+ completeCode);
result.add(block);
break;
}
- case 0xff: // 255 (hex 0xFF) Application Extension Label
+ case APPLICATION_EXTENSION_LABEL: // 255 (hex 0xFF) Application
+ // Extension Label
{
byte label[] = readSubBlock(is);
if (formatCompliance != null)
- formatCompliance.addComment(
- "Unknown Application Extension ("
- + new String(label) + ")",
- complete_code);
+ formatCompliance
+ .addComment("Unknown Application Extension ("
+ + new String(label) + ")", completeCode);
// if (label == new String("ICCRGBG1"))
{
@@ -293,7 +297,7 @@
if ((label != null) && (label.length > 0))
{
GenericGIFBlock block = readGenericGIFBlock(is,
- complete_code, label);
+ completeCode, label);
byte bytes[] = block.appendSubBlocks();
result.add(block);
@@ -305,10 +309,10 @@
if (formatCompliance != null)
formatCompliance.addComment("Unknown block",
- complete_code);
+ completeCode);
GenericGIFBlock block = readGenericGIFBlock(is,
- complete_code);
+ completeCode);
result.add(block);
break;
}
@@ -839,6 +843,13 @@
if (params.containsKey(PARAM_KEY_VERBOSE))
params.remove(PARAM_KEY_VERBOSE);
+ String xmpXml = null;
+ if (params.containsKey(PARAM_KEY_XMP_XML))
+ {
+ xmpXml = (String) params.get(PARAM_KEY_XMP_XML);
+ params.remove(PARAM_KEY_XMP_XML);
+ }
+
if (params.size() > 0)
{
Object firstKey = params.keySet().iterator().next();
@@ -926,7 +937,7 @@
if (hasAlpha)
{ // write GraphicControlExtension
- bos.write((byte) 0x21);
+ bos.write(EXTENSION_CODE);
bos.write((byte) 0xf9);
// bos.write(0xff & (kGraphicControlExtension >> 8));
// bos.write(0xff & (kGraphicControlExtension >> 0));
@@ -942,6 +953,25 @@
bos.write((byte) 0); // terminator
}
+ if (null != xmpXml)
+ {
+ bos.write(EXTENSION_CODE);
+ bos.write(APPLICATION_EXTENSION_LABEL);
+
+ bos.write(XMP_APPLICATION_ID_AND_AUTH_CODE.length); // 0x0B
+ bos.write(XMP_APPLICATION_ID_AND_AUTH_CODE);
+
+ byte xmpXmlBytes[] = xmpXml.getBytes("utf-8");
+ bos.write(xmpXmlBytes);
+
+ // write "magic trailer"
+ for (int magic = 0; magic <= 0xff; magic++)
+ bos.write(0xff - magic);
+
+ bos.write((byte) 0); // terminator
+
+ }
+
{ // Image Descriptor.
bos.write(IMAGE_SEPARATOR);
bos.write2Bytes(0); // Image Left Position
@@ -1079,58 +1109,66 @@
FormatCompliance formatCompliance = null;
GIFHeaderInfo ghi = readHeader(is, formatCompliance);
-
byte globalColorTable[] = null;
if (ghi.globalColorTableFlag)
globalColorTable = readColorTable(is,
ghi.sizeOfGlobalColorTable, formatCompliance);
-
+
ArrayList blocks = readBlocks(ghi, is, true, formatCompliance);
List result = new ArrayList();
for (int i = 0; i < blocks.size(); i++)
{
GIFBlock block = (GIFBlock) blocks.get(i);
- if (block.blockCode != XMP_EXTENSION)
+ if (block.blockCode != XMP_COMPLETE_CODE)
continue;
GenericGIFBlock genericBlock = (GenericGIFBlock) block;
- byte blockBytes[] = genericBlock.appendSubBlocks();
+ byte blockBytes[] = genericBlock.appendSubBlocks(true);
if (blockBytes.length < XMP_APPLICATION_ID_AND_AUTH_CODE.length)
continue;
+
+ // this.debugByteArray("blockBytes", blockBytes);
+
if (!compareByteArrays(blockBytes, 0,
XMP_APPLICATION_ID_AND_AUTH_CODE, 0,
XMP_APPLICATION_ID_AND_AUTH_CODE.length))
continue;
-
-// this.debugByteArray("xmp block bytes", blockBytes);
+
+ // this.debugByteArray("xmp block bytes", blockBytes);
byte GIF_MAGIC_TRAILER[] = new byte[256];
- for(int magic=0;magic<=0xff;magic++)
- GIF_MAGIC_TRAILER[magic] = (byte) (0xff-magic);
-
- if (blockBytes.length < XMP_APPLICATION_ID_AND_AUTH_CODE.length + GIF_MAGIC_TRAILER.length)
+ for (int magic = 0; magic <= 0xff; magic++)
+ GIF_MAGIC_TRAILER[magic] = (byte) (0xff - magic);
+
+ if (blockBytes.length < XMP_APPLICATION_ID_AND_AUTH_CODE.length
+ + GIF_MAGIC_TRAILER.length)
continue;
- if (!compareByteArrays(blockBytes, blockBytes.length-GIF_MAGIC_TRAILER.length,
- GIF_MAGIC_TRAILER, 0,
+ if (!compareByteArrays(blockBytes, blockBytes.length
+ - GIF_MAGIC_TRAILER.length, GIF_MAGIC_TRAILER, 0,
GIF_MAGIC_TRAILER.length))
- throw new ImageReadException("XMP block in GIF missing magic trailer.");
-
+ throw new ImageReadException(
+ "XMP block in GIF missing magic trailer.");
+
try
{
// XMP is UTF-8 encoded xml.
- String xml = new String(blockBytes, XMP_APPLICATION_ID_AND_AUTH_CODE.length, blockBytes.length
- - (XMP_APPLICATION_ID_AND_AUTH_CODE.length + GIF_MAGIC_TRAILER.length), "utf-8");
+ String xml = new String(
+ blockBytes,
+ XMP_APPLICATION_ID_AND_AUTH_CODE.length,
+ blockBytes.length
+ - (XMP_APPLICATION_ID_AND_AUTH_CODE.length + GIF_MAGIC_TRAILER.length),
+ "utf-8");
result.add(xml);
} catch (UnsupportedEncodingException e)
{
throw new ImageReadException("Invalid XMP Block in GIF.");
}
}
-
- if(result.size()<1)
+
+ if (result.size() < 1)
return null;
- if(result.size()>1)
+ if (result.size() > 1)
throw new ImageReadException("More than one XMP Block in GIF.");
return (String) result.get(0);
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngConstants.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngConstants.java?rev=680193&r1=680192&r2=680193&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngConstants.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngConstants.java Sun Jul 27 14:34:36 2008
@@ -23,18 +23,11 @@
public static final int COMPRESSION_DEFLATE_INFLATE = 0;
- public final static byte[] IHDR_CHUNK_TYPE = new byte[]{
- 73, 72, 68, 82
- };
- public final static byte[] PLTE_CHUNK_TYPE = new byte[]{
- 80, 76, 84, 69
- };
- public final static byte[] IEND_CHUNK_TYPE = new byte[]{
- 73, 69, 78, 68
- };
- public final static byte[] IDAT_CHUNK_TYPE = new byte[]{
- 73, 68, 65, 84
- };
+ public final static byte[] IHDR_CHUNK_TYPE = new byte[] { 73, 72, 68, 82 };
+ public final static byte[] PLTE_CHUNK_TYPE = new byte[] { 80, 76, 84, 69 };
+ public final static byte[] IEND_CHUNK_TYPE = new byte[] { 73, 69, 78, 68 };
+ public final static byte[] IDAT_CHUNK_TYPE = new byte[] { 73, 68, 65, 84 };
+ public final static byte[] iTXt_CHUNK_TYPE = new byte[] { 105, 84, 88, 116 };
public final static int IEND = PngImageParser.CharsToQuad('I', 'E', 'N',
'D');
@@ -57,22 +50,21 @@
public final static int gAMA = PngImageParser.CharsToQuad('g', 'A', 'M',
'A');
public final static int sRGB = PngImageParser.CharsToQuad('s', 'R', 'G',
- 'B');
-
+ 'B');
+
// XMP chunk type.
public final static int iTXt = PngImageParser.CharsToQuad('i', 'T', 'X',
- 't');
+ 't');
- public static final byte PNG_Signature[] = {
- (byte) 137, 80, 78, 71, 13, 10, 26, 10,
- };
+ public static final byte PNG_Signature[] = { (byte) 137, 80, 78, 71, 13,
+ 10, 26, 10, };
public static final String PARAM_KEY_PNG_BIT_DEPTH = "PNG_BIT_DEPTH";
public static final String PARAM_KEY_PNG_FORCE_INDEXED_COLOR = "PNG_FORCE_INDEXED_COLOR";
public static final String PARAM_KEY_PNG_FORCE_TRUE_COLOR = "PNG_FORCE_TRUE_COLOR";
- // public static final Object PARAM_KEY_PNG_BIT_DEPTH_YES = "YES";
- // public static final Object PARAM_KEY_PNG_BIT_DEPTH_NO = "NO";
+ // public static final Object PARAM_KEY_PNG_BIT_DEPTH_YES = "YES";
+ // public static final Object PARAM_KEY_PNG_BIT_DEPTH_NO = "NO";
public static final int COLOR_TYPE_GREYSCALE = 0;
public static final int COLOR_TYPE_TRUE_COLOR = 2;
@@ -93,19 +85,27 @@
public static final byte FILTER_TYPE_PAETH = 4;
/*
- Background colour Solid background colour to be used when presenting the image if no better option is available.
- Gamma and chromaticity Gamma characteristic of the image with respect to the desired output intensity, and chromaticity characteristics of the RGB values used in the image.
- ICC profile Description of the colour space (in the form of an International Color Consortium (ICC) profile) to which the samples in the image conform.
- Image histogram Estimates of how frequently the image uses each palette entry.
- Physical pixel dimensions Intended pixel size and aspect ratio to be used in presenting the PNG image.
- Significant bits The number of bits that are significant in the samples.
- sRGB colour space A rendering intent (as defined by the International Color Consortium) and an indication that the image samples conform to this colour space.
- Suggested palette A reduced palette that may be used when the display device is not capable of displaying the full range of colours in the image.
- Textual data Textual information (which may be compressed) associated with the image.
- Time The time when the PNG image was last modified.
- Transparency Alpha information that allows the reference image to be reconstructed when the alpha channel is not retained in the PNG image.
+ * Background colour Solid background colour to be used when presenting the
+ * image if no better option is available. Gamma and chromaticity Gamma
+ * characteristic of the image with respect to the desired output intensity,
+ * and chromaticity characteristics of the RGB values used in the image. ICC
+ * profile Description of the colour space (in the form of an International
+ * Color Consortium (ICC) profile) to which the samples in the image
+ * conform. Image histogram Estimates of how frequently the image uses each
+ * palette entry. Physical pixel dimensions Intended pixel size and aspect
+ * ratio to be used in presenting the PNG image. Significant bits The number
+ * of bits that are significant in the samples. sRGB colour space A
+ * rendering intent (as defined by the International Color Consortium) and
+ * an indication that the image samples conform to this colour space.
+ * Suggested palette A reduced palette that may be used when the display
+ * device is not capable of displaying the full range of colours in the
+ * image. Textual data Textual information (which may be compressed)
+ * associated with the image. Time The time when the PNG image was last
+ * modified. Transparency Alpha information that allows the reference image
+ * to be reconstructed when the alpha channel is not retained in the PNG
+ * image.
*/
-
- public final String XMP_KEYWORD = "XML:com.adobe.xmp";
+
+ public final String XMP_KEYWORD = "XML:com.adobe.xmp";
}
\ No newline at end of file
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngWriter.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngWriter.java?rev=680193&r1=680192&r2=680193&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngWriter.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngWriter.java Sun Jul 27 14:34:36 2008
@@ -25,20 +25,24 @@
import java.util.zip.DeflaterOutputStream;
import org.apache.sanselan.ImageWriteException;
+import org.apache.sanselan.common.ZLibInflater;
import org.apache.sanselan.palette.MedianCutQuantizer;
import org.apache.sanselan.palette.Palette;
import org.apache.sanselan.palette.PaletteFactory;
import org.apache.sanselan.util.Debug;
import org.apache.sanselan.util.ParamMap;
-public class PngWriter implements PngConstants {
+public class PngWriter implements PngConstants
+{
private final boolean verbose;
- public PngWriter(boolean verbose) {
+ public PngWriter(boolean verbose)
+ {
this.verbose = verbose;
}
- public PngWriter(Map params) {
+ public PngWriter(Map params)
+ {
this.verbose = ParamMap.getParamBoolean(params, PARAM_KEY_VERBOSE,
false);
}
@@ -60,7 +64,8 @@
* tIME (see 11.3.6: Time stamp information).
*/
- private final void writeInt(OutputStream os, int value) throws IOException {
+ private final void writeInt(OutputStream os, int value) throws IOException
+ {
os.write(0xff & (value >> 24));
os.write(0xff & (value >> 16));
os.write(0xff & (value >> 8));
@@ -68,7 +73,8 @@
}
private final void writeChunk(OutputStream os, byte chunk_type[],
- byte data[]) throws IOException {
+ byte data[]) throws IOException
+ {
int data_length = data == null ? 0 : data.length;
writeInt(os, data_length);
os.write(chunk_type);
@@ -98,7 +104,8 @@
}
}
- private static class ImageHeader {
+ private static class ImageHeader
+ {
public final int width;
public final int height;
public final byte bit_depth;
@@ -109,7 +116,8 @@
public ImageHeader(int width, int height, byte bit_depth,
byte colorType, byte compression_method, byte filter_method,
- byte interlace_method) {
+ byte interlace_method)
+ {
this.width = width;
this.height = height;
this.bit_depth = bit_depth;
@@ -122,7 +130,8 @@
}
private void writeChunkIHDR(OutputStream os, ImageHeader value)
- throws IOException {
+ throws IOException
+ {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
writeInt(baos, value.width);
writeInt(baos, value.height);
@@ -137,13 +146,39 @@
writeChunk(os, IHDR_CHUNK_TYPE, baos.toByteArray());
}
+ private void writeChunkiTXt(OutputStream os, String xmpXml)
+ throws IOException
+ {
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ // keyword
+ baos.write(XMP_KEYWORD.getBytes("ISO-8859-1"));
+ baos.write(0);
+
+ baos.write(1); // compressed flag, true
+ baos.write(COMPRESSION_DEFLATE_INFLATE); // compression method
+
+ baos.write(0); // language tag (ignore). TODO
+
+ // translated keyword
+ baos.write(XMP_KEYWORD.getBytes("utf-8"));
+ baos.write(0);
+
+ baos.write(new ZLibInflater().deflate(xmpXml.getBytes("utf-8")));
+
+ writeChunk(os, iTXt_CHUNK_TYPE, baos.toByteArray());
+ }
+
private void writeChunkPLTE(OutputStream os, Palette palette)
- throws IOException {
+ throws IOException
+ {
int length = palette.length();
byte bytes[] = new byte[length * 3];
// Debug.debug("length", length);
- for (int i = 0; i < length; i++) {
+ for (int i = 0; i < length; i++)
+ {
int rgb = palette.getEntry(i);
int index = i * 3;
// Debug.debug("index", index);
@@ -155,23 +190,27 @@
writeChunk(os, PLTE_CHUNK_TYPE, bytes);
}
- private void writeChunkIEND(OutputStream os) throws IOException {
+ private void writeChunkIEND(OutputStream os) throws IOException
+ {
writeChunk(os, IEND_CHUNK_TYPE, null);
}
private void writeChunkIDAT(OutputStream os, byte bytes[])
- throws IOException {
+ throws IOException
+ {
writeChunk(os, IDAT_CHUNK_TYPE, bytes);
}
- private byte getColourType(boolean hasAlpha, boolean isGrayscale) {
+ private byte getColourType(boolean hasAlpha, boolean isGrayscale)
+ {
byte result;
boolean index = false; // charles
if (index)
result = COLOR_TYPE_INDEXED_COLOR;
- else if (isGrayscale) {
+ else if (isGrayscale)
+ {
if (hasAlpha)
result = COLOR_TYPE_GREYSCALE_WITH_ALPHA;
else
@@ -184,13 +223,16 @@
return result;
}
- private byte getBitDepth(final byte colorType, Map params) {
+ private byte getBitDepth(final byte colorType, Map params)
+ {
byte result = 8;
Object o = params.get(PARAM_KEY_PNG_BIT_DEPTH);
- if (o != null && o instanceof Number) {
+ if (o != null && o instanceof Number)
+ {
int value = ((Number) o).intValue();
- switch (value) {
+ switch (value)
+ {
case 1:
case 2:
case 4:
@@ -199,7 +241,8 @@
result = (byte) value;
default:
}
- switch (colorType) {
+ switch (colorType)
+ {
case COLOR_TYPE_GREYSCALE:
break;
case COLOR_TYPE_INDEXED_COLOR:
@@ -234,7 +277,8 @@
*/
public void writeImage(BufferedImage src, OutputStream os, Map params)
- throws ImageWriteException, IOException {
+ throws ImageWriteException, IOException
+ {
// make copy of params; we'll clear keys as we consume them.
params = new HashMap(params);
@@ -252,7 +296,10 @@
params.remove(PARAM_KEY_PNG_FORCE_INDEXED_COLOR);
if (params.containsKey(PARAM_KEY_PNG_BIT_DEPTH))
params.remove(PARAM_KEY_PNG_BIT_DEPTH);
- if (params.size() > 0) {
+ if (params.containsKey(PARAM_KEY_XMP_XML))
+ params.remove(PARAM_KEY_XMP_XML);
+ if (params.size() > 0)
+ {
Object firstKey = params.keySet().iterator().next();
throw new ImageWriteException("Unknown parameter: " + firstKey);
}
@@ -280,9 +327,11 @@
if (force_indexed_color && force_true_color)
throw new ImageWriteException(
"Params: Cannot force both indexed and true color modes");
- else if (force_indexed_color) {
+ else if (force_indexed_color)
+ {
colorType = COLOR_TYPE_INDEXED_COLOR;
- } else if (force_true_color) {
+ } else if (force_true_color)
+ {
colorType = (byte) (hasAlpha ? COLOR_TYPE_TRUE_COLOR_WITH_ALPHA
: COLOR_TYPE_TRUE_COLOR);
} else
@@ -328,7 +377,8 @@
}
Palette palette = null;
- if (colorType == COLOR_TYPE_INDEXED_COLOR) {
+ if (colorType == COLOR_TYPE_INDEXED_COLOR)
+ {
// PLTE No Before first IDAT
int max_colors = hasAlpha ? 255 : 256;
@@ -343,6 +393,12 @@
writeChunkPLTE(os, palette);
}
+ if (params.containsKey(PARAM_KEY_XMP_XML))
+ {
+ String xmpXml = (String) params.get(PARAM_KEY_XMP_XML);
+ writeChunkiTXt(os, xmpXml);
+ }
+
{
// Debug.debug("writing IDAT");
@@ -356,25 +412,30 @@
|| colorType == COLOR_TYPE_TRUE_COLOR_WITH_ALPHA;
int row[] = new int[width];
- for (int y = 0; y < height; y++) {
+ for (int y = 0; y < height; y++)
+ {
// Debug.debug("y", y + "/" + height);
src.getRGB(0, y, width, 1, row, 0, width);
byte filter_type = FILTER_TYPE_NONE;
baos.write(filter_type);
- for (int x = 0; x < width; x++) {
+ for (int x = 0; x < width; x++)
+ {
int argb = row[x];
- if (palette != null) {
+ if (palette != null)
+ {
int index = palette.getPaletteIndex(argb);
baos.write(0xff & index);
- } else {
+ } else
+ {
int alpha = 0xff & (argb >> 24);
int red = 0xff & (argb >> 16);
int green = 0xff & (argb >> 8);
int blue = 0xff & (argb >> 0);
- if (isGrayscale) {
+ if (isGrayscale)
+ {
int gray = (red + green + blue) / 3;
// if(y==0)
// {
@@ -387,7 +448,8 @@
// Debug.debug();
// }
baos.write(gray);
- } else {
+ } else
+ {
baos.write(red);
baos.write(green);
baos.write(blue);
@@ -405,7 +467,8 @@
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DeflaterOutputStream dos = new DeflaterOutputStream(baos);
int chunk_size = 256 * 1024;
- for (int index = 0; index < uncompressed.length; index += chunk_size) {
+ for (int index = 0; index < uncompressed.length; index += chunk_size)
+ {
int end = Math.min(uncompressed.length, index + chunk_size);
int length = end - index;
@@ -415,7 +478,8 @@
byte compressed[] = baos.toByteArray();
baos.reset();
- if (compressed.length > 0) {
+ if (compressed.length > 0)
+ {
// Debug.debug("compressed", compressed.length);
writeChunkIDAT(os, compressed);
}
@@ -424,7 +488,8 @@
{
dos.finish();
byte compressed[] = baos.toByteArray();
- if (compressed.length > 0) {
+ if (compressed.length > 0)
+ {
// Debug.debug("compressed final", compressed.length);
writeChunkIDAT(os, compressed);
}
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunkiCCP.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunkiCCP.java?rev=680193&r1=680192&r2=680193&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunkiCCP.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunkiCCP.java Sun Jul 27 14:34:36 2008
@@ -64,7 +64,7 @@
}
UncompressedProfile = new ZLibInflater()
- .zlibInflate(CompressedProfile);
+ .inflate(CompressedProfile);
if (getDebug())
{
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunkiTXt.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunkiTXt.java?rev=680193&r1=680192&r2=680193&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunkiTXt.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunkiTXt.java Sun Jul 27 14:34:36 2008
@@ -97,7 +97,7 @@
compressedTextLength);
text = new String(new ZLibInflater()
- .zlibInflate(compressedText), "utf-8");
+ .inflate(compressedText), "utf-8");
} else
text = new String(bytes, index, bytes.length - index, "utf-8");
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunkzTXt.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunkzTXt.java?rev=680193&r1=680192&r2=680193&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunkzTXt.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunkzTXt.java Sun Jul 27 14:34:36 2008
@@ -51,7 +51,7 @@
System.arraycopy(bytes, index + 1 + 1, compressedText, 0,
compressedTextLength);
- text = new String(new ZLibInflater().zlibInflate(compressedText),
+ text = new String(new ZLibInflater().inflate(compressedText),
"ISO-8859-1");
}
}
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterBase.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterBase.java?rev=680193&r1=680192&r2=680193&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterBase.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterBase.java Sun Jul 27 14:34:36 2008
@@ -35,13 +35,10 @@
import org.apache.sanselan.formats.tiff.TiffImageData;
import org.apache.sanselan.formats.tiff.constants.TiffConstants;
-public abstract class TiffImageWriterBase
- implements
- TiffConstants,
- BinaryConstants
+public abstract class TiffImageWriterBase implements TiffConstants,
+ BinaryConstants
{
-
protected final int byteOrder;
public TiffImageWriterBase()
@@ -69,7 +66,7 @@
if (1 > directories.size())
throw new ImageWriteException("No directories.");
-
+
TiffOutputDirectory exifDirectory = null;
TiffOutputDirectory gpsDirectory = null;
TiffOutputDirectory interoperabilityDirectory = null;
@@ -86,46 +83,45 @@
int dirType = directory.type;
Integer key = new Integer(dirType);
directoryTypeMap.put(key, directory);
- // Debug.debug("validating dirType", dirType + " ("
- // + directory.getFields().size() + " fields)");
+ // Debug.debug("validating dirType", dirType + " ("
+ // + directory.getFields().size() + " fields)");
if (dirType < 0)
{
switch (dirType)
{
- case DIRECTORY_TYPE_EXIF :
- if (exifDirectory != null)
- throw new ImageWriteException(
- "More than one EXIF directory.");
- exifDirectory = directory;
- break;
-
- case DIRECTORY_TYPE_GPS :
- if (gpsDirectory != null)
- throw new ImageWriteException(
- "More than one GPS directory.");
- gpsDirectory = directory;
- break;
-
- case DIRECTORY_TYPE_INTEROPERABILITY :
- if (interoperabilityDirectory != null)
- throw new ImageWriteException(
- "More than one Interoperability directory.");
- interoperabilityDirectory = directory;
- break;
- default :
- throw new ImageWriteException("Unknown directory: "
- + dirType);
+ case DIRECTORY_TYPE_EXIF:
+ if (exifDirectory != null)
+ throw new ImageWriteException(
+ "More than one EXIF directory.");
+ exifDirectory = directory;
+ break;
+
+ case DIRECTORY_TYPE_GPS:
+ if (gpsDirectory != null)
+ throw new ImageWriteException(
+ "More than one GPS directory.");
+ gpsDirectory = directory;
+ break;
+
+ case DIRECTORY_TYPE_INTEROPERABILITY:
+ if (interoperabilityDirectory != null)
+ throw new ImageWriteException(
+ "More than one Interoperability directory.");
+ interoperabilityDirectory = directory;
+ break;
+ default:
+ throw new ImageWriteException("Unknown directory: "
+ + dirType);
}
- }
- else
+ } else
{
if (directoryIndices.contains(key))
throw new ImageWriteException(
"More than one directory with index: " + dirType
+ ".");
directoryIndices.add(new Integer(dirType));
- // dirMap.put(arg0, arg1)
+ // dirMap.put(arg0, arg1)
}
HashSet fieldTags = new HashSet();
@@ -147,15 +143,13 @@
throw new ImageWriteException(
"More than one Exif directory offset field.");
exifDirectoryOffsetField = field;
- }
- else if (field.tag == EXIF_TAG_INTEROP_OFFSET.tag)
+ } else if (field.tag == EXIF_TAG_INTEROP_OFFSET.tag)
{
if (interoperabilityDirectoryOffsetField != null)
throw new ImageWriteException(
"More than one Interoperability directory offset field.");
interoperabilityDirectoryOffsetField = field;
- }
- else if (field.tag == EXIF_TAG_GPSINFO.tag)
+ } else if (field.tag == EXIF_TAG_GPSINFO.tag)
{
if (gpsDirectoryOffsetField != null)
throw new ImageWriteException(
@@ -163,13 +157,14 @@
gpsDirectoryOffsetField = field;
}
}
- // directory.
+ // directory.
}
if (directoryIndices.size() < 1)
throw new ImageWriteException("Missing root directory.");
- // "normal" TIFF directories should have continous indices starting with 0, ie. 0, 1, 2...
+ // "normal" TIFF directories should have continous indices starting with
+ // 0, ie. 0, 1, 2...
Collections.sort(directoryIndices);
TiffOutputDirectory previousDirectory = null;
@@ -200,8 +195,7 @@
// perhaps we should just discard field?
throw new ImageWriteException(
"Output set has Interoperability Directory Offset field, but no Interoperability Directory");
- }
- else if (interoperabilityDirectory != null)
+ } else if (interoperabilityDirectory != null)
{
if (exifDirectory == null)
{
@@ -225,8 +219,7 @@
// perhaps we should just discard field?
throw new ImageWriteException(
"Output set has Exif Directory Offset field, but no Exif Directory");
- }
- else if (exifDirectory != null)
+ } else if (exifDirectory != null)
{
if (exifDirectoryOffsetField == null)
{
@@ -243,8 +236,7 @@
// perhaps we should just discard field?
throw new ImageWriteException(
"Output set has GPS Directory Offset field, but no GPS Directory");
- }
- else if (gpsDirectory != null)
+ } else if (gpsDirectory != null)
{
if (gpsDirectoryOffsetField == null)
{
@@ -258,18 +250,19 @@
return result;
- // Debug.debug();
+ // Debug.debug();
}
public void writeImage(BufferedImage src, OutputStream os, Map params)
throws ImageWriteException, IOException
{
- // writeImageNew(src, os, params);
- // }
+ // writeImageNew(src, os, params);
+ // }
//
- // public void writeImageNew(BufferedImage src, OutputStream os, Map params)
- // throws ImageWriteException, IOException
- // {
+ // public void writeImageNew(BufferedImage src, OutputStream os, Map
+ // params)
+ // throws ImageWriteException, IOException
+ // {
// make copy of params; we'll clear keys as we consume them.
params = new HashMap(params);
@@ -278,16 +271,24 @@
if (params.containsKey(PARAM_KEY_FORMAT))
params.remove(PARAM_KEY_FORMAT);
+ String xmpXml = null;
+ if (params.containsKey(PARAM_KEY_XMP_XML))
+ {
+ xmpXml = (String) params.get(PARAM_KEY_XMP_XML);
+ params.remove(PARAM_KEY_XMP_XML);
+ }
+
int width = src.getWidth();
int height = src.getHeight();
- // BinaryOutputStream bos = new BinaryOutputStream(os, WRITE_BYTE_ORDER);
+ // BinaryOutputStream bos = new BinaryOutputStream(os,
+ // WRITE_BYTE_ORDER);
//
- // writeImageFileHeader(bos, WRITE_BYTE_ORDER);
+ // writeImageFileHeader(bos, WRITE_BYTE_ORDER);
- // ArrayList directoryFields = new ArrayList();
+ // ArrayList directoryFields = new ArrayList();
- final int photometricInterpretation = 2; // TODO:
+ final int photometricInterpretation = 2; // TODO:
int compression = TIFF_COMPRESSION_LZW; // LZW is default
if (params.containsKey(PARAM_KEY_COMPRESSION))
@@ -303,18 +304,18 @@
params.remove(PARAM_KEY_COMPRESSION);
}
- final int samplesPerPixel = 3; // TODO:
- final int bitsPerSample = 8; // TODO:
+ final int samplesPerPixel = 3; // TODO:
+ final int bitsPerSample = 8; // TODO:
- // int fRowsPerStrip; // TODO:
- int rowsPerStrip = 8000 / (width * samplesPerPixel); // TODO:
+ // int fRowsPerStrip; // TODO:
+ int rowsPerStrip = 8000 / (width * samplesPerPixel); // TODO:
rowsPerStrip = Math.max(1, rowsPerStrip); // must have at least one.
byte strips[][] = getStrips(src, samplesPerPixel, bitsPerSample,
rowsPerStrip);
- // int stripCount = (height + fRowsPerStrip - 1) / fRowsPerStrip;
- // int stripCount = strips.length;
+ // int stripCount = (height + fRowsPerStrip - 1) / fRowsPerStrip;
+ // int stripCount = strips.length;
if (params.size() > 0)
{
@@ -322,18 +323,17 @@
throw new ImageWriteException("Unknown parameter: " + firstKey);
}
- // System.out.println("width: " + width);
- // System.out.println("height: " + height);
- // System.out.println("fRowsPerStrip: " + fRowsPerStrip);
- // System.out.println("fSamplesPerPixel: " + fSamplesPerPixel);
- // System.out.println("stripCount: " + stripCount);
+ // System.out.println("width: " + width);
+ // System.out.println("height: " + height);
+ // System.out.println("fRowsPerStrip: " + fRowsPerStrip);
+ // System.out.println("fSamplesPerPixel: " + fSamplesPerPixel);
+ // System.out.println("stripCount: " + stripCount);
if (compression == TIFF_COMPRESSION_PACKBITS)
{
for (int i = 0; i < strips.length; i++)
strips[i] = new PackBits().compress(strips[i]);
- }
- else if (compression == TIFF_COMPRESSION_LZW)
+ } else if (compression == TIFF_COMPRESSION_LZW)
{
for (int i = 0; i < strips.length; i++)
{
@@ -347,12 +347,10 @@
strips[i] = compressed;
}
- }
- else if (compression == TIFF_COMPRESSION_UNCOMPRESSED)
+ } else if (compression == TIFF_COMPRESSION_UNCOMPRESSED)
{
// do nothing.
- }
- else
+ } else
throw new ImageWriteException(
"Invalid compression parameter (Only LZW, Packbits and uncompressed supported).");
@@ -361,85 +359,79 @@
imageData[i] = new TiffImageData.Data(0, strips[i].length,
strips[i]);
- // int stripOffsets[] = new int[stripCount];
- // int stripByteCounts[] = new int[stripCount];
+ // int stripOffsets[] = new int[stripCount];
+ // int stripByteCounts[] = new int[stripCount];
//
- // for (int i = 0; i < strips.length; i++)
- // stripByteCounts[i] = strips[i].length;
+ // for (int i = 0; i < strips.length; i++)
+ // stripByteCounts[i] = strips[i].length;
TiffOutputSet outputSet = new TiffOutputSet(byteOrder);
TiffOutputDirectory directory = outputSet.addRootDirectory();
- // WriteField stripOffsetsField;
+ // WriteField stripOffsetsField;
{
{
TiffOutputField field = new TiffOutputField(
TIFF_TAG_IMAGE_WIDTH, FIELD_TYPE_LONG, 1,
- FIELD_TYPE_LONG.writeData(new int[]{
- width,
- }, byteOrder));
+ FIELD_TYPE_LONG.writeData(new int[] { width, },
+ byteOrder));
directory.add(field);
}
{
TiffOutputField field = new TiffOutputField(
TIFF_TAG_IMAGE_LENGTH, FIELD_TYPE_LONG, 1,
- FIELD_TYPE_LONG.writeData(new int[]{
- height,
- }, byteOrder));
+ FIELD_TYPE_LONG.writeData(new int[] { height, },
+ byteOrder));
directory.add(field);
}
{
TiffOutputField field = new TiffOutputField(
TIFF_TAG_PHOTOMETRIC_INTERPRETATION, FIELD_TYPE_SHORT,
- 1, FIELD_TYPE_SHORT.writeData(new int[]{
- photometricInterpretation,
- }, byteOrder));
+ 1, FIELD_TYPE_SHORT.writeData(
+ new int[] { photometricInterpretation, },
+ byteOrder));
directory.add(field);
}
{
TiffOutputField field = new TiffOutputField(
TIFF_TAG_COMPRESSION, FIELD_TYPE_SHORT, 1,
- FIELD_TYPE_SHORT.writeData(new int[]{
- compression,
- }, byteOrder));
+ FIELD_TYPE_SHORT.writeData(new int[] { compression, },
+ byteOrder));
directory.add(field);
}
{
TiffOutputField field = new TiffOutputField(
TIFF_TAG_SAMPLES_PER_PIXEL, FIELD_TYPE_SHORT, 1,
- FIELD_TYPE_SHORT.writeData(new int[]{
- samplesPerPixel,
- }, byteOrder));
+ FIELD_TYPE_SHORT.writeData(
+ new int[] { samplesPerPixel, }, byteOrder));
directory.add(field);
}
{
TiffOutputField field = new TiffOutputField(
TIFF_TAG_BITS_PER_SAMPLE, FIELD_TYPE_SHORT, 3,
- FIELD_TYPE_SHORT.writeData(new int[]{
- bitsPerSample, bitsPerSample, bitsPerSample,
- }, byteOrder));
- directory.add(field);
- }
- // {
- // stripOffsetsField = new WriteField(TIFF_TAG_STRIP_OFFSETS,
- // FIELD_TYPE_LONG, stripOffsets.length, FIELD_TYPE_LONG
- // .writeData(stripOffsets, byteOrder));
- // directory.add(stripOffsetsField);
- // }
- // {
- // WriteField field = new WriteField(TIFF_TAG_STRIP_BYTE_COUNTS,
- // FIELD_TYPE_LONG, stripByteCounts.length,
- // FIELD_TYPE_LONG.writeData(stripByteCounts,
- // WRITE_BYTE_ORDER));
- // directory.add(field);
- // }
+ FIELD_TYPE_SHORT.writeData(new int[] { bitsPerSample,
+ bitsPerSample, bitsPerSample, }, byteOrder));
+ directory.add(field);
+ }
+ // {
+ // stripOffsetsField = new WriteField(TIFF_TAG_STRIP_OFFSETS,
+ // FIELD_TYPE_LONG, stripOffsets.length, FIELD_TYPE_LONG
+ // .writeData(stripOffsets, byteOrder));
+ // directory.add(stripOffsetsField);
+ // }
+ // {
+ // WriteField field = new WriteField(TIFF_TAG_STRIP_BYTE_COUNTS,
+ // FIELD_TYPE_LONG, stripByteCounts.length,
+ // FIELD_TYPE_LONG.writeData(stripByteCounts,
+ // WRITE_BYTE_ORDER));
+ // directory.add(field);
+ // }
{
TiffOutputField field = new TiffOutputField(
TIFF_TAG_ROWS_PER_STRIP, FIELD_TYPE_LONG, 1,
- FIELD_TYPE_LONG.writeData(new int[]{
- rowsPerStrip,
- }, byteOrder));
+ FIELD_TYPE_LONG.writeData(new int[] { rowsPerStrip, },
+ byteOrder));
directory.add(field);
}
@@ -447,9 +439,8 @@
int resolutionUnit = 2;// inches.
TiffOutputField field = new TiffOutputField(
TIFF_TAG_RESOLUTION_UNIT, FIELD_TYPE_SHORT, 1,
- FIELD_TYPE_SHORT.writeData(new int[]{
- resolutionUnit,
- }, byteOrder));
+ FIELD_TYPE_SHORT.writeData(
+ new int[] { resolutionUnit, }, byteOrder));
directory.add(field);
}
@@ -471,6 +462,15 @@
directory.add(field);
}
+ if (null != xmpXml)
+ {
+ byte xmpXmlBytes[] = xmpXml.getBytes("utf-8");
+
+ TiffOutputField field = new TiffOutputField(TIFF_TAG_XMP,
+ FIELD_TYPE_BYTE, xmpXmlBytes.length, xmpXmlBytes);
+ directory.add(field);
+ }
+
}
TiffImageData tiffImageData = new TiffImageData.Strips(imageData,
Added: incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/xmp/XmpUpdateTest.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/xmp/XmpUpdateTest.java?rev=680193&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/xmp/XmpUpdateTest.java (added)
+++ incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/xmp/XmpUpdateTest.java Sun Jul 27 14:34:36 2008
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sanselan.formats.xmp;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sanselan.ImageFormat;
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.ImageWriteException;
+import org.apache.sanselan.Sanselan;
+import org.apache.sanselan.SanselanTest;
+import org.apache.sanselan.util.Debug;
+
+public class XmpUpdateTest extends SanselanTest
+{
+
+ public void test() throws IOException, ImageReadException,
+ ImageWriteException
+ {
+ List images = getTestImages();
+ for (int i = 0; i < images.size(); i++)
+ {
+ if (i % 10 == 0)
+ Debug.purgeMemory();
+
+ File imageFile = (File) images.get(i);
+ Debug.debug("imageFile", imageFile);
+ Debug.debug();
+
+ ImageFormat imageFormat = Sanselan.guessFormat(imageFile);
+
+ String xmpXml = Sanselan.getXmpXml(imageFile);
+ if (null == xmpXml
+ && imageFormat.equals(ImageFormat.IMAGE_FORMAT_GIF))
+ xmpXml = "temporary test until I can locate a GIF with XMP in the wild.";
+ if (null == xmpXml)
+ continue;
+
+ assertNotNull(xmpXml);
+
+ if (imageFormat.equals(ImageFormat.IMAGE_FORMAT_PNG))
+ ;
+ else if (imageFormat.equals(ImageFormat.IMAGE_FORMAT_TIFF))
+ ;
+ else if (imageFormat.equals(ImageFormat.IMAGE_FORMAT_GIF))
+ ;
+ else
+ continue;
+
+ File tempFile = this.createTempFile(imageFile.getName() + ".", "."
+ + imageFormat.extension);
+ BufferedImage image = Sanselan.getBufferedImage(imageFile);
+
+ // ----
+
+ String testSrc = "<test>hi</test>";
+ Map params = new HashMap();
+ params.put(PARAM_KEY_XMP_XML, testSrc);
+ Sanselan.writeImage(image, tempFile, imageFormat, params);
+
+ String testDst = Sanselan.getXmpXml(tempFile);
+
+ assertNotNull(testDst);
+
+ assertEquals(testDst, testSrc);
+
+ // ----
+
+ params.put(PARAM_KEY_XMP_XML, xmpXml);
+ Sanselan.writeImage(image, tempFile, imageFormat, params);
+
+ String xmpXmlOut = Sanselan.getXmpXml(tempFile);
+
+ assertNotNull(xmpXmlOut);
+
+ assertEquals(xmpXmlOut, xmpXml);
+
+// Debug.debug("xmpXmlOut", xmpXmlOut.length());
+ // Debug.debug("xmpXml", xmpXml);
+ // Debug.debug();
+ }
+ }
+}
Propchange: incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/xmp/XmpUpdateTest.java
------------------------------------------------------------------------------
svn:eol-style = native