All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.drew.imaging.png.PngChunkType Maven / Gradle / Ivy

/*
 * Copyright 2002-2017 Drew Noakes
 *
 *    Licensed 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.
 *
 * More information about this project is available at:
 *
 *    https://drewnoakes.com/code/exif/
 *    https://github.com/drewnoakes/metadata-extractor
 */
package com.drew.imaging.png;

import com.drew.lang.annotations.NotNull;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * @author Drew Noakes https://drewnoakes.com
 */
public class PngChunkType
{
    private static final Set _identifiersAllowingMultiples
        = new HashSet(Arrays.asList("IDAT", "sPLT", "iTXt", "tEXt", "zTXt"));

    //
    // Standard critical chunks
    //
    /**
     * Denotes a critical {@link PngChunk} that contains basic information about the PNG image.
     * This must be the first chunk in the data sequence, and may only occur once.
     * 

* The format is: *

    *
  • pixel width 4 bytes, unsigned and greater than zero
  • *
  • pixel height 4 bytes, unsigned and greater than zero
  • *
  • bit depth 1 byte, number of bits per sample or per palette index (not per pixel)
  • *
  • color type 1 byte, maps to {@link PngColorType} enum
  • *
  • compression method 1 byte, currently only a value of zero (deflate/inflate) is in the standard
  • *
  • filter method 1 byte, currently only a value of zero (adaptive filtering with five basic filter types) is in the standard
  • *
  • interlace method 1 byte, indicates the transmission order of image data, currently only 0 (no interlace) and 1 (Adam7 interlace) are in the standard
  • *
*/ public static final PngChunkType IHDR; /** * Denotes a critical {@link PngChunk} that contains palette entries. * This chunk should only appear for a {@link PngColorType} of IndexedColor, * and may only occur once in the PNG data sequence. *

* The chunk contains between one and 256 entries, each of three bytes: *

    *
  • red 1 byte
  • *
  • green 1 byte
  • *
  • blue 1 byte
  • *
* The number of entries is determined by the chunk length. A chunk length indivisible by three is an error. */ public static final PngChunkType PLTE; public static final PngChunkType IDAT; public static final PngChunkType IEND; // // Standard ancillary chunks // public static final PngChunkType cHRM; public static final PngChunkType gAMA; public static final PngChunkType iCCP; public static final PngChunkType sBIT; public static final PngChunkType sRGB; public static final PngChunkType bKGD; public static final PngChunkType hIST; public static final PngChunkType tRNS; public static final PngChunkType pHYs; public static final PngChunkType sPLT; public static final PngChunkType tIME; public static final PngChunkType iTXt; /** * Denotes an ancillary {@link PngChunk} that contains textual data, having first a keyword and then a value. * If multiple text data keywords are needed, then multiple chunks are included in the PNG data stream. *

* The format is: *

    *
  • keyword 1-79 bytes
  • *
  • null separator 1 byte (\0)
  • *
  • text string 0 or more bytes
  • *
* Text is interpreted according to the Latin-1 character set [ISO-8859-1]. * Newlines should be represented by a single linefeed character (0x9). */ public static final PngChunkType tEXt; public static final PngChunkType zTXt; static { try { IHDR = new PngChunkType("IHDR"); PLTE = new PngChunkType("PLTE"); IDAT = new PngChunkType("IDAT", true); IEND = new PngChunkType("IEND"); cHRM = new PngChunkType("cHRM"); gAMA = new PngChunkType("gAMA"); iCCP = new PngChunkType("iCCP"); sBIT = new PngChunkType("sBIT"); sRGB = new PngChunkType("sRGB"); bKGD = new PngChunkType("bKGD"); hIST = new PngChunkType("hIST"); tRNS = new PngChunkType("tRNS"); pHYs = new PngChunkType("pHYs"); sPLT = new PngChunkType("sPLT", true); tIME = new PngChunkType("tIME"); iTXt = new PngChunkType("iTXt", true); tEXt = new PngChunkType("tEXt", true); zTXt = new PngChunkType("zTXt", true); } catch (PngProcessingException e) { throw new IllegalArgumentException(e); } } private final byte[] _bytes; private final boolean _multipleAllowed; public PngChunkType(@NotNull String identifier) throws PngProcessingException { this(identifier, false); } public PngChunkType(@NotNull String identifier, boolean multipleAllowed) throws PngProcessingException { _multipleAllowed = multipleAllowed; try { byte[] bytes = identifier.getBytes("ASCII"); validateBytes(bytes); _bytes = bytes; } catch (UnsupportedEncodingException e) { throw new IllegalArgumentException("Unable to convert string code to bytes."); } } public PngChunkType(@NotNull byte[] bytes) throws PngProcessingException { validateBytes(bytes); _bytes = bytes; _multipleAllowed = _identifiersAllowingMultiples.contains(getIdentifier()); } private static void validateBytes(byte[] bytes) throws PngProcessingException { if (bytes.length != 4) { throw new PngProcessingException("PNG chunk type identifier must be four bytes in length"); } for (byte b : bytes) { if (!isValidByte(b)) { throw new PngProcessingException("PNG chunk type identifier may only contain alphabet characters"); } } } public boolean isCritical() { return isUpperCase(_bytes[0]); } public boolean isAncillary() { return !isCritical(); } public boolean isPrivate() { return isUpperCase(_bytes[1]); } public boolean isSafeToCopy() { return isLowerCase(_bytes[3]); } public boolean areMultipleAllowed() { return _multipleAllowed; } private static boolean isLowerCase(byte b) { return (b & (1 << 5)) != 0; } private static boolean isUpperCase(byte b) { return (b & (1 << 5)) == 0; } private static boolean isValidByte(byte b) { return (b >= 65 && b <= 90) || (b >= 97 && b <= 122); } public String getIdentifier() { try { return new String(_bytes, "ASCII"); } catch (UnsupportedEncodingException e) { // The constructor should ensure that we're always able to encode the bytes in ASCII. // noinspection ConstantConditions assert(false); return "Invalid object instance"; } } @Override public String toString() { return getIdentifier(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PngChunkType that = (PngChunkType)o; return Arrays.equals(_bytes, that._bytes); } @Override public int hashCode() { return Arrays.hashCode(_bytes); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy