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/08/04 23:23:46 UTC
svn commit: r682538 - in /incubator/sanselan/trunk: ./
src/main/java/org/apache/sanselan/ src/main/java/org/apache/sanselan/common/
src/main/java/org/apache/sanselan/formats/png/
src/main/java/org/apache/sanselan/formats/png/chunks/ src/main/java/org/a...
Author: cmchen
Date: Mon Aug 4 16:23:45 2008
New Revision: 682538
URL: http://svn.apache.org/viewvc?rev=682538&view=rev
Log:
* Added improved support for reading and writing iTXt, tEXt, zTXt Png chunks.
Added a unit test that demonstrates the feature.
* Found a new regression wherein DeflaterOutputStream needs to be closed.
Added:
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/SanselanException.java (with props)
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibUtils.java (with props)
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngImageInfo.java (with props)
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngText.java (with props)
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/util/UnicodeUtils.java (with props)
incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/png/PngTextTest.java (with props)
Removed:
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibInflater.java
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/sampleUsage/
Modified:
incubator/sanselan/trunk/RELEASE_NOTES
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/ImageInfo.java
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/ImageReadException.java
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/ImageWriteException.java
incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryConstants.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/PngImageParser.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/PNGChunktEXt.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/png/chunks/PNGTextChunk.java
Modified: incubator/sanselan/trunk/RELEASE_NOTES
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/RELEASE_NOTES?rev=682538&r1=682537&r2=682538&view=diff
==============================================================================
--- incubator/sanselan/trunk/RELEASE_NOTES (original)
+++ incubator/sanselan/trunk/RELEASE_NOTES Mon Aug 4 16:23:45 2008
@@ -15,6 +15,11 @@
Release 0.95
------------
+ * Added improved support for reading and writing iTXt, tEXt, zTXt Png chunks.
+ Added a unit test that demonstrates the feature.
+ * Found a new regression wherein DeflaterOutputStream needs to be closed.
+ * Added the .tar.bz2 distributions back into the maven assembly descriptors.
+ * Moved the example/sample code to a new top-level source folder, "example."
* Replaced dependency on java.util.zip.DeflaterOutputStream, which is only available in Java 1.6.
* Added a unit test around reading and writing images in every format.
* We now sort some (but not all) GIF color tables.
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/ImageInfo.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/ImageInfo.java?rev=682538&r1=682537&r2=682538&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/ImageInfo.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/ImageInfo.java Mon Aug 4 16:23:45 2008
@@ -22,8 +22,8 @@
import java.util.ArrayList;
/**
- * ImageInfo represents a collection of basic properties of an image,
- * such as width, height, format, bit depth, etc.
+ * ImageInfo represents a collection of basic properties of an image, such as
+ * width, height, format, bit depth, etc.
*/
public class ImageInfo
{
@@ -71,40 +71,40 @@
private final String compressionAlgorithm;
- public ImageInfo(String FormatDetails, int BitsPerPixel,
- ArrayList Comments, ImageFormat Format, String FormatName,
- int Height, String MimeType, int NumberOfImages,
- int PhysicalHeightDpi, float PhysicalHeightInch,
- int PhysicalWidthDpi, float PhysicalWidthInch, int Width,
+ public ImageInfo(String formatDetails, int bitsPerPixel,
+ ArrayList comments, ImageFormat format, String formatName,
+ int height, String mimeType, int numberOfImages,
+ int physicalHeightDpi, float physicalHeightInch,
+ int physicalWidthDpi, float physicalWidthInch, int width,
boolean isProgressive, boolean isTransparent, boolean usesPalette,
- int ColorType, String compressionAlgorithm)
+ int colorType, String compressionAlgorithm)
{
- this.formatDetails = FormatDetails;
+ this.formatDetails = formatDetails;
- this.bitsPerPixel = BitsPerPixel;
- this.comments = Comments;
+ this.bitsPerPixel = bitsPerPixel;
+ this.comments = comments;
- this.format = Format;
- this.formatName = FormatName;
- this.height = Height;
- this.mimeType = MimeType;
-
- this.numberOfImages = NumberOfImages;
- this.physicalHeightDpi = PhysicalHeightDpi;
- this.physicalHeightInch = PhysicalHeightInch;
- this.physicalWidthDpi = PhysicalWidthDpi;
- this.physicalWidthInch = PhysicalWidthInch;
- this.width = Width;
+ this.format = format;
+ this.formatName = formatName;
+ this.height = height;
+ this.mimeType = mimeType;
+
+ this.numberOfImages = numberOfImages;
+ this.physicalHeightDpi = physicalHeightDpi;
+ this.physicalHeightInch = physicalHeightInch;
+ this.physicalWidthDpi = physicalWidthDpi;
+ this.physicalWidthInch = physicalWidthInch;
+ this.width = width;
this.isProgressive = isProgressive;
this.isTransparent = isTransparent;
this.usesPalette = usesPalette;
- this.colorType = ColorType;
+ this.colorType = colorType;
this.compressionAlgorithm = compressionAlgorithm;
}
- /**
+ /**
* Returns the bits per pixel of the image data.
*/
public int getBitsPerPixel()
@@ -112,30 +112,28 @@
return bitsPerPixel;
}
- /**
- * Returns a list of comments from the image file.
- * <p/>
- * This is mostly obsolete.
+ /**
+ * Returns a list of comments from the image file. <p/> This is mostly
+ * obsolete.
*/
public ArrayList getComments()
{
return new ArrayList(comments);
}
- /**
- * Returns the image file format, ie. ImageFormat.IMAGE_FORMAT_PNG.
- * <p/>
+ /**
+ * Returns the image file format, ie. ImageFormat.IMAGE_FORMAT_PNG. <p/>
* Returns ImageFormat.IMAGE_FORMAT_UNKNOWN if format is unknown.
*
- * @return A constant defined in ImageFormat.
- * @see ImageFormat
+ * @return A constant defined in ImageFormat.
+ * @see ImageFormat
*/
public ImageFormat getFormat()
{
return format;
}
- /**
+ /**
* Returns a string with the name of the image file format.
*
* @see #getFormat()
@@ -145,7 +143,7 @@
return formatName;
}
- /**
+ /**
* Returns the height of the image in pixels.
*
* @see #getWidth()
@@ -155,7 +153,7 @@
return height;
}
- /**
+ /**
* Returns the MIME type of the image.
*
* @see #getFormat()
@@ -165,70 +163,74 @@
return mimeType;
}
- /**
+ /**
* Returns the number of images in the file.
* <p>
- * Applies mostly to GIF and TIFF; reading PSD/Photoshop layers is not supported,
- * and Jpeg/JFIF EXIF thumbnails are not included in this count.
+ * Applies mostly to GIF and TIFF; reading PSD/Photoshop layers is not
+ * supported, and Jpeg/JFIF EXIF thumbnails are not included in this count.
*/
public int getNumberOfImages()
{
return numberOfImages;
}
- /**
+ /**
* Returns horizontal dpi of the image, if available.
* <p>
- * Applies to TIFF (optional), BMP (always), GIF (constant: 72),
- * Jpeg (optional), PNG (optional), PNM (constant: 72), PSD/Photoshop (constant: 72).
+ * Applies to TIFF (optional), BMP (always), GIF (constant: 72), Jpeg
+ * (optional), PNG (optional), PNM (constant: 72), PSD/Photoshop (constant:
+ * 72).
*
- * @return returns -1 if not present.
+ * @return returns -1 if not present.
*/
public int getPhysicalHeightDpi()
{
return physicalHeightDpi;
}
- /**
+ /**
* Returns physical height of the image in inches, if available.
* <p>
- * Applies to TIFF (optional), BMP (always), GIF (constant: 72),
- * Jpeg (optional), PNG (optional), PNM (constant: 72), PSD/Photoshop (constant: 72).
+ * Applies to TIFF (optional), BMP (always), GIF (constant: 72), Jpeg
+ * (optional), PNG (optional), PNM (constant: 72), PSD/Photoshop (constant:
+ * 72).
*
- * @return returns -1 if not present.
+ * @return returns -1 if not present.
*/
public float getPhysicalHeightInch()
{
return physicalHeightInch;
}
- /**
+ /**
* Returns vertical dpi of the image, if available.
* <p>
- * Applies to TIFF (optional), BMP (always), GIF (constant: 72),
- * Jpeg (optional), PNG (optional), PNM (constant: 72), PSD/Photoshop (constant: 72).
+ * Applies to TIFF (optional), BMP (always), GIF (constant: 72), Jpeg
+ * (optional), PNG (optional), PNM (constant: 72), PSD/Photoshop (constant:
+ * 72).
*
- * @return returns -1 if not present.
+ * @return returns -1 if not present.
*/
public int getPhysicalWidthDpi()
{
return physicalWidthDpi;
}
- /**
+ /**
* Returns physical width of the image in inches, if available.
* <p>
- * Applies to TIFF (optional), BMP (always), GIF (constant: 72),
- * Jpeg (optional), PNG (optional), PNM (constant: 72), PSD/Photoshop (constant: 72).
+ * Applies to TIFF (optional), BMP (always), GIF (constant: 72), Jpeg
+ * (optional), PNG (optional), PNM (constant: 72), PSD/Photoshop (constant:
+ * 72).
*
- * @return returns -1 if not present.
+ * @return returns -1 if not present.
*/
public float getPhysicalWidthInch()
{
return physicalWidthInch;
}
- /**
+ /**
* Returns the width of the image in pixels.
*
* @see #getHeight()
@@ -238,7 +240,7 @@
return width;
}
- /**
+ /**
* Returns true if the image is progressive or interlaced.
*/
public boolean getIsProgressive()
@@ -246,8 +248,9 @@
return isProgressive;
}
- /**
- * Returns the color type of the image, as a constant (ie. ImageFormat.COLOR_TYPE_CMYK).
+ /**
+ * Returns the color type of the image, as a constant (ie.
+ * ImageFormat.COLOR_TYPE_CMYK).
*
* @see #getColorTypeDescription()
*/
@@ -256,7 +259,7 @@
return colorType;
}
- /**
+ /**
* Returns a description of the color type of the image.
*
* @see #getColorType()
@@ -265,21 +268,21 @@
{
switch (colorType)
{
- case COLOR_TYPE_BW :
- return "Black and White";
- case COLOR_TYPE_GRAYSCALE :
- return "Grayscale";
- case COLOR_TYPE_RGB :
- return "RGB";
- case COLOR_TYPE_CMYK :
- return "CMYK";
- case COLOR_TYPE_OTHER :
- return "Other";
- case COLOR_TYPE_UNKNOWN :
- return "Unknown";
+ case COLOR_TYPE_BW:
+ return "Black and White";
+ case COLOR_TYPE_GRAYSCALE:
+ return "Grayscale";
+ case COLOR_TYPE_RGB:
+ return "RGB";
+ case COLOR_TYPE_CMYK:
+ return "CMYK";
+ case COLOR_TYPE_OTHER:
+ return "Other";
+ case COLOR_TYPE_UNKNOWN:
+ return "Unknown";
- default :
- return "Unknown";
+ default:
+ return "Unknown";
}
}
@@ -298,10 +301,9 @@
toString(pw, "");
pw.flush();
-
+
return sw.toString();
- }
- catch (Exception e)
+ } catch (Exception e)
{
return "Image Data: Error";
}
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/ImageReadException.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/ImageReadException.java?rev=682538&r1=682537&r2=682538&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/ImageReadException.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/ImageReadException.java Mon Aug 4 16:23:45 2008
@@ -16,7 +16,7 @@
*/
package org.apache.sanselan;
-public class ImageReadException extends Exception
+public class ImageReadException extends SanselanException
{
static final long serialVersionUID = -1L;
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/ImageWriteException.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/ImageWriteException.java?rev=682538&r1=682537&r2=682538&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/ImageWriteException.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/ImageWriteException.java Mon Aug 4 16:23:45 2008
@@ -16,7 +16,7 @@
*/
package org.apache.sanselan;
-public class ImageWriteException extends Exception
+public class ImageWriteException extends SanselanException
{
static final long serialVersionUID = -1L;
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/SanselanException.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/SanselanException.java?rev=682538&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/SanselanException.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/SanselanException.java Mon Aug 4 16:23:45 2008
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+public class SanselanException extends Exception
+{
+ static final long serialVersionUID = -1L;
+
+ public SanselanException(String s)
+ {
+ super(s);
+ }
+
+ public SanselanException(String s, Exception e)
+ {
+ super(s, e);
+ }
+}
\ No newline at end of file
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/SanselanException.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryConstants.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryConstants.java?rev=682538&r1=682537&r2=682538&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryConstants.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryConstants.java Mon Aug 4 16:23:45 2008
@@ -21,10 +21,12 @@
public static final int BYTE_ORDER_INTEL = 'I';
public static final int BYTE_ORDER_LEAST_SIGNIFICANT_BYTE = BYTE_ORDER_INTEL;
public static final int BYTE_ORDER_LSB = BYTE_ORDER_INTEL;
+ public static final int BYTE_ORDER_LITTLE_ENDIAN = BYTE_ORDER_INTEL;
public static final int BYTE_ORDER_MOTOROLA = 'M';
public static final int BYTE_ORDER_MOST_SIGNIFICANT_BYTE = BYTE_ORDER_MOTOROLA;
public static final int BYTE_ORDER_MSB = BYTE_ORDER_MOTOROLA;
public static final int BYTE_ORDER_NETWORK = BYTE_ORDER_MOTOROLA;
+ public static final int BYTE_ORDER_BIG_ENDIAN = BYTE_ORDER_MOTOROLA;
}
\ No newline at end of file
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibUtils.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibUtils.java?rev=682538&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibUtils.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibUtils.java Mon Aug 4 16:23:45 2008
@@ -0,0 +1,44 @@
+/*
+ * 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.common;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.InflaterInputStream;
+
+public class ZLibUtils extends BinaryFileFunctions
+{
+ public final byte[] inflate(byte bytes[]) throws IOException
+ // slow, probably.
+ {
+ ByteArrayInputStream in = new ByteArrayInputStream(bytes);
+ InflaterInputStream zIn = new InflaterInputStream(in);
+ return getStreamBytes(zIn);
+ }
+
+ public final byte[] deflate(byte bytes[]) throws IOException
+ {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DeflaterOutputStream dos = new DeflaterOutputStream(baos);
+ dos.write(bytes);
+ dos.close();
+ return baos.toByteArray();
+ }
+
+}
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibUtils.java
------------------------------------------------------------------------------
svn:eol-style = native
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=682538&r1=682537&r2=682538&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 Mon Aug 4 16:23:45 2008
@@ -27,7 +27,24 @@
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 byte[] iTXt_CHUNK_TYPE = new byte[] { //
+ 105, //
+ 84, //
+ 88, //
+ 116, //
+ };
+ public final static byte[] tEXt_CHUNK_TYPE = new byte[] { //
+ 0x74, //
+ 0x45, //
+ 0x58, //
+ 0x74, //
+ };
+ public final static byte[] zTXt_CHUNK_TYPE = new byte[] { //
+ 0x7A, //
+ 0x54, //
+ 0x58, //
+ 0x74, //
+ };
public final static int IEND = PngImageParser.CharsToQuad('I', 'E', 'N',
'D');
@@ -108,4 +125,14 @@
public final String XMP_KEYWORD = "XML:com.adobe.xmp";
+ /**
+ * Parameter key.
+ *
+ * Only used when writing Png images.
+ * <p>
+ * Valid values: a list of WriteTexts.
+ * <p>
+ */
+ public static final String PARAM_KEY_PNG_TEXT_CHUNKS = "PNG_TEXT_CHUNKS";
+
}
\ No newline at end of file
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngImageInfo.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngImageInfo.java?rev=682538&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngImageInfo.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngImageInfo.java Mon Aug 4 16:23:45 2008
@@ -0,0 +1,35 @@
+package org.apache.sanselan.formats.png;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sanselan.ImageFormat;
+import org.apache.sanselan.ImageInfo;
+
+public class PngImageInfo extends ImageInfo
+{
+ private final List textChunks;
+
+ public PngImageInfo(String formatDetails, int bitsPerPixel,
+ ArrayList comments, ImageFormat format, String formatName,
+ int height, String mimeType, int numberOfImages,
+ int physicalHeightDpi, float physicalHeightInch,
+ int physicalWidthDpi, float physicalWidthInch, int width,
+ boolean isProgressive, boolean isTransparent, boolean usesPalette,
+ int colorType, String compressionAlgorithm, final List textChunks)
+ {
+ super(formatDetails, bitsPerPixel, comments, format, formatName,
+ height, mimeType, numberOfImages, physicalHeightDpi,
+ physicalHeightInch, physicalWidthDpi, physicalWidthInch, width,
+ isProgressive, isTransparent, usesPalette, colorType,
+ compressionAlgorithm);
+
+ this.textChunks = textChunks;
+ }
+
+ public List getTextChunks()
+ {
+ return new ArrayList(textChunks);
+ }
+
+}
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngImageInfo.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngImageParser.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngImageParser.java?rev=682538&r1=682537&r2=682538&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngImageParser.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngImageParser.java Mon Aug 4 16:23:45 2008
@@ -474,7 +474,7 @@
throws ImageReadException, IOException
{
ArrayList chunks = readChunks(byteSource, new int[] { IHDR, pHYs, tEXt,
- zTXt, tRNS, PLTE, }, false);
+ zTXt, tRNS, PLTE, iTXt, }, false);
// if(chunks!=null)
// System.out.println("chunks: " + chunks.size());
@@ -510,35 +510,29 @@
ArrayList tEXts = filterChunks(chunks, tEXt);
ArrayList zTXts = filterChunks(chunks, zTXt);
-
- // private class PNGChunkpHYs extends PNGChunk
- // {
- // public final int PixelsPerUnitXAxis;
- // public final int PixelsPerUnitYAxis;
- // public final int UnitSpecifier;
+ ArrayList iTXts = filterChunks(chunks, iTXt);
{
- // private class PNGChunkIHDR extends PNGChunk
- // {
- // public final int Width;
- // public final int Height;
- // public final int BitDepth;
- // public final int ColorType;
- // public final int CompressionMethod;
- // public final int FilterMethod;
- // public final int InterlaceMethod;
-
- ArrayList Comments = new ArrayList();
+ ArrayList comments = new ArrayList();
+ List textChunks = new ArrayList();
for (int i = 0; i < tEXts.size(); i++)
{
PNGChunktEXt pngChunktEXt = (PNGChunktEXt) tEXts.get(i);
- Comments.add(pngChunktEXt.keyword + ": " + pngChunktEXt.text);
+ comments.add(pngChunktEXt.keyword + ": " + pngChunktEXt.text);
+ textChunks.add(pngChunktEXt.getContents());
}
for (int i = 0; i < zTXts.size(); i++)
{
PNGChunkzTXt pngChunkzTXt = (PNGChunkzTXt) zTXts.get(i);
- Comments.add(pngChunkzTXt.keyword + ": " + pngChunkzTXt.text);
+ comments.add(pngChunkzTXt.keyword + ": " + pngChunkzTXt.text);
+ textChunks.add(pngChunkzTXt.getContents());
+ }
+ for (int i = 0; i < iTXts.size(); i++)
+ {
+ PNGChunkiTXt pngChunkiTXt = (PNGChunkiTXt) iTXts.get(i);
+ comments.add(pngChunkiTXt.keyword + ": " + pngChunkiTXt.text);
+ textChunks.add(pngChunkiTXt.getContents());
}
int BitsPerPixel = pngChunkIHDR.bitDepth
@@ -614,11 +608,12 @@
String compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_PNG_FILTER;
- ImageInfo result = new ImageInfo(FormatDetails, BitsPerPixel,
- Comments, Format, FormatName, Height, MimeType,
+ ImageInfo result = new PngImageInfo(FormatDetails, BitsPerPixel,
+ comments, Format, FormatName, Height, MimeType,
NumberOfImages, PhysicalHeightDpi, PhysicalHeightInch,
PhysicalWidthDpi, PhysicalWidthInch, Width, isProgressive,
- isTransparent, usesPalette, ColorType, compressionAlgorithm);
+ isTransparent, usesPalette, ColorType,
+ compressionAlgorithm, textChunks);
return result;
}
@@ -841,7 +836,7 @@
pw.println("");
pw.flush();
-
+
return true;
}
@@ -882,7 +877,8 @@
if (xmpChunks.size() < 1)
return null;
if (xmpChunks.size() > 1)
- throw new ImageReadException("PNG contains more than one XMP chunk.");
+ throw new ImageReadException(
+ "PNG contains more than one XMP chunk.");
PNGChunkiTXt chunk = (PNGChunkiTXt) xmpChunks.get(0);
return chunk.getText();
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngText.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngText.java?rev=682538&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngText.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngText.java Mon Aug 4 16:23:45 2008
@@ -0,0 +1,59 @@
+package org.apache.sanselan.formats.png;
+
+import org.apache.sanselan.ImageWriteException;
+import org.apache.sanselan.SanselanException;
+import org.apache.sanselan.util.UnicodeUtils;
+
+public abstract class PngText
+{
+ public PngText(String keyword, String text)
+ {
+ this.keyword = keyword;
+ this.text = text;
+ }
+
+ public final String keyword, text;
+
+ public static class tEXt extends PngText
+ {
+ public tEXt(String keyword, String text)
+ {
+ super(keyword, text);
+ }
+ }
+
+ public static class zTXt extends PngText
+ {
+ public zTXt(String keyword, String text)
+ {
+ super(keyword, text);
+ }
+ }
+
+ public static class iTXt extends PngText
+ {
+
+ /*
+ * The language tag defined in [RFC-3066] indicates the human language
+ * used by the translated keyword and the text. Unlike the keyword, the
+ * language tag is case-insensitive. It is an ISO 646.IRV:1991 [ISO 646]
+ * string consisting of hyphen-separated words of 1-8 alphanumeric
+ * characters each (for example cn, en-uk, no-bok, x-klingon,
+ * x-KlInGoN). If the first word is two or three letters long, it is an
+ * ISO language code [ISO-639]. If the language tag is empty, the
+ * language is unspecified.
+ */
+ public final String languageTag;
+
+ public final String translatedKeyword;
+
+ public iTXt(String keyword, String text, String languageTag,
+ String translatedKeyword)
+ {
+ super(keyword, text);
+ this.languageTag = languageTag;
+ this.translatedKeyword = translatedKeyword;
+ }
+ }
+
+}
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngText.java
------------------------------------------------------------------------------
svn:eol-style = native
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=682538&r1=682537&r2=682538&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 Mon Aug 4 16:23:45 2008
@@ -21,16 +21,18 @@
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.zip.DeflaterOutputStream;
import org.apache.sanselan.ImageWriteException;
-import org.apache.sanselan.common.ZLibInflater;
+import org.apache.sanselan.common.ZLibUtils;
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;
+import org.apache.sanselan.util.UnicodeUtils;
public class PngWriter implements PngConstants
{
@@ -72,23 +74,22 @@
os.write(0xff & (value >> 0));
}
- private final void writeChunk(OutputStream os, byte chunk_type[],
+ private final void writeChunk(OutputStream os, byte chunkType[],
byte data[]) throws IOException
{
- int data_length = data == null ? 0 : data.length;
- writeInt(os, data_length);
- os.write(chunk_type);
+ int dataLength = data == null ? 0 : data.length;
+ writeInt(os, dataLength);
+ os.write(chunkType);
if (data != null)
os.write(data);
- // Debug.debug("writeChunk chunk_type", chunk_type);
+ // Debug.debug("writeChunk chunkType", chunkType);
// Debug.debug("writeChunk data", data);
{
PngCrc png_crc = new PngCrc();
- long crc1 = png_crc
- .start_partial_crc(chunk_type, chunk_type.length);
+ long crc1 = png_crc.start_partial_crc(chunkType, chunkType.length);
long crc2 = data == null ? crc1 : png_crc.continue_partial_crc(
crc1, data, data.length);
int crc = (int) png_crc.finish_partial_crc(crc2);
@@ -146,7 +147,89 @@
writeChunk(os, IHDR_CHUNK_TYPE, baos.toByteArray());
}
- private void writeChunkiTXt(OutputStream os, String xmpXml)
+ private void writeChunkiTXt(OutputStream os, PngText.iTXt text)
+ throws IOException, ImageWriteException
+ {
+ if (!UnicodeUtils.isValidISO_8859_1(text.keyword))
+ throw new ImageWriteException(
+ "Png tEXt chunk keyword is not ISO-8859-1: " + text.keyword);
+ if (!UnicodeUtils.isValidISO_8859_1(text.languageTag))
+ throw new ImageWriteException(
+ "Png tEXt chunk language tag is not ISO-8859-1: "
+ + text.languageTag);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ // keyword
+ baos.write(text.keyword.getBytes("ISO-8859-1"));
+ baos.write(0);
+
+ baos.write(1); // compressed flag, true
+ baos.write(COMPRESSION_DEFLATE_INFLATE); // compression method
+
+ // language tag
+ baos.write(text.languageTag.getBytes("ISO-8859-1"));
+ baos.write(0);
+
+ // translated keyword
+ baos.write(text.translatedKeyword.getBytes("utf-8"));
+ baos.write(0);
+
+ baos.write(new ZLibUtils().deflate(text.text.getBytes("utf-8")));
+
+ writeChunk(os, iTXt_CHUNK_TYPE, baos.toByteArray());
+ }
+
+ private void writeChunkzTXt(OutputStream os, PngText.zTXt text)
+ throws IOException, ImageWriteException
+ {
+ if (!UnicodeUtils.isValidISO_8859_1(text.keyword))
+ throw new ImageWriteException(
+ "Png zTXt chunk keyword is not ISO-8859-1: " + text.keyword);
+ if (!UnicodeUtils.isValidISO_8859_1(text.text))
+ throw new ImageWriteException(
+ "Png zTXt chunk text is not ISO-8859-1: " + text.text);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ // keyword
+ baos.write(text.keyword.getBytes("ISO-8859-1"));
+ baos.write(0);
+
+ // compression method
+ baos.write(PngConstants.COMPRESSION_DEFLATE_INFLATE);
+
+ // text
+ baos
+ .write(new ZLibUtils().deflate(text.text
+ .getBytes("ISO-8859-1")));
+
+ writeChunk(os, zTXt_CHUNK_TYPE, baos.toByteArray());
+ }
+
+ private void writeChunktEXt(OutputStream os, PngText.tEXt text)
+ throws IOException, ImageWriteException
+ {
+ if (!UnicodeUtils.isValidISO_8859_1(text.keyword))
+ throw new ImageWriteException(
+ "Png tEXt chunk keyword is not ISO-8859-1: " + text.keyword);
+ if (!UnicodeUtils.isValidISO_8859_1(text.text))
+ throw new ImageWriteException(
+ "Png tEXt chunk text is not ISO-8859-1: " + text.text);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ // keyword
+ baos.write(text.keyword.getBytes("ISO-8859-1"));
+ baos.write(0);
+
+ // text
+ baos.write(text.text.getBytes("ISO-8859-1"));
+
+ writeChunk(os, tEXt_CHUNK_TYPE, baos.toByteArray());
+ }
+
+ private void writeChunkXmpiTXt(OutputStream os, String xmpXml)
throws IOException
{
@@ -165,7 +248,7 @@
baos.write(XMP_KEYWORD.getBytes("utf-8"));
baos.write(0);
- baos.write(new ZLibInflater().deflate(xmpXml.getBytes("utf-8")));
+ baos.write(new ZLibUtils().deflate(xmpXml.getBytes("utf-8")));
writeChunk(os, iTXt_CHUNK_TYPE, baos.toByteArray());
}
@@ -298,6 +381,8 @@
params.remove(PARAM_KEY_PNG_BIT_DEPTH);
if (params.containsKey(PARAM_KEY_XMP_XML))
params.remove(PARAM_KEY_XMP_XML);
+ if (params.containsKey(PARAM_KEY_PNG_TEXT_CHUNKS))
+ params.remove(PARAM_KEY_PNG_TEXT_CHUNKS);
if (params.size() > 0)
{
Object firstKey = params.keySet().iterator().next();
@@ -395,7 +480,25 @@
if (params.containsKey(PARAM_KEY_XMP_XML))
{
String xmpXml = (String) params.get(PARAM_KEY_XMP_XML);
- writeChunkiTXt(os, xmpXml);
+ writeChunkXmpiTXt(os, xmpXml);
+ }
+
+ if (params.containsKey(PARAM_KEY_PNG_TEXT_CHUNKS))
+ {
+ List outputTexts = (List) params.get(PARAM_KEY_PNG_TEXT_CHUNKS);
+ for (int i = 0; i < outputTexts.size(); i++)
+ {
+ PngText text = (PngText) outputTexts.get(i);
+ if (text instanceof PngText.tEXt)
+ writeChunktEXt(os, (PngText.tEXt) text);
+ else if (text instanceof PngText.zTXt)
+ writeChunkzTXt(os, (PngText.zTXt) text);
+ else if (text instanceof PngText.iTXt)
+ writeChunkiTXt(os, (PngText.iTXt) text);
+ else
+ throw new ImageWriteException(
+ "Unknown text to embed in PNG: " + text);
+ }
}
{
@@ -438,9 +541,10 @@
int gray = (red + green + blue) / 3;
// if(y==0)
// {
- // Debug.debug("gray: " + x + ", " + y + " argb: 0x"
- // + Integer.toHexString(argb) + " gray: 0x"
- // + Integer.toHexString(gray));
+ // Debug.debug("gray: " + x + ", " + y +
+ // " argb: 0x"
+ // + Integer.toHexString(argb) + " gray: 0x"
+ // + Integer.toHexString(gray));
// // Debug.debug(x + ", " + y + " gray", gray);
// // Debug.debug(x + ", " + y + " gray", gray);
// Debug.debug(x + ", " + y + " gray", gray +
@@ -462,7 +566,7 @@
uncompressed = baos.toByteArray();
}
- // Debug.debug("uncompressed", uncompressed.length);
+ // Debug.debug("uncompressed", uncompressed.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DeflaterOutputStream dos = new DeflaterOutputStream(baos);
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=682538&r1=682537&r2=682538&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 Mon Aug 4 16:23:45 2008
@@ -19,7 +19,7 @@
import java.io.IOException;
import org.apache.sanselan.ImageReadException;
-import org.apache.sanselan.common.ZLibInflater;
+import org.apache.sanselan.common.ZLibUtils;
public class PNGChunkiCCP extends PNGChunk
{
@@ -63,7 +63,7 @@
System.out.println("bytes.length: " + bytes.length);
}
- UncompressedProfile = new ZLibInflater()
+ UncompressedProfile = new ZLibUtils()
.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=682538&r1=682537&r2=682538&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 Mon Aug 4 16:23:45 2008
@@ -19,8 +19,9 @@
import java.io.IOException;
import org.apache.sanselan.ImageReadException;
-import org.apache.sanselan.common.ZLibInflater;
+import org.apache.sanselan.common.ZLibUtils;
import org.apache.sanselan.formats.png.PngConstants;
+import org.apache.sanselan.formats.png.PngText;
public class PNGChunkiTXt extends PNGTextChunk
{
@@ -91,13 +92,14 @@
if (compressed)
{
- int compressedTextLength = bytes.length - index;;
+ int compressedTextLength = bytes.length - index;
+ ;
byte compressedText[] = new byte[compressedTextLength];
System.arraycopy(bytes, index, compressedText, 0,
compressedTextLength);
- text = new String(new ZLibInflater()
- .inflate(compressedText), "utf-8");
+ text = new String(new ZLibUtils().inflate(compressedText),
+ "utf-8");
} else
text = new String(bytes, index, bytes.length - index, "utf-8");
@@ -119,4 +121,9 @@
{
return text;
}
+
+ public PngText getContents()
+ {
+ return new PngText.iTXt(keyword, text, languageTag, translatedKeyword);
+ }
}
\ No newline at end of file
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunktEXt.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunktEXt.java?rev=682538&r1=682537&r2=682538&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunktEXt.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGChunktEXt.java Mon Aug 4 16:23:45 2008
@@ -19,6 +19,8 @@
import java.io.IOException;
import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.ImageWriteException;
+import org.apache.sanselan.formats.png.PngText;
public class PNGChunktEXt extends PNGTextChunk
{
@@ -31,7 +33,8 @@
{
int index = findNull(bytes);
if (index < 0)
- throw new ImageReadException("PNG tEXt chunk keyword is not terminated.");
+ throw new ImageReadException(
+ "PNG tEXt chunk keyword is not terminated.");
keyword = new String(bytes, 0, index, "ISO-8859-1");
@@ -62,4 +65,10 @@
{
return text;
}
+
+ public PngText getContents()
+ {
+ return new PngText.tEXt(keyword, text);
+ }
+
}
\ No newline at end of file
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=682538&r1=682537&r2=682538&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 Mon Aug 4 16:23:45 2008
@@ -19,8 +19,10 @@
import java.io.IOException;
import org.apache.sanselan.ImageReadException;
-import org.apache.sanselan.common.ZLibInflater;
+import org.apache.sanselan.common.ZLibUtils;
import org.apache.sanselan.formats.png.PngConstants;
+import org.apache.sanselan.formats.png.PngText;
+import org.apache.sanselan.util.Debug;
public class PNGChunkzTXt extends PNGTextChunk
{
@@ -39,19 +41,20 @@
"PNG zTXt chunk keyword is unterminated.");
keyword = new String(bytes, 0, index, "ISO-8859-1");
+ index++;
- int compressionMethod = bytes[index + 1];
+ int compressionMethod = bytes[index++];
if (compressionMethod != PngConstants.COMPRESSION_DEFLATE_INFLATE)
throw new ImageReadException(
"PNG zTXt chunk has unexpected compression method: "
+ compressionMethod);
- int compressedTextLength = bytes.length - (index + 1 + 1);
+ int compressedTextLength = bytes.length - index;
byte compressedText[] = new byte[compressedTextLength];
- System.arraycopy(bytes, index + 1 + 1, compressedText, 0,
+ System.arraycopy(bytes, index, compressedText, 0,
compressedTextLength);
- text = new String(new ZLibInflater().inflate(compressedText),
+ text = new String(new ZLibUtils().inflate(compressedText),
"ISO-8859-1");
}
}
@@ -72,4 +75,9 @@
return text;
}
+ public PngText getContents()
+ {
+ return new PngText.zTXt(keyword, text);
+ }
+
}
\ No newline at end of file
Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGTextChunk.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGTextChunk.java?rev=682538&r1=682537&r2=682538&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGTextChunk.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/chunks/PNGTextChunk.java Mon Aug 4 16:23:45 2008
@@ -18,6 +18,8 @@
import java.io.IOException;
+import org.apache.sanselan.formats.png.PngText;
+
public abstract class PNGTextChunk extends PNGChunk
{
@@ -32,4 +34,6 @@
public abstract String getText();
+ public abstract PngText getContents();
+
}
\ No newline at end of file
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/util/UnicodeUtils.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/util/UnicodeUtils.java?rev=682538&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/util/UnicodeUtils.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/util/UnicodeUtils.java Mon Aug 4 16:23:45 2008
@@ -0,0 +1,457 @@
+/*
+ * 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.util;
+
+import java.io.UnsupportedEncodingException;
+
+import org.apache.sanselan.common.BinaryConstants;
+
+public abstract class UnicodeUtils implements BinaryConstants
+{
+ public static class UnicodeException extends Exception
+ {
+ public UnicodeException(String message)
+ {
+ super(message);
+ }
+ }
+
+ // A default single-byte charset.
+ public static final int CHAR_ENCODING_CODE_ISO_8859_1 = 0;
+ public static final int CHAR_ENCODING_CODE_UTF_16_BIG_ENDIAN_WITH_BOM = 1;
+ public static final int CHAR_ENCODING_CODE_UTF_16_LITTLE_ENDIAN_WITH_BOM = 2;
+ public static final int CHAR_ENCODING_CODE_UTF_16_BIG_ENDIAN_NO_BOM = 3;
+ public static final int CHAR_ENCODING_CODE_UTF_16_LITTLE_ENDIAN_NO_BOM = 4;
+ public static final int CHAR_ENCODING_CODE_UTF_8 = 5;
+ public static final int CHAR_ENCODING_CODE_AMBIGUOUS = -1;
+
+ // /*
+ // * Guess the character encoding of arbitrary character data in a data
+ // * buffer.
+ // *
+ // * The data may not run to the end of the buffer; it may be terminated.
+ // This
+ // * makes the problem much harder, since the character data may be followed
+ // * by arbitrary data.
+ // */
+ // public static int guessCharacterEncoding(byte bytes[], int index)
+ // {
+ // int length = bytes.length - index;
+ //
+ // if (length < 1)
+ // return CHAR_ENCODING_CODE_AMBIGUOUS;
+ //
+ // if (length >= 2)
+ // {
+ // // look for BOM.
+ //
+ // int c1 = 0xff & bytes[index];
+ // int c2 = 0xff & bytes[index + 1];
+ // if (c1 == 0xFF && c2 == 0xFE)
+ // return CHAR_ENCODING_CODE_UTF_16_LITTLE_ENDIAN_WITH_BOM;
+ // else if (c1 == 0xFE && c2 == 0xFF)
+ // return CHAR_ENCODING_CODE_UTF_16_BIG_ENDIAN_WITH_BOM;
+ // }
+ //
+ // }
+ //
+ // /*
+ // * Guess the character encoding of arbitrary character data in a data
+ // * buffer.
+ // *
+ // * The data fills the entire buffer. If it is terminated, the terminator
+ // * byte(s) will be the last bytes in the buffer.
+ // *
+ // * This makes the problem a bit easier.
+ // */
+ // public static int guessCharacterEncodingSimple(byte bytes[], int index)
+ // throws UnicodeException
+ // {
+ // int length = bytes.length - index;
+ //
+ // if (length < 1)
+ // return CHAR_ENCODING_CODE_AMBIGUOUS;
+ //
+ // if (length >= 2)
+ // {
+ // // identify or eliminate UTF-16 with a BOM.
+ //
+ // int c1 = 0xff & bytes[index];
+ // int c2 = 0xff & bytes[index + 1];
+ // if (c1 == 0xFF && c2 == 0xFE)
+ // return CHAR_ENCODING_CODE_UTF_16_LITTLE_ENDIAN_WITH_BOM;
+ // else if (c1 == 0xFE && c2 == 0xFF)
+ // return CHAR_ENCODING_CODE_UTF_16_BIG_ENDIAN_WITH_BOM;
+ // }
+ //
+ // if (length >= 2)
+ // {
+ // // look for optional double-byte terminator.
+ //
+ // int c1 = 0xff & bytes[bytes.length - 2];
+ // int c2 = 0xff & bytes[bytes.length - 1];
+ // if (c1 == 0 && c2 == 0)
+ // {
+ // // definitely a flavor of UTF-16.
+ // if (length % 2 != 0)
+ // throw new UnicodeException(
+ // "Character data with double-byte terminator has an odd length.");
+ //
+ // boolean mayHaveTerminator = true;
+ // boolean mustHaveTerminator = false;
+ // boolean possibleBigEndian = new UnicodeMetricsUTF16NoBOM(
+ // BYTE_ORDER_BIG_ENDIAN).isValid(bytes, index,
+ // mayHaveTerminator, mustHaveTerminator);
+ // boolean possibleLittleEndian = new UnicodeMetricsUTF16NoBOM(
+ // BYTE_ORDER_LITTLE_ENDIAN).isValid(bytes, index,
+ // mayHaveTerminator, mustHaveTerminator);
+ // if ((!possibleBigEndian) && (!possibleLittleEndian))
+ // throw new UnicodeException(
+ // "Invalid character data, possibly UTF-16.");
+ // if (possibleBigEndian && possibleLittleEndian)
+ // return CHAR_ENCODING_CODE_AMBIGUOUS;
+ // if (possibleBigEndian)
+ // return CHAR_ENCODING_CODE_UTF_16_BIG_ENDIAN_NO_BOM;
+ // if (possibleLittleEndian)
+ // return CHAR_ENCODING_CODE_UTF_16_LITTLE_ENDIAN_NO_BOM;
+ // }
+ // }
+ //
+ // List possibleEncodings = new ArrayList();
+ // if (length % 2 == 0)
+ // {
+ // boolean mayHaveTerminator = true;
+ // boolean mustHaveTerminator = false;
+ // boolean possibleBigEndian = new UnicodeMetricsUTF16NoBOM(
+ // BYTE_ORDER_BIG_ENDIAN).isValid(bytes, index,
+ // mayHaveTerminator, mustHaveTerminator);
+ // boolean possibleLittleEndian = new UnicodeMetricsUTF16NoBOM(
+ // BYTE_ORDER_LITTLE_ENDIAN).isValid(bytes, index,
+ // mayHaveTerminator, mustHaveTerminator);
+ //
+ // if (possibleBigEndian)
+ // return CHAR_ENCODING_CODE_UTF_16_BIG_ENDIAN_NO_BOM;
+ // if (possibleLittleEndian)
+ // return CHAR_ENCODING_CODE_UTF_16_LITTLE_ENDIAN_NO_BOM;
+ // }
+ //
+ // }
+
+ public static final boolean isValidISO_8859_1(String s)
+ {
+ try
+ {
+ String roundtrip = new String(s.getBytes("ISO-8859-1"),
+ "ISO-8859-1");
+ return s.equals(roundtrip);
+ } catch (UnsupportedEncodingException e)
+ {
+ // should never be thrown.
+ throw new RuntimeException("Error parsing string.", e);
+ }
+ }
+
+ /*
+ * Return the index of the first utf-16 terminator (ie. two even-aligned
+ * nulls). If not found, return -1.
+ */
+ private static int findFirstDoubleByteTerminator(byte bytes[], int index)
+ {
+ for (int i = index; i < bytes.length - 1; i += 2)
+ {
+ int c1 = 0xff & bytes[index];
+ int c2 = 0xff & bytes[index + 1];
+ if (c1 == 0 && c2 == 0)
+ return i;
+ }
+ return -1;
+ }
+
+ public final int findEndWithTerminator(byte bytes[], int index)
+ throws UnicodeException
+ {
+ return findEnd(bytes, index, true);
+ }
+
+ public final int findEndWithoutTerminator(byte bytes[], int index)
+ throws UnicodeException
+ {
+ return findEnd(bytes, index, false);
+ }
+
+ protected abstract int findEnd(byte bytes[], int index,
+ boolean includeTerminator) throws UnicodeException;
+
+ public static UnicodeUtils getInstance(int charEncodingCode)
+ throws UnicodeException
+ {
+ switch (charEncodingCode)
+ {
+ case CHAR_ENCODING_CODE_ISO_8859_1:
+ return new UnicodeMetricsASCII();
+ case CHAR_ENCODING_CODE_UTF_8:
+ // Debug.debug("CHAR_ENCODING_CODE_UTF_8");
+ return new UnicodeMetricsUTF8();
+ case CHAR_ENCODING_CODE_UTF_16_BIG_ENDIAN_WITH_BOM:
+ case CHAR_ENCODING_CODE_UTF_16_LITTLE_ENDIAN_WITH_BOM:
+ // Debug.debug("CHAR_ENCODING_CODE_UTF_16_WITH_BOM");
+ return new UnicodeMetricsUTF16WithBOM();
+ case CHAR_ENCODING_CODE_UTF_16_BIG_ENDIAN_NO_BOM:
+ return new UnicodeMetricsUTF16NoBOM(BYTE_ORDER_BIG_ENDIAN);
+ case CHAR_ENCODING_CODE_UTF_16_LITTLE_ENDIAN_NO_BOM:
+ return new UnicodeMetricsUTF16NoBOM(BYTE_ORDER_LITTLE_ENDIAN);
+ default:
+ throw new UnicodeException("Unknown char encoding code: "
+ + charEncodingCode);
+ }
+ }
+
+ private static class UnicodeMetricsASCII extends UnicodeUtils
+ {
+ public int findEnd(byte bytes[], int index, boolean includeTerminator)
+ throws UnicodeException
+ {
+ for (int i = index; i < bytes.length; i++)
+ {
+ if (bytes[i] == 0)
+ return includeTerminator ? i + 1 : i;
+ }
+ return bytes.length;
+ // throw new UnicodeException("Terminator not found.");
+ }
+ }
+
+ // private static class UnicodeMetricsISO_8859_1 extends UnicodeUtils
+ // {
+ // public int findEnd(byte bytes[], int index, boolean includeTerminator)
+ // throws UnicodeException
+ // {
+ // for (int i = index; i < bytes.length; i++)
+ // {
+ // if (bytes[i] == 0)
+ // return includeTerminator ? i + 1 : i;
+ // }
+ // return bytes.length;
+ // // throw new UnicodeException("Terminator not found.");
+ // }
+ // }
+
+ private static class UnicodeMetricsUTF8 extends UnicodeUtils
+ {
+
+ public int findEnd(byte bytes[], int index, boolean includeTerminator)
+ throws UnicodeException
+ {
+ // http://en.wikipedia.org/wiki/UTF-8
+
+ while (true)
+ {
+ if (index == bytes.length)
+ return bytes.length;
+ if (index > bytes.length)
+ throw new UnicodeException("Terminator not found.");
+
+ int c1 = 0xff & bytes[index++];
+ if (c1 == 0)
+ return includeTerminator ? index : index - 1;
+ else if (c1 <= 0x7f)
+ continue;
+ else if (c1 <= 0xDF)
+ {
+ if (index >= bytes.length)
+ throw new UnicodeException("Invalid unicode.");
+
+ int c2 = 0xff & bytes[index++];
+ if (c2 < 0x80 || c2 > 0xBF)
+ throw new UnicodeException("Invalid code point.");
+ } else if (c1 <= 0xEF)
+ {
+ if (index >= bytes.length - 1)
+ throw new UnicodeException("Invalid unicode.");
+
+ int c2 = 0xff & bytes[index++];
+ if (c2 < 0x80 || c2 > 0xBF)
+ throw new UnicodeException("Invalid code point.");
+ int c3 = 0xff & bytes[index++];
+ if (c3 < 0x80 || c3 > 0xBF)
+ throw new UnicodeException("Invalid code point.");
+ } else if (c1 <= 0xF4)
+ {
+ if (index >= bytes.length - 2)
+ throw new UnicodeException("Invalid unicode.");
+
+ int c2 = 0xff & bytes[index++];
+ if (c2 < 0x80 || c2 > 0xBF)
+ throw new UnicodeException("Invalid code point.");
+ int c3 = 0xff & bytes[index++];
+ if (c3 < 0x80 || c3 > 0xBF)
+ throw new UnicodeException("Invalid code point.");
+ int c4 = 0xff & bytes[index++];
+ if (c4 < 0x80 || c4 > 0xBF)
+ throw new UnicodeException("Invalid code point.");
+ } else
+ throw new UnicodeException("Invalid code point.");
+ }
+ }
+ }
+
+ private abstract static class UnicodeMetricsUTF16 extends UnicodeUtils
+ {
+ protected static final int BYTE_ORDER_BIG_ENDIAN = 0;
+ protected static final int BYTE_ORDER_LITTLE_ENDIAN = 1;
+ protected int byteOrder = BYTE_ORDER_BIG_ENDIAN;
+
+ public UnicodeMetricsUTF16(int byteOrder)
+ {
+ this.byteOrder = byteOrder;
+ }
+
+ public boolean isValid(byte bytes[], int index,
+ boolean mayHaveTerminator, boolean mustHaveTerminator)
+ throws UnicodeException
+ {
+ // http://en.wikipedia.org/wiki/UTF-16/UCS-2
+
+ while (true)
+ {
+ if (index == bytes.length)
+ {
+ // end of buffer, no terminator found.
+ return !mustHaveTerminator;
+ }
+
+ if (index >= bytes.length - 1)
+ {
+ // end of odd-length buffer, no terminator found.
+ return false;
+ }
+
+ int c1 = 0xff & bytes[index++];
+ int c2 = 0xff & bytes[index++];
+ int msb1 = byteOrder == BYTE_ORDER_BIG_ENDIAN ? c1 : c2;
+
+ if (c1 == 0 && c2 == 0)
+ {
+ // terminator found.
+ return mayHaveTerminator;
+ }
+
+ if (msb1 >= 0xD8)
+ {
+ // Surrogate pair found.
+
+ if (msb1 >= 0xDC)
+ {
+ // invalid first surrogate.
+ return false;
+ }
+
+ if (index >= bytes.length - 1)
+ {
+ // missing second surrogate.
+ return false;
+ }
+
+ // second word.
+ int c3 = 0xff & bytes[index++];
+ int c4 = 0xff & bytes[index++];
+ int msb2 = byteOrder == BYTE_ORDER_BIG_ENDIAN ? c3 : c4;
+ if (msb2 < 0xDC)
+ {
+ // invalid second surrogate.
+ return false;
+ }
+ }
+ }
+ }
+
+ public int findEnd(byte bytes[], int index, boolean includeTerminator)
+ throws UnicodeException
+ {
+ // http://en.wikipedia.org/wiki/UTF-16/UCS-2
+
+ while (true)
+ {
+ if (index == bytes.length)
+ return bytes.length;
+ if (index > bytes.length - 1)
+ throw new UnicodeException("Terminator not found.");
+
+ int c1 = 0xff & bytes[index++];
+ int c2 = 0xff & bytes[index++];
+ int msb1 = byteOrder == BYTE_ORDER_BIG_ENDIAN ? c1 : c2;
+
+ if (c1 == 0 && c2 == 0)
+ {
+ return includeTerminator ? index : index - 2;
+ } else if (msb1 >= 0xD8)
+ {
+ if (index > bytes.length - 1)
+ throw new UnicodeException("Terminator not found.");
+
+ // second word.
+ int c3 = 0xff & bytes[index++];
+ int c4 = 0xff & bytes[index++];
+ int msb2 = byteOrder == BYTE_ORDER_BIG_ENDIAN ? c3 : c4;
+ if (msb2 < 0xDC)
+ throw new UnicodeException("Invalid code point.");
+ }
+ }
+ }
+ }
+
+ private static class UnicodeMetricsUTF16NoBOM extends UnicodeMetricsUTF16
+ {
+
+ public UnicodeMetricsUTF16NoBOM(final int byteOrder)
+ {
+ super(byteOrder);
+ }
+
+ }
+
+ private static class UnicodeMetricsUTF16WithBOM extends UnicodeMetricsUTF16
+ {
+
+ public UnicodeMetricsUTF16WithBOM()
+ {
+ super(BYTE_ORDER_BIG_ENDIAN);
+ }
+
+ public int findEnd(byte bytes[], int index, boolean includeTerminator)
+ throws UnicodeException
+ {
+ // http://en.wikipedia.org/wiki/UTF-16/UCS-2
+
+ if (index >= bytes.length - 1)
+ throw new UnicodeException("Missing BOM.");
+
+ int c1 = 0xff & bytes[index++];
+ int c2 = 0xff & bytes[index++];
+ if (c1 == 0xFF && c2 == 0xFE)
+ byteOrder = BYTE_ORDER_LITTLE_ENDIAN;
+ else if (c1 == 0xFE && c2 == 0xFF)
+ byteOrder = BYTE_ORDER_BIG_ENDIAN;
+ else
+ throw new UnicodeException("Invalid byte order mark.");
+
+ return super.findEnd(bytes, index, includeTerminator);
+ }
+ }
+
+}
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/util/UnicodeUtils.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/png/PngTextTest.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/png/PngTextTest.java?rev=682538&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/png/PngTextTest.java (added)
+++ incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/png/PngTextTest.java Mon Aug 4 16:23:45 2008
@@ -0,0 +1,96 @@
+/*
+ * 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.png;
+
+import java.awt.Color;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+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.util.IOUtils;
+
+public class PngTextTest extends PngBaseTest
+{
+
+ public void test() throws IOException, ImageReadException,
+ ImageWriteException
+ {
+ int width = 1;
+ int height = 1;
+ BufferedImage srcImage = new BufferedImage(width, height,
+ BufferedImage.TYPE_INT_ARGB);
+ srcImage.setRGB(0, 0, Color.red.getRGB());
+
+ Map writeParams = new HashMap();
+
+ List writeTexts = new ArrayList();
+ {
+ String keyword = "a";
+ String text = "b";
+ writeTexts.add(new PngText.tEXt(keyword, text));
+ }
+ {
+ String keyword = "c";
+ String text = "d";
+ writeTexts.add(new PngText.zTXt(keyword, text));
+ }
+ {
+ String keyword = "e";
+ String text = "f";
+ String languageTag = "g";
+ String translatedKeyword = "h";
+ writeTexts.add(new PngText.iTXt(keyword, text, languageTag,
+ translatedKeyword));
+ }
+
+ writeParams.put(PngConstants.PARAM_KEY_PNG_TEXT_CHUNKS, writeTexts);
+
+ byte bytes[] = Sanselan.writeImageToBytes(srcImage,
+ ImageFormat.IMAGE_FORMAT_PNG, writeParams);
+
+ File tempFile = createTempFile("temp", ".png");
+ IOUtils.writeToFile(bytes, tempFile);
+
+ PngImageInfo imageInfo = (PngImageInfo) Sanselan.getImageInfo(bytes);
+ assertTrue(null != imageInfo);
+
+ List readTexts = imageInfo.getTextChunks();
+ assertEquals(readTexts.size(), 3);
+ for (int i = 0; i < readTexts.size(); i++)
+ {
+ PngText text = (PngText) readTexts.get(i);
+ if (text.keyword.equals("a"))
+ assertEquals(text.text, "b");
+ else if (text.keyword.equals("c"))
+ assertEquals(text.text, "d");
+ else if (text.keyword.equals("e"))
+ assertEquals(text.text, "f");
+ else
+ fail("unknown text chunk.");
+ }
+ }
+
+}
Propchange: incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/png/PngTextTest.java
------------------------------------------------------------------------------
svn:eol-style = native