| /* |
| * 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. |
| */ |
| |
| /* $Id$ */ |
| |
| package org.apache.xmlgraphics.image.codec.png; |
| |
| import java.io.DataInputStream; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| public class PNGChunk { |
| int length; |
| int type; |
| byte[] data; |
| int crc; |
| |
| String typeString; |
| |
| /** logger */ |
| protected static Log log = LogFactory.getLog(PNGChunk.class); |
| |
| /** |
| * See http://en.wikipedia.org/wiki/Portable_Network_Graphics for a light explanation; |
| * See http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html for the spec. |
| */ |
| public enum ChunkType { |
| IHDR, // IHDR must be the first chunk |
| PLTE, // PLTE contains the palette |
| IDAT, // IDAT contains the image, which may be split among multiple IDAT chunks |
| IEND, // IEND marks the image end |
| bKGD, // bKGD gives the default background color |
| cHRM, // cHRM gives the chromaticity coordinates |
| gAMA, // gAMA specifies gamma |
| hIST, // hIST can store the histogram |
| iCCP, // iCCP is an ICC color profile |
| iTXt, // iTXt contains UTF-8 text |
| pHYs, // pHYs holds the intended pixel size |
| sBIT, // sBIT (significant bits) indicates the color-accuracy |
| sPLT, // sPLT suggests a palette to use |
| sRGB, // sRGB indicates that the standard sRGB color space is used |
| sTER, // sTER stereo-image indicator chunk for stereoscopic images |
| tEXt, // tEXt can store text that can be represented in ISO/IEC 8859-1 |
| tIME, // tIME stores the time that the image was last changed |
| tRNS, // tRNS contains transparency information |
| zTXt; // zTXt contains compressed text with the same limits as tEXt |
| } |
| |
| public PNGChunk(int length, int type, byte[] data, int crc) { |
| this.length = length; |
| this.type = type; |
| this.data = data; |
| this.crc = crc; |
| this.typeString = typeIntToString(this.type); |
| } |
| |
| public int getLength() { |
| return length; |
| } |
| |
| public int getType() { |
| return type; |
| } |
| |
| public String getTypeString() { |
| return typeString; |
| } |
| |
| public byte[] getData() { |
| return data; |
| } |
| |
| public byte getByte(int offset) { |
| return data[offset]; |
| } |
| |
| public int getInt1(int offset) { |
| return data[offset] & 0xff; |
| } |
| |
| public int getInt2(int offset) { |
| return ((data[offset] & 0xff) << 8) | (data[offset + 1] & 0xff); |
| } |
| |
| public int getInt4(int offset) { |
| return ((data[offset] & 0xff) << 24) | ((data[offset + 1] & 0xff) << 16) |
| | ((data[offset + 2] & 0xff) << 8) | (data[offset + 3] & 0xff); |
| } |
| |
| public String getString4(int offset) { |
| return "" + (char) data[offset] + (char) data[offset + 1] + (char) data[offset + 2] |
| + (char) data[offset + 3]; |
| } |
| |
| public boolean isType(String typeName) { |
| return typeString.equals(typeName); |
| } |
| |
| /** |
| * Reads the next chunk from the input stream. |
| * @param distream the input stream |
| * @return the chunk |
| */ |
| public static PNGChunk readChunk(DataInputStream distream) { |
| try { |
| int length = distream.readInt(); |
| int type = distream.readInt(); |
| byte[] data = new byte[length]; |
| distream.readFully(data); |
| int crc = distream.readInt(); |
| |
| return new PNGChunk(length, type, data, crc); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the PNG chunk type, a four letter case sensitive ASCII type/name. |
| * @param distream the input stream |
| * @return a four letter case sensitive ASCII type/name |
| */ |
| public static String getChunkType(DataInputStream distream) { |
| try { |
| distream.mark(8); |
| /* int length = */distream.readInt(); |
| int type = distream.readInt(); |
| distream.reset(); |
| |
| return typeIntToString(type); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| return null; |
| } |
| } |
| |
| private static String typeIntToString(int type) { |
| String typeString = ""; |
| typeString += (char) (type >> 24); |
| typeString += (char) ((type >> 16) & 0xff); |
| typeString += (char) ((type >> 8) & 0xff); |
| typeString += (char) (type & 0xff); |
| return typeString; |
| } |
| |
| /** |
| * Skips the next chunk from the input stream. |
| * @param distream the input stream |
| * @return true if skipping successful, false otherwise |
| */ |
| public static boolean skipChunk(DataInputStream distream) { |
| try { |
| int length = distream.readInt(); |
| int type = distream.readInt(); |
| // is this really faster than reading? |
| int skipped = distream.skipBytes(length); |
| int crc = distream.readInt(); |
| if (skipped != length) { |
| log.warn("Incorrect number of bytes skipped."); |
| return false; |
| } |
| return true; |
| } catch (Exception e) { |
| log.warn(e.getMessage()); |
| return false; |
| } |
| } |
| } |