Search in sources :

Example 16 with IIOException

use of javax.imageio.IIOException in project imageio-ext by geosolutions-it.

the class TIFFFaxDecompressor method decodeT4.

public void decodeT4() throws IIOException {
    int height = h;
    int a0, a1, b1, b2;
    int[] b = new int[2];
    int entry, code, bits, color;
    boolean isWhite;
    int currIndex = 0;
    int[] temp;
    if (data.length < 2) {
        throw new IIOException("Insufficient data to read initial EOL.");
    }
    // The data should start with an EOL code
    int next12 = nextNBits(12);
    if (next12 != 1) {
        warning("T.4 compressed data should begin with EOL.");
    }
    updatePointer(12);
    // Find the first one-dimensionally encoded line.
    int modeFlag = 0;
    // indicates imaginary line before first actual line.
    int lines = -1;
    while (modeFlag != 1) {
        try {
            modeFlag = findNextLine();
            // Normally 'lines' will be 0 on exiting loop.
            lines++;
        } catch (EOFException eofe) {
            throw new IIOException("No reference line present.");
        }
    }
    int bitOffset;
    // Then the 1D encoded scanline data will occur, changing elements
    // array gets set.
    decodeNextScanline(srcMinY);
    lines++;
    lineBitNum += bitsPerScanline;
    while (lines < height) {
        // indicates whether the following scanline is 1D or 2D encoded.
        try {
            modeFlag = findNextLine();
        } catch (EOFException eofe) {
            warning("Input exhausted before EOL found at line " + (srcMinY + lines) + ": read 0 of " + w + " expected pixels.");
            break;
        }
        if (modeFlag == 0) {
            // 2D encoded scanline follows
            // Initialize previous scanlines changing elements, and
            // initialize current scanline's changing elements array
            temp = prevChangingElems;
            prevChangingElems = currChangingElems;
            currChangingElems = temp;
            currIndex = 0;
            // a0 has to be set just before the start of this scanline.
            a0 = -1;
            isWhite = true;
            bitOffset = 0;
            lastChangingElement = 0;
            while (bitOffset < w) {
                // Get the next changing element
                getNextChangingElement(a0, isWhite, b);
                b1 = b[0];
                b2 = b[1];
                // Get the next seven bits
                entry = nextLesserThan8Bits(7);
                // Run these through the 2DCodes table
                entry = (int) (twoDCodes[entry] & 0xff);
                // Get the code and the number of bits used up
                code = (entry & 0x78) >>> 3;
                bits = entry & 0x07;
                if (code == 0) {
                    if (!isWhite) {
                        setToBlack(bitOffset, b2 - bitOffset);
                    }
                    bitOffset = a0 = b2;
                    // Set pointer to consume the correct number of bits.
                    updatePointer(7 - bits);
                } else if (code == 1) {
                    // Horizontal
                    updatePointer(7 - bits);
                    // identify the next 2 codes.
                    int number;
                    if (isWhite) {
                        number = decodeWhiteCodeWord();
                        bitOffset += number;
                        currChangingElems[currIndex++] = bitOffset;
                        number = decodeBlackCodeWord();
                        setToBlack(bitOffset, number);
                        bitOffset += number;
                        currChangingElems[currIndex++] = bitOffset;
                    } else {
                        number = decodeBlackCodeWord();
                        setToBlack(bitOffset, number);
                        bitOffset += number;
                        currChangingElems[currIndex++] = bitOffset;
                        number = decodeWhiteCodeWord();
                        bitOffset += number;
                        currChangingElems[currIndex++] = bitOffset;
                    }
                    a0 = bitOffset;
                } else if (code <= 8) {
                    // Vertical
                    a1 = b1 + (code - 5);
                    currChangingElems[currIndex++] = a1;
                    // since a1 is where the next color starts
                    if (!isWhite) {
                        setToBlack(bitOffset, a1 - bitOffset);
                    }
                    bitOffset = a0 = a1;
                    isWhite = !isWhite;
                    updatePointer(7 - bits);
                } else {
                    warning("Unknown coding mode encountered at line " + (srcMinY + lines) + ": read " + bitOffset + " of " + w + " expected pixels.");
                    // Find the next one-dimensionally encoded line.
                    int numLinesTested = 0;
                    while (modeFlag != 1) {
                        try {
                            modeFlag = findNextLine();
                            numLinesTested++;
                        } catch (EOFException eofe) {
                            warning("Sync loss at line " + (srcMinY + lines) + ": read " + lines + " of " + height + " lines.");
                            return;
                        }
                    }
                    lines += numLinesTested - 1;
                    updatePointer(13);
                    break;
                }
            }
            // Add the changing element beyond the current scanline for the
            // other color too
            currChangingElems[currIndex++] = bitOffset;
            changingElemSize = currIndex;
        } else {
            // modeFlag == 1
            // 1D encoded scanline follows
            decodeNextScanline(srcMinY + lines);
        }
        lineBitNum += bitsPerScanline;
        lines++;
    }
// while(lines < height)
}
Also used : EOFException(java.io.EOFException) IIOException(javax.imageio.IIOException)

Example 17 with IIOException

use of javax.imageio.IIOException in project imageio-ext by geosolutions-it.

the class EmptyImage method prepareReplacePixels.

public void prepareReplacePixels(int imageIndex, Rectangle region) throws IOException {
    synchronized (replacePixelsLock) {
        // Check state and parameters vis-a-vis ImageWriter specification.
        if (stream == null) {
            throw new IllegalStateException("Output not set!");
        }
        if (region == null) {
            throw new IllegalArgumentException("region == null!");
        }
        if (region.getWidth() < 1) {
            throw new IllegalArgumentException("region.getWidth() < 1!");
        }
        if (region.getHeight() < 1) {
            throw new IllegalArgumentException("region.getHeight() < 1!");
        }
        if (inReplacePixelsNest) {
            throw new IllegalStateException("In nested call to prepareReplacePixels!");
        }
        // Read the IFD for the pixel replacement index.
        TIFFIFD replacePixelsIFD = readIFD(imageIndex);
        // Ensure that compression is "none".
        TIFFField f = replacePixelsIFD.getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION);
        int compression = f.getAsInt(0);
        if (compression != BaselineTIFFTagSet.COMPRESSION_NONE) {
            throw new UnsupportedOperationException("canReplacePixels(imageIndex) == false!");
        }
        // Get the image dimensions.
        f = replacePixelsIFD.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH);
        if (f == null) {
            throw new IIOException("Cannot read ImageWidth field.");
        }
        int w = f.getAsInt(0);
        f = replacePixelsIFD.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_LENGTH);
        if (f == null) {
            throw new IIOException("Cannot read ImageHeight field.");
        }
        int h = f.getAsInt(0);
        // Create image bounds.
        Rectangle bounds = new Rectangle(0, 0, w, h);
        // Intersect region with bounds.
        region = region.intersection(bounds);
        // Check for empty intersection.
        if (region.isEmpty()) {
            throw new IIOException("Region does not intersect image bounds");
        }
        // Save the region.
        replacePixelsRegion = region;
        // Get the tile offsets.
        f = replacePixelsIFD.getTIFFField(BaselineTIFFTagSet.TAG_TILE_OFFSETS);
        if (f == null) {
            f = replacePixelsIFD.getTIFFField(BaselineTIFFTagSet.TAG_STRIP_OFFSETS);
        }
        replacePixelsTileOffsets = f.getAsLongs();
        // Get the byte counts.
        f = replacePixelsIFD.getTIFFField(BaselineTIFFTagSet.TAG_TILE_BYTE_COUNTS);
        if (f == null) {
            f = replacePixelsIFD.getTIFFField(BaselineTIFFTagSet.TAG_STRIP_BYTE_COUNTS);
        }
        replacePixelsByteCounts = f.getAsLongs();
        replacePixelsOffsetsPosition = replacePixelsIFD.getStripOrTileOffsetsPosition();
        replacePixelsByteCountsPosition = replacePixelsIFD.getStripOrTileByteCountsPosition();
        // Get the image metadata.
        replacePixelsMetadata = new TIFFImageMetadata(replacePixelsIFD);
        // Save the image index.
        replacePixelsIndex = imageIndex;
        // Set the pixel replacement flag.
        inReplacePixelsNest = true;
    }
}
Also used : TIFFField(it.geosolutions.imageio.plugins.tiff.TIFFField) Rectangle(java.awt.Rectangle) IIOException(javax.imageio.IIOException) Point(java.awt.Point)

Example 18 with IIOException

use of javax.imageio.IIOException in project imageio-ext by geosolutions-it.

the class EmptyImage method convertImageMetadata.

public IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param) {
    // Check arguments.
    if (inData == null) {
        throw new IllegalArgumentException("inData == null!");
    }
    if (imageType == null) {
        throw new IllegalArgumentException("imageType == null!");
    }
    TIFFImageMetadata outData = null;
    // Obtain a TIFFImageMetadata object.
    if (inData instanceof TIFFImageMetadata) {
        // Create a new metadata object from a clone of the input IFD.
        TIFFIFD inIFD = ((TIFFImageMetadata) inData).getRootIFD();
        outData = new TIFFImageMetadata(inIFD.getShallowClone());
    } else if (Arrays.asList(inData.getMetadataFormatNames()).contains(TIFFImageMetadata.nativeMetadataFormatName)) {
        // Initialize from the native metadata form of the input tree.
        try {
            outData = convertNativeImageMetadata(inData);
        } catch (IIOInvalidTreeException e) {
        // XXX Warning
        }
    } else if (inData.isStandardMetadataFormatSupported()) {
        // Initialize from the standard metadata form of the input tree.
        try {
            outData = convertStandardImageMetadata(inData);
        } catch (IIOInvalidTreeException e) {
        // XXX Warning
        }
    }
    // Update the metadata per the image type and param.
    if (outData != null) {
        TIFFImageWriter bogusWriter = new TIFFImageWriter(this.originatingProvider);
        bogusWriter.imageMetadata = outData;
        bogusWriter.param = param;
        SampleModel sm = imageType.getSampleModel();
        try {
            bogusWriter.setupMetadata(imageType.getColorModel(), sm, sm.getWidth(), sm.getHeight());
            return bogusWriter.imageMetadata;
        } catch (IIOException e) {
            // XXX Warning
            return null;
        }
    }
    return outData;
}
Also used : ComponentSampleModel(java.awt.image.ComponentSampleModel) SampleModel(java.awt.image.SampleModel) IIOInvalidTreeException(javax.imageio.metadata.IIOInvalidTreeException) IIOException(javax.imageio.IIOException)

Example 19 with IIOException

use of javax.imageio.IIOException 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 20 with IIOException

use of javax.imageio.IIOException in project imageio-ext by geosolutions-it.

the class EmptyImage method write.

private void write(IIOMetadata sm, IIOImage iioimage, ImageWriteParam p, boolean writeHeader, boolean writeData) throws IOException {
    if (stream == null) {
        throw new IllegalStateException("output == null!");
    }
    if (iioimage == null) {
        throw new IllegalArgumentException("image == null!");
    }
    if (iioimage.hasRaster() && !canWriteRasters()) {
        throw new UnsupportedOperationException("TIFF ImageWriter cannot write Rasters!");
    }
    this.image = iioimage.getRenderedImage();
    SampleModel sampleModel = image.getSampleModel();
    this.sourceXOffset = image.getMinX();
    this.sourceYOffset = image.getMinY();
    this.sourceWidth = image.getWidth();
    this.sourceHeight = image.getHeight();
    Rectangle imageBounds = new Rectangle(sourceXOffset, sourceYOffset, sourceWidth, sourceHeight);
    ColorModel colorModel = null;
    if (p == null) {
        this.param = getDefaultWriteParam();
        this.sourceBands = null;
        this.periodX = 1;
        this.periodY = 1;
        this.numBands = sampleModel.getNumBands();
        colorModel = image.getColorModel();
    } else {
        this.param = p;
        // Get source region and subsampling factors
        Rectangle sourceRegion = param.getSourceRegion();
        if (sourceRegion != null) {
            // Clip to actual image bounds
            sourceRegion = sourceRegion.intersection(imageBounds);
            sourceXOffset = sourceRegion.x;
            sourceYOffset = sourceRegion.y;
            sourceWidth = sourceRegion.width;
            sourceHeight = sourceRegion.height;
        }
        // Adjust for subsampling offsets
        int gridX = param.getSubsamplingXOffset();
        int gridY = param.getSubsamplingYOffset();
        this.sourceXOffset += gridX;
        this.sourceYOffset += gridY;
        this.sourceWidth -= gridX;
        this.sourceHeight -= gridY;
        // Get subsampling factors
        this.periodX = param.getSourceXSubsampling();
        this.periodY = param.getSourceYSubsampling();
        int[] sBands = param.getSourceBands();
        if (sBands != null) {
            sourceBands = sBands;
            this.numBands = sourceBands.length;
        } else {
            this.numBands = sampleModel.getNumBands();
        }
        ImageTypeSpecifier destType = p.getDestinationType();
        if (destType != null) {
            ColorModel cm = destType.getColorModel();
            if (cm.getNumComponents() == numBands) {
                colorModel = cm;
            }
        }
        if (colorModel == null) {
            colorModel = image.getColorModel();
        }
    }
    this.imageType = new ImageTypeSpecifier(colorModel, sampleModel);
    ImageUtil.canEncodeImage(this, this.imageType);
    // Compute output dimensions
    int destWidth = (sourceWidth + periodX - 1) / periodX;
    int destHeight = (sourceHeight + periodY - 1) / periodY;
    if (destWidth <= 0 || destHeight <= 0) {
        throw new IllegalArgumentException("Empty source region!");
    }
    // this.bitDepth = 8; // XXX fix?
    clearAbortRequest();
    int progressStep = 1;
    processImageStarted(0);
    int[] sampleSize = sampleModel.getSampleSize();
    long tot = 0;
    for (int i = 0; i < this.numBands; i++) tot += sampleSize[i];
    long sizeImage = (tot * this.sourceHeight * this.sourceWidth) / 8;
    long var = 4294967296L;
    boolean isForceToBigTIFF = false;
    if (p instanceof TIFFImageWriteParam) {
        isForceToBigTIFF = ((TIFFImageWriteParam) p).isForceToBigTIFF();
    }
    if (sizeImage > var || isForceToBigTIFF || isBtiff == true)
        isBtiff = true;
    else
        isBtiff = false;
    // Optionally write the header.
    if (writeHeader) {
        // Clear previous stream metadata.
        this.streamMetadata = null;
        // Try to convert non-null input stream metadata.
        if (sm != null) {
            this.streamMetadata = (TIFFStreamMetadata) convertStreamMetadata(sm, param);
        }
        // Set to default if not converted.
        if (this.streamMetadata == null) {
            this.streamMetadata = (TIFFStreamMetadata) getDefaultStreamMetadata(param);
        }
        // Write the header.
        writeHeader();
        // 3) Write the pointer to the first IFD after the header.
        if (!isBtiff) {
            stream.seek(headerPosition + 4);
            nextSpace = (nextSpace + 3) & ~0x3;
            stream.writeInt((int) nextSpace);
        } else {
            stream.seek(headerPosition + 8);
            nextSpace = (nextSpace + 7) & ~0x7;
            stream.writeLong(nextSpace);
        }
    }
    // Write out the IFD and any sub IFDs, followed by a zero
    // Clear previous image metadata.
    this.imageMetadata = null;
    // Initialize the metadata object.
    IIOMetadata im = iioimage.getMetadata();
    if (im != null) {
        if (im instanceof TIFFImageMetadata) {
            // Clone the one passed in.
            this.imageMetadata = ((TIFFImageMetadata) im).getShallowClone();
        } else if (Arrays.asList(im.getMetadataFormatNames()).contains(TIFFImageMetadata.nativeMetadataFormatName)) {
            this.imageMetadata = convertNativeImageMetadata(im);
        } else if (im.isStandardMetadataFormatSupported()) {
            try {
                // Convert standard metadata.
                this.imageMetadata = convertStandardImageMetadata(im);
            } catch (IIOInvalidTreeException e) {
            // XXX Warning
            }
        }
    }
    // Use default metadata if still null.
    if (this.imageMetadata == null) {
        this.imageMetadata = (TIFFImageMetadata) getDefaultImageMetadata(this.imageType, this.param);
    }
    // Set or overwrite mandatory fields in the root IFD
    setupMetadata(colorModel, sampleModel, destWidth, destHeight);
    // Set compressor fields.
    compressor.setWriter(this);
    // Metadata needs to be set on the compressor before the IFD is
    // written as the compressor could modify the metadata.
    compressor.setMetadata(imageMetadata);
    compressor.setStream(stream);
    // Initialize scaling tables for this image
    initializeScaleTables(sampleModel.getSampleSize());
    // Determine whether bilevel.
    this.isBilevel = ImageUtil.isBinary(this.image.getSampleModel());
    // Check for photometric inversion.
    this.isInverted = (nativePhotometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO && photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO) || (nativePhotometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO && photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO);
    // Analyze image data suitability for direct copy.
    this.isImageSimple = (isBilevel || (!isInverted && ImageUtil.imageIsContiguous(this.image))) && // no value rescaling
    !isRescaling && // no subbanding
    sourceBands == null && periodX == 1 && // no subsampling
    periodY == 1 && colorConverter == null;
    TIFFIFD rootIFD = imageMetadata.getRootIFD();
    rootIFD.writeToStream(stream, isBtiff);
    this.nextIFDPointerPos = stream.getStreamPosition();
    if (!isBtiff) {
        stream.writeInt(0);
    } else {
        stream.writeLong(0);
    }
    // Seek to end of IFD data
    long lastIFDPosition = rootIFD.getLastPosition();
    stream.seek(lastIFDPosition);
    if (lastIFDPosition > this.nextSpace) {
        this.nextSpace = lastIFDPosition;
    }
    // empty image, return.
    if (!writeData) {
        return;
    }
    // Get positions of fields within the IFD to update as we write
    // each strip or tile
    long stripOrTileByteCountsPosition = rootIFD.getStripOrTileByteCountsPosition();
    long stripOrTileOffsetsPosition = rootIFD.getStripOrTileOffsetsPosition();
    // Compute total number of pixels for progress notification
    this.totalPixels = tileWidth * tileLength * tilesDown * tilesAcross;
    this.pixelsDone = 0;
    // Write the image, a strip or tile at a time
    for (int tj = 0; tj < tilesDown; tj++) {
        for (int ti = 0; ti < tilesAcross; ti++) {
            long pos = stream.getStreamPosition();
            // Write the (possibly compressed) tile data
            Rectangle tileRect = new Rectangle(sourceXOffset + ti * tileWidth * periodX, sourceYOffset + tj * tileLength * periodY, tileWidth * periodX, tileLength * periodY);
            try {
                int byteCount = writeTile(tileRect, compressor);
                if (pos + byteCount > nextSpace) {
                    nextSpace = pos + byteCount;
                }
                pixelsDone += tileRect.width * tileRect.height;
                float currentProgress = 100.0F * pixelsDone / totalPixels;
                if (currentProgress > progressStep * PROGRESS_FACTOR_MULTIPLIER) {
                    processImageProgress(currentProgress);
                    progressStep++;
                }
                // Fill in the offset and byte count for the file
                stream.mark();
                stream.seek(stripOrTileOffsetsPosition);
                if (!isBtiff) {
                    stream.writeInt((int) pos);
                    stripOrTileOffsetsPosition += 4;
                    stream.seek(stripOrTileByteCountsPosition);
                    stream.writeInt(byteCount);
                    stripOrTileByteCountsPosition += 4;
                } else {
                    stream.writeLong(pos);
                    stripOrTileOffsetsPosition += 8;
                    stream.seek(stripOrTileByteCountsPosition);
                    stream.writeLong(byteCount);
                    stripOrTileByteCountsPosition += 8;
                }
                stream.reset();
            } catch (IOException e) {
                throw new IIOException("I/O error writing TIFF file!", e);
            }
            if (abortRequested()) {
                processWriteAborted();
                return;
            }
        }
    }
    processImageComplete();
}
Also used : IIOInvalidTreeException(javax.imageio.metadata.IIOInvalidTreeException) Rectangle(java.awt.Rectangle) TIFFImageWriteParam(it.geosolutions.imageio.plugins.tiff.TIFFImageWriteParam) IIOException(javax.imageio.IIOException) IIOException(javax.imageio.IIOException) IOException(java.io.IOException) Point(java.awt.Point) ImageTypeSpecifier(javax.imageio.ImageTypeSpecifier) IIOMetadata(javax.imageio.metadata.IIOMetadata) ComponentSampleModel(java.awt.image.ComponentSampleModel) SampleModel(java.awt.image.SampleModel) IndexColorModel(java.awt.image.IndexColorModel) ComponentColorModel(java.awt.image.ComponentColorModel) ColorModel(java.awt.image.ColorModel)

Aggregations

IIOException (javax.imageio.IIOException)60 Point (java.awt.Point)23 IOException (java.io.IOException)23 BufferedImage (java.awt.image.BufferedImage)12 Rectangle (java.awt.Rectangle)11 IndexColorModel (java.awt.image.IndexColorModel)7 SampleModel (java.awt.image.SampleModel)7 WritableRaster (java.awt.image.WritableRaster)7 Iterator (java.util.Iterator)7 ColorModel (java.awt.image.ColorModel)6 ArrayList (java.util.ArrayList)6 ImageTypeSpecifier (javax.imageio.ImageTypeSpecifier)6 ImageInputStream (javax.imageio.stream.ImageInputStream)6 TIFFField (it.geosolutions.imageio.plugins.tiff.TIFFField)5 ColorSpace (java.awt.color.ColorSpace)5 ComponentSampleModel (java.awt.image.ComponentSampleModel)5 DataBufferByte (java.awt.image.DataBufferByte)5 ImageReader (javax.imageio.ImageReader)5 IIOMetadata (javax.imageio.metadata.IIOMetadata)5 ICC_ColorSpace (java.awt.color.ICC_ColorSpace)4