blob: f809e8791f2b80c1216ec74881aebb34f52f4526 [file] [log] [blame]
/*
* 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.commons.imaging.formats.tiff;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
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.commons.imaging.FormatCompliance;
import org.apache.commons.imaging.ImageFormat;
import org.apache.commons.imaging.ImageFormats;
import org.apache.commons.imaging.ImageInfo;
import org.apache.commons.imaging.ImageParser;
import org.apache.commons.imaging.ImageReadException;
import org.apache.commons.imaging.ImageWriteException;
import org.apache.commons.imaging.common.ByteOrder;
import org.apache.commons.imaging.common.IImageMetadata;
import org.apache.commons.imaging.common.ImageBuilder;
import org.apache.commons.imaging.common.bytesource.ByteSource;
import org.apache.commons.imaging.formats.tiff.TiffDirectory.ImageDataElement;
import org.apache.commons.imaging.formats.tiff.constants.TiffConstants;
import org.apache.commons.imaging.formats.tiff.constants.TiffEpTagConstants;
import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
import org.apache.commons.imaging.formats.tiff.datareaders.DataReader;
import org.apache.commons.imaging.formats.tiff.photometricinterpreters.PhotometricInterpreter;
import org.apache.commons.imaging.formats.tiff.photometricinterpreters.PhotometricInterpreterBiLevel;
import org.apache.commons.imaging.formats.tiff.photometricinterpreters.PhotometricInterpreterCieLab;
import org.apache.commons.imaging.formats.tiff.photometricinterpreters.PhotometricInterpreterCmyk;
import org.apache.commons.imaging.formats.tiff.photometricinterpreters.PhotometricInterpreterLogLuv;
import org.apache.commons.imaging.formats.tiff.photometricinterpreters.PhotometricInterpreterPalette;
import org.apache.commons.imaging.formats.tiff.photometricinterpreters.PhotometricInterpreterRgb;
import org.apache.commons.imaging.formats.tiff.photometricinterpreters.PhotometricInterpreterYCbCr;
import org.apache.commons.imaging.formats.tiff.write.TiffImageWriterLossy;
public class TiffImageParser extends ImageParser implements TiffConstants {
public TiffImageParser() {
// setDebug(true);
}
@Override
public String getName() {
return "Tiff-Custom";
}
@Override
public String getDefaultExtension() {
return DEFAULT_EXTENSION;
}
private static final String DEFAULT_EXTENSION = ".tif";
private static final String ACCEPTED_EXTENSIONS[] = { ".tif", ".tiff", };
@Override
protected String[] getAcceptedExtensions() {
return ACCEPTED_EXTENSIONS;
}
@Override
protected ImageFormat[] getAcceptedTypes() {
return new ImageFormat[] { ImageFormats.TIFF, //
};
}
@Override
public byte[] getICCProfileBytes(final ByteSource byteSource, final Map<String,Object> params)
throws ImageReadException, IOException {
final FormatCompliance formatCompliance = FormatCompliance.getDefault();
final TiffContents contents = new TiffReader(isStrict(params))
.readFirstDirectory(byteSource, params, false, formatCompliance);
final TiffDirectory directory = contents.directories.get(0);
return directory.getFieldValue(TiffEpTagConstants.EXIF_TAG_INTER_COLOR_PROFILE,
false);
}
@Override
public Dimension getImageSize(final ByteSource byteSource, final Map<String,Object> params)
throws ImageReadException, IOException {
final FormatCompliance formatCompliance = FormatCompliance.getDefault();
final TiffContents contents = new TiffReader(isStrict(params))
.readFirstDirectory(byteSource, params, false, formatCompliance);
final TiffDirectory directory = contents.directories.get(0);
final TiffField widthField = directory.findField(
TiffTagConstants.TIFF_TAG_IMAGE_WIDTH, true);
final TiffField heightField = directory.findField(
TiffTagConstants.TIFF_TAG_IMAGE_LENGTH, true);
if ((widthField == null) || (heightField == null)) {
throw new ImageReadException("TIFF image missing size info.");
}
final int height = heightField.getIntValue();
final int width = widthField.getIntValue();
return new Dimension(width, height);
}
public byte[] embedICCProfile(final byte image[], final byte profile[]) {
return null;
}
@Override
public boolean embedICCProfile(final File src, final File dst, final byte profile[]) {
return false;
}
@Override
public IImageMetadata getMetadata(final ByteSource byteSource, final Map<String,Object> params)
throws ImageReadException, IOException {
final FormatCompliance formatCompliance = FormatCompliance.getDefault();
final TiffReader tiffReader = new TiffReader(isStrict(params));
final TiffContents contents = tiffReader.readContents(byteSource, params,
formatCompliance);
final List<TiffDirectory> directories = contents.directories;
final TiffImageMetadata result = new TiffImageMetadata(contents);
for (int i = 0; i < directories.size(); i++) {
final TiffDirectory dir = directories.get(i);
final TiffImageMetadata.Directory metadataDirectory = new TiffImageMetadata.Directory(
tiffReader.getByteOrder(), dir);
final List<TiffField> entries = dir.getDirectoryEntries();
for (int j = 0; j < entries.size(); j++) {
final TiffField entry = entries.get(j);
metadataDirectory.add(entry);
}
result.add(metadataDirectory);
}
return result;
}
@Override
public ImageInfo getImageInfo(final ByteSource byteSource, final Map<String,Object> params)
throws ImageReadException, IOException {
final FormatCompliance formatCompliance = FormatCompliance.getDefault();
final TiffContents contents = new TiffReader(isStrict(params))
.readDirectories(byteSource, false, formatCompliance);
final TiffDirectory directory = contents.directories.get(0);
final TiffField widthField = directory.findField(
TiffTagConstants.TIFF_TAG_IMAGE_WIDTH, true);
final TiffField heightField = directory.findField(
TiffTagConstants.TIFF_TAG_IMAGE_LENGTH, true);
if ((widthField == null) || (heightField == null)) {
throw new ImageReadException("TIFF image missing size info.");
}
final int height = heightField.getIntValue();
final int width = widthField.getIntValue();
// -------------------
final TiffField resolutionUnitField = directory
.findField(TiffTagConstants.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: // Centimeter
unitsPerInch = 2.54;
break;
default:
break;
}
final TiffField xResolutionField = directory
.findField(TiffTagConstants.TIFF_TAG_XRESOLUTION);
final TiffField yResolutionField = directory
.findField(TiffTagConstants.TIFF_TAG_YRESOLUTION);
int physicalWidthDpi = -1;
float physicalWidthInch = -1;
int physicalHeightDpi = -1;
float physicalHeightInch = -1;
if (unitsPerInch > 0) {
if ((xResolutionField != null)
&& (xResolutionField.getValue() != null)) {
final double XResolutionPixelsPerUnit = xResolutionField
.getDoubleValue();
physicalWidthDpi = (int) Math
.round((XResolutionPixelsPerUnit * unitsPerInch));
physicalWidthInch = (float) (width / (XResolutionPixelsPerUnit * unitsPerInch));
}
if ((yResolutionField != null)
&& (yResolutionField.getValue() != null)) {
final double YResolutionPixelsPerUnit = yResolutionField
.getDoubleValue();
physicalHeightDpi = (int) Math
.round((YResolutionPixelsPerUnit * unitsPerInch));
physicalHeightInch = (float) (height / (YResolutionPixelsPerUnit * unitsPerInch));
}
}
// -------------------
final TiffField bitsPerSampleField = directory
.findField(TiffTagConstants.TIFF_TAG_BITS_PER_SAMPLE);
int bitsPerSample = 1;
if ((bitsPerSampleField != null)
&& (bitsPerSampleField.getValue() != null)) {
bitsPerSample = bitsPerSampleField.getIntValueOrArraySum();
}
final int bitsPerPixel = bitsPerSample; // assume grayscale;
// dunno if this handles colormapped images correctly.
// -------------------
final List<String> comments = new ArrayList<String>();
final List<TiffField> entries = directory.entries;
for (int i = 0; i < entries.size(); i++) {
final TiffField field = entries.get(i);
final String comment = field.toString();
comments.add(comment);
}
final ImageFormat format = ImageFormats.TIFF;
final String formatName = "TIFF Tag-based Image File Format";
final String mimeType = "image/tiff";
final int numberOfImages = contents.directories.size();
// not accurate ... only reflects first
final boolean isProgressive = false;
// is TIFF ever interlaced/progressive?
final String formatDetails = "Tiff v." + contents.header.tiffVersion;
final boolean isTransparent = false; // TODO: wrong
boolean usesPalette = false;
final TiffField colorMapField = directory
.findField(TiffTagConstants.TIFF_TAG_COLOR_MAP);
if (colorMapField != null) {
usesPalette = true;
}
final int colorType = ImageInfo.COLOR_TYPE_RGB;
final int compression = 0xffff & directory
.getSingleFieldValue(TiffTagConstants.TIFF_TAG_COMPRESSION);
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;
}
final ImageInfo result = new ImageInfo(formatDetails, bitsPerPixel, comments,
format, formatName, height, mimeType, numberOfImages,
physicalHeightDpi, physicalHeightInch, physicalWidthDpi,
physicalWidthInch, width, isProgressive, isTransparent,
usesPalette, colorType, compressionAlgorithm);
return result;
}
@Override
public String getXmpXml(final ByteSource byteSource, final Map<String,Object> params)
throws ImageReadException, IOException {
final FormatCompliance formatCompliance = FormatCompliance.getDefault();
final TiffContents contents = new TiffReader(isStrict(params))
.readDirectories(byteSource, false, formatCompliance);
final TiffDirectory directory = contents.directories.get(0);
final byte bytes[] = directory.getFieldValue(TiffTagConstants.TIFF_TAG_XMP,
false);
if (bytes == null) {
return null;
}
try {
// segment data is UTF-8 encoded xml.
final String xml = new String(bytes, "utf-8");
return xml;
} catch (final UnsupportedEncodingException e) {
throw new ImageReadException("Invalid JPEG XMP Segment.");
}
}
@Override
public boolean dumpImageFile(final PrintWriter pw, final ByteSource byteSource)
throws ImageReadException, IOException {
try {
pw.println("tiff.dumpImageFile");
{
final ImageInfo imageData = getImageInfo(byteSource);
if (imageData == null) {
return false;
}
imageData.toString(pw, "");
}
pw.println("");
// try
{
final FormatCompliance formatCompliance = FormatCompliance
.getDefault();
final Map<String,Object> params = null;
final TiffContents contents = new TiffReader(true).readContents(
byteSource, params, formatCompliance);
final List<TiffDirectory> directories = contents.directories;
if (directories == null) {
return false;
}
for (int d = 0; d < directories.size(); d++) {
final TiffDirectory directory = directories.get(d);
final List<TiffField> entries = directory.entries;
if (entries == null) {
return false;
}
// Debug.debug("directory offset", directory.offset);
for (int i = 0; i < entries.size(); i++) {
final TiffField field = entries.get(i);
field.dump(pw, d + "");
}
}
pw.println("");
}
// catch (Exception e)
// {
// Debug.debug(e);
// pw.println("");
// return false;
// }
return true;
} finally {
pw.println("");
}
}
@Override
public FormatCompliance getFormatCompliance(final ByteSource byteSource)
throws ImageReadException, IOException {
final FormatCompliance formatCompliance = FormatCompliance.getDefault();
final Map<String,Object> params = null;
new TiffReader(isStrict(params)).readContents(byteSource, params,
formatCompliance);
return formatCompliance;
}
public List<byte[]> collectRawImageData(final ByteSource byteSource, final Map<String,Object> params)
throws ImageReadException, IOException {
final FormatCompliance formatCompliance = FormatCompliance.getDefault();
final TiffContents contents = new TiffReader(isStrict(params))
.readDirectories(byteSource, true, formatCompliance);
final List<byte[]> result = new ArrayList<byte[]>();
for (int i = 0; i < contents.directories.size(); i++) {
final TiffDirectory directory = contents.directories.get(i);
final List<ImageDataElement> dataElements = directory
.getTiffRawImageDataElements();
for (int j = 0; j < dataElements.size(); j++) {
final TiffDirectory.ImageDataElement element = dataElements.get(j);
final byte bytes[] = byteSource.getBlock(element.offset,
element.length);
result.add(bytes);
}
}
return result;
}
/**
* Gets a buffered image specified by the byte source.
* The TiffImageParser class features support for a number of options that
* are unique to the TIFF format. These options can be specified by
* supplying the appropriate parameters using the keys from the
* TiffConstants class and the params argument for this method.
* <h4>Loading Partial Images</h4>
* The TIFF parser includes support for loading partial images without
* committing significantly more memory resources than are necessary
* to store the image. This feature is useful for conserving memory
* in applications that require a relatively small sub image from a
* very large TIFF file. The specifications for partial images are
* as follows:
* <code><pre>
* HashMap<String, Object> params = new HashMap<String, Object>();
* params.put(TiffConstants.PARAM_KEY_SUBIMAGE_X, new Integer(x));
* params.put(TiffConstants.PARAM_KEY_SUBIMAGE_Y, new Integer(y));
* params.put(TiffConstants.PARAM_KEY_SUBIMAGE_WIDTH, new Integer(width));
* params.put(TiffConstants.PARAM_KEY_SUBIMAGE_HEIGHT, new Integer(height));
* </pre></code>
* Note that the arguments x, y, width, and height must specify a
* valid rectangular region that is fully contained within the
* source TIFF image.
* @param byteSource A valid instance of ByteSource
* @param params Optional instructions for special-handling or
* interpretation of the input data (null objects are permitted and
* must be supported by implementations).
* @return A valid instance of BufferedImage.
* @throws ImageReadException In the event that the the specified
* content does not conform to the format of the specific parser
* implementation.
* @throws IOException In the event of unsuccessful read or
* access operation.
*/
@Override
public BufferedImage getBufferedImage(final ByteSource byteSource, final Map<String,Object> params)
throws ImageReadException, IOException {
final FormatCompliance formatCompliance = FormatCompliance.getDefault();
final TiffReader reader = new TiffReader(isStrict(params));
final TiffContents contents = reader.readFirstDirectory(byteSource, params,
true, formatCompliance);
final ByteOrder byteOrder = reader.getByteOrder();
final TiffDirectory directory = contents.directories.get(0);
final BufferedImage result = directory.getTiffImage(byteOrder, params);
if (null == result) {
throw new ImageReadException("TIFF does not contain an image.");
}
return result;
}
@Override
public List<BufferedImage> getAllBufferedImages(final ByteSource byteSource)
throws ImageReadException, IOException {
final FormatCompliance formatCompliance = FormatCompliance.getDefault();
final TiffReader tiffReader = new TiffReader(true);
final TiffContents contents = tiffReader.readDirectories(byteSource, true,
formatCompliance);
final List<BufferedImage> results = new ArrayList<BufferedImage>();
for (int i = 0; i < contents.directories.size(); i++) {
final TiffDirectory directory = contents.directories.get(i);
final BufferedImage result = directory.getTiffImage(
tiffReader.getByteOrder(), null);
if (result != null) {
results.add(result);
}
}
return results;
}
private Integer getIntegerParameter(
final String key, final Map<String, Object>params)
throws ImageReadException
{
if (params == null) {
return null;
}
if(!params.containsKey(key)) {
return null;
}
final Object obj = params.get(key);
if(obj instanceof Integer){
return (Integer)obj;
}
throw new ImageReadException(
"Non-Integer parameter "+key);
}
private Rectangle checkForSubImage(
final Map<String, Object> params)
throws ImageReadException
{
Integer ix0, iy0, iwidth, iheight;
ix0 = getIntegerParameter(
TiffConstants.PARAM_KEY_SUBIMAGE_X, params);
iy0 = getIntegerParameter(
TiffConstants.PARAM_KEY_SUBIMAGE_Y, params);
iwidth = getIntegerParameter(
TiffConstants.PARAM_KEY_SUBIMAGE_WIDTH, params);
iheight = getIntegerParameter(
TiffConstants.PARAM_KEY_SUBIMAGE_HEIGHT, params);
if (ix0 == null && iy0 == null && iwidth == null && iheight == null) {
return null;
}
final StringBuilder sb = new StringBuilder();
if (ix0 == null) {
sb.append(" x0,");
}
if (iy0 == null) {
sb.append(" y0,");
}
if (iwidth == null) {
sb.append(" width,");
}
if (iheight == null) {
sb.append(" height,");
}
if (sb.length() > 0) {
sb.setLength(sb.length() - 1);
throw new ImageReadException(
"Incomplete subimage parameters, missing"
+ sb.toString());
}
final int x0 = ix0.intValue();
final int y0 = iy0.intValue();
final int width = iwidth.intValue();
final int height = iheight.intValue();
return new Rectangle(x0, y0, width, height);
}
protected BufferedImage getBufferedImage(final TiffDirectory directory,
final ByteOrder byteOrder, final Map<String,Object> params)
throws ImageReadException, IOException
{
final List<TiffField> entries = directory.entries;
if (entries == null) {
throw new ImageReadException("TIFF missing entries");
}
final int photometricInterpretation = 0xffff & directory.getSingleFieldValue(
TiffTagConstants.TIFF_TAG_PHOTOMETRIC_INTERPRETATION);
final int compression = 0xffff & directory.getSingleFieldValue(
TiffTagConstants.TIFF_TAG_COMPRESSION);
final int width = directory.getSingleFieldValue(
TiffTagConstants.TIFF_TAG_IMAGE_WIDTH);
final int height = directory.getSingleFieldValue(
TiffTagConstants.TIFF_TAG_IMAGE_LENGTH);
Rectangle subImage = checkForSubImage(params);
if(subImage!=null){
// Check for valid subimage specification. The following checks
// are consistent with BufferedImage.getSubimage()
if (subImage.width <= 0) {
throw new ImageReadException("negative or zero subimage width");
}
if (subImage.height <= 0) {
throw new ImageReadException("negative or zero subimage height");
}
if(subImage.x<0 || subImage.x>=width){
throw new ImageReadException("subimage x is outside raster");
}
if(subImage.x+subImage.width>width){
throw new ImageReadException(
"subimage (x+width) is outside raster");
}
if(subImage.y<0 || subImage.y>=height){
throw new ImageReadException("subimage y is outside raster");
}
if(subImage.y+subImage.height>height){
throw new ImageReadException(
"subimage (y+height) is outside raster");
}
// if the subimage is just the same thing as the whole
// image, suppress the subimage processing
if(subImage.x==0
&& subImage.y==0
&& subImage.width==width
&& subImage.height==height){
subImage = null;
}
}
int samplesPerPixel = 1;
final TiffField samplesPerPixelField = directory.findField(
TiffTagConstants.TIFF_TAG_SAMPLES_PER_PIXEL);
if (samplesPerPixelField != null) {
samplesPerPixel = samplesPerPixelField.getIntValue();
}
int bitsPerSample[] = { 1 };
int bitsPerPixel = samplesPerPixel;
final TiffField bitsPerSampleField = directory.findField(
TiffTagConstants.TIFF_TAG_BITS_PER_SAMPLE);
if (bitsPerSampleField != null) {
bitsPerSample = bitsPerSampleField.getIntArrayValue();
bitsPerPixel = bitsPerSampleField.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);
final TiffField predictorField = directory.findField(
TiffTagConstants.TIFF_TAG_PREDICTOR);
if (null != predictorField) {
predictor = predictorField.getIntValueOrArraySum();
}
}
if (samplesPerPixel != bitsPerSample.length) {
throw new ImageReadException("Tiff: samplesPerPixel ("
+ samplesPerPixel + ")!=fBitsPerSample.length ("
+ bitsPerSample.length + ")");
}
final PhotometricInterpreter photometricInterpreter = getPhotometricInterpreter(
directory, photometricInterpretation, bitsPerPixel,
bitsPerSample, predictor, samplesPerPixel, width, height);
final TiffImageData imageData = directory.getTiffImageData();
final DataReader dataReader = imageData.getDataReader(directory,
photometricInterpreter, bitsPerPixel, bitsPerSample, predictor,
samplesPerPixel, width, height, compression, byteOrder);
BufferedImage result = null;
if (subImage != null) {
result = dataReader.readImageData(subImage);
} else {
final boolean hasAlpha = false;
final ImageBuilder imageBuilder = new ImageBuilder(width, height, hasAlpha);
dataReader.readImageData(imageBuilder);
result = imageBuilder.getBufferedImage();
}
photometricInterpreter.dumpstats();
return result;
}
private PhotometricInterpreter getPhotometricInterpreter(
final TiffDirectory directory, final int photometricInterpretation,
final int bitsPerPixel, final int bitsPerSample[], final int predictor,
final int samplesPerPixel, final int width, final int height)
throws ImageReadException {
switch (photometricInterpretation) {
case 0:
case 1:
final boolean invert = photometricInterpretation == 0;
return new PhotometricInterpreterBiLevel(bitsPerPixel,
samplesPerPixel, bitsPerSample, predictor, width, height,
invert);
case 3: // Palette
{
final int colorMap[] = directory.findField(
TiffTagConstants.TIFF_TAG_COLOR_MAP, true)
.getIntArrayValue();
final 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: //
{
final double yCbCrCoefficients[] = directory.findField(
TiffTagConstants.TIFF_TAG_YCBCR_COEFFICIENTS, true)
.getDoubleArrayValue();
final int yCbCrPositioning[] = directory.findField(
TiffTagConstants.TIFF_TAG_YCBCR_POSITIONING, true)
.getIntArrayValue();
final int yCbCrSubSampling[] = directory.findField(
TiffTagConstants.TIFF_TAG_YCBCR_SUB_SAMPLING, true)
.getIntArrayValue();
final double referenceBlackWhite[] = directory.findField(
TiffTagConstants.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: {
final boolean yonly = (photometricInterpretation == 32844);
return new PhotometricInterpreterLogLuv(samplesPerPixel,
bitsPerSample, predictor, width, height, yonly);
}
default:
throw new ImageReadException(
"TIFF: Unknown fPhotometricInterpretation: "
+ photometricInterpretation);
}
}
@Override
public void writeImage(final BufferedImage src, final OutputStream os, final Map<String,Object> params)
throws ImageWriteException, IOException {
new TiffImageWriterLossy().writeImage(src, os, params);
}
}