Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4782879
Votes 7
Synopsis PNG plug-in should support 2- and 4-bit data
Category jai:codec_imageio
Reported Against 1.0
Release Fixed
State 3-Accepted, request for enhancement
Priority: 4-Low
Related Bugs 6345283
Submit Date 21-NOV-2002
Description
PNG plug-in should support 2- and 4-bit data.
Work Around
N/A
Evaluation
Reading portion of fix is in the Java codec_imageio code. This is fixed now.

The writing portion cannot be fixed until RFE 6345283 is implemented.
Posted Date : 2005-11-03 01:58:15.0
Comments
  
  Include a link with my name & email   

Submitted On 15-DEC-2005
davidelewis
This issue is causing tremedous difficulties for us ... we have build distributed imgae processing tools that retrieve map images (via WMS) in real-time. Returned images are often encoded as 4-bit PNG's. The bottom line is ... our code breaks! 


Submitted On 15-DEC-2005
davidelewis
Not only are 2-bit and 4-bit bugs are completely unsupported, but some PNG files that have less colors that the bit depth (such as 8-bit with only 7 colors)  can also cause a "LUT has improper length" message. (Perhaps not all leaves have a value on the LUT tree?)


Submitted On 16-DEC-2005
We have a project that depends on this library and is a bit stalled because of this bug.  While I am not on the project, my colleagues are miserable because of this problem. When this problem is fixed, working conditions around here will definitely improve!


Submitted On 24-DEC-2005
jozart
Also see Bug #5098176


Submitted On 23-NOV-2009
Lars.Engholm.Johansen
I know this is fixed in 5.0_08 and 6.0 but for those of us that have clients still running older jre's lets fix this once and for all.

The code below catches the "LUT has improper length" exeption and extends the troublesome PNG palettes to 32 entries.

(If needed, please make your own InputStream wrapper method that knows how to rewind the stream on the LUT exception)
---------------------------------

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;

/**
 *  Wrapper methods to catch ImageIO's "LUT has improper length" exception
 *  and fix it by converting the PNG image to 32 colors
 *  @author Lars Engholm Johansen
 */
public class PNGFixLutError {
	public static BufferedImage read(File file) throws IOException {
		try {
			return ImageIO.read(file);
		} catch (IllegalArgumentException e) {
			if (e.getMessage().startsWith("LUT")) {
				return ImageIO.read(fixLUTproblem(new FileInputStream(file)));
			} else
				throw e;
		}
	}

	public static BufferedImage read(byte[] data) throws IOException {
		try {
			return ImageIO.read(new ByteArrayInputStream(data));
		} catch (IllegalArgumentException e) {
			if (e.getMessage().startsWith("LUT")) {
				return ImageIO.read(fixLUTproblem(new ByteArrayInputStream(data)));
			} else
				throw e;
		}
	}

	public static BufferedImage read(URL url) throws IOException {
		try {
			return ImageIO.read(url);
		} catch (IllegalArgumentException e) {
			if (e.getMessage().startsWith("LUT")) {
				return ImageIO.read(fixLUTproblem(url.openStream()));
			} else
				throw e;
		}
	}

	private final static byte[] PNG_SIGNATURE = {(byte) 137, 'P', 'N', 'G', '\r', '\n', 26, '\n'};
	private static InputStream fixLUTproblem(InputStream original) throws IOException {
		final ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
		final DataOutputStream dos = new DataOutputStream(baos);
		try {
			DataInputStream dis = new DataInputStream(original);
			for (int i = 0; i < 8; i++) {
				final byte b = dis.readByte();
				if (b != PNG_SIGNATURE[i])
					throw new IllegalArgumentException("Not a PNG image");
				dos.write(b);
			}
			String name = "";
			final byte[] nameData = new byte[4];
			int bitDepth = -1;
			int colorType = -1;
			while (!name.equals("IEND")) {
				final int length = dis.readInt();
				dis.readFully(nameData);
				name = new String(nameData);
				if (name.equals("IHDR")) {
					final byte[] headerData = new byte[length+4];	// Including CRC int
					dis.readFully(headerData);
					dos.writeInt(length);
					dos.write(nameData);
					dos.write(headerData);
					bitDepth = headerData[8];
					colorType = headerData[9];
				}
				else if (name.equals("PLTE") && colorType==3 && bitDepth==8 && length < 32*3) {
					final byte[] newPLTEChunk = new byte[32*3];
					dis.readFully(newPLTEChunk, 0, length);
					dis.readInt();	// CRC
					dos.writeInt(newPLTEChunk.length);
					dos.write(nameData);
					dos.write(newPLTEChunk);
					dos.writeInt(crc32(nameData, newPLTEChunk));
				}
				else {
					dos.writeInt(length);
					dos.write(nameData);
					for (int n=length+4; n>0; n--) {	// Including CRC int
						dos.write(dis.read());
					}
				}
			}
		} finally {
			original.close();
		}
		return new ByteArrayInputStream(baos.toByteArray());
	}

	private static int crc32(byte[]... buffers) {
		int crc = 0xffffffff;
		int p;
		for (byte[] buffer : buffers) {
			for (byte b : buffer) {
				p = (crc ^ b) & 0xff;
				for (int k = 0; k < 8; k++) {
					if ((p & 1) == 0)
						p >>>= 1;
					else
						p = 0xedb88320 ^ (p >>> 1);
				}
				crc = p ^ (crc >>> 8);
			}
		}
		return ~crc;
	}
}



PLEASE NOTE: JDK6 is formerly known as Project Mustang