Package org.apache.sanselan.formats.tiff

Source Code of org.apache.sanselan.formats.tiff.TiffImageParser

/*
* 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.
*/
package org.apache.sanselan.formats.tiff;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.sanselan.FormatCompliance;
import org.apache.sanselan.ImageFormat;
import org.apache.sanselan.ImageInfo;
import org.apache.sanselan.ImageParser;
import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.ImageWriteException;
import org.apache.sanselan.common.IImageMetadata;
import org.apache.sanselan.common.byteSources.ByteSource;
import org.apache.sanselan.formats.tiff.constants.TiffConstants;
import org.apache.sanselan.formats.tiff.datareaders.DataReader;
import org.apache.sanselan.formats.tiff.photometricinterpreters.PhotometricInterpreter;
import org.apache.sanselan.formats.tiff.photometricinterpreters.PhotometricInterpreterBiLevel;
import org.apache.sanselan.formats.tiff.photometricinterpreters.PhotometricInterpreterCIELAB;
import org.apache.sanselan.formats.tiff.photometricinterpreters.PhotometricInterpreterCMYK;
import org.apache.sanselan.formats.tiff.photometricinterpreters.PhotometricInterpreterLogLUV;
import org.apache.sanselan.formats.tiff.photometricinterpreters.PhotometricInterpreterPalette;
import org.apache.sanselan.formats.tiff.photometricinterpreters.PhotometricInterpreterRGB;
import org.apache.sanselan.formats.tiff.photometricinterpreters.PhotometricInterpreterYCbCr;
import org.apache.sanselan.formats.tiff.write.TiffImageWriterLossy;

import com.google.code.appengine.awt.Dimension;
import com.google.code.appengine.awt.image.BufferedImage;


public class TiffImageParser extends ImageParser implements TiffConstants
{
    public TiffImageParser()
    {
        // setDebug(true);
    }

    public String getName()
    {
        return "Tiff-Custom";
    }

    public String getDefaultExtension()
    {
        return DEFAULT_EXTENSION;
    }

    private static final String DEFAULT_EXTENSION = ".tif";

    private static final String ACCEPTED_EXTENSIONS[] = { ".tif", ".tiff", };

    protected String[] getAcceptedExtensions()
    {
        return ACCEPTED_EXTENSIONS;
    }

    protected ImageFormat[] getAcceptedTypes()
    {
        return new ImageFormat[] { ImageFormat.IMAGE_FORMAT_TIFF, //
        };
    }

    public byte[] getICCProfileBytes(ByteSource byteSource, Map params)
            throws ImageReadException, IOException
    {
        FormatCompliance formatCompliance = FormatCompliance.getDefault();
        TiffContents contents = new TiffReader(isStrict(params))
                .readFirstDirectory(byteSource, params, false, formatCompliance);
        TiffDirectory directory = (TiffDirectory) contents.directories.get(0);

        TiffField field = directory.findField(EXIF_TAG_ICC_PROFILE);
        if (null == field)
            return null;
        return field.oversizeValue;
    }

    public Dimension getImageSize(ByteSource byteSource, Map params)
            throws ImageReadException, IOException
    {
        FormatCompliance formatCompliance = FormatCompliance.getDefault();
        TiffContents contents = new TiffReader(isStrict(params))
                .readFirstDirectory(byteSource, params, false, formatCompliance);
        TiffDirectory directory = (TiffDirectory) contents.directories.get(0);

        int width = directory.findField(TIFF_TAG_IMAGE_WIDTH).getIntValue();
        int height = directory.findField(TIFF_TAG_IMAGE_LENGTH).getIntValue();

        return new Dimension(width, height);
    }

    public byte[] embedICCProfile(byte image[], byte profile[])
    {
        return null;
    }

    public boolean embedICCProfile(File src, File dst, byte profile[])
    {
        return false;
    }

