    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.imaging.formats.png.chunks;
    018
    019import java.io.ByteArrayInputStream;
    020import java.io.IOException;
    021import java.nio.charset.StandardCharsets;
    022import java.util.Arrays;
    023import java.util.logging.Level;
    024import java.util.logging.Logger;
    025import java.util.zip.InflaterInputStream;
    026
    027import org.apache.commons.imaging.ImagingException;
    028import org.apache.commons.imaging.common.Allocator;
    029import org.apache.commons.imaging.common.BinaryFunctions;
    030import org.apache.commons.io.IOUtils;
    031
    032/**
    033 * The PNG iCCP chunk. If "present, the image samples conform to the color space represented by the embedded ICC profile as defined by the International Color
    034 * Consortium".
    035 *
    036 * @see <a href="http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html">PNG Specification</a>
    037 */
    038public final class PngChunkIccp extends PngChunk {
    039
    040    /*
    041     * Logger.
    042     */
    043    private static final Logger LOGGER = Logger.getLogger(PngChunkIccp.class.getName());
    044
    045    /**
    046     * ICC profile name.
    047     */
    048    private final String profileName;
    049
    050    /**
    051     * Compression method.
    052     */
    053    private final int compressionMethod;
    054
    055    /**
    056     * Compressed profile data.
    057     */
    058    private final byte[] compressedProfile;
    059
    060    /**
    061     * Uncompressed profile data.
    062     */
    063    private final byte[] uncompressedProfile;
    064
    065    /**
    066     * Constructs a new instance.
    067     *
    068     * @param length    chunk length
    069     * @param chunkType chunk type
    070     * @param crc       CRC computed over the chunk type and chunk data (but not the length)
    071     * @param bytes     chunk data bytes
    072     * @throws ImagingException when no profile name is present
    073     * @throws IOException      when an error happens while reading the profile data
    074     */
    075    public PngChunkIccp(final int length, final int chunkType, final int crc, final byte[] bytes) throws ImagingException, IOException {
    076        super(length, chunkType, crc, bytes);
    077
    078        final int index = BinaryFunctions.indexOf0(bytes, "PngChunkIccp: No Profile Name");
    079        final byte[] nameBytes = Arrays.copyOf(bytes, index);
    080        profileName = new String(nameBytes, StandardCharsets.ISO_8859_1);
    081
    082        compressionMethod = bytes[index + 1];
    083
    084        final int compressedProfileLength = bytes.length - (index + 1 + 1);
    085        compressedProfile = Allocator.byteArray(compressedProfileLength);
    086        System.arraycopy(bytes, index + 1 + 1, compressedProfile, 0, compressedProfileLength);
    087
    088        if (LOGGER.isLoggable(Level.FINEST)) {
    089            LOGGER.finest("ProfileName: " + profileName);
    090            LOGGER.finest("ProfileName.length(): " + profileName.length());
    091            LOGGER.finest("CompressionMethod: " + compressionMethod);
    092            LOGGER.finest("CompressedProfileLength: " + compressedProfileLength);
    093            LOGGER.finest("bytes.length: " + bytes.length);
    094        }
    095
    096        uncompressedProfile = IOUtils.toByteArray(new InflaterInputStream(new ByteArrayInputStream(compressedProfile)));
    097
    098        if (LOGGER.isLoggable(Level.FINEST)) {
    099            LOGGER.finest("UncompressedProfile: " + bytes.length);
    100        }
    101    }
    102
    103    public byte[] getCompressedProfile() {
    104        return compressedProfile.clone();
    105    }
    106
    107    public int getCompressionMethod() {
    108        return compressionMethod;
    109    }
    110
    111    public String getProfileName() {
    112        return profileName;
    113    }
    114
    115    /**
    116     * Gets a copy of the uncompressed profile data.
    117     *
    118     * @return the uncompressed profile data
    119     */
    120    public byte[] getUncompressedProfile() {
    121        return uncompressedProfile.clone();
    122    }
    123
    124}