use of javax.imageio.IIOException in project imageio-ext by geosolutions-it.
the class TIFFFaxDecompressor method decodeBlackCodeWord.
// Returns run length
private int decodeBlackCodeWord() throws IIOException {
int current, entry, bits, isT, twoBits, code = -1;
int runLength = 0;
boolean isWhite = false;
while (!isWhite) {
current = nextLesserThan8Bits(4);
entry = initBlack[current];
// Get the 3 fields from the entry
isT = entry & 0x0001;
bits = (entry >>> 1) & 0x000f;
code = (entry >>> 5) & 0x07ff;
if (code == 100) {
current = nextNBits(9);
entry = black[current];
// Get the 3 fields from the entry
isT = entry & 0x0001;
bits = (entry >>> 1) & 0x000f;
code = (entry >>> 5) & 0x07ff;
if (bits == 12) {
// Additional makeup codes
updatePointer(5);
current = nextLesserThan8Bits(4);
entry = additionalMakeup[current];
// 3 bits 0000 0111
bits = (entry >>> 1) & 0x07;
// 12 bits
code = (entry >>> 4) & 0x0fff;
runLength += code;
updatePointer(4 - bits);
} else if (bits == 15) {
// EOL code
throw new IIOException("Error 2");
} else {
runLength += code;
updatePointer(9 - bits);
if (isT == 0) {
isWhite = true;
}
}
} else if (code == 200) {
// Is a Terminating code
current = nextLesserThan8Bits(2);
entry = twoBitBlack[current];
code = (entry >>> 5) & 0x07ff;
runLength += code;
bits = (entry >>> 1) & 0x0f;
updatePointer(2 - bits);
isWhite = true;
} else {
// Is a Terminating code
runLength += code;
updatePointer(4 - bits);
isWhite = true;
}
}
return runLength;
}
use of javax.imageio.IIOException 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 javax.imageio.IIOException 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;
}
use of javax.imageio.IIOException 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;
}
use of javax.imageio.IIOException 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();
}
Aggregations