    public IImageMetadata getMetadata(ByteSource byteSource, Map params)
            throws ImageReadException, IOException
    {
        FormatCompliance formatCompliance = FormatCompliance.getDefault();
        TiffContents contents = new TiffReader(isStrict(params)).readContents(
                byteSource, params, formatCompliance);

        ArrayList directories = contents.directories;

        TiffImageMetadata result = new TiffImageMetadata(contents);

        for (int i = 0; i < directories.size(); i++)
        {
            TiffDirectory dir = (TiffDirectory) directories.get(i);

            TiffImageMetadata.Directory metadataDirectory = new TiffImageMetadata.Directory(
                    dir);

            ArrayList entries = dir.getDirectoryEntrys();

            for (int j = 0; j < entries.size(); j++)
            {
                TiffField entry = (TiffField) entries.get(j);
                metadataDirectory.add(entry);
            }

            result.add(metadataDirectory);
        }

        return result;
    }

    public ImageInfo getImageInfo(ByteSource byteSource, Map params)
            throws ImageReadException, IOException
    {
        FormatCompliance formatCompliance = FormatCompliance.getDefault();
        TiffContents contents = new TiffReader(isStrict(params))
                .readDirectories(byteSource, false, formatCompliance);
        TiffDirectory directory = (TiffDirectory) contents.directories.get(0);

        TiffField widthField = directory.findField(TIFF_TAG_IMAGE_WIDTH, true);
        TiffField heightField = directory
                .findField(TIFF_TAG_IMAGE_LENGTH, true);

        if ((widthField == null) || (heightField == null))
            throw new ImageReadException("TIFF image missing size info.");

        int height = heightField.getIntValue();
        int width = widthField.getIntValue();

        // -------------------

        TiffField resolutionUnitField = directory
                .findField(TIFF_TAG_RESOLUTION_UNIT);
        int resolutionUnit = 2; // Inch
        if ((resolutionUnitField != null)
                && (resolutionUnitField.getValue() != null))
            resolutionUnit = resolutionUnitField.getIntValue();

        double unitsPerInch = -1;
        switch (resolutionUnit)
        {
        case 1:
            break;
        case 2: // Inch
            unitsPerInch = 1.0;
            break;
        case 3: // Meter
            unitsPerInch = 0.0254;
            break;
        default:
            break;

        }
        TiffField xResolutionField = directory.findField(TIFF_TAG_XRESOLUTION);
        TiffField yResolutionField = directory.findField(TIFF_TAG_YRESOLUTION);

        int physicalWidthDpi = -1;
        float physicalWidthInch = -1;
        int physicalHeightDpi = -1;
        float physicalHeightInch = -1;

        if (unitsPerInch > 0)
        {
            if ((xResolutionField != null)
                    && (xResolutionField.getValue() != null))
            {
                double XResolutionPixelsPerUnit = xResolutionField
                        .getDoubleValue();
                physicalWidthDpi = (int) (XResolutionPixelsPerUnit / unitsPerInch);
                physicalWidthInch = (float) (width / (XResolutionPixelsPerUnit * unitsPerInch));
            }
            if ((yResolutionField != null)
                    && (yResolutionField.getValue() != null))
            {
                double YResolutionPixelsPerUnit = yResolutionField
                        .getDoubleValue();
                physicalHeightDpi = (int) (YResolutionPixelsPerUnit / unitsPerInch);
                physicalHeightInch = (float) (height / (YResolutionPixelsPerUnit * unitsPerInch));
            }
        }

        // -------------------

        TiffField bitsPerSampleField = directory
                .findField(TIFF_TAG_BITS_PER_SAMPLE);

        int bitsPerSample = -1;
        if ((bitsPerSampleField != null)
                && (bitsPerSampleField.getValue() != null))
            bitsPerSample = bitsPerSampleField.getIntValueOrArraySum();

        int bitsPerPixel = bitsPerSample; // assume grayscale;
        // dunno if this handles colormapped images correctly.

        // -------------------

        ArrayList comments = new ArrayList();
        ArrayList entries = directory.entries;
        for (int i = 0; i < entries.size(); i++)
        {
            TiffField field = (TiffField) entries.get(i);
            String comment = field.toString();
            comments.add(comment);
        }

        ImageFormat format = ImageFormat.IMAGE_FORMAT_TIFF;
        String formatName = "TIFF Tag-based Image File Format";
        String mimeType = "image/tiff";
        int numberOfImages = contents.directories.size();
        // not accurate ... only reflects first
        boolean isProgressive = false;
        // is TIFF ever interlaced/progressive?

        String formatDetails = "Tiff v." + contents.header.tiffVersion;

        boolean isTransparent = false; // TODO: wrong
        boolean usesPalette = false;
        TiffField colorMapField = directory.findField(TIFF_TAG_COLOR_MAP);
        if (colorMapField != null)
            usesPalette = true;

        int colorType = ImageInfo.COLOR_TYPE_RGB;

        int compression = directory.findField(TIFF_TAG_COMPRESSION)
                .getIntValue();
        String compressionAlgorithm;

        switch (compression)
        {
        case TIFF_COMPRESSION_UNCOMPRESSED_1:
            compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_NONE;
            break;
        case TIFF_COMPRESSION_CCITT_1D:
            compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_CCITT_1D;
            break;
        case TIFF_COMPRESSION_CCITT_GROUP_3:
            compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_CCITT_GROUP_3;
            break;
        case TIFF_COMPRESSION_CCITT_GROUP_4:
            compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_CCITT_GROUP_4;
            break;
        case TIFF_COMPRESSION_LZW:
            compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_LZW;
            break;
        case TIFF_COMPRESSION_JPEG:
            compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_JPEG;
            break;
        case TIFF_COMPRESSION_UNCOMPRESSED_2:
            compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_NONE;
            break;
        case TIFF_COMPRESSION_PACKBITS:
            compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_PACKBITS;
            break;
        default:
            compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_UNKNOWN;
            break;
        }

        ImageInfo result = new ImageInfo(formatDetails, bitsPerPixel, comments,
                format, formatName, height, mimeType, numberOfImages,
                physicalHeightDpi, physicalHeightInch, physicalWidthDpi,
                physicalWidthInch, width, isProgressive, isTransparent,
                usesPalette, colorType, compressionAlgorithm);

        return result;
    }

    public String getXmpXml(ByteSource byteSource, Map params)
            throws ImageReadException, IOException
    {
        FormatCompliance formatCompliance = FormatCompliance.getDefault();
        TiffContents contents = new TiffReader(isStrict(params))
                .readDirectories(byteSource, false, formatCompliance);
        TiffDirectory directory = (TiffDirectory) contents.directories.get(0);

        TiffField xmpField = directory.findField(TIFF_TAG_XMP, false);
        if (xmpField == null)
            return null;

        byte bytes[] = xmpField.getByteArrayValue();

        try
        {
            // segment data is UTF-8 encoded xml.
            String xml = new String(bytes, "utf-8");
            return xml;
        } catch (UnsupportedEncodingException e)
        {
            throw new ImageReadException("Invalid JPEG XMP Segment.");
        }
    }

    public boolean dumpImageFile(PrintWriter pw, ByteSource byteSource)
            throws ImageReadException, IOException
    {
        try
        {
            pw.println("tiff.dumpImageFile");

            {
                ImageInfo imageData = getImageInfo(byteSource);
                if (imageData == null)
                    return false;

                imageData.toString(pw, "");
            }

            pw.println("");

            // try
            {
                FormatCompliance formatCompliance = FormatCompliance
                        .getDefault();
                Map params = null;
                TiffContents contents = new TiffReader(true).readContents(
                        byteSource, params, formatCompliance);

                ArrayList directories = contents.directories;

                if (directories == null)
                    return false;

                for (int d = 0; d < directories.size(); d++)
                {
                    TiffDirectory directory = (TiffDirectory) directories
                            .get(d);

                    ArrayList entries = directory.entries;

                    if (entries == null)
                        return false;

                    // Debug.debug("directory offset", directory.offset);

                    for (int i = 0; i < entries.size(); i++)
                    {
                        TiffField field = (TiffField) entries.get(i);

                        field.dump(pw, d + "");
                    }
                }

                pw.println("");
            }
            // catch (Exception e)
            // {
            // Debug.debug(e);
            // pw.println("");
            // return false;
            // }

            return true;
        } finally
        {
            pw.println("");
        }
    }

