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.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
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;

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 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 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.