Search in sources :

Example 11 with ICC_ColorSpace

use of java.awt.color.ICC_ColorSpace in project pdfbox-graphics2d by rototor.

the class PdfBoxGraphics2DLosslessImageEncoder method encodeImage.

@Override
public PDImageXObject encodeImage(PDDocument document, PDPageContentStream contentStream, Image image) {
    final BufferedImage bi;
    if (image instanceof BufferedImage) {
        bi = (BufferedImage) image;
    } else {
        int width = image.getWidth(null);
        int height = image.getHeight(null);
        bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
        Graphics graphics = bi.getGraphics();
        if (!graphics.drawImage(image, 0, 0, null, null))
            throw new IllegalStateException("Not fully loaded images are not supported.");
        graphics.dispose();
    }
    try {
        if (doc == null || doc.get() != document) {
            imageMap = new HashMap<ImageSoftReference, SoftReference<PDImageXObject>>();
            profileMap = new HashMap<ProfileSoftReference, SoftReference<PDICCBased>>();
            doc = new SoftReference<PDDocument>(document);
        }
        SoftReference<PDImageXObject> pdImageXObjectSoftReference = imageMap.get(new ImageSoftReference(image));
        PDImageXObject imageXObject = pdImageXObjectSoftReference == null ? null : pdImageXObjectSoftReference.get();
        if (imageXObject == null) {
            imageXObject = LosslessFactory.createFromImage(document, bi);
            /*
				 * Do we have a color profile we need to embed?
				 */
            if (bi.getColorModel().getColorSpace() instanceof ICC_ColorSpace) {
                ICC_Profile profile = ((ICC_ColorSpace) bi.getColorModel().getColorSpace()).getProfile();
                /*
					 * Only tag a profile if it is not the default sRGB profile.
					 */
                if (((ICC_ColorSpace) bi.getColorModel().getColorSpace()).getProfile() != ICC_Profile.getInstance(ColorSpace.CS_sRGB)) {
                    SoftReference<PDICCBased> pdProfileRef = profileMap.get(new ProfileSoftReference(profile));
                    PDICCBased pdProfile = pdProfileRef == null ? null : pdProfileRef.get();
                    if (pdProfile == null) {
                        pdProfile = new PDICCBased(document);
                        OutputStream outputStream = pdProfile.getPDStream().createOutputStream(COSName.FLATE_DECODE);
                        outputStream.write(profile.getData());
                        outputStream.close();
                        pdProfile.getPDStream().getCOSObject().setInt(COSName.N, profile.getNumComponents());
                        profileMap.put(new ProfileSoftReference(profile), new SoftReference<PDICCBased>(pdProfile));
                    }
                    imageXObject.setColorSpace(pdProfile);
                }
            }
            imageMap.put(new ImageSoftReference(image), new SoftReference<PDImageXObject>(imageXObject));
        }
        return imageXObject;
    } catch (IOException e) {
        throw new RuntimeException("Could not encode Image", e);
    }
}
Also used : PDICCBased(org.apache.pdfbox.pdmodel.graphics.color.PDICCBased) OutputStream(java.io.OutputStream) IOException(java.io.IOException) BufferedImage(java.awt.image.BufferedImage) PDImageXObject(org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject) ICC_ColorSpace(java.awt.color.ICC_ColorSpace) SoftReference(java.lang.ref.SoftReference) PDDocument(org.apache.pdfbox.pdmodel.PDDocument) ICC_Profile(java.awt.color.ICC_Profile)

Example 12 with ICC_ColorSpace

use of java.awt.color.ICC_ColorSpace in project imageio-ext by geosolutions-it.

the class TIFFImageReader method getImageTypes.

public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IIOException {
    Integer imageIndexInteger = Integer.valueOf(imageIndex);
    if (imageTypeMap.containsKey(imageIndexInteger))
        // Return the cached ITS List.
        return imageTypeMap.get(imageIndexInteger).iterator();
    // Create a new ITS List.
    final List<ImageTypeSpecifier> l = new ArrayList<ImageTypeSpecifier>();
    // Create the ITS and cache if for later use so that this method
    // always returns an Iterator containing the same ITS objects.
    seekToImage(imageIndex, true);
    ImageTypeSpecifier itsRaw = TIFFDecompressor.getRawImageTypeSpecifier(photometricInterpretation, compression, samplesPerPixel, bitsPerSample, sampleFormat, extraSamples, colorMap);
    // Check for an ICCProfile field.
    TIFFField iccProfileField = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_ICC_PROFILE);
    // to use it if the data layout is component type.
    if (iccProfileField != null && itsRaw.getColorModel() instanceof ComponentColorModel) {
        // Create a ColorSpace from the profile.
        byte[] iccProfileValue = iccProfileField.getAsBytes();
        ICC_Profile iccProfile = ICC_Profile.getInstance(iccProfileValue);
        ICC_ColorSpace iccColorSpace = new ICC_ColorSpace(iccProfile);
        // Get the raw sample and color information.
        ColorModel cmRaw = itsRaw.getColorModel();
        ColorSpace csRaw = cmRaw.getColorSpace();
        SampleModel smRaw = itsRaw.getSampleModel();
        // Get the number of samples per pixel and the number
        // of color components.
        int numBands = smRaw.getNumBands();
        int numComponents = iccColorSpace.getNumComponents();
        // numbers of samples and color components are amenable.
        if (numBands == numComponents || numBands == numComponents + 1) {
            // Set alpha flags.
            boolean hasAlpha = numComponents != numBands;
            boolean isAlphaPre = hasAlpha && cmRaw.isAlphaPremultiplied();
            // Create a ColorModel of the same class and with
            // the same transfer type.
            ColorModel iccColorModel = new ComponentColorModel(iccColorSpace, cmRaw.getComponentSize(), hasAlpha, isAlphaPre, cmRaw.getTransparency(), cmRaw.getTransferType());
            // Prepend the ICC profile-based ITS to the List. The
            // ColorModel and SampleModel are guaranteed to be
            // compatible as the old and new ColorModels are both
            // ComponentColorModels with the same transfer type
            // and the same number of components.
            l.add(new ImageTypeSpecifier(iccColorModel, smRaw));
            // as the ICC ColorSpace.
            if (csRaw.getType() == iccColorSpace.getType() && csRaw.getNumComponents() == iccColorSpace.getNumComponents()) {
                l.add(itsRaw);
            }
        } else {
            // ICCProfile not compatible with SampleModel.
            // Append the raw ITS to the List.
            l.add(itsRaw);
        }
    } else {
        // No ICCProfile field or raw ColorModel not component.
        // Append the raw ITS to the List.
        l.add(itsRaw);
    }
    // Cache the ITS List.
    imageTypeMap.put(imageIndexInteger, l);
    return l.iterator();
}
Also used : ColorSpace(java.awt.color.ColorSpace) ICC_ColorSpace(java.awt.color.ICC_ColorSpace) ICC_ColorSpace(java.awt.color.ICC_ColorSpace) TIFFField(it.geosolutions.imageio.plugins.tiff.TIFFField) ICC_Profile(java.awt.color.ICC_Profile)