    public FormatCompliance getFormatCompliance(ByteSource byteSource)
            throws ImageReadException, IOException
    {
        FormatCompliance formatCompliance = FormatCompliance.getDefault();
        Map params = null;
        new TiffReader(isStrict(params)).readContents(byteSource, params,
                formatCompliance);
        return formatCompliance;
    }

    public List collectRawImageData(ByteSource byteSource, Map params)
            throws ImageReadException, IOException
    {
        FormatCompliance formatCompliance = FormatCompliance.getDefault();
        TiffContents contents = new TiffReader(isStrict(params))
                .readDirectories(byteSource, true, formatCompliance);

        List result = new ArrayList();
        for (int i = 0; i < contents.directories.size(); i++)
        {
            TiffDirectory directory = (TiffDirectory) contents.directories
                    .get(i);
            List dataElements = directory.getTiffRawImageDataElements();
            for (int j = 0; j < dataElements.size(); j++)
            {
                TiffDirectory.ImageDataElement element = (TiffDirectory.ImageDataElement) dataElements
                        .get(j);
                byte bytes[] = byteSource.getBlock(element.offset,
                        element.length);
                result.add(bytes);
            }
        }
        return result;
    }

    public BufferedImage getBufferedImage(ByteSource byteSource, Map params)
            throws ImageReadException, IOException
    {
        FormatCompliance formatCompliance = FormatCompliance.getDefault();
        TiffContents contents = new TiffReader(isStrict(params))
                .readFirstDirectory(byteSource, params, true, formatCompliance);
        TiffDirectory directory = (TiffDirectory) contents.directories.get(0);
        BufferedImage result = directory.getTiffImage(params);
        if (null == result)
            throw new ImageReadException("TIFF does not contain an image.");
        return result;
    }

    protected BufferedImage getBufferedImage(TiffDirectory directory, Map params)
            throws ImageReadException, IOException
    {
        ArrayList entries = directory.entries;

        if (entries == null)
            throw new ImageReadException("TIFF missing entries");

        int photometricInterpretation = directory.findField(
                TIFF_TAG_PHOTOMETRIC_INTERPRETATION, true).getIntValue();
        int compression = directory.findField(TIFF_TAG_COMPRESSION, true)
                .getIntValue();
        int width = directory.findField(TIFF_TAG_IMAGE_WIDTH, true)
                .getIntValue();
        int height = directory.findField(TIFF_TAG_IMAGE_LENGTH, true)
                .getIntValue();
        int samplesPerPixel = directory.findField(TIFF_TAG_SAMPLES_PER_PIXEL,
                true).getIntValue();
        int bitsPerSample[] = directory.findField(TIFF_TAG_BITS_PER_SAMPLE,
                true).getIntArrayValue();
        // TODO: why are we using bits per sample twice? because one is a sum.
        int bitsPerPixel = directory.findField(TIFF_TAG_BITS_PER_SAMPLE, true)
                .getIntValueOrArraySum();

        // int bitsPerPixel = getTagAsValueOrArraySum(entries,
        // TIFF_TAG_BITS_PER_SAMPLE);

        int predictor = -1;
        {
            // dumpOptionalNumberTag(entries, TIFF_TAG_FILL_ORDER);
            // dumpOptionalNumberTag(entries, TIFF_TAG_FREE_BYTE_COUNTS);
            // dumpOptionalNumberTag(entries, TIFF_TAG_FREE_OFFSETS);
            // dumpOptionalNumberTag(entries, TIFF_TAG_ORIENTATION);
            // dumpOptionalNumberTag(entries, TIFF_TAG_PLANAR_CONFIGURATION);
            TiffField predictorField = directory.findField(TIFF_TAG_PREDICTOR);
            if (null != predictorField)
                predictor = predictorField.getIntValueOrArraySum();
        }

        if (samplesPerPixel != bitsPerSample.length)
            throw new ImageReadException("Tiff: samplesPerPixel ("
                    + samplesPerPixel + ")!=fBitsPerSample.length ("
                    + bitsPerSample.length + ")");

        boolean hasAlpha = false;
        BufferedImage result = getBufferedImageFactory(params)
                .getColorBufferedImage(width, height, hasAlpha);

        PhotometricInterpreter photometricInterpreter = getPhotometricInterpreter(
                directory, photometricInterpretation, bitsPerPixel,
                bitsPerSample, predictor, samplesPerPixel, width, height);

        TiffImageData imageData = directory.getTiffImageData();

        DataReader dataReader = imageData.getDataReader(entries,
                photometricInterpreter, bitsPerPixel, bitsPerSample, predictor,
                samplesPerPixel, width, height, compression);

        dataReader.readImageData(result);

        photometricInterpreter.dumpstats();

        return result;
    }

    private PhotometricInterpreter getPhotometricInterpreter(
            TiffDirectory directory, int photometricInterpretation,
            int bitsPerPixel, int bitsPerSample[], int predictor,
            int samplesPerPixel, int width, int height) throws IOException,
            ImageReadException
    {
        switch (photometricInterpretation)
        {
        case 0:
        case 1:
            boolean invert = photometricInterpretation == 0;

            return new PhotometricInterpreterBiLevel(bitsPerPixel,
                    samplesPerPixel, bitsPerSample, predictor, width, height,
                    invert);
        case 3: // Palette
        {
            int colorMap[] = directory.findField(TIFF_TAG_COLOR_MAP, true)
                    .getIntArrayValue();

            int expected_colormap_size = 3 * (1 << bitsPerPixel);

            if (colorMap.length != expected_colormap_size)
                throw new ImageReadException("Tiff: fColorMap.length ("
                        + colorMap.length + ")!=expected_colormap_size ("
                        + expected_colormap_size + ")");

            return new PhotometricInterpreterPalette(samplesPerPixel,
                    bitsPerSample, predictor, width, height, colorMap);
        }
        case 2: // RGB
            return new PhotometricInterpreterRGB(samplesPerPixel,
                    bitsPerSample, predictor, width, height);
        case 5: // CMYK
            return new PhotometricInterpreterCMYK(samplesPerPixel,
                    bitsPerSample, predictor, width, height);
        case 6: //
        {
            double yCbCrCoefficients[] = directory.findField(
                    TIFF_TAG_YCBCR_COEFFICIENTS, true).getDoubleArrayValue();

            int yCbCrPositioning[] = directory.findField(
                    TIFF_TAG_YCBCR_POSITIONING, true).getIntArrayValue();
            int yCbCrSubSampling[] = directory.findField(
                    TIFF_TAG_YCBCR_SUB_SAMPLING, true).getIntArrayValue();

            double referenceBlackWhite[] = directory.findField(
                    TIFF_TAG_REFERENCE_BLACK_WHITE, true).getDoubleArrayValue();

            return new PhotometricInterpreterYCbCr(yCbCrCoefficients,
                    yCbCrPositioning, yCbCrSubSampling, referenceBlackWhite,
                    samplesPerPixel, bitsPerSample, predictor, width, height);
        }

        case 8:
            return new PhotometricInterpreterCIELAB(samplesPerPixel,
                    bitsPerSample, predictor, width, height);

        case 32844:
        case 32845: {
            boolean yonly = (photometricInterpretation == 32844);
            return new PhotometricInterpreterLogLUV(samplesPerPixel,
                    bitsPerSample, predictor, width, height, yonly);
        }

        default:
            throw new ImageReadException(
                    "TIFF: Unknown fPhotometricInterpretation: "
                            + photometricInterpretation);
        }
    }

    public void writeImage(BufferedImage src, OutputStream os, Map params)
            throws ImageWriteException, IOException
    {
        new TiffImageWriterLossy().writeImage(src, os, params);
    }

}
TOP

Related Classes of org.apache.sanselan.formats.tiff.TiffImageParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.