Search in sources :

Example 26 with TIFFField

use of it.geosolutions.imageio.plugins.tiff.TIFFField in project imageio-ext by geosolutions-it.

the class EmptyImage method replacePixels.

public void replacePixels(RenderedImage image, ImageWriteParam param) throws IOException {
    synchronized (replacePixelsLock) {
        // Check state and parameters vis-a-vis ImageWriter specification.
        if (stream == null) {
            throw new IllegalStateException("stream == null!");
        }
        if (image == null) {
            throw new IllegalArgumentException("image == null!");
        }
        if (!inReplacePixelsNest) {
            throw new IllegalStateException("No previous call to prepareReplacePixels!");
        }
        // Subsampling values.
        int stepX = 1, stepY = 1, gridX = 0, gridY = 0;
        // Initialize the ImageWriteParam.
        if (param == null) {
            // Use the default.
            param = getDefaultWriteParam();
        } else {
            // Make a copy of the ImageWriteParam.
            ImageWriteParam paramCopy = getDefaultWriteParam();
            // Force uncompressed.
            paramCopy.setCompressionMode(ImageWriteParam.MODE_DISABLED);
            // Force tiling to remain as in the already written image.
            paramCopy.setTilingMode(ImageWriteParam.MODE_COPY_FROM_METADATA);
            // Retain source and destination region and band settings.
            paramCopy.setDestinationOffset(param.getDestinationOffset());
            paramCopy.setSourceBands(param.getSourceBands());
            paramCopy.setSourceRegion(param.getSourceRegion());
            // Save original subsampling values for subsampling the
            // replacement data - not the data re-read from the image.
            stepX = param.getSourceXSubsampling();
            stepY = param.getSourceYSubsampling();
            gridX = param.getSubsamplingXOffset();
            gridY = param.getSubsamplingYOffset();
            // Replace the param.
            param = paramCopy;
        }
        // Check band count and bit depth compatibility.
        TIFFField f = replacePixelsMetadata.getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
        if (f == null) {
            throw new IIOException("Cannot read destination BitsPerSample");
        }
        int[] dstBitsPerSample = f.getAsInts();
        int[] srcBitsPerSample = image.getSampleModel().getSampleSize();
        int[] sourceBands = param.getSourceBands();
        if (sourceBands != null) {
            if (sourceBands.length != dstBitsPerSample.length) {
                throw new IIOException("Source and destination have different SamplesPerPixel");
            }
            for (int i = 0; i < sourceBands.length; i++) {
                if (dstBitsPerSample[i] != srcBitsPerSample[sourceBands[i]]) {
                    throw new IIOException("Source and destination have different BitsPerSample");
                }
            }
        } else {
            int srcNumBands = image.getSampleModel().getNumBands();
            if (srcNumBands != dstBitsPerSample.length) {
                throw new IIOException("Source and destination have different SamplesPerPixel");
            }
            for (int i = 0; i < srcNumBands; i++) {
                if (dstBitsPerSample[i] != srcBitsPerSample[i]) {
                    throw new IIOException("Source and destination have different BitsPerSample");
                }
            }
        }
        // Get the source image bounds.
        Rectangle srcImageBounds = new Rectangle(image.getMinX(), image.getMinY(), image.getWidth(), image.getHeight());
        // Initialize the source rect.
        Rectangle srcRect = param.getSourceRegion();
        if (srcRect == null) {
            srcRect = srcImageBounds;
        }
        // Set subsampling grid parameters.
        int subPeriodX = stepX;
        int subPeriodY = stepY;
        int subOriginX = gridX + srcRect.x;
        int subOriginY = gridY + srcRect.y;
        // Intersect with the source bounds.
        if (!srcRect.equals(srcImageBounds)) {
            srcRect = srcRect.intersection(srcImageBounds);
            if (srcRect.isEmpty()) {
                throw new IllegalArgumentException("Source region does not intersect source image!");
            }
        }
        // Get the destination offset.
        Point dstOffset = param.getDestinationOffset();
        // Forward map source rectangle to determine destination width.
        int dMinX = XToTileX(srcRect.x, subOriginX, subPeriodX) + dstOffset.x;
        int dMinY = YToTileY(srcRect.y, subOriginY, subPeriodY) + dstOffset.y;
        int dMaxX = XToTileX(srcRect.x + srcRect.width, subOriginX, subPeriodX) + dstOffset.x;
        int dMaxY = YToTileY(srcRect.y + srcRect.height, subOriginY, subPeriodY) + dstOffset.y;
        // Initialize the destination rectangle.
        Rectangle dstRect = new Rectangle(dstOffset.x, dstOffset.y, dMaxX - dMinX, dMaxY - dMinY);
        // Intersect with the replacement region.
        dstRect = dstRect.intersection(replacePixelsRegion);
        if (dstRect.isEmpty()) {
            throw new IllegalArgumentException("Forward mapped source region does not intersect destination region!");
        }
        // Backward map to the active source region.
        int activeSrcMinX = (dstRect.x - dstOffset.x) * subPeriodX + subOriginX;
        int sxmax = (dstRect.x + dstRect.width - 1 - dstOffset.x) * subPeriodX + subOriginX;
        int activeSrcWidth = sxmax - activeSrcMinX + 1;
        int activeSrcMinY = (dstRect.y - dstOffset.y) * subPeriodY + subOriginY;
        int symax = (dstRect.y + dstRect.height - 1 - dstOffset.y) * subPeriodY + subOriginY;
        int activeSrcHeight = symax - activeSrcMinY + 1;
        Rectangle activeSrcRect = new Rectangle(activeSrcMinX, activeSrcMinY, activeSrcWidth, activeSrcHeight);
        if (activeSrcRect.intersection(srcImageBounds).isEmpty()) {
            throw new IllegalArgumentException("Backward mapped destination region does not intersect source image!");
        }
        if (reader == null) {
            reader = new TIFFImageReader(new TIFFImageReaderSpi());
        } else {
            reader.reset();
        }
        stream.mark();
        try {
            stream.seek(headerPosition);
            reader.setInput(stream);
            this.imageMetadata = replacePixelsMetadata;
            this.param = param;
            SampleModel sm = image.getSampleModel();
            ColorModel cm = image.getColorModel();
            this.numBands = sm.getNumBands();
            this.imageType = new ImageTypeSpecifier(image);
            this.periodX = param.getSourceXSubsampling();
            this.periodY = param.getSourceYSubsampling();
            this.sourceBands = null;
            int[] sBands = param.getSourceBands();
            if (sBands != null) {
                this.sourceBands = sBands;
                this.numBands = sourceBands.length;
            }
            setupMetadata(cm, sm, reader.getWidth(replacePixelsIndex), reader.getHeight(replacePixelsIndex));
            int[] scaleSampleSize = sm.getSampleSize();
            initializeScaleTables(scaleSampleSize);
            // Determine whether bilevel.
            this.isBilevel = ImageUtil.isBinary(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(image))) && // no value rescaling
            !isRescaling && // no subbanding
            sourceBands == null && periodX == 1 && // no subsampling
            periodY == 1 && colorConverter == null;
            int minTileX = XToTileX(dstRect.x, 0, tileWidth);
            int minTileY = YToTileY(dstRect.y, 0, tileLength);
            int maxTileX = XToTileX(dstRect.x + dstRect.width - 1, 0, tileWidth);
            int maxTileY = YToTileY(dstRect.y + dstRect.height - 1, 0, tileLength);
            TIFFCompressor encoder = new TIFFNullCompressor();
            encoder.setWriter(this);
            encoder.setStream(stream);
            encoder.setMetadata(this.imageMetadata);
            Rectangle tileRect = new Rectangle();
            for (int ty = minTileY; ty <= maxTileY; ty++) {
                for (int tx = minTileX; tx <= maxTileX; tx++) {
                    int tileIndex = ty * tilesAcross + tx;
                    boolean isEmpty = replacePixelsByteCounts[tileIndex] == 0L;
                    WritableRaster raster;
                    if (isEmpty) {
                        SampleModel tileSM = sm.createCompatibleSampleModel(tileWidth, tileLength);
                        raster = Raster.createWritableRaster(tileSM, null);
                    } else {
                        BufferedImage tileImage = reader.readTile(replacePixelsIndex, tx, ty);
                        raster = tileImage.getRaster();
                    }
                    tileRect.setLocation(tx * tileWidth, ty * tileLength);
                    tileRect.setSize(raster.getWidth(), raster.getHeight());
                    raster = raster.createWritableTranslatedChild(tileRect.x, tileRect.y);
                    Rectangle replacementRect = tileRect.intersection(dstRect);
                    int srcMinX = (replacementRect.x - dstOffset.x) * subPeriodX + subOriginX;
                    int srcXmax = (replacementRect.x + replacementRect.width - 1 - dstOffset.x) * subPeriodX + subOriginX;
                    int srcWidth = srcXmax - srcMinX + 1;
                    int srcMinY = (replacementRect.y - dstOffset.y) * subPeriodY + subOriginY;
                    int srcYMax = (replacementRect.y + replacementRect.height - 1 - dstOffset.y) * subPeriodY + subOriginY;
                    int srcHeight = srcYMax - srcMinY + 1;
                    Rectangle srcTileRect = new Rectangle(srcMinX, srcMinY, srcWidth, srcHeight);
                    Raster replacementData = image.getData(srcTileRect);
                    if (subPeriodX == 1 && subPeriodY == 1 && subOriginX == 0 && subOriginY == 0) {
                        replacementData = replacementData.createChild(srcTileRect.x, srcTileRect.y, srcTileRect.width, srcTileRect.height, replacementRect.x, replacementRect.y, sourceBands);
                    } else {
                        replacementData = subsample(replacementData, sourceBands, subOriginX, subOriginY, subPeriodX, subPeriodY, dstOffset.x, dstOffset.y, replacementRect);
                        if (replacementData == null) {
                            continue;
                        }
                    }
                    raster.setRect(replacementData);
                    if (isEmpty) {
                        stream.seek(nextSpace);
                    } else {
                        stream.seek(replacePixelsTileOffsets[tileIndex]);
                    }
                    this.image = new SingleTileRenderedImage(raster, cm);
                    int numBytes = writeTile(tileRect, encoder);
                    if (isEmpty) {
                        // Update Strip/TileOffsets and
                        // Strip/TileByteCounts fields.
                        stream.mark();
                        stream.seek(replacePixelsOffsetsPosition + 4 * tileIndex);
                        stream.writeInt((int) nextSpace);
                        stream.seek(replacePixelsByteCountsPosition + 4 * tileIndex);
                        stream.writeInt(numBytes);
                        stream.reset();
                        // Increment location of next available space.
                        nextSpace += numBytes;
                    }
                }
            }
        } catch (IOException e) {
            throw e;
        } finally {
            stream.reset();
        }
    }
}
Also used : SingleTileRenderedImage(com.sun.media.imageioimpl.common.SingleTileRenderedImage) Raster(java.awt.image.Raster) WritableRaster(java.awt.image.WritableRaster) Rectangle(java.awt.Rectangle) IIOException(javax.imageio.IIOException) Point(java.awt.Point) IIOException(javax.imageio.IIOException) IOException(java.io.IOException) TIFFImageWriteParam(it.geosolutions.imageio.plugins.tiff.TIFFImageWriteParam) ImageWriteParam(javax.imageio.ImageWriteParam) Point(java.awt.Point) ImageTypeSpecifier(javax.imageio.ImageTypeSpecifier) BufferedImage(java.awt.image.BufferedImage) TIFFCompressor(it.geosolutions.imageio.plugins.tiff.TIFFCompressor) 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) WritableRaster(java.awt.image.WritableRaster) TIFFField(it.geosolutions.imageio.plugins.tiff.TIFFField)

Example 27 with TIFFField

use of it.geosolutions.imageio.plugins.tiff.TIFFField in project imageio-ext by geosolutions-it.

the class TIFFT6Compressor method encode.

public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, int scanlineStride) throws IOException {
    if (bitsPerSample.length != 1 || bitsPerSample[0] != 1) {
        throw new IIOException("Bits per sample must be 1 for T6 compression!");
    }
    if (metadata instanceof TIFFImageMetadata) {
        TIFFImageMetadata tim = (TIFFImageMetadata) metadata;
        long[] options = new long[1];
        options[0] = 0;
        BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
        TIFFField T6Options = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_T6_OPTIONS), TIFFTag.TIFF_LONG, 1, options);
        tim.rootIFD.addTIFFField(T6Options);
    }
    // See comment in TIFFT4Compressor
    int maxBits = 9 * ((width + 1) / 2) + 2;
    int bufSize = (maxBits + 7) / 8;
    bufSize = height * (bufSize + 2) + 12;
    byte[] compData = new byte[bufSize];
    int bytes = encodeT6(b, scanlineStride, 8 * off, width, height, compData);
    stream.write(compData, 0, bytes);
    return bytes;
}
Also used : BaselineTIFFTagSet(it.geosolutions.imageio.plugins.tiff.BaselineTIFFTagSet) TIFFField(it.geosolutions.imageio.plugins.tiff.TIFFField) IIOException(javax.imageio.IIOException)

Example 28 with TIFFField

use of it.geosolutions.imageio.plugins.tiff.TIFFField in project imageio-ext by geosolutions-it.

the class TIFFYCbCrDecompressor method beginDecoding.

public void beginDecoding() {
    if (decompressor != null) {
        decompressor.beginDecoding();
    }
    TIFFImageMetadata tmetadata = (TIFFImageMetadata) metadata;
    TIFFField f;
    f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_SUBSAMPLING);
    if (f != null) {
        if (f.getCount() == 2) {
            this.chromaSubsampleH = f.getAsInt(0);
            this.chromaSubsampleV = f.getAsInt(1);
            if (chromaSubsampleH != 1 && chromaSubsampleH != 2 && chromaSubsampleH != 4) {
                warning("Y_CB_CR_SUBSAMPLING[0] has illegal value " + chromaSubsampleH + " (should be 1, 2, or 4), setting to 1");
                chromaSubsampleH = 1;
            }
            if (chromaSubsampleV != 1 && chromaSubsampleV != 2 && chromaSubsampleV != 4) {
                warning("Y_CB_CR_SUBSAMPLING[1] has illegal value " + chromaSubsampleV + " (should be 1, 2, or 4), setting to 1");
                chromaSubsampleV = 1;
            }
        } else {
            warning("Y_CB_CR_SUBSAMPLING count != 2, " + "assuming no subsampling");
        }
    }
    f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_COEFFICIENTS);
    if (f != null) {
        if (f.getCount() == 3) {
            this.LumaRed = f.getAsFloat(0);
            this.LumaGreen = f.getAsFloat(1);
            this.LumaBlue = f.getAsFloat(2);
        } else {
            warning("Y_CB_CR_COEFFICIENTS count != 3, " + "assuming default values for CCIR 601-1");
        }
    }
    f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_REFERENCE_BLACK_WHITE);
    if (f != null) {
        if (f.getCount() == 6) {
            this.referenceBlackY = f.getAsFloat(0);
            this.referenceWhiteY = f.getAsFloat(1);
            this.referenceBlackCb = f.getAsFloat(2);
            this.referenceWhiteCb = f.getAsFloat(3);
            this.referenceBlackCr = f.getAsFloat(4);
            this.referenceWhiteCr = f.getAsFloat(5);
        } else {
            warning("REFERENCE_BLACK_WHITE count != 6, ignoring it");
        }
    } else {
        warning("REFERENCE_BLACK_WHITE not found, assuming 0-255/128-255/128-255");
    }
    this.colorConvert = true;
    float BCb = (2.0f - 2.0f * LumaBlue);
    float RCr = (2.0f - 2.0f * LumaRed);
    float GY = (1.0f - LumaBlue - LumaRed) / LumaGreen;
    float GCb = 2.0f * LumaBlue * (LumaBlue - 1.0f) / LumaGreen;
    float GCr = 2.0f * LumaRed * (LumaRed - 1.0f) / LumaGreen;
    for (int i = 0; i < 256; i++) {
        float fY = (i - referenceBlackY) * codingRangeY / (referenceWhiteY - referenceBlackY);
        float fCb = (i - referenceBlackCb) * 127.0f / (referenceWhiteCb - referenceBlackCb);
        float fCr = (i - referenceBlackCr) * 127.0f / (referenceWhiteCr - referenceBlackCr);
        iYTab[i] = (int) (fY * FRAC_SCALE);
        iCbTab[i] = (int) (fCb * BCb * FRAC_SCALE);
        iCrTab[i] = (int) (fCr * RCr * FRAC_SCALE);
        iGYTab[i] = (int) (fY * GY * FRAC_SCALE);
        iGCbTab[i] = (int) (fCb * GCb * FRAC_SCALE);
        iGCrTab[i] = (int) (fCr * GCr * FRAC_SCALE);
    }
}
Also used : TIFFField(it.geosolutions.imageio.plugins.tiff.TIFFField)

Example 29 with TIFFField

use of it.geosolutions.imageio.plugins.tiff.TIFFField in project imageio-ext by geosolutions-it.

the class TIFFJPEGDecompressor method beginDecoding.

/* XXX
    private static class JPEGSPIFilter implements ServiceRegistry.Filter {
        JPEGSPIFilter() {}

        public boolean filter(Object provider) {
            ImageReaderSpi readerSPI = (ImageReaderSpi)provider;

            if(readerSPI.getPluginClassName().startsWith("com.sun.imageio")) {
                String streamMetadataName =
                    readerSPI.getNativeStreamMetadataFormatName();
                if(streamMetadataName != null) {
                    return streamMetadataName.indexOf("jpeg_stream") != -1;
                } else {
                    return false;
                }
            }

            return false;
        }
    }
    */
public void beginDecoding() {
    // Initialize the JPEG reader if needed.
    if (this.JPEGReader == null) {
        if (DEBUG)
            System.out.println("Initializing JPEGReader");
        /* XXX
            if(this.jpegReaderSPI != null) {
                try {
                    this.JPEGReader = jpegReaderSPI.createReaderInstance();
                } catch(Exception e) {
                }
            }

            if(this.JPEGReader == null) {
            */
        // Get all JPEG readers.
        Iterator iter = ImageIO.getImageReadersByFormatName("jpeg");
        if (!iter.hasNext()) {
            // XXX The exception thrown should be an IIOException.
            throw new IllegalStateException("No JPEG readers found!");
        }
        // Initialize reader to the first one.
        this.JPEGReader = (ImageReader) iter.next();
        String className = JPEGReader.getClass().getName();
        if (DEBUG)
            System.out.println("Using " + className);
        if (className.equalsIgnoreCase(TURBO_JPEG_DECOMPRESSOR)) {
            useTurbo = true;
        }
        this.JPEGParam = JPEGReader.getDefaultReadParam();
    }
    // Get the JPEGTables field.
    TIFFImageMetadata tmetadata = (TIFFImageMetadata) metadata;
    TIFFField f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_TABLES);
    if (f != null) {
        this.hasJPEGTables = true;
        this.tables = f.getAsBytes();
    } else {
        this.hasJPEGTables = false;
    }
}
Also used : Iterator(java.util.Iterator) TIFFField(it.geosolutions.imageio.plugins.tiff.TIFFField)

Example 30 with TIFFField

use of it.geosolutions.imageio.plugins.tiff.TIFFField in project imageio-ext by geosolutions-it.

the class TIFFOldJPEGDecompressor method initialize.

// 
// Intialize instance variables according to an analysis of the
// TIFF field content. See bug 4929147 for test image information.
// 
// Case 1: Image contains a single strip or tile and the offset to
// that strip or tile points to an SOI marker.
// 
// Example:
// "Visionshape Inc. Compression Software, version 2.5"
// ColorTiffWithBarcode.tif
// Color2.tif (pages 2-5 (indexes 1-4)
// color3.tif (pages 2-5 (indexes 1-4)
// 
// "Kofax standard Multi-Page TIFF Storage Filter v2.01.000"
// 01.tif (pages 1 and 3(indexes 0 and 2))
// 
// Instance variables set: JPEGStreamOffset
// 
// Case 2: Image contains a single strip or tile and a
// JPEGInterchangeFormat field is present but the
// JPEGInterchangeFormatLength is erroneously missing.
// 
// Example:
// "Kofax standard Multi-Page TIFF Storage Filter v2.01.000"
// 01.tif (pages 1 and 3(indexes 0 and 2))
// (but this example also satisfies case 1)
// 
// Instance variables set: JPEGStreamOffset
// 
// Case 3: Image contains a single strip or tile, the
// JPEGInterchangeFormat and JPEGInterchangeFormatLength
// fields are both present, the value of JPEGInterchangeFormat
// is less than the offset to the strip or tile, and the sum
// of the values of JPEGInterchangeFormat and
// JPEGInterchangeFormatLength is greater than the offset to
// the strip or tile.
// 
// Instance variables set: JPEGStreamOffset
// 
// Example:
// "HP IL v1.1"
// smallliz.tif from libtiff test data.
// 
// Instance variables set: JPEGStreamOffset
// 
// Cases 4-5 apply if none of cases 1-3 applies or the image has multiple
// strips or tiles.
// 
// Case 4: JPEGInterchangeFormat and JPEGInterchangeFormatLength are
// present, the value of JPEGInterchangeFormatLength is at least 2,
// and the sum of the values of these two fields is at most the
// value of the offset to the first strip or tile.
// 
// Instance variables set: tables, SOFPosition, SOSMarker
// 
// Example:
// "Oi/GFS, writer v00.06.00P, (c) Wang Labs, Inc. 1990, 1991"
// 03.tif (pages 1 and 3(indexes 0 and 2))
// 
// "Oi/GFS, writer v00.06.02"
// Color2.tif (page 1 (index 0))
// color3.tif (page 1 (index 0))
// 
// Case 5: If none of the foregoing cases apply. For this case the
// JPEGQTables, JPEGACTables, and JPEGDCTables must be valid.
// 
// Instance variables set: tables, SOFPosition, SOSMarker
// 
// Example:
// "NeXT"
// zackthecat.tif from libtiff test data.
// 
private synchronized void initialize() throws IOException {
    if (isInitialized) {
        return;
    }
    // Get the TIFF metadata object.
    TIFFImageMetadata tim = (TIFFImageMetadata) metadata;
    // Get the JPEGInterchangeFormat field.
    TIFFField JPEGInterchangeFormatField = tim.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT);
    // Get the tile or strip offsets.
    TIFFField segmentOffsetField = tim.getTIFFField(BaselineTIFFTagSet.TAG_TILE_OFFSETS);
    if (segmentOffsetField == null) {
        segmentOffsetField = tim.getTIFFField(BaselineTIFFTagSet.TAG_STRIP_OFFSETS);
        if (segmentOffsetField == null) {
            segmentOffsetField = JPEGInterchangeFormatField;
        }
    }
    long[] segmentOffsets = segmentOffsetField.getAsLongs();
    // Determine whether the image has more than one strip or tile.
    boolean isTiled = segmentOffsets.length > 1;
    if (!isTiled) {
        // 
        // If the image has only a single strip or tile and it looks
        // as if a complete JPEG stream is present then set the value
        // of JPEGStreamOffset to the offset of the JPEG stream;
        // otherwise leave JPEGStreamOffset set to null.
        // 
        stream.seek(offset);
        stream.mark();
        if (stream.read() == 0xff && stream.read() == SOI) {
            // Tile or strip offset points to SOI.
            JPEGStreamOffset = new Long(offset);
            // Set initialization flag and return.
            if (DEBUG)
                System.out.println("OLD JPEG CASE 1");
            ((TIFFImageReader) reader).forwardWarningMessage("SOI marker detected at start of strip or tile.");
            isInitialized = true;
            stream.reset();
            return;
        }
        stream.reset();
        if (JPEGInterchangeFormatField != null) {
            // Get the value of JPEGInterchangeFormat.
            long jpegInterchangeOffset = JPEGInterchangeFormatField.getAsLong(0);
            // Check that the value of JPEGInterchangeFormat points to SOI.
            stream.mark();
            stream.seek(jpegInterchangeOffset);
            if (stream.read() == 0xff && stream.read() == SOI)
                // JPEGInterchangeFormat offset points to SOI.
                JPEGStreamOffset = new Long(jpegInterchangeOffset);
            else
                ((TIFFImageReader) reader).forwardWarningMessage("JPEGInterchangeFormat does not point to SOI");
            stream.reset();
            // Get the JPEGInterchangeFormatLength field.
            TIFFField JPEGInterchangeFormatLengthField = tim.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
            if (JPEGInterchangeFormatLengthField == null) {
                if (DEBUG)
                    System.out.println("OLD JPEG CASE 2");
                ((TIFFImageReader) reader).forwardWarningMessage("JPEGInterchangeFormatLength field is missing");
            } else {
                // Get the JPEGInterchangeFormatLength field's value.
                long jpegInterchangeLength = JPEGInterchangeFormatLengthField.getAsLong(0);
                if (jpegInterchangeOffset < segmentOffsets[0] && (jpegInterchangeOffset + jpegInterchangeLength) > segmentOffsets[0]) {
                    if (DEBUG)
                        System.out.println("OLD JPEG CASE 3");
                } else {
                    if (DEBUG)
                        System.out.println("OLD JPEG CASE 3A");
                    ((TIFFImageReader) reader).forwardWarningMessage("JPEGInterchangeFormatLength field value is invalid");
                }
            }
            // Return if JPEGInterchangeFormat pointed to SOI.
            if (JPEGStreamOffset != null) {
                isInitialized = true;
                return;
            }
        }
    }
    // Get the subsampling factors.
    TIFFField YCbCrSubsamplingField = tim.getTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_SUBSAMPLING);
    if (YCbCrSubsamplingField != null) {
        subsamplingX = YCbCrSubsamplingField.getAsChars()[0];
        subsamplingY = YCbCrSubsamplingField.getAsChars()[1];
    }
    // 
    if (JPEGInterchangeFormatField != null) {
        // Get the value of JPEGInterchangeFormat.
        long jpegInterchangeOffset = JPEGInterchangeFormatField.getAsLong(0);
        // Get the JPEGInterchangeFormatLength field.
        TIFFField JPEGInterchangeFormatLengthField = tim.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
        if (JPEGInterchangeFormatLengthField != null) {
            // Get the JPEGInterchangeFormatLength field's value.
            long jpegInterchangeLength = JPEGInterchangeFormatLengthField.getAsLong(0);
            if (jpegInterchangeLength >= 2 && jpegInterchangeOffset + jpegInterchangeLength <= segmentOffsets[0]) {
                // Determine the length excluding any terminal EOI marker
                // and allocate table memory.
                stream.mark();
                stream.seek(jpegInterchangeOffset + jpegInterchangeLength - 2);
                if (stream.read() == 0xff && stream.read() == EOI) {
                    this.tables = new byte[(int) (jpegInterchangeLength - 2)];
                } else {
                    this.tables = new byte[(int) jpegInterchangeLength];
                }
                stream.reset();
                // Read the tables.
                stream.mark();
                stream.seek(jpegInterchangeOffset);
                stream.readFully(tables);
                stream.reset();
                if (DEBUG)
                    System.out.println("OLD JPEG CASE 4");
                ((TIFFImageReader) reader).forwardWarningMessage("Incorrect JPEG interchange format: using JPEGInterchangeFormat offset to derive tables.");
            } else {
                ((TIFFImageReader) reader).forwardWarningMessage("JPEGInterchangeFormat+JPEGInterchangeFormatLength > offset to first strip or tile.");
            }
        }
    }
    if (this.tables == null) {
        // 
        // Create tables-only stream in tables[] consisting of
        // SOI+DQTs+DHTs
        // 
        ByteArrayOutputStream baos = // XXX length
        new ByteArrayOutputStream();
        // Save stream length;
        long streamLength = stream.length();
        // SOI
        baos.write(0xff);
        baos.write(SOI);
        // Quantization Tables
        TIFFField f = tim.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_Q_TABLES);
        if (f == null) {
            throw new IIOException("JPEGQTables field missing!");
        }
        long[] off = f.getAsLongs();
        for (int i = 0; i < off.length; i++) {
            // Marker ID
            baos.write(0xff);
            baos.write(DQT);
            char markerLength = (char) 67;
            // Length
            baos.write((markerLength >>> 8) & 0xff);
            baos.write(markerLength & 0xff);
            // Table ID and precision
            baos.write(i);
            byte[] qtable = new byte[64];
            if (streamLength != -1 && off[i] > streamLength) {
                throw new IIOException("JPEGQTables offset for index " + i + " is not in the stream!");
            }
            stream.seek(off[i]);
            stream.readFully(qtable);
            // Table data
            baos.write(qtable);
        }
        // Huffman Tables (k == 0 ? DC : AC).
        for (int k = 0; k < 2; k++) {
            int tableTagNumber = k == 0 ? BaselineTIFFTagSet.TAG_JPEG_DC_TABLES : BaselineTIFFTagSet.TAG_JPEG_AC_TABLES;
            f = tim.getTIFFField(tableTagNumber);
            String fieldName = tableTagNumber == BaselineTIFFTagSet.TAG_JPEG_DC_TABLES ? "JPEGDCTables" : "JPEGACTables";
            if (f == null) {
                throw new IIOException(fieldName + " field missing!");
            }
            off = f.getAsLongs();
            for (int i = 0; i < off.length; i++) {
                // Marker ID
                baos.write(0xff);
                baos.write(DHT);
                byte[] blengths = new byte[16];
                if (streamLength != -1 && off[i] > streamLength) {
                    throw new IIOException(fieldName + " offset for index " + i + " is not in the stream!");
                }
                stream.seek(off[i]);
                stream.readFully(blengths);
                int numCodes = 0;
                for (int j = 0; j < 16; j++) {
                    numCodes += blengths[j] & 0xff;
                }
                char markerLength = (char) (19 + numCodes);
                // Length
                baos.write((markerLength >>> 8) & 0xff);
                baos.write(markerLength & 0xff);
                // Table ID and type
                baos.write(i | (k << 4));
                // Number of codes
                baos.write(blengths);
                byte[] bcodes = new byte[numCodes];
                stream.readFully(bcodes);
                // Codes
                baos.write(bcodes);
            }
        }
        // SOF0
        // Marker identifier
        baos.write((byte) 0xff);
        baos.write((byte) SOF0);
        // Length
        short sval = (short) (8 + 3 * samplesPerPixel);
        baos.write((byte) ((sval >>> 8) & 0xff));
        baos.write((byte) (sval & 0xff));
        // Data precision
        baos.write((byte) 8);
        // Tile/strip height
        sval = (short) srcHeight;
        baos.write((byte) ((sval >>> 8) & 0xff));
        baos.write((byte) (sval & 0xff));
        // Tile/strip width
        sval = (short) srcWidth;
        baos.write((byte) ((sval >>> 8) & 0xff));
        baos.write((byte) (sval & 0xff));
        // Number of components
        baos.write((byte) samplesPerPixel);
        if (samplesPerPixel == 1) {
            // Component ID
            baos.write((byte) 1);
            // Subsampling factor
            baos.write((byte) 0x11);
            // Quantization table ID
            baos.write((byte) 0);
        } else {
            // 3
            for (int i = 0; i < 3; i++) {
                // Component ID
                baos.write((byte) (i + 1));
                baos.write((i != 0) ? (byte) 0x11 : (byte) (((subsamplingX & 0x0f) << 4) | (subsamplingY & 0x0f)));
                // Quantization table ID
                baos.write((byte) i);
            }
        }
        ;
        // DRI (optional).
        f = tim.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_RESTART_INTERVAL);
        if (f != null) {
            char restartInterval = f.getAsChars()[0];
            if (restartInterval != 0) {
                // Marker identifier
                baos.write((byte) 0xff);
                baos.write((byte) DRI);
                sval = 4;
                // Length
                baos.write((byte) ((sval >>> 8) & 0xff));
                baos.write((byte) (sval & 0xff));
                // RestartInterval
                baos.write((byte) ((restartInterval >>> 8) & 0xff));
                baos.write((byte) (restartInterval & 0xff));
            }
        }
        tables = baos.toByteArray();
        if (DEBUG)
            System.out.println("OLD JPEG CASE 5");
    }
    // 
    // Check for presence of SOF marker and save its position.
    // 
    int idx = 0;
    int idxMax = tables.length - 1;
    while (idx < idxMax) {
        if ((tables[idx] & 0xff) == 0xff && (tables[idx + 1] & 0xff) == SOF0) {
            SOFPosition = idx;
            break;
        }
        idx++;
    }
    // 
    if (SOFPosition == -1) {
        byte[] tmpTables = new byte[tables.length + 10 + 3 * samplesPerPixel];
        System.arraycopy(tables, 0, tmpTables, 0, tables.length);
        int tmpOffset = tables.length;
        SOFPosition = tables.length;
        tables = tmpTables;
        // Marker identifier
        tables[tmpOffset++] = (byte) 0xff;
        tables[tmpOffset++] = (byte) SOF0;
        // Length
        short sval = (short) (8 + 3 * samplesPerPixel);
        tables[tmpOffset++] = (byte) ((sval >>> 8) & 0xff);
        tables[tmpOffset++] = (byte) (sval & 0xff);
        // Data precision
        tables[tmpOffset++] = (byte) 8;
        // Tile/strip height
        sval = (short) srcHeight;
        tables[tmpOffset++] = (byte) ((sval >>> 8) & 0xff);
        tables[tmpOffset++] = (byte) (sval & 0xff);
        // Tile/strip width
        sval = (short) srcWidth;
        tables[tmpOffset++] = (byte) ((sval >>> 8) & 0xff);
        tables[tmpOffset++] = (byte) (sval & 0xff);
        // Number of components
        tables[tmpOffset++] = (byte) samplesPerPixel;
        if (samplesPerPixel == 1) {
            // Component ID
            tables[tmpOffset++] = (byte) 1;
            // Subsampling factor
            tables[tmpOffset++] = (byte) 0x11;
            // Quantization table ID
            tables[tmpOffset++] = (byte) 0;
        } else {
            // 3
            for (int i = 0; i < 3; i++) {
                // Component ID
                tables[tmpOffset++] = (byte) (i + 1);
                tables[tmpOffset++] = (i != 0) ? (byte) 0x11 : (byte) (((subsamplingX & 0x0f) << 4) | (subsamplingY & 0x0f));
                // Quantization table ID
                tables[tmpOffset++] = (byte) i;
            }
        }
        ;
    }
    // 
    // Initialize SOSMarker.
    // 
    stream.mark();
    stream.seek(segmentOffsets[0]);
    if (stream.read() == 0xff && stream.read() == SOS) {
        // 
        // If the first segment starts with an SOS marker save it.
        // 
        int SOSLength = (stream.read() << 8) | stream.read();
        SOSMarker = new byte[SOSLength + 2];
        SOSMarker[0] = (byte) 0xff;
        SOSMarker[1] = (byte) SOS;
        SOSMarker[2] = (byte) ((SOSLength & 0xff00) >> 8);
        SOSMarker[3] = (byte) (SOSLength & 0xff);
        stream.readFully(SOSMarker, 4, SOSLength - 2);
    } else {
        // 
        // Manufacture an SOS marker.
        // 
        SOSMarker = new byte[2 + 6 + 2 * samplesPerPixel];
        int SOSMarkerIndex = 0;
        // Marker identifier
        SOSMarker[SOSMarkerIndex++] = (byte) 0xff;
        SOSMarker[SOSMarkerIndex++] = (byte) SOS;
        // Length
        short sval = (short) (6 + 2 * samplesPerPixel);
        SOSMarker[SOSMarkerIndex++] = (byte) ((sval >>> 8) & 0xff);
        SOSMarker[SOSMarkerIndex++] = (byte) (sval & 0xff);
        // Number of components in scan
        SOSMarker[SOSMarkerIndex++] = (byte) samplesPerPixel;
        if (samplesPerPixel == 1) {
            // Component ID
            SOSMarker[SOSMarkerIndex++] = (byte) 1;
            // Huffman table ID
            SOSMarker[SOSMarkerIndex++] = (byte) 0;
        } else {
            // 3
            for (int i = 0; i < 3; i++) {
                SOSMarker[SOSMarkerIndex++] = // Component ID
                (byte) (i + 1);
                SOSMarker[SOSMarkerIndex++] = // Huffman table IDs
                (byte) ((i << 4) | i);
            }
        }
        ;
        SOSMarker[SOSMarkerIndex++] = (byte) 0;
        SOSMarker[SOSMarkerIndex++] = (byte) 0x3f;
        SOSMarker[SOSMarkerIndex++] = (byte) 0;
    }
    stream.reset();
    // Set initialization flag.
    isInitialized = true;
}
Also used : IIOException(javax.imageio.IIOException) ByteArrayOutputStream(java.io.ByteArrayOutputStream) Point(java.awt.Point) TIFFField(it.geosolutions.imageio.plugins.tiff.TIFFField)

Aggregations

TIFFField (it.geosolutions.imageio.plugins.tiff.TIFFField)35 IIOMetadataNode (javax.imageio.metadata.IIOMetadataNode)11 BaselineTIFFTagSet (it.geosolutions.imageio.plugins.tiff.BaselineTIFFTagSet)8 TIFFTag (it.geosolutions.imageio.plugins.tiff.TIFFTag)7 Iterator (java.util.Iterator)7 List (java.util.List)7 TIFFTagSet (it.geosolutions.imageio.plugins.tiff.TIFFTagSet)6 ArrayList (java.util.ArrayList)6 Point (java.awt.Point)5 IIOException (javax.imageio.IIOException)5 EXIFParentTIFFTagSet (it.geosolutions.imageio.plugins.tiff.EXIFParentTIFFTagSet)4 IOException (java.io.IOException)4 Node (org.w3c.dom.Node)4 NodeList (org.w3c.dom.NodeList)4 TIFFImageWriteParam (it.geosolutions.imageio.plugins.tiff.TIFFImageWriteParam)2 Rectangle (java.awt.Rectangle)2 ICC_ColorSpace (java.awt.color.ICC_ColorSpace)2 IndexColorModel (java.awt.image.IndexColorModel)2 ByteArrayOutputStream (java.io.ByteArrayOutputStream)2 EOFException (java.io.EOFException)2