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();
}
}
}
Aggregations