use of java.awt.image.SampleModel in project imageio-ext by geosolutions-it.
the class EmptyImage method prepareWriteEmpty.
public void prepareWriteEmpty(IIOMetadata streamMetadata, ImageTypeSpecifier imageType, int width, int height, IIOMetadata imageMetadata, List thumbnails, ImageWriteParam param) throws IOException {
checkParamsEmpty(imageType, width, height, thumbnails);
this.isWritingEmpty = true;
SampleModel emptySM = imageType.getSampleModel();
RenderedImage emptyImage = new EmptyImage(0, 0, width, height, 0, 0, emptySM.getWidth(), emptySM.getHeight(), emptySM, imageType.getColorModel());
write(streamMetadata, new IIOImage(emptyImage, null, imageMetadata), param, true, false);
}
use of java.awt.image.SampleModel 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();
}
}
}
use of java.awt.image.SampleModel in project imageio-ext by geosolutions-it.
the class PNMImageWriter method write.
public void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException {
clearAbortRequest();
processImageStarted(0);
if (param == null)
param = getDefaultWriteParam();
RenderedImage input = null;
Raster inputRaster = null;
boolean writeRaster = image.hasRaster();
Rectangle sourceRegion = param.getSourceRegion();
SampleModel sampleModel = null;
ColorModel colorModel = null;
if (writeRaster) {
inputRaster = image.getRaster();
sampleModel = inputRaster.getSampleModel();
if (sourceRegion == null)
sourceRegion = inputRaster.getBounds();
else
sourceRegion = sourceRegion.intersection(inputRaster.getBounds());
} else {
input = image.getRenderedImage();
sampleModel = input.getSampleModel();
colorModel = input.getColorModel();
Rectangle rect = new Rectangle(input.getMinX(), input.getMinY(), input.getWidth(), input.getHeight());
if (sourceRegion == null)
sourceRegion = rect;
else
sourceRegion = sourceRegion.intersection(rect);
}
if (sourceRegion.isEmpty())
throw new RuntimeException(I18N.getString("PNMImageWrite1"));
ImageUtil.canEncodeImage(this, colorModel, sampleModel);
int scaleX = param.getSourceXSubsampling();
int scaleY = param.getSourceYSubsampling();
int xOffset = param.getSubsamplingXOffset();
int yOffset = param.getSubsamplingYOffset();
sourceRegion.translate(xOffset, yOffset);
sourceRegion.width -= xOffset;
sourceRegion.height -= yOffset;
int w = (sourceRegion.width + scaleX - 1) / scaleX;
int h = (sourceRegion.height + scaleY - 1) / scaleY;
int tileWidth = sampleModel.getWidth();
// Raw data can only handle bytes, everything greater must be ASCII.
int[] sampleSize = sampleModel.getSampleSize();
int[] sourceBands = param.getSourceBands();
int numBands = sampleModel.getNumBands();
if (sourceBands != null) {
sampleModel = sampleModel.createSubsetSampleModel(sourceBands);
colorModel = null;
numBands = sampleModel.getNumBands();
} else {
sourceBands = new int[numBands];
for (int i = 0; i < numBands; i++) sourceBands[i] = i;
}
// Colormap populated for non-bilevel IndexColorModel only.
byte[] reds = null;
byte[] greens = null;
byte[] blues = null;
// Flag indicating that PB data should be inverted before writing.
boolean isPBMInverted = false;
if (numBands == 1) {
if (colorModel instanceof IndexColorModel) {
IndexColorModel icm = (IndexColorModel) colorModel;
int mapSize = icm.getMapSize();
if (mapSize < (1 << sampleSize[0]))
throw new RuntimeException(I18N.getString("PNMImageWrite2"));
if (sampleSize[0] == 1) {
variant = PBM_RAW;
// Set PBM inversion flag if 1 maps to a higher color
// value than 0: PBM expects white-is-zero so if this
// does not obtain then inversion needs to occur.
isPBMInverted = icm.getRed(1) > icm.getRed(0);
} else {
variant = PPM_RAW;
reds = new byte[mapSize];
greens = new byte[mapSize];
blues = new byte[mapSize];
icm.getReds(reds);
icm.getGreens(greens);
icm.getBlues(blues);
}
} else if (sampleSize[0] == 1) {
variant = PBM_RAW;
} else if (sampleSize[0] <= 8) {
variant = PGM_RAW;
} else {
variant = PGM_ASCII;
}
} else if (numBands == 3) {
if (sampleSize[0] <= 8 && sampleSize[1] <= 8 && sampleSize[2] <= 8) {
// all 3 bands must be <= 8
variant = PPM_RAW;
} else {
variant = PPM_ASCII;
}
} else {
throw new RuntimeException(I18N.getString("PNMImageWrite3"));
}
IIOMetadata inputMetadata = image.getMetadata();
ImageTypeSpecifier imageType;
if (colorModel != null) {
imageType = new ImageTypeSpecifier(colorModel, sampleModel);
} else {
int dataType = sampleModel.getDataType();
switch(numBands) {
case 1:
imageType = ImageTypeSpecifier.createGrayscale(sampleSize[0], dataType, false);
break;
case 3:
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
imageType = ImageTypeSpecifier.createInterleaved(cs, new int[] { 0, 1, 2 }, dataType, false, false);
break;
default:
throw new IIOException("Cannot encode image with " + numBands + " bands!");
}
}
PNMMetadata metadata;
if (inputMetadata != null) {
// Convert metadata.
metadata = (PNMMetadata) convertImageMetadata(inputMetadata, imageType, param);
} else {
// Use default.
metadata = (PNMMetadata) getDefaultImageMetadata(imageType, param);
}
// Read parameters
boolean isRawPNM;
if (param instanceof PNMImageWriteParam) {
isRawPNM = ((PNMImageWriteParam) param).getRaw();
} else {
isRawPNM = metadata.isRaw();
}
maxValue = metadata.getMaxValue();
for (int i = 0; i < sampleSize.length; i++) {
int v = (1 << sampleSize[i]) - 1;
if (v > maxValue) {
maxValue = v;
}
}
if (isRawPNM) {
// Raw output is desired.
int maxBitDepth = metadata.getMaxBitDepth();
if (!isRaw(variant) && maxBitDepth <= 8) {
// Current variant is ASCII and the bit depth is acceptable
// so convert to RAW variant by adding '3' to variant.
variant += 0x3;
} else if (isRaw(variant) && maxBitDepth > 8) {
// Current variant is RAW and the bit depth it too large for
// RAW so convert to ASCII.
variant -= 0x3;
}
// Omitted cases are (variant == RAW && max <= 8) and
// (variant == ASCII && max > 8) neither of which requires action.
} else if (isRaw(variant)) {
// Raw output is NOT desired so convert to ASCII
variant -= 0x3;
}
// Write PNM file.
// magic value: 'P'
stream.writeByte('P');
stream.writeByte(variant);
stream.write(lineSeparator);
// comment line
stream.write(COMMENT.getBytes());
// Write the comments provided in the metadata
Iterator comments = metadata.getComments();
if (comments != null) {
while (comments.hasNext()) {
stream.write(lineSeparator);
String comment = "# " + (String) comments.next();
stream.write(comment.getBytes());
}
}
stream.write(lineSeparator);
// width
writeInteger(stream, w);
stream.write(SPACE);
// height
writeInteger(stream, h);
// Write sample max value for non-binary images
if ((variant != PBM_RAW) && (variant != PBM_ASCII)) {
stream.write(lineSeparator);
writeInteger(stream, maxValue);
}
// last header value and the start of the raw data.
if (variant == PBM_RAW || variant == PGM_RAW || variant == PPM_RAW) {
stream.write('\n');
}
// Set flag for optimal image writing case: row-packed data with
// correct band order if applicable.
boolean writeOptimal = false;
if (variant == PBM_RAW && sampleModel.getTransferType() == DataBuffer.TYPE_BYTE && sampleModel instanceof MultiPixelPackedSampleModel) {
MultiPixelPackedSampleModel mppsm = (MultiPixelPackedSampleModel) sampleModel;
int originX = 0;
if (writeRaster)
originX = inputRaster.getMinX();
else
originX = input.getMinX();
// Must have left-aligned bytes with unity bit stride.
if (mppsm.getBitOffset((sourceRegion.x - originX) % tileWidth) == 0 && mppsm.getPixelBitStride() == 1 && scaleX == 1)
writeOptimal = true;
} else if ((variant == PGM_RAW || variant == PPM_RAW) && sampleModel instanceof ComponentSampleModel && !(colorModel instanceof IndexColorModel)) {
ComponentSampleModel csm = (ComponentSampleModel) sampleModel;
// Pixel stride must equal band count.
if (csm.getPixelStride() == numBands && scaleX == 1) {
writeOptimal = true;
// Band offsets must equal band indices.
if (variant == PPM_RAW) {
int[] bandOffsets = csm.getBandOffsets();
for (int b = 0; b < numBands; b++) {
if (bandOffsets[b] != b) {
writeOptimal = false;
break;
}
}
}
}
}
// Write using an optimal approach if possible.
if (writeOptimal) {
int bytesPerRow = variant == PBM_RAW ? (w + 7) / 8 : w * sampleModel.getNumBands();
byte[] bdata = null;
byte[] invertedData = new byte[bytesPerRow];
// Loop over tiles to minimize cobbling.
for (int j = 0; j < sourceRegion.height; j++) {
if (abortRequested())
break;
Raster lineRaster = null;
if (writeRaster) {
lineRaster = inputRaster.createChild(sourceRegion.x, j, sourceRegion.width, 1, 0, 0, null);
} else {
lineRaster = input.getData(new Rectangle(sourceRegion.x, sourceRegion.y + j, w, 1));
lineRaster = lineRaster.createTranslatedChild(0, 0);
}
bdata = ((DataBufferByte) lineRaster.getDataBuffer()).getData();
sampleModel = lineRaster.getSampleModel();
int offset = 0;
if (sampleModel instanceof ComponentSampleModel) {
offset = ((ComponentSampleModel) sampleModel).getOffset(lineRaster.getMinX() - lineRaster.getSampleModelTranslateX(), lineRaster.getMinY() - lineRaster.getSampleModelTranslateY());
} else if (sampleModel instanceof MultiPixelPackedSampleModel) {
offset = ((MultiPixelPackedSampleModel) sampleModel).getOffset(lineRaster.getMinX() - lineRaster.getSampleModelTranslateX(), lineRaster.getMinX() - lineRaster.getSampleModelTranslateY());
}
if (isPBMInverted) {
for (int k = offset, m = 0; m < bytesPerRow; k++, m++) invertedData[m] = (byte) ~bdata[k];
bdata = invertedData;
offset = 0;
}
stream.write(bdata, offset, bytesPerRow);
processImageProgress(100.0F * j / sourceRegion.height);
}
// Write all buffered bytes and return.
stream.flush();
if (abortRequested())
processWriteAborted();
else
processImageComplete();
return;
}
// Buffer for 1 rows of original pixels
int size = sourceRegion.width * numBands;
int[] pixels = new int[size];
// Also allocate a buffer to hold the data to be written to the file,
// so we can use array writes.
byte[] bpixels = reds == null ? new byte[w * numBands] : new byte[w * 3];
// The index of the sample being written, used to
// place a line separator after every 16th sample in
// ASCII mode. Not used in raw mode.
int count = 0;
// Process line by line
int lastRow = sourceRegion.y + sourceRegion.height;
for (int row = sourceRegion.y; row < lastRow; row += scaleY) {
if (abortRequested())
break;
// Grab the pixels
Raster src = null;
if (writeRaster)
src = inputRaster.createChild(sourceRegion.x, row, sourceRegion.width, 1, sourceRegion.x, row, sourceBands);
else
src = input.getData(new Rectangle(sourceRegion.x, row, sourceRegion.width, 1));
src.getPixels(sourceRegion.x, row, sourceRegion.width, 1, pixels);
if (isPBMInverted)
for (int i = 0; i < size; i += scaleX) bpixels[i] ^= 1;
switch(variant) {
case PBM_ASCII:
for (int i = 0; i < size; i += scaleX) {
if ((count++ % 16) == 0)
stream.write(lineSeparator);
else
stream.write(SPACE);
writeInteger(stream, isPBMInverted ? (byte) ~pixels[i] : pixels[i]);
}
stream.write(lineSeparator);
break;
case PGM_ASCII:
for (int i = 0; i < size; i += scaleX) {
if ((count++ % 16) == 0)
stream.write(lineSeparator);
else
stream.write(SPACE);
writeInteger(stream, pixels[i]);
}
stream.write(lineSeparator);
break;
case PPM_ASCII:
if (reds == null) {
for (int i = 0; i < size; i += scaleX * numBands) {
for (int j = 0; j < numBands; j++) {
if ((count++ % 16) == 0)
stream.write(lineSeparator);
else
stream.write(SPACE);
writeInteger(stream, pixels[i + j]);
}
}
} else {
for (int i = 0; i < size; i += scaleX) {
if ((count++ % 5) == 0)
stream.write(lineSeparator);
else
stream.write(SPACE);
writeInteger(stream, (reds[pixels[i]] & 0xFF));
stream.write(SPACE);
writeInteger(stream, (greens[pixels[i]] & 0xFF));
stream.write(SPACE);
writeInteger(stream, (blues[pixels[i]] & 0xFF));
}
}
stream.write(lineSeparator);
break;
case PBM_RAW:
// 8 pixels packed into 1 byte, the leftovers are padded.
int kdst = 0;
int b = 0;
int pos = 7;
for (int i = 0; i < size; i += scaleX) {
b |= pixels[i] << pos;
pos--;
if (pos == -1) {
bpixels[kdst++] = (byte) b;
b = 0;
pos = 7;
}
}
if (pos != 7)
bpixels[kdst++] = (byte) b;
stream.write(bpixels, 0, kdst);
break;
case PGM_RAW:
for (int i = 0, j = 0; i < size; i += scaleX) {
bpixels[j++] = (byte) (pixels[i]);
}
stream.write(bpixels, 0, w);
break;
case PPM_RAW:
if (reds == null) {
// no need to expand
for (int i = 0, k = 0; i < size; i += scaleX * numBands) {
for (int j = 0; j < numBands; j++) bpixels[k++] = (byte) (pixels[i + j] & 0xFF);
}
} else {
for (int i = 0, j = 0; i < size; i += scaleX) {
bpixels[j++] = reds[pixels[i]];
bpixels[j++] = greens[pixels[i]];
bpixels[j++] = blues[pixels[i]];
}
}
stream.write(bpixels, 0, bpixels.length);
break;
}
processImageProgress(100.0F * (row - sourceRegion.y) / sourceRegion.height);
}
// Force all buffered bytes to be written out.
stream.flush();
if (abortRequested())
processWriteAborted();
else
processImageComplete();
}
use of java.awt.image.SampleModel in project imageio-ext by geosolutions-it.
the class PNMMetadata method initialize.
void initialize(ImageTypeSpecifier imageType, ImageWriteParam param) {
ImageTypeSpecifier destType = null;
if (param != null) {
destType = param.getDestinationType();
if (destType == null) {
destType = imageType;
}
} else {
destType = imageType;
}
if (destType != null) {
SampleModel sm = destType.getSampleModel();
int[] sampleSize = sm.getSampleSize();
this.width = sm.getWidth();
this.height = sm.getHeight();
for (int i = 0; i < sampleSize.length; i++) {
if (sampleSize[i] > maxSampleSize) {
maxSampleSize = sampleSize[i];
}
}
this.maxSample = (1 << maxSampleSize) - 1;
// default value
boolean isRaw = true;
if (param instanceof PNMImageWriteParam) {
isRaw = ((PNMImageWriteParam) param).getRaw();
}
if (maxSampleSize == 1)
variant = '1';
else if (sm.getNumBands() == 1) {
variant = '2';
} else if (sm.getNumBands() == 3) {
variant = '3';
}
// Force to Raw if the sample size is small enough.
if (variant <= '3' && isRaw && maxSampleSize <= 8) {
variant += 0x3;
}
}
}
use of java.awt.image.SampleModel in project imageio-ext by geosolutions-it.
the class TIFFDecompressor method decode.
/**
* Decodes the input bit stream (located in the
* <code>ImageInputStream</code> <code>stream</code>, at offset
* <code>offset</code>, and continuing for <code>byteCount</code>
* bytes) into the output <code>BufferedImage</code>
* <code>image</code>.
*
* <p> The default implementation analyzes the destination image
* to determine if it is suitable as the destination for the
* <code>decodeRaw</code> method. If not, a suitable image is
* created. Next, <code>decodeRaw</code> is called to perform the
* actual decoding, and the results are copied into the
* destination image if necessary. Subsampling and offsetting are
* performed automatically.
*
* <p> The precise responsibilities of this routine are as
* follows. The input bit stream is defined by the instance
* variables <code>stream</code>, <code>offset</code>, and
* <code>byteCount</code>. These bits contain the data for the
* region of the source image defined by <code>srcMinX</code>,
* <code>srcMinY</code>, <code>srcWidth</code>, and
* <code>srcHeight</code>.
*
* <p> The source data is required to be subsampling, starting at
* the <code>sourceXOffset</code>th column and including
* every <code>subsampleX</code>th pixel thereafter (and similarly
* for <code>sourceYOffset</code> and
* <code>subsampleY</code>).
*
* <p> Pixels are copied into the destination with an addition shift of
* (<code>dstXOffset</code>, <code>dstYOffset</code>). The complete
* set of formulas relating the source and destination coordinate spaces
* are:
*
* <pre>
* dx = (sx - sourceXOffset)/subsampleX + dstXOffset;
* dy = (sy - sourceYOffset)/subsampleY + dstYOffset;
* </pre>
*
* Only source pixels such that <code>(sx - sourceXOffset) %
* subsampleX == 0</code> and <code>(sy - sourceYOffset) %
* subsampleY == 0</code> are copied.
*
* <p> The inverse mapping, from destination to source coordinates,
* is one-to-one:
*
* <pre>
* sx = (dx - dstXOffset)*subsampleX + sourceXOffset;
* sy = (dy - dstYOffset)*subsampleY + sourceYOffset;
* </pre>
*
* <p> The region of the destination image to be updated is given
* by the instance variables <code>dstMinX</code>,
* <code>dstMinY</code>, <code>dstWidth</code>, and
* <code>dstHeight</code>.
*
* <p> It is possible that not all of the source data being read
* will contribute to the destination image. For example, the
* destination offsets could be set such that some of the source
* pixels land outside of the bounds of the image. As a
* convenience, the bounds of the active source region (that is,
* the region of the strip or tile being read that actually
* contributes to the destination image, taking clipping into
* account) are available as <code>activeSrcMinX</code>,
* <code>activeSrcMinY</code>, <code>activeSrcWidth</code> and
* <code>activeSrcHeight</code>. Thus, the source pixel at
* (<code>activeSrcMinX</code>, <code>activeSrcMinY</code>) will
* map to the destination pixel (<code>dstMinX</code>,
* <code>dstMinY</code>).
*
* <p> The sequence of source bands given by
* <code>sourceBands</code> are to be copied into the sequence of
* bands in the destination given by
* <code>destinationBands</code>.
*
* <p> Some standard tag information is provided the instance
* variables <code>photometricInterpretation</code>,
* <code>compression</code>, <code>samplesPerPixel</code>,
* <code>bitsPerSample</code>, <code>sampleFormat</code>,
* <code>extraSamples</code>, and <code>colorMap</code>.
*
* <p> In practice, unless there is a significant performance
* advantage to be gained by overriding this routine, most users
* will prefer to use the default implementation of this routine,
* and instead override the <code>decodeRaw</code> and/or
* <code>getRawImageType</code> methods.
*
* @exception IOException if an error occurs in
* <code>decodeRaw</code>.
*/
public void decode() throws IOException {
byte[] byteData = null;
short[] shortData = null;
int[] intData = null;
float[] floatData = null;
double[] doubleData = null;
int dstOffset = 0;
int pixelBitStride = 1;
int scanlineStride = 0;
if (useTurbo) {
decodeRaw(byteData, dstOffset, pixelBitStride, scanlineStride);
} else {
// Analyze raw image
this.rawImage = null;
if (isImageSimple) {
if (isBilevel) {
rawImage = this.image;
} else if (isContiguous) {
rawImage = image.getSubimage(dstMinX, dstMinY, dstWidth, dstHeight);
}
}
boolean isDirectCopy = rawImage != null;
if (rawImage == null) {
rawImage = createRawImage();
if (rawImage == null) {
throw new IIOException("Couldn't create image buffer!");
}
}
WritableRaster ras = rawImage.getRaster();
if (isBilevel) {
Rectangle rect = isImageSimple ? new Rectangle(dstMinX, dstMinY, dstWidth, dstHeight) : ras.getBounds();
byteData = ImageUtil.getPackedBinaryData(ras, rect);
dstOffset = 0;
pixelBitStride = 1;
scanlineStride = (rect.width + 7) / 8;
} else {
SampleModel sm = ras.getSampleModel();
DataBuffer db = ras.getDataBuffer();
boolean isSupportedType = false;
if (sm instanceof ComponentSampleModel) {
ComponentSampleModel csm = (ComponentSampleModel) sm;
dstOffset = csm.getOffset(-ras.getSampleModelTranslateX(), -ras.getSampleModelTranslateY());
scanlineStride = csm.getScanlineStride();
if (db instanceof DataBufferByte) {
DataBufferByte dbb = (DataBufferByte) db;
byteData = dbb.getData();
pixelBitStride = csm.getPixelStride() * 8;
isSupportedType = true;
} else if (db instanceof DataBufferUShort) {
DataBufferUShort dbus = (DataBufferUShort) db;
shortData = dbus.getData();
pixelBitStride = csm.getPixelStride() * 16;
isSupportedType = true;
} else if (db instanceof DataBufferShort) {
DataBufferShort dbs = (DataBufferShort) db;
shortData = dbs.getData();
pixelBitStride = csm.getPixelStride() * 16;
isSupportedType = true;
} else if (db instanceof DataBufferInt) {
DataBufferInt dbi = (DataBufferInt) db;
intData = dbi.getData();
pixelBitStride = csm.getPixelStride() * 32;
isSupportedType = true;
} else if (db instanceof DataBufferFloat) {
DataBufferFloat dbf = (DataBufferFloat) db;
floatData = dbf.getData();
pixelBitStride = csm.getPixelStride() * 32;
isSupportedType = true;
} else if (db instanceof DataBufferDouble) {
DataBufferDouble dbf = (DataBufferDouble) db;
doubleData = dbf.getData();
pixelBitStride = csm.getPixelStride() * 64;
isSupportedType = true;
}
} else if (sm instanceof MultiPixelPackedSampleModel) {
MultiPixelPackedSampleModel mppsm = (MultiPixelPackedSampleModel) sm;
dstOffset = mppsm.getOffset(-ras.getSampleModelTranslateX(), -ras.getSampleModelTranslateY());
pixelBitStride = mppsm.getPixelBitStride();
scanlineStride = mppsm.getScanlineStride();
if (db instanceof DataBufferByte) {
DataBufferByte dbb = (DataBufferByte) db;
byteData = dbb.getData();
isSupportedType = true;
} else if (db instanceof DataBufferUShort) {
DataBufferUShort dbus = (DataBufferUShort) db;
shortData = dbus.getData();
isSupportedType = true;
} else if (db instanceof DataBufferInt) {
DataBufferInt dbi = (DataBufferInt) db;
intData = dbi.getData();
isSupportedType = true;
}
} else if (sm instanceof SinglePixelPackedSampleModel) {
SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
dstOffset = sppsm.getOffset(-ras.getSampleModelTranslateX(), -ras.getSampleModelTranslateY());
scanlineStride = sppsm.getScanlineStride();
if (db instanceof DataBufferByte) {
DataBufferByte dbb = (DataBufferByte) db;
byteData = dbb.getData();
pixelBitStride = 8;
isSupportedType = true;
} else if (db instanceof DataBufferUShort) {
DataBufferUShort dbus = (DataBufferUShort) db;
shortData = dbus.getData();
pixelBitStride = 16;
isSupportedType = true;
} else if (db instanceof DataBufferInt) {
DataBufferInt dbi = (DataBufferInt) db;
intData = dbi.getData();
pixelBitStride = 32;
isSupportedType = true;
}
}
if (!isSupportedType) {
throw new IIOException("Unsupported raw image type: SampleModel = " + sm + "; DataBuffer = " + db);
}
}
if (isBilevel) {
// Bilevel data are always in a contiguous byte buffer.
decodeRaw(byteData, dstOffset, pixelBitStride, scanlineStride);
} else {
SampleModel sm = ras.getSampleModel();
// bits except at the end of a row.
if (isDataBufferBitContiguous(sm)) {
// Use byte or float data directly.
if (byteData != null) {
if (DEBUG) {
System.out.println("Decoding bytes directly");
}
if (offset == 0 && byteCount == 0 && noData != null) {
setEmptyTile(byteData, dstOffset, pixelBitStride, scanlineStride, noData.byteValue());
} else {
decodeRaw(byteData, dstOffset, pixelBitStride, scanlineStride);
}
} else if (floatData != null) {
if (DEBUG) {
System.out.println("Decoding floats directly");
}
if (offset == 0 && byteCount == 0 && noData != null) {
setEmptyTile(floatData, dstOffset, pixelBitStride, scanlineStride, noData.floatValue());
} else {
decodeRaw(floatData, dstOffset, pixelBitStride, scanlineStride);
}
} else if (doubleData != null) {
if (DEBUG) {
System.out.println("Decoding doubles directly");
}
if (offset == 0 && byteCount == 0 && noData != null) {
setEmptyTile(doubleData, dstOffset, pixelBitStride, scanlineStride, noData.doubleValue());
} else {
decodeRaw(doubleData, dstOffset, pixelBitStride, scanlineStride);
}
} else {
if (shortData != null) {
if (offset == 0 && byteCount == 0 && noData != null) {
setEmptyTile(shortData, dstOffset, pixelBitStride, scanlineStride, noData.shortValue());
} else if (areSampleSizesEqual(sm) && sm.getSampleSize(0) == 16) {
if (DEBUG) {
System.out.println("Decoding shorts directly");
}
// Decode directly into short data.
decodeRaw(shortData, dstOffset, pixelBitStride, scanlineStride);
} else {
if (DEBUG) {
System.out.println("Decoding bytes->shorts");
}
// Decode into bytes and reformat into shorts.
int bpp = getBitsPerPixel(sm);
int bytesPerRow = (bpp * srcWidth + 7) / 8;
byte[] buf = new byte[bytesPerRow * srcHeight];
decodeRaw(buf, 0, bpp, bytesPerRow);
reformatData(buf, bytesPerRow, srcHeight, shortData, null, dstOffset, scanlineStride);
}
} else if (intData != null) {
if (offset == 0 && byteCount == 0 && noData != null) {
setEmptyTile(intData, dstOffset, pixelBitStride, scanlineStride, noData.intValue());
} else if (areSampleSizesEqual(sm) && sm.getSampleSize(0) == 32) {
if (DEBUG) {
System.out.println("Decoding ints directly");
}
// Decode directly into int data.
decodeRaw(intData, dstOffset, pixelBitStride, scanlineStride);
} else {
if (DEBUG) {
System.out.println("Decoding bytes->ints");
}
// Decode into bytes and reformat into ints.
int bpp = getBitsPerPixel(sm);
int bytesPerRow = (bpp * srcWidth + 7) / 8;
byte[] buf = new byte[bytesPerRow * srcHeight];
decodeRaw(buf, 0, bpp, bytesPerRow);
reformatData(buf, bytesPerRow, srcHeight, null, intData, dstOffset, scanlineStride);
}
}
}
} else {
if (DEBUG) {
System.out.println("Decoding discontiguous data");
}
// Read discontiguous data into bytes and set the samples
// into the Raster.
int bpp = getBitsPerPixel(sm);
int bytesPerRow = (bpp * srcWidth + 7) / 8;
byte[] buf = new byte[bytesPerRow * srcHeight];
decodeRaw(buf, 0, bpp, bytesPerRow);
reformatDiscontiguousData(buf, bytesPerRow, srcWidth, srcHeight, ras);
}
}
if (colorConverter != null) {
float[] rgb = new float[3];
if (byteData != null) {
for (int j = 0; j < dstHeight; j++) {
int idx = dstOffset;
for (int i = 0; i < dstWidth; i++) {
float x0 = (float) (byteData[idx] & 0xff);
float x1 = (float) (byteData[idx + 1] & 0xff);
float x2 = (float) (byteData[idx + 2] & 0xff);
colorConverter.toRGB(x0, x1, x2, rgb);
byteData[idx] = (byte) (rgb[0]);
byteData[idx + 1] = (byte) (rgb[1]);
byteData[idx + 2] = (byte) (rgb[2]);
idx += 3;
}
dstOffset += scanlineStride;
}
} else if (shortData != null) {
if (sampleFormat[0] == BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER) {
for (int j = 0; j < dstHeight; j++) {
int idx = dstOffset;
for (int i = 0; i < dstWidth; i++) {
float x0 = (float) shortData[idx];
float x1 = (float) shortData[idx + 1];
float x2 = (float) shortData[idx + 2];
colorConverter.toRGB(x0, x1, x2, rgb);
shortData[idx] = (short) (rgb[0]);
shortData[idx + 1] = (short) (rgb[1]);
shortData[idx + 2] = (short) (rgb[2]);
idx += 3;
}
dstOffset += scanlineStride;
}
} else {
for (int j = 0; j < dstHeight; j++) {
int idx = dstOffset;
for (int i = 0; i < dstWidth; i++) {
float x0 = (float) (shortData[idx] & 0xffff);
float x1 = (float) (shortData[idx + 1] & 0xffff);
float x2 = (float) (shortData[idx + 2] & 0xffff);
colorConverter.toRGB(x0, x1, x2, rgb);
shortData[idx] = (short) (rgb[0]);
shortData[idx + 1] = (short) (rgb[1]);
shortData[idx + 2] = (short) (rgb[2]);
idx += 3;
}
dstOffset += scanlineStride;
}
}
} else if (intData != null) {
for (int j = 0; j < dstHeight; j++) {
int idx = dstOffset;
for (int i = 0; i < dstWidth; i++) {
float x0 = (float) intData[idx];
float x1 = (float) intData[idx + 1];
float x2 = (float) intData[idx + 2];
colorConverter.toRGB(x0, x1, x2, rgb);
intData[idx] = (int) (rgb[0]);
intData[idx + 1] = (int) (rgb[1]);
intData[idx + 2] = (int) (rgb[2]);
idx += 3;
}
dstOffset += scanlineStride;
}
} else if (floatData != null) {
for (int j = 0; j < dstHeight; j++) {
int idx = dstOffset;
for (int i = 0; i < dstWidth; i++) {
float x0 = floatData[idx];
float x1 = floatData[idx + 1];
float x2 = floatData[idx + 2];
colorConverter.toRGB(x0, x1, x2, rgb);
floatData[idx] = rgb[0];
floatData[idx + 1] = rgb[1];
floatData[idx + 2] = rgb[2];
idx += 3;
}
dstOffset += scanlineStride;
}
}
// int[] p = new int[3];
// ras.getPixel(0, 0, p);
// System.out.println("p00 = " +
// p[0] + " " + p[1] + " " + p[2]);
// ras.getPixel(1, 0, p);
// System.out.println("p10 = " +
// p[0] + " " + p[1] + " " + p[2]);
// ras.getPixel(2, 0, p);
// System.out.println("p20 = " +
// p[0] + " " + p[1] + " " + p[2]);
// ras.getPixel(3, 0, p);
// System.out.println("p30 = " +
// p[0] + " " + p[1] + " " + p[2]);
// ColorSpace rgb = ColorSpace.getInstance(ColorSpace.CS_sRGB);
// ColorConvertOp op = new ColorConvertOp(colorSpace, rgb, null);
// WritableRaster dest = op.createCompatibleDestRaster(ras);
// op.filter(ras, dest);
// ras = dest;
}
if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO) {
if (byteData != null) {
int bytesPerRow = (srcWidth * pixelBitStride + 7) / 8;
for (int y = 0; y < srcHeight; y++) {
int offset = dstOffset + y * scanlineStride;
for (int i = 0; i < bytesPerRow; i++) {
byteData[offset + i] ^= 0xff;
}
}
} else if (shortData != null) {
int shortsPerRow = (srcWidth * pixelBitStride + 15) / 16;
if (sampleFormat[0] == BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER) {
for (int y = 0; y < srcHeight; y++) {
int offset = dstOffset + y * scanlineStride;
for (int i = 0; i < shortsPerRow; i++) {
int shortOffset = offset + i;
// XXX Does this make any sense?
shortData[shortOffset] = (short) (Short.MAX_VALUE - shortData[shortOffset]);
}
}
} else {
for (int y = 0; y < srcHeight; y++) {
int offset = dstOffset + y * scanlineStride;
for (int i = 0; i < shortsPerRow; i++) {
shortData[offset + i] ^= 0xffff;
}
}
}
} else if (intData != null) {
int intsPerRow = (srcWidth * pixelBitStride + 15) / 16;
for (int y = 0; y < srcHeight; y++) {
int offset = dstOffset + y * scanlineStride;
for (int i = 0; i < intsPerRow; i++) {
int intOffset = offset + i;
// XXX Does this make any sense?
intData[intOffset] = Integer.MAX_VALUE - intData[intOffset];
}
}
} else if (floatData != null) {
int floatsPerRow = (srcWidth * pixelBitStride + 15) / 16;
for (int y = 0; y < srcHeight; y++) {
int offset = dstOffset + y * scanlineStride;
for (int i = 0; i < floatsPerRow; i++) {
int floatOffset = offset + i;
// XXX Does this make any sense?
floatData[floatOffset] = 1.0F - floatData[floatOffset];
}
}
}
}
if (isBilevel) {
Rectangle rect = isImageSimple ? new Rectangle(dstMinX, dstMinY, dstWidth, dstHeight) : ras.getBounds();
ImageUtil.setPackedBinaryData(byteData, ras, rect);
}
// equals the raster of 'image' or is a child thereof.
if (isDirectCopy) {
// rawImage == image) {
return;
}
}
// Copy the raw image data into the true destination image
Raster src = rawImage.getRaster();
// Create band child of source
Raster srcChild = src.createChild(0, 0, srcWidth, srcHeight, srcMinX, srcMinY, planar ? null : sourceBands);
WritableRaster dst = image.getRaster();
// Create dst child covering area and bands to be written
WritableRaster dstChild = dst.createWritableChild(dstMinX, dstMinY, dstWidth, dstHeight, dstMinX, dstMinY, destinationBands);
if (subsampleX == 1 && subsampleY == 1 && !adjustBitDepths) {
srcChild = srcChild.createChild(activeSrcMinX, activeSrcMinY, activeSrcWidth, activeSrcHeight, dstMinX, dstMinY, null);
dstChild.setRect(srcChild);
} else if (subsampleX == 1 && !adjustBitDepths) {
int sy = activeSrcMinY;
int dy = dstMinY;
while (sy < srcMinY + srcHeight) {
Raster srcRow = srcChild.createChild(activeSrcMinX, sy, activeSrcWidth, 1, dstMinX, dy, null);
dstChild.setRect(srcRow);
sy += subsampleY;
++dy;
}
} else {
// /init vars
int numBands = srcChild.getNumBands();
int sy = activeSrcMinY;
int dy = dstMinY;
// get the databuffer type
final int type = srcChild.getDataBuffer().getDataType();
switch(type) {
case DataBuffer.TYPE_BYTE:
case DataBuffer.TYPE_INT:
case DataBuffer.TYPE_SHORT:
case DataBuffer.TYPE_USHORT:
int[] p = srcChild.getPixel(srcMinX, srcMinY, (int[]) null);
while (sy < activeSrcMinY + activeSrcHeight) {
int sx = activeSrcMinX;
int dx = dstMinX;
while (sx < activeSrcMinX + activeSrcWidth) {
srcChild.getPixel(sx, sy, p);
if (adjustBitDepths) {
for (int band = 0; band < numBands; band++) {
p[band] = bitDepthScale[band][p[band]];
}
}
dstChild.setPixel(dx, dy, p);
sx += subsampleX;
++dx;
}
sy += subsampleY;
++dy;
}
break;
case DataBuffer.TYPE_DOUBLE:
double[] d = srcChild.getPixel(srcMinX, srcMinY, (double[]) null);
while (sy < activeSrcMinY + activeSrcHeight) {
int sx = activeSrcMinX;
int dx = dstMinX;
while (sx < activeSrcMinX + activeSrcWidth) {
srcChild.getPixel(sx, sy, d);
// if (adjustBitDepths) {
// for (int band = 0; band < numBands; band++) {
// d[band] = bitDepthScale[band][d[band]];
// }
// }
dstChild.setPixel(dx, dy, d);
sx += subsampleX;
++dx;
}
sy += subsampleY;
++dy;
}
break;
case DataBuffer.TYPE_FLOAT:
float[] f = srcChild.getPixel(srcMinX, srcMinY, (float[]) null);
while (sy < activeSrcMinY + activeSrcHeight) {
int sx = activeSrcMinX;
int dx = dstMinX;
while (sx < activeSrcMinX + activeSrcWidth) {
srcChild.getPixel(sx, sy, f);
// if (adjustBitDepths) {
// for (int band = 0; band < numBands; band++) {
// d[band] = bitDepthScale[band][d[band]];
// }
// }
dstChild.setPixel(dx, dy, f);
sx += subsampleX;
++dx;
}
sy += subsampleY;
++dy;
}
break;
default:
break;
}
}
}
Aggregations