United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6541476 PNG imageio plugin incorrectly handles iTXt chunk
JDK-6541476 : PNG imageio plugin incorrectly handles iTXt chunk

Details
Type:
Bug
Submit Date:
2007-04-02
Status:
Resolved
Updated Date:
2011-01-19
Project Name:
JDK
Resolved Date:
2009-01-09
Component:
client-libs
OS:
solaris_2.5.1
Sub-Component:
javax.imageio
CPU:
x86
Priority:
P4
Resolution:
Fixed
Affected Versions:
5.0
Fixed Versions:

Related Reports
Backport:
Backport:

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.6.0",
java version "1.5.0_04",
java version "1.4.2_05"

ADDITIONAL OS VERSION INFORMATION :
Linux 2.6.19-1.2288.2.4.fc5,
Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
com.sun.imageio.plugins.pngPNGMetadata#mergeNativeTree incorrectly stores iTXt_compressionFlag values.   At line 1406 (iTXt_compressionFlag.add(new Boolean(compressionFlag));), values are added to the iTXt_compressionFlag ArrayList as Boolean objects.  If they are later retieved in a call to getNativeTree the objects are cast to Integer, which creates an exception.  Other references to iTXt_compressionFlag use Integer, so line 1406 should store the value as an integer.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
a new test.png file, with an iTXt cluster containing the text "<xml></xml>"
ACTUAL -
java.lang.ClassCastException, see below

ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.ClassCastException: java.lang.Boolean cannot be cast to java.lang.Integer
	at com.sun.imageio.plugins.png.PNGImageWriter.write_iTXt(PNGImageWriter.java:680)
	at com.sun.imageio.plugins.png.PNGImageWriter.write(PNGImageWriter.java:1120)
	at javax.imageio.ImageWriter.write(ImageWriter.java:580)
	at org.mbari.aosn.moqua.image.Test1.main(Test1.java:56)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package org.mbari.aosn.moqua.image;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.IIOImage;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataFormat;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageOutputStream;

import org.w3c.dom.Node;

import com.sun.imageio.plugins.png.PNGImageWriter;
import com.sun.imageio.plugins.png.PNGImageWriterSpi;

public class Test1 {

	static public void main(String args[]) {
		try {
			File file = new File("test.png");
			BufferedImage image = new BufferedImage(128, 128,
					BufferedImage.TYPE_4BYTE_ABGR_PRE);
			Graphics2D graph = image.createGraphics();
			graph.setPaintMode();
			graph.setColor(Color.orange);
			graph.fillRect(32, 32, 64, 64);
			graph.dispose();
			ImageOutputStream imageOutputStream = new FileImageOutputStream(
					file);
			ImageTypeSpecifier imageTypeSpecifier = new ImageTypeSpecifier(
					image);
			ImageWriter imageWriter = new PNGImageWriter(
					new PNGImageWriterSpi());
			imageWriter.setOutput(imageOutputStream);
			IIOMetadata metadata = imageWriter.getDefaultImageMetadata(
					imageTypeSpecifier, null);
			String formatNames[] = metadata.getMetadataFormatNames();
			for (String formatName : formatNames) {
				IIOMetadataFormat format = metadata
						.getMetadataFormat(formatName);
				Node node = metadata.getAsTree(formatName);
				if (formatName.contains("png")) {
					IIOMetadataNode iTXt = new IIOMetadataNode("iTXt");
					IIOMetadataNode iTXtEntry = new IIOMetadataNode("iTXtEntry");
					iTXtEntry.setAttribute("keyword", "XML:com.adobe.xmp");
					iTXtEntry.setAttribute("compressionFlag", "false");
					iTXtEntry.setAttribute("compressionMethod", "0");
					iTXtEntry.setAttribute("languageTag", "en");
					iTXtEntry.setAttribute("translatedKeyword",
							"XML:com.adobe.xmp");
					iTXtEntry.setAttribute("text", "<xml></xml>");
					iTXt.appendChild(iTXtEntry);
					node.appendChild(iTXt);
					metadata.setFromTree(formatName, node);
					break;
				}
			}
			imageWriter.write(new IIOImage(image, null, metadata));
			imageOutputStream.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
before calling mageWriter.write(new IIOImage(image, null, metadata));
insert the following lines (which resolves this problem and a similar problem involving iTXt_compressionMethod):

			if(metadata instanceof PNGMetadata){
				List iTXt_compressionFlag = ((PNGMetadata)metadata).iTXt_compressionFlag;
				for(int i = 0; i < iTXt_compressionFlag.size(); ++i){
					Object flag = iTXt_compressionFlag.get(i);
					if(flag instanceof Boolean){
						iTXt_compressionFlag.set(i,Integer.valueOf(((Boolean)flag).booleanValue()?1:0));
					}
				}
				List iTXt_compressionMethod = ((PNGMetadata)metadata).iTXt_compressionMethod;
				for(int i = 0; i < iTXt_compressionMethod.size(); ++i){
					Object method = iTXt_compressionMethod.get(i);
					if(method instanceof String){
						try{
							iTXt_compressionMethod.set(i,Integer.valueOf((String)method));
						} catch (NumberFormatException NFE) {
							iTXt_compressionMethod.set(i,Integer.valueOf(0));
						}
					}
				}
			}

                                    

Comments
EVALUATION

The CR 6541476 is about problem with a writing of iTXt chunk
 but we read it incorrectly too if this chunk contains 
 non-ascii data (namely, translatedKeyword and text attributes
 may contain UTF8 data).

The main reason of reading failures is the DataInputStream.readUTF()
 function usage.  This function interprets first two bytes in the
 input stream as a string data length and seems to be designed 
 for de-serialization purposes only.

The idea of fix is to avoid usage of this function and pay attention
 to expected data encoding on writing and reading stage.

Another problem is that PNG metadata class uses collections (ArraList,
 for example) without specifying the type of stored data. It may lead
 to  problem like described in this CR. To avoid this, we can specify 
 data type for each collection.
                                     
2008-10-31
SUGGESTED FIX

http://sa.sfbay.sun.com/projects/java2d_data/7/6541476.0
                                     
2008-11-01



Hardware and Software, Engineered to Work Together