Example 13 with ICC_ColorSpace

use of java.awt.color.ICC_ColorSpace in project imageio-ext by geosolutions-it.

the class EmptyImage method setupMetadata.

/**
 * Sets up the output metadata adding, removing, and overriding fields
 * as needed. The destination image dimensions are provided as parameters
 * because these might differ from those of the source due to subsampling.
 *
 * @param cm The <code>ColorModel</code> of the image being written.
 * @param sm The <code>SampleModel</code> of the image being written.
 * @param destWidth The width of the written image after subsampling.
 * @param destHeight The height of the written image after subsampling.
 */
void setupMetadata(ColorModel cm, SampleModel sm, int destWidth, int destHeight) throws IIOException {
    // Get initial IFD from metadata
    // Always emit these fields:
    // 
    // Override values from metadata:
    // 
    // planarConfiguration -> chunky (planar not supported on output)
    // 
    // Override values from metadata with image-derived values:
    // 
    // bitsPerSample (if not bilivel)
    // colorMap (if palette color)
    // photometricInterpretation (derive from image)
    // imageLength
    // imageWidth
    // 
    // rowsPerStrip     \      /   tileLength
    // stripOffsets      | OR |   tileOffsets
    // stripByteCounts  /     |   tileByteCounts
    // \   tileWidth
    // 
    // 
    // Override values from metadata with write param values:
    // 
    // compression
    // Use values from metadata if present for these fields,
    // otherwise use defaults:
    // 
    // resolutionUnit
    // XResolution (take from metadata if present)
    // YResolution
    // rowsPerStrip
    // sampleFormat
    TIFFIFD rootIFD = imageMetadata.getRootIFD();
    BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
    // If PlanarConfiguration field present, set value to chunky.
    TIFFField f = rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_PLANAR_CONFIGURATION);
    if (f != null && f.getAsInt(0) != BaselineTIFFTagSet.PLANAR_CONFIGURATION_CHUNKY) {
        // XXX processWarningOccurred()
        TIFFField planarConfigurationField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_PLANAR_CONFIGURATION), BaselineTIFFTagSet.PLANAR_CONFIGURATION_CHUNKY);
        rootIFD.addTIFFField(planarConfigurationField);
    }
    char[] extraSamples = null;
    this.photometricInterpretation = -1;
    boolean forcePhotometricInterpretation = false;
    f = rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION);
    if (f != null) {
        photometricInterpretation = f.getAsInt(0);
        if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR && !(cm instanceof IndexColorModel)) {
            photometricInterpretation = -1;
        } else {
            forcePhotometricInterpretation = true;
        }
    }
    // f = rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES);
    // if (f != null) {
    // extraSamples = f.getAsChars();
    // }
    // f = rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
    // if (f != null) {
    // bitsPerSample = f.getAsChars();
    // }
    int[] sampleSize = sm.getSampleSize();
    int numBands = sm.getNumBands();
    int numExtraSamples = 0;
    // cannot be zero.
    if (numBands > 1 && cm != null && cm.hasAlpha()) {
        --numBands;
        numExtraSamples = 1;
        extraSamples = new char[1];
        if (cm.isAlphaPremultiplied()) {
            extraSamples[0] = BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA;
        } else {
            extraSamples[0] = BaselineTIFFTagSet.EXTRA_SAMPLES_UNASSOCIATED_ALPHA;
        }
    }
    if (numBands == 3) {
        this.nativePhotometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_RGB;
        if (photometricInterpretation == -1) {
            photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_RGB;
        }
    } else if (sm.getNumBands() == 1 && cm instanceof IndexColorModel) {
        IndexColorModel icm = (IndexColorModel) cm;
        int r0 = icm.getRed(0);
        int r1 = icm.getRed(1);
        if (icm.getMapSize() == 2 && (r0 == icm.getGreen(0)) && (r0 == icm.getBlue(0)) && (r1 == icm.getGreen(1)) && (r1 == icm.getBlue(1)) && (r0 == 0 || r0 == 255) && (r1 == 0 || r1 == 255) && (r0 != r1)) {
            if (r0 == 0) {
                nativePhotometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO;
            } else {
                nativePhotometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO;
            }
            // WhiteIsZero or BlackIsZero, leave it alone
            if (photometricInterpretation != BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO && photometricInterpretation != BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO) {
                photometricInterpretation = r0 == 0 ? BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO : BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO;
            }
        } else {
            nativePhotometricInterpretation = photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR;
        }
    } else {
        if (cm != null) {
            switch(cm.getColorSpace().getType()) {
                case ColorSpace.TYPE_Lab:
                    nativePhotometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CIELAB;
                    break;
                case ColorSpace.TYPE_YCbCr:
                    nativePhotometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_Y_CB_CR;
                    break;
                case ColorSpace.TYPE_CMYK:
                    nativePhotometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CMYK;
                    break;
                default:
                    nativePhotometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO;
            }
        } else {
            nativePhotometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO;
        }
        if (photometricInterpretation == -1) {
            photometricInterpretation = nativePhotometricInterpretation;
        }
    }
    // Set the compressor and color converter.
    this.compressor = null;
    this.colorConverter = null;
    if (param instanceof TIFFImageWriteParam) {
        TIFFImageWriteParam tparam = (TIFFImageWriteParam) param;
        if (tparam.getCompressionMode() == tparam.MODE_EXPLICIT) {
            compressor = tparam.getTIFFCompressor();
            String compressionType = param.getCompressionType();
            if (compressor != null && !compressor.getCompressionType().equals(compressionType)) {
                // Unset the TIFFCompressor if its compression type is
                // not the one selected.
                compressor = null;
            }
        } else {
            // Compression mode not MODE_EXPLICIT.
            compressor = null;
        }
        colorConverter = tparam.getColorConverter();
        if (colorConverter != null) {
            photometricInterpretation = tparam.getPhotometricInterpretation();
        }
    }
    // Emit compression tag
    int compressionMode = param instanceof TIFFImageWriteParam ? param.getCompressionMode() : ImageWriteParam.MODE_DEFAULT;
    switch(compressionMode) {
        case ImageWriteParam.MODE_EXPLICIT:
            {
                String compressionType = param.getCompressionType();
                if (compressionType == null) {
                    this.compression = BaselineTIFFTagSet.COMPRESSION_NONE;
                } else {
                    // Determine corresponding compression tag value.
                    int len = compressionTypes.length;
                    for (int i = 0; i < len; i++) {
                        if (compressionType.equals(compressionTypes[i])) {
                            this.compression = compressionNumbers[i];
                        }
                    }
                }
                // with the precedence described in TIFFImageWriteParam.
                if (compressor != null && compressor.getCompressionTagValue() != this.compression) {
                    // Does not match: unset the compressor.
                    compressor = null;
                }
            }
            break;
        case ImageWriteParam.MODE_COPY_FROM_METADATA:
            {
                TIFFField compField = rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION);
                if (compField != null) {
                    this.compression = compField.getAsInt(0);
                    break;
                }
            }
        case ImageWriteParam.MODE_DEFAULT:
        case ImageWriteParam.MODE_DISABLED:
        default:
            this.compression = BaselineTIFFTagSet.COMPRESSION_NONE;
    }
    TIFFField predictorField = rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_PREDICTOR);
    if (predictorField != null) {
        this.predictor = predictorField.getAsInt(0);
        // We only support Horizontal Predictor for a bitDepth of 8
        if (sampleSize[0] != 8 || // Check the value of the tag for validity
        (predictor != BaselineTIFFTagSet.PREDICTOR_NONE && predictor != BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING)) {
            // XXX processWarningOccured ???
            // Set to default
            predictor = BaselineTIFFTagSet.PREDICTOR_NONE;
            // Emit this changed predictor value to metadata
            TIFFField newPredictorField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_PREDICTOR), predictor);
            rootIFD.addTIFFField(newPredictorField);
        }
    // XXX Do we need to ensure that predictor is not passed on if
    // the compression is not either Deflate or LZW?
    }
    TIFFField compressionField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_COMPRESSION), compression);
    rootIFD.addTIFFField(compressionField);
    // Set EXIF flag. Note that there is no way to determine definitively
    // when an uncompressed thumbnail is being written as the EXIF IFD
    // pointer field is optional for thumbnails.
    boolean isEXIF = false;
    if (numBands == 3 && sampleSize[0] == 8 && sampleSize[1] == 8 && sampleSize[2] == 8) {
        // Three bands with 8 bits per sample.
        if (rootIFD.getTIFFField(EXIFParentTIFFTagSet.TAG_EXIF_IFD_POINTER) != null) {
            // EXIF IFD pointer present.
            if (compression == BaselineTIFFTagSet.COMPRESSION_NONE && (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_RGB || photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_Y_CB_CR)) {
                // Uncompressed RGB or YCbCr.
                isEXIF = true;
            } else if (compression == BaselineTIFFTagSet.COMPRESSION_OLD_JPEG) {
                // Compressed.
                isEXIF = true;
            }
        } else if (compressionMode == ImageWriteParam.MODE_EXPLICIT && EXIF_JPEG_COMPRESSION_TYPE.equals(param.getCompressionType())) {
            // EXIF IFD pointer absent but EXIF JPEG compression set.
            isEXIF = true;
        }
    }
    // Initialize JPEG interchange format flag which is used to
    // indicate that the image is stored as a single JPEG stream.
    // This flag is separated from the 'isEXIF' flag in case JPEG
    // interchange format is eventually supported for non-EXIF images.
    boolean isJPEGInterchange = isEXIF && compression == BaselineTIFFTagSet.COMPRESSION_OLD_JPEG;
    if (compressor == null) {
        if (compression == BaselineTIFFTagSet.COMPRESSION_CCITT_RLE) {
            if (PackageUtil.isCodecLibAvailable()) {
                try {
                    compressor = new TIFFCodecLibRLECompressor();
                    if (DEBUG) {
                        System.out.println("Using codecLib RLE compressor");
                    }
                } catch (RuntimeException e) {
                    if (DEBUG) {
                        System.out.println(e);
                    }
                }
            }
            if (compressor == null) {
                compressor = new TIFFRLECompressor();
                if (DEBUG) {
                    System.out.println("Using Java RLE compressor");
                }
            }
            if (!forcePhotometricInterpretation) {
                photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO;
            }
        } else if (compression == BaselineTIFFTagSet.COMPRESSION_CCITT_T_4) {
            if (PackageUtil.isCodecLibAvailable()) {
                try {
                    compressor = new TIFFCodecLibT4Compressor();
                    if (DEBUG) {
                        System.out.println("Using codecLib T.4 compressor");
                    }
                } catch (RuntimeException e) {
                    if (DEBUG) {
                        System.out.println(e);
                    }
                }
            }
            if (compressor == null) {
                compressor = new TIFFT4Compressor();
                if (DEBUG) {
                    System.out.println("Using Java T.4 compressor");
                }
            }
            if (!forcePhotometricInterpretation) {
                photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO;
            }
        } else if (compression == BaselineTIFFTagSet.COMPRESSION_CCITT_T_6) {
            if (PackageUtil.isCodecLibAvailable()) {
                try {
                    compressor = new TIFFCodecLibT6Compressor();
                    if (DEBUG) {
                        System.out.println("Using codecLib T.6 compressor");
                    }
                } catch (RuntimeException e) {
                    if (DEBUG) {
                        System.out.println(e);
                    }
                }
            }
            if (compressor == null) {
                compressor = new TIFFT6Compressor();
                if (DEBUG) {
                    System.out.println("Using Java T.6 compressor");
                }
            }
            if (!forcePhotometricInterpretation) {
                photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO;
            }
        } else if (compression == BaselineTIFFTagSet.COMPRESSION_LZW) {
            compressor = new TIFFLZWCompressor(predictor);
        } else if (compression == BaselineTIFFTagSet.COMPRESSION_OLD_JPEG) {
            if (isEXIF) {
                compressor = new TIFFEXIFJPEGCompressor(param);
            } else {
                throw new IIOException("Old JPEG compression not supported!");
            }
        } else if (compression == BaselineTIFFTagSet.COMPRESSION_JPEG) {
            if (numBands == 3 && sampleSize[0] == 8 && sampleSize[1] == 8 && sampleSize[2] == 8) {
                photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_Y_CB_CR;
            } else if (numBands == 1 && sampleSize[0] == 8) {
                photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO;
            } else {
                throw new IIOException("JPEG compression supported for 1- and 3-band byte images only!");
            }
            compressor = new TIFFJPEGCompressor(param);
        } else if (compression == BaselineTIFFTagSet.COMPRESSION_ZLIB) {
            compressor = new TIFFZLibCompressor(param, predictor);
        } else if (compression == BaselineTIFFTagSet.COMPRESSION_PACKBITS) {
            compressor = new TIFFPackBitsCompressor();
        } else if (compression == BaselineTIFFTagSet.COMPRESSION_DEFLATE) {
            compressor = new TIFFDeflateCompressor(param, predictor);
        } else {
            // Determine inverse fill setting.
            f = rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_FILL_ORDER);
            boolean inverseFill = (f != null && f.getAsInt(0) == 2);
            if (inverseFill) {
                compressor = new TIFFLSBCompressor();
            } else {
                compressor = new TIFFNullCompressor();
            }
        }
    // compression == ?
    }
    if (DEBUG) {
        if (param != null && param.getCompressionMode() == param.MODE_EXPLICIT) {
            System.out.println("compressionType = " + param.getCompressionType());
        }
        if (compressor != null) {
            System.out.println("compressor = " + compressor.getClass().getName());
        }
    }
    if (colorConverter == null) {
        if (cm != null && cm.getColorSpace().getType() == ColorSpace.TYPE_RGB) {
            // 
            if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_Y_CB_CR && compression != BaselineTIFFTagSet.COMPRESSION_JPEG) {
                // 
                // Convert RGB to YCbCr only if compression type is not
                // JPEG in which case this is handled implicitly by the
                // compressor.
                // 
                colorConverter = new TIFFYCbCrColorConverter(imageMetadata);
            } else if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CIELAB) {
                colorConverter = new TIFFCIELabColorConverter();
            }
        }
    }
    // 
    if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_Y_CB_CR && compression != BaselineTIFFTagSet.COMPRESSION_JPEG) {
        // Remove old subsampling and positioning fields.
        rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_SUBSAMPLING);
        rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_POSITIONING);
        // Add unity chrominance subsampling factors.
        rootIFD.addTIFFField(new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_Y_CB_CR_SUBSAMPLING), TIFFTag.TIFF_SHORT, 2, new char[] { (char) 1, (char) 1 }));
        // Add cosited positioning.
        rootIFD.addTIFFField(new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_Y_CB_CR_POSITIONING), TIFFTag.TIFF_SHORT, 1, new char[] { (char) BaselineTIFFTagSet.Y_CB_CR_POSITIONING_COSITED }));
    }
    TIFFField photometricInterpretationField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION), photometricInterpretation);
    rootIFD.addTIFFField(photometricInterpretationField);
    this.bitsPerSample = new char[numBands + numExtraSamples];
    this.bitDepth = 0;
    for (int i = 0; i < numBands; i++) {
        this.bitDepth = Math.max(bitDepth, sampleSize[i]);
    }
    if (bitDepth == 3) {
        bitDepth = 4;
    } else if (bitDepth > 4 && bitDepth <= 8) {
        bitDepth = 8;
    } else if (bitDepth > 8 && bitDepth <= 16) {
        bitDepth = 16;
    } else if (bitDepth > 16 && bitDepth <= 32) {
        bitDepth = 32;
    } else if (bitDepth > 32) {
        bitDepth = 64;
    }
    for (int i = 0; i < bitsPerSample.length; i++) {
        bitsPerSample[i] = (char) bitDepth;
    }
    // if already in the metadata and correct (count and value == 1).
    if (bitsPerSample.length != 1 || bitsPerSample[0] != 1) {
        TIFFField bitsPerSampleField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE), TIFFTag.TIFF_SHORT, bitsPerSample.length, bitsPerSample);
        rootIFD.addTIFFField(bitsPerSampleField);
    } else {
        // bitsPerSample.length == 1 && bitsPerSample[0] == 1
        TIFFField bitsPerSampleField = rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
        if (bitsPerSampleField != null) {
            int[] bps = bitsPerSampleField.getAsInts();
            if (bps == null || bps.length != 1 || bps[0] != 1) {
                rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
            }
        }
    }
    // Prepare SampleFormat field.
    f = rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_SAMPLE_FORMAT);
    if (f == null && (bitDepth == 16 || bitDepth == 32 || bitDepth == 64)) {
        // Set up default content for 16- and 32-bit cases.
        char sampleFormatValue;
        int dataType = sm.getDataType();
        if (bitDepth == 16 && dataType == DataBuffer.TYPE_USHORT) {
            sampleFormatValue = (char) BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER;
        } else if (bitDepth == 32 && dataType == DataBuffer.TYPE_FLOAT) {
            sampleFormatValue = (char) BaselineTIFFTagSet.SAMPLE_FORMAT_FLOATING_POINT;
        } else if (bitDepth == 64 && dataType == DataBuffer.TYPE_DOUBLE) {
            sampleFormatValue = (char) BaselineTIFFTagSet.SAMPLE_FORMAT_FLOATING_POINT;
        } else {
            sampleFormatValue = BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER;
        }
        this.sampleFormat = (int) sampleFormatValue;
        char[] sampleFormatArray = new char[bitsPerSample.length];
        Arrays.fill(sampleFormatArray, sampleFormatValue);
        // Update the metadata.
        TIFFTag sampleFormatTag = base.getTag(BaselineTIFFTagSet.TAG_SAMPLE_FORMAT);
        TIFFField sampleFormatField = new TIFFField(sampleFormatTag, TIFFTag.TIFF_SHORT, sampleFormatArray.length, sampleFormatArray);
        rootIFD.addTIFFField(sampleFormatField);
    } else if (f != null) {
        // Get whatever was provided.
        sampleFormat = f.getAsInt(0);
    } else {
        // Set default value for internal use only.
        sampleFormat = BaselineTIFFTagSet.SAMPLE_FORMAT_UNDEFINED;
    }
    if (extraSamples != null) {
        TIFFField extraSamplesField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES), TIFFTag.TIFF_SHORT, extraSamples.length, extraSamples);
        rootIFD.addTIFFField(extraSamplesField);
    } else {
        rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES);
    }
    TIFFField samplesPerPixelField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL), bitsPerSample.length);
    rootIFD.addTIFFField(samplesPerPixelField);
    // Emit ColorMap if image is of palette color type
    if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR && cm instanceof IndexColorModel) {
        char[] colorMap = new char[3 * (1 << bitsPerSample[0])];
        IndexColorModel icm = (IndexColorModel) cm;
        // mapSize is determined by BitsPerSample, not by incoming ICM.
        int mapSize = 1 << bitsPerSample[0];
        int indexBound = Math.min(mapSize, icm.getMapSize());
        for (int i = 0; i < indexBound; i++) {
            colorMap[i] = (char) ((icm.getRed(i) * 65535) / 255);
            colorMap[mapSize + i] = (char) ((icm.getGreen(i) * 65535) / 255);
            colorMap[2 * mapSize + i] = (char) ((icm.getBlue(i) * 65535) / 255);
        }
        TIFFField colorMapField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_COLOR_MAP), TIFFTag.TIFF_SHORT, colorMap.length, colorMap);
        rootIFD.addTIFFField(colorMapField);
    } else {
        rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_COLOR_MAP);
    }
    // metadata and the ColorSpace is non-standard ICC.
    if (cm != null && rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_ICC_PROFILE) == null && ImageUtil.isNonStandardICCColorSpace(cm.getColorSpace())) {
        ICC_ColorSpace iccColorSpace = (ICC_ColorSpace) cm.getColorSpace();
        byte[] iccProfileData = iccColorSpace.getProfile().getData();
        TIFFField iccProfileField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_ICC_PROFILE), TIFFTag.TIFF_UNDEFINED, iccProfileData.length, iccProfileData);
        rootIFD.addTIFFField(iccProfileField);
    }
    // Always emit XResolution and YResolution.
    TIFFField XResolutionField = rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_X_RESOLUTION);
    TIFFField YResolutionField = rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_Y_RESOLUTION);
    if (XResolutionField == null && YResolutionField == null) {
        long[][] resRational = new long[1][2];
        resRational[0] = new long[2];
        TIFFField ResolutionUnitField = rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT);
        // quantities is present.
        if (ResolutionUnitField == null && rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_X_POSITION) == null && rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_Y_POSITION) == null) {
            // Set resolution to unit and units to dimensionless.
            resRational[0][0] = 1;
            resRational[0][1] = 1;
            ResolutionUnitField = new TIFFField(rootIFD.getTag(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT), BaselineTIFFTagSet.RESOLUTION_UNIT_NONE);
            rootIFD.addTIFFField(ResolutionUnitField);
        } else {
            // Set resolution to a value which would make the maximum
            // image dimension equal to 4 inches as arbitrarily stated
            // in the description of ResolutionUnit in the TIFF 6.0
            // specification. If the ResolutionUnit field specifies
            // "none" then set the resolution to unity (1/1).
            int resolutionUnit = ResolutionUnitField != null ? ResolutionUnitField.getAsInt(0) : BaselineTIFFTagSet.RESOLUTION_UNIT_INCH;
            int maxDimension = Math.max(destWidth, destHeight);
            switch(resolutionUnit) {
                case BaselineTIFFTagSet.RESOLUTION_UNIT_INCH:
                    resRational[0][0] = maxDimension;
                    resRational[0][1] = 4;
                    break;
                case BaselineTIFFTagSet.RESOLUTION_UNIT_CENTIMETER:
                    // divide out 100
                    resRational[0][0] = 100L * maxDimension;
                    // 2.54 cm/inch * 100
                    resRational[0][1] = 4 * 254;
                    break;
                default:
                    resRational[0][0] = 1;
                    resRational[0][1] = 1;
            }
        }
        XResolutionField = new TIFFField(rootIFD.getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION), TIFFTag.TIFF_RATIONAL, 1, resRational);
        rootIFD.addTIFFField(XResolutionField);
        YResolutionField = new TIFFField(rootIFD.getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION), TIFFTag.TIFF_RATIONAL, 1, resRational);
        rootIFD.addTIFFField(YResolutionField);
    } else if (XResolutionField == null && YResolutionField != null) {
        // Set XResolution to YResolution.
        long[] yResolution = (long[]) YResolutionField.getAsRational(0).clone();
        XResolutionField = new TIFFField(rootIFD.getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION), TIFFTag.TIFF_RATIONAL, 1, yResolution);
        rootIFD.addTIFFField(XResolutionField);
    } else if (XResolutionField != null && YResolutionField == null) {
        // Set YResolution to XResolution.
        long[] xResolution = (long[]) XResolutionField.getAsRational(0).clone();
        YResolutionField = new TIFFField(rootIFD.getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION), TIFFTag.TIFF_RATIONAL, 1, xResolution);
        rootIFD.addTIFFField(YResolutionField);
    }
    // Set mandatory fields, overriding metadata passed in
    int width = destWidth;
    TIFFField imageWidthField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_IMAGE_WIDTH), width);
    rootIFD.addTIFFField(imageWidthField);
    int height = destHeight;
    TIFFField imageLengthField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_IMAGE_LENGTH), height);
    rootIFD.addTIFFField(imageLengthField);
    // Determine rowsPerStrip
    int rowsPerStrip;
    TIFFField rowsPerStripField = rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_ROWS_PER_STRIP);
    if (rowsPerStripField != null) {
        rowsPerStrip = rowsPerStripField.getAsInt(0);
        if (rowsPerStrip < 0) {
            rowsPerStrip = height;
        }
    } else {
        int bitsPerPixel = bitDepth * (numBands + numExtraSamples);
        int bytesPerRow = (bitsPerPixel * width + 7) / 8;
        rowsPerStrip = Math.max(Math.max(DEFAULT_BYTES_PER_STRIP / bytesPerRow, 1), 8);
    }
    rowsPerStrip = Math.min(rowsPerStrip, height);
    // Tiling flag.
    boolean useTiling = false;
    // Analyze tiling parameters
    int tilingMode = param instanceof TIFFImageWriteParam ? param.getTilingMode() : ImageWriteParam.MODE_DEFAULT;
    if (tilingMode == ImageWriteParam.MODE_DISABLED || tilingMode == ImageWriteParam.MODE_DEFAULT) {
        this.tileWidth = width;
        this.tileLength = rowsPerStrip;
        useTiling = false;
    } else if (tilingMode == ImageWriteParam.MODE_EXPLICIT) {
        tileWidth = param.getTileWidth();
        tileLength = param.getTileHeight();
        useTiling = true;
    } else if (tilingMode == ImageWriteParam.MODE_COPY_FROM_METADATA) {
        f = rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_TILE_WIDTH);
        if (f == null) {
            tileWidth = width;
            useTiling = false;
        } else {
            tileWidth = f.getAsInt(0);
            useTiling = true;
        }
        f = rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_TILE_LENGTH);
        if (f == null) {
            tileLength = rowsPerStrip;
        } else {
            tileLength = f.getAsInt(0);
            useTiling = true;
        }
    } else {
        throw new IIOException("Illegal value of tilingMode!");
    }
    if (compression == BaselineTIFFTagSet.COMPRESSION_JPEG) {
        // Reset tile size per TTN2 spec for JPEG compression.
        int subX;
        int subY;
        if (numBands == 1) {
            subX = subY = 1;
        } else {
            subX = subY = TIFFJPEGCompressor.CHROMA_SUBSAMPLING;
        }
        if (useTiling) {
            int MCUMultipleX = 8 * subX;
            int MCUMultipleY = 8 * subY;
            tileWidth = Math.max(MCUMultipleX * ((tileWidth + MCUMultipleX / 2) / MCUMultipleX), MCUMultipleX);
            tileLength = Math.max(MCUMultipleY * ((tileLength + MCUMultipleY / 2) / MCUMultipleY), MCUMultipleY);
        } else if (rowsPerStrip < height) {
            int MCUMultiple = 8 * Math.max(subX, subY);
            rowsPerStrip = tileLength = Math.max(MCUMultiple * ((tileLength + MCUMultiple / 2) / MCUMultiple), MCUMultiple);
        }
    } else if (isJPEGInterchange) {
        // Force tile size to equal image size.
        tileWidth = width;
        tileLength = height;
    } else if (useTiling) {
        // Round tile size to multiple of 16 per TIFF 6.0 specification
        // (see pages 67-68 of version 6.0.1 from Adobe).
        int tileWidthRemainder = tileWidth % 16;
        if (tileWidthRemainder != 0) {
            // Round to nearest multiple of 16 not less than 16.
            tileWidth = Math.max(16 * ((tileWidth + 8) / 16), 16);
        // XXX insert processWarningOccurred(int,String);
        }
        int tileLengthRemainder = tileLength % 16;
        if (tileLengthRemainder != 0) {
            // Round to nearest multiple of 16 not less than 16.
            tileLength = Math.max(16 * ((tileLength + 8) / 16), 16);
        // XXX insert processWarningOccurred(int,String);
        }
    }
    this.tilesAcross = (width + tileWidth - 1) / tileWidth;
    this.tilesDown = (height + tileLength - 1) / tileLength;
    if (!useTiling) {
        this.isTiled = false;
        rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_TILE_WIDTH);
        rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_TILE_LENGTH);
        rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_TILE_OFFSETS);
        rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_TILE_BYTE_COUNTS);
        rowsPerStripField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_ROWS_PER_STRIP), rowsPerStrip);
        rootIFD.addTIFFField(rowsPerStripField);
        TIFFField stripOffsetsField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_STRIP_OFFSETS), isBtiff ? TIFFTag.TIFF_LONG8 : TIFFTag.TIFF_LONG, tilesDown);
        rootIFD.addTIFFField(stripOffsetsField);
        TIFFField stripByteCountsField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_STRIP_BYTE_COUNTS), isBtiff ? TIFFTag.TIFF_LONG8 : TIFFTag.TIFF_LONG, tilesDown);
        rootIFD.addTIFFField(stripByteCountsField);
    } else {
        this.isTiled = true;
        rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_ROWS_PER_STRIP);
        rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_STRIP_OFFSETS);
        rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_STRIP_BYTE_COUNTS);
        TIFFField tileWidthField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_TILE_WIDTH), tileWidth);
        rootIFD.addTIFFField(tileWidthField);
        TIFFField tileLengthField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_TILE_LENGTH), tileLength);
        rootIFD.addTIFFField(tileLengthField);
        TIFFField tileOffsetsField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_TILE_OFFSETS), isBtiff ? TIFFTag.TIFF_LONG8 : TIFFTag.TIFF_LONG, tilesDown * tilesAcross);
        rootIFD.addTIFFField(tileOffsetsField);
        TIFFField tileByteCountsField = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_TILE_BYTE_COUNTS), isBtiff ? TIFFTag.TIFF_LONG8 : TIFFTag.TIFF_LONG, tilesDown * tilesAcross);
        rootIFD.addTIFFField(tileByteCountsField);
    }
    if (isEXIF) {
        // 
        // Ensure presence of mandatory fields and absence of prohibited
        // fields and those that duplicate information in JPEG marker
        // segments per tables 14-18 of the EXIF 2.2 specification.
        // 
        // If an empty image is being written or inserted then infer
        // that the primary IFD is being set up.
        boolean isPrimaryIFD = isEncodingEmpty();
        // Handle TIFF fields in order of increasing tag number.
        if (compression == BaselineTIFFTagSet.COMPRESSION_OLD_JPEG) {
            // ImageWidth
            rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH);
            // ImageLength
            rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_IMAGE_LENGTH);
            // BitsPerSample
            rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
            // Compression
            if (isPrimaryIFD) {
                rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION);
            }
            // PhotometricInterpretation
            rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION);
            // StripOffsets
            rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_STRIP_OFFSETS);
            // SamplesPerPixel
            rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL);
            // RowsPerStrip
            rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_ROWS_PER_STRIP);
            // StripByteCounts
            rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_STRIP_BYTE_COUNTS);
            // XResolution and YResolution are handled above for all TIFFs.
            // PlanarConfiguration
            rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_PLANAR_CONFIGURATION);
            // ResolutionUnit
            if (rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT) == null) {
                f = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT), BaselineTIFFTagSet.RESOLUTION_UNIT_INCH);
                rootIFD.addTIFFField(f);
            }
            if (isPrimaryIFD) {
                // JPEGInterchangeFormat
                rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT);
                // JPEGInterchangeFormatLength
                rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
                // YCbCrSubsampling
                rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_SUBSAMPLING);
                // YCbCrPositioning
                if (rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_POSITIONING) == null) {
                    f = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_Y_CB_CR_POSITIONING), TIFFTag.TIFF_SHORT, 1, new char[] { (char) BaselineTIFFTagSet.Y_CB_CR_POSITIONING_CENTERED });
                    rootIFD.addTIFFField(f);
                }
            } else {
                // Thumbnail IFD
                // JPEGInterchangeFormat
                f = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT), TIFFTag.TIFF_LONG, 1);
                rootIFD.addTIFFField(f);
                // JPEGInterchangeFormatLength
                f = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH), TIFFTag.TIFF_LONG, 1);
                rootIFD.addTIFFField(f);
                // YCbCrSubsampling
                rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_SUBSAMPLING);
            }
        } else {
            // ResolutionUnit
            if (rootIFD.getTIFFField(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT) == null) {
                f = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT), BaselineTIFFTagSet.RESOLUTION_UNIT_INCH);
                rootIFD.addTIFFField(f);
            }
            // JPEGInterchangeFormat
            rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT);
            // JPEGInterchangeFormatLength
            rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
            if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_RGB) {
                // YCbCrCoefficients
                rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_COEFFICIENTS);
                // YCbCrSubsampling
                rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_SUBSAMPLING);
                // YCbCrPositioning
                rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_POSITIONING);
            }
        }
        // Get EXIF tags.
        TIFFTagSet exifTags = EXIFTIFFTagSet.getInstance();
        // Retrieve or create the EXIF IFD.
        TIFFIFD exifIFD = null;
        f = rootIFD.getTIFFField(EXIFParentTIFFTagSet.TAG_EXIF_IFD_POINTER);
        if (f != null) {
            // Retrieve the EXIF IFD.
            exifIFD = (TIFFIFD) f.getData();
        } else if (isPrimaryIFD) {
            // Create the EXIF IFD.
            List exifTagSets = new ArrayList(1);
            exifTagSets.add(exifTags);
            exifIFD = new TIFFIFD(exifTagSets);
            // Add it to the root IFD.
            TIFFTagSet tagSet = EXIFParentTIFFTagSet.getInstance();
            TIFFTag exifIFDTag = tagSet.getTag(EXIFParentTIFFTagSet.TAG_EXIF_IFD_POINTER);
            rootIFD.addTIFFField(new TIFFField(exifIFDTag, TIFFTag.TIFF_LONG, 1, exifIFD));
        }
        if (exifIFD != null) {
            // ExifVersion
            if (exifIFD.getTIFFField(EXIFTIFFTagSet.TAG_EXIF_VERSION) == null) {
                f = new TIFFField(exifTags.getTag(EXIFTIFFTagSet.TAG_EXIF_VERSION), TIFFTag.TIFF_UNDEFINED, 4, EXIFTIFFTagSet.EXIF_VERSION_2_2);
                exifIFD.addTIFFField(f);
            }
            if (compression == BaselineTIFFTagSet.COMPRESSION_OLD_JPEG) {
                // ComponentsConfiguration
                if (exifIFD.getTIFFField(EXIFTIFFTagSet.TAG_COMPONENTS_CONFIGURATION) == null) {
                    f = new TIFFField(exifTags.getTag(EXIFTIFFTagSet.TAG_COMPONENTS_CONFIGURATION), TIFFTag.TIFF_UNDEFINED, 4, new byte[] { (byte) EXIFTIFFTagSet.COMPONENTS_CONFIGURATION_Y, (byte) EXIFTIFFTagSet.COMPONENTS_CONFIGURATION_CB, (byte) EXIFTIFFTagSet.COMPONENTS_CONFIGURATION_CR, (byte) 0 });
                    exifIFD.addTIFFField(f);
                }
            } else {
                // ComponentsConfiguration
                exifIFD.removeTIFFField(EXIFTIFFTagSet.TAG_COMPONENTS_CONFIGURATION);
                // CompressedBitsPerPixel
                exifIFD.removeTIFFField(EXIFTIFFTagSet.TAG_COMPRESSED_BITS_PER_PIXEL);
            }
            // FlashpixVersion
            if (exifIFD.getTIFFField(EXIFTIFFTagSet.TAG_FLASHPIX_VERSION) == null) {
                f = new TIFFField(exifTags.getTag(EXIFTIFFTagSet.TAG_FLASHPIX_VERSION), TIFFTag.TIFF_UNDEFINED, 4, new byte[] { (byte) '0', (byte) '1', (byte) '0', (byte) '0' });
                exifIFD.addTIFFField(f);
            }
            // ColorSpace
            if (exifIFD.getTIFFField(EXIFTIFFTagSet.TAG_COLOR_SPACE) == null) {
                f = new TIFFField(exifTags.getTag(EXIFTIFFTagSet.TAG_COLOR_SPACE), TIFFTag.TIFF_SHORT, 1, new char[] { (char) EXIFTIFFTagSet.COLOR_SPACE_SRGB });
                exifIFD.addTIFFField(f);
            }
            if (compression == BaselineTIFFTagSet.COMPRESSION_OLD_JPEG) {
                // PixelXDimension
                if (exifIFD.getTIFFField(EXIFTIFFTagSet.TAG_PIXEL_X_DIMENSION) == null) {
                    f = new TIFFField(exifTags.getTag(EXIFTIFFTagSet.TAG_PIXEL_X_DIMENSION), width);
                    exifIFD.addTIFFField(f);
                }
                // PixelYDimension
                if (exifIFD.getTIFFField(EXIFTIFFTagSet.TAG_PIXEL_Y_DIMENSION) == null) {
                    f = new TIFFField(exifTags.getTag(EXIFTIFFTagSet.TAG_PIXEL_Y_DIMENSION), height);
                    exifIFD.addTIFFField(f);
                }
            } else {
                exifIFD.removeTIFFField(EXIFTIFFTagSet.TAG_INTEROPERABILITY_IFD_POINTER);
            }
        }
    }
// if(isEXIF)
}
Also used : TIFFImageWriteParam(it.geosolutions.imageio.plugins.tiff.TIFFImageWriteParam) ArrayList(java.util.ArrayList) BaselineTIFFTagSet(it.geosolutions.imageio.plugins.tiff.BaselineTIFFTagSet) TIFFField(it.geosolutions.imageio.plugins.tiff.TIFFField) ArrayList(java.util.ArrayList) List(java.util.List) IndexColorModel(java.awt.image.IndexColorModel) IIOException(javax.imageio.IIOException) Point(java.awt.Point) ICC_ColorSpace(java.awt.color.ICC_ColorSpace) BaselineTIFFTagSet(it.geosolutions.imageio.plugins.tiff.BaselineTIFFTagSet) TIFFTagSet(it.geosolutions.imageio.plugins.tiff.TIFFTagSet) EXIFParentTIFFTagSet(it.geosolutions.imageio.plugins.tiff.EXIFParentTIFFTagSet) EXIFTIFFTagSet(it.geosolutions.imageio.plugins.tiff.EXIFTIFFTagSet) TIFFTag(it.geosolutions.imageio.plugins.tiff.TIFFTag)

Example 14 with ICC_ColorSpace

use of java.awt.color.ICC_ColorSpace in project pdfbox by apache.

the class PDICCBased method loadICCProfile.

/**
 * Load the ICC profile, or init alternateColorSpace color space.
 */
private void loadICCProfile() throws IOException {
    if (useOnlyAlternateColorSpace) {
        try {
            fallbackToAlternateColorSpace(null);
            return;
        } catch (IOException e) {
            LOG.warn("Error initializing alternate color space: " + e.getLocalizedMessage());
        }
    }
    try (InputStream input = this.stream.createInputStream()) {
        // if the embedded profile is sRGB then we can use Java's built-in profile, which
        // results in a large performance gain as it's our native color space, see PDFBOX-2587
        ICC_Profile profile;
        synchronized (LOG) {
            profile = ICC_Profile.getInstance(input);
            if (is_sRGB(profile)) {
                isRGB = true;
                awtColorSpace = (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_sRGB);
                iccProfile = awtColorSpace.getProfile();
            } else {
                profile = ensureDisplayProfile(profile);
                awtColorSpace = new ICC_ColorSpace(profile);
                iccProfile = profile;
            }
            // set initial colour
            float[] initial = new float[getNumberOfComponents()];
            for (int c = 0; c < initial.length; c++) {
                initial[c] = Math.max(0, getRangeForComponent(c).getMin());
            }
            initialColor = new PDColor(initial, this);
            if (IS_KCMS) {
                // do things that trigger a ProfileDataException
                // or CMMException due to invalid profiles, see PDFBOX-1295 and PDFBOX-1740 (ΓΌ-file)
                // or ArrayIndexOutOfBoundsException, see PDFBOX-3610
                // also triggers a ProfileDataException for PDFBOX-3549 with KCMS
                awtColorSpace.toRGB(new float[getNumberOfComponents()]);
            } else {
                // PDFBOX-4015: this one triggers "CMMException: LCMS error 13" with LCMS
                new ComponentColorModel(awtColorSpace, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
            }
        }
    } catch (ProfileDataException | CMMException | IllegalArgumentException | ArrayIndexOutOfBoundsException | IOException e) {
        fallbackToAlternateColorSpace(e);
    }
}
Also used : InputStream(java.io.InputStream) ComponentColorModel(java.awt.image.ComponentColorModel) ProfileDataException(java.awt.color.ProfileDataException) IOException(java.io.IOException) CMMException(java.awt.color.CMMException) ICC_ColorSpace(java.awt.color.ICC_ColorSpace) ICC_Profile(java.awt.color.ICC_Profile)

Example 15 with ICC_ColorSpace

use of java.awt.color.ICC_ColorSpace in project pdfbox by apache.

the class PDDeviceCMYK method init.

/**
 * Lazy load the ICC profile, because it's slow.
 */
protected void init() throws IOException {
    // no need to synchronize this check as it is atomic
    if (initDone) {
        return;
    }
    synchronized (this) {
        // we might have been waiting for another thread, so check again
        if (initDone) {
            return;
        }
        // loads the ICC color profile for CMYK
        ICC_Profile iccProfile = getICCProfile();
        if (iccProfile == null) {
            throw new IOException("Default CMYK color profile could not be loaded");
        }
        awtColorSpace = new ICC_ColorSpace(iccProfile);
        // there is a JVM bug which results in a CMMException which appears to be a race
        // condition caused by lazy initialization of the color transform, so we perform
        // an initial color conversion while we're still in a static context, see PDFBOX-2184
        awtColorSpace.toRGB(new float[] { 0, 0, 0, 0 });
        usePureJavaCMYKConversion = System.getProperty("org.apache.pdfbox.rendering.UsePureJavaCMYKConversion") != null;
        // Assignment to volatile must be the LAST statement in this block!
        initDone = true;
    }
}
Also used : ICC_ColorSpace(java.awt.color.ICC_ColorSpace) IOException(java.io.IOException) ICC_Profile(java.awt.color.ICC_Profile)

Aggregations

ICC_ColorSpace (java.awt.color.ICC_ColorSpace)28 ColorSpace (java.awt.color.ColorSpace)10 ICC_Profile (java.awt.color.ICC_Profile)10 WeakHashMap (java.util.WeakHashMap)8 ColorTransform (sun.java2d.cmm.ColorTransform)8 PCMM (sun.java2d.cmm.PCMM)8 BufferedImage (java.awt.image.BufferedImage)5 IndexColorModel (java.awt.image.IndexColorModel)4 IOException (java.io.IOException)4 CMMException (java.awt.color.CMMException)3 ColorConvertOp (java.awt.image.ColorConvertOp)3 ComponentColorModel (java.awt.image.ComponentColorModel)3 InputStream (java.io.InputStream)3 IIOException (javax.imageio.IIOException)3 TIFFField (it.geosolutions.imageio.plugins.tiff.TIFFField)2 Point (java.awt.Point)2 ColorModel (java.awt.image.ColorModel)2 ImageTypeSpecifier (javax.imageio.ImageTypeSpecifier)2 IIOMetadata (javax.imageio.metadata.IIOMetadata)2 PDDocument (org.apache.pdfbox.pdmodel.PDDocument)2