Search in sources :

Example 1 with TIFFCompressor

use of it.geosolutions.imageio.plugins.tiff.TIFFCompressor 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)

Aggregations

SingleTileRenderedImage (com.sun.media.imageioimpl.common.SingleTileRenderedImage)1 TIFFCompressor (it.geosolutions.imageio.plugins.tiff.TIFFCompressor)1 TIFFField (it.geosolutions.imageio.plugins.tiff.TIFFField)1 TIFFImageWriteParam (it.geosolutions.imageio.plugins.tiff.TIFFImageWriteParam)1 Point (java.awt.Point)1 Rectangle (java.awt.Rectangle)1 BufferedImage (java.awt.image.BufferedImage)1 ColorModel (java.awt.image.ColorModel)1 ComponentColorModel (java.awt.image.ComponentColorModel)1 ComponentSampleModel (java.awt.image.ComponentSampleModel)1 IndexColorModel (java.awt.image.IndexColorModel)1 Raster (java.awt.image.Raster)1 SampleModel (java.awt.image.SampleModel)1 WritableRaster (java.awt.image.WritableRaster)1 IOException (java.io.IOException)1 IIOException (javax.imageio.IIOException)1 ImageTypeSpecifier (javax.imageio.ImageTypeSpecifier)1 ImageWriteParam (javax.imageio.ImageWriteParam)1