use of it.geosolutions.imageio.plugins.tiff.TIFFField in project imageio-ext by geosolutions-it.
the class EmptyImage method replacePixels.
public void replacePixels(RenderedImage image, ImageWriteParam param) throws IOException {
synchronized (replacePixelsLock) {
// Check state and parameters vis-a-vis ImageWriter specification.
if (stream == null) {
throw new IllegalStateException("stream == null!");
}
if (image == null) {
throw new IllegalArgumentException("image == null!");
}
if (!inReplacePixelsNest) {
throw new IllegalStateException("No previous call to prepareReplacePixels!");
}
// Subsampling values.
int stepX = 1, stepY = 1, gridX = 0, gridY = 0;
// Initialize the ImageWriteParam.
if (param == null) {
// Use the default.
param = getDefaultWriteParam();
} else {
// Make a copy of the ImageWriteParam.
ImageWriteParam paramCopy = getDefaultWriteParam();
// Force uncompressed.
paramCopy.setCompressionMode(ImageWriteParam.MODE_DISABLED);
// Force tiling to remain as in the already written image.
paramCopy.setTilingMode(ImageWriteParam.MODE_COPY_FROM_METADATA);
// Retain source and destination region and band settings.
paramCopy.setDestinationOffset(param.getDestinationOffset());
paramCopy.setSourceBands(param.getSourceBands());
paramCopy.setSourceRegion(param.getSourceRegion());
// Save original subsampling values for subsampling the
// replacement data - not the data re-read from the image.
stepX = param.getSourceXSubsampling();
stepY = param.getSourceYSubsampling();
gridX = param.getSubsamplingXOffset();
gridY = param.getSubsamplingYOffset();
// Replace the param.
param = paramCopy;
}
// Check band count and bit depth compatibility.
TIFFField f = replacePixelsMetadata.getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
if (f == null) {
throw new IIOException("Cannot read destination BitsPerSample");
}
int[] dstBitsPerSample = f.getAsInts();
int[] srcBitsPerSample = image.getSampleModel().getSampleSize();
int[] sourceBands = param.getSourceBands();
if (sourceBands != null) {
if (sourceBands.length != dstBitsPerSample.length) {
throw new IIOException("Source and destination have different SamplesPerPixel");
}
for (int i = 0; i < sourceBands.length; i++) {
if (dstBitsPerSample[i] != srcBitsPerSample[sourceBands[i]]) {
throw new IIOException("Source and destination have different BitsPerSample");
}
}
} else {
int srcNumBands = image.getSampleModel().getNumBands();
if (srcNumBands != dstBitsPerSample.length) {
throw new IIOException("Source and destination have different SamplesPerPixel");
}
for (int i = 0; i < srcNumBands; i++) {
if (dstBitsPerSample[i] != srcBitsPerSample[i]) {
throw new IIOException("Source and destination have different BitsPerSample");
}
}
}
// Get the source image bounds.
Rectangle srcImageBounds = new Rectangle(image.getMinX(), image.getMinY(), image.getWidth(), image.getHeight());
// Initialize the source rect.
Rectangle srcRect = param.getSourceRegion();
if (srcRect == null) {
srcRect = srcImageBounds;
}
// Set subsampling grid parameters.
int subPeriodX = stepX;
int subPeriodY = stepY;
int subOriginX = gridX + srcRect.x;
int subOriginY = gridY + srcRect.y;
// Intersect with the source bounds.
if (!srcRect.equals(srcImageBounds)) {
srcRect = srcRect.intersection(srcImageBounds);
if (srcRect.isEmpty()) {
throw new IllegalArgumentException("Source region does not intersect source image!");
}
}
// Get the destination offset.
Point dstOffset = param.getDestinationOffset();
// Forward map source rectangle to determine destination width.
int dMinX = XToTileX(srcRect.x, subOriginX, subPeriodX) + dstOffset.x;
int dMinY = YToTileY(srcRect.y, subOriginY, subPeriodY) + dstOffset.y;
int dMaxX = XToTileX(srcRect.x + srcRect.width, subOriginX, subPeriodX) + dstOffset.x;
int dMaxY = YToTileY(srcRect.y + srcRect.height, subOriginY, subPeriodY) + dstOffset.y;
// Initialize the destination rectangle.
Rectangle dstRect = new Rectangle(dstOffset.x, dstOffset.y, dMaxX - dMinX, dMaxY - dMinY);
// Intersect with the replacement region.
dstRect = dstRect.intersection(replacePixelsRegion);
if (dstRect.isEmpty()) {
throw new IllegalArgumentException("Forward mapped source region does not intersect destination region!");
}
// Backward map to the active source region.
int activeSrcMinX = (dstRect.x - dstOffset.x) * subPeriodX + subOriginX;
int sxmax = (dstRect.x + dstRect.width - 1 - dstOffset.x) * subPeriodX + subOriginX;
int activeSrcWidth = sxmax - activeSrcMinX + 1;
int activeSrcMinY = (dstRect.y - dstOffset.y) * subPeriodY + subOriginY;
int symax = (dstRect.y + dstRect.height - 1 - dstOffset.y) * subPeriodY + subOriginY;
int activeSrcHeight = symax - activeSrcMinY + 1;
Rectangle activeSrcRect = new Rectangle(activeSrcMinX, activeSrcMinY, activeSrcWidth, activeSrcHeight);
if (activeSrcRect.intersection(srcImageBounds).isEmpty()) {
throw new IllegalArgumentException("Backward mapped destination region does not intersect source image!");
}
if (reader == null) {
reader = new TIFFImageReader(new TIFFImageReaderSpi());
} else {
reader.reset();
}
stream.mark();
try {
stream.seek(headerPosition);
reader.setInput(stream);
this.imageMetadata = replacePixelsMetadata;
this.param = param;
SampleModel sm = image.getSampleModel();
ColorModel cm = image.getColorModel();
this.numBands = sm.getNumBands();
this.imageType = new ImageTypeSpecifier(image);
this.periodX = param.getSourceXSubsampling();
this.periodY = param.getSourceYSubsampling();
this.sourceBands = null;
int[] sBands = param.getSourceBands();
if (sBands != null) {
this.sourceBands = sBands;
this.numBands = sourceBands.length;
}
setupMetadata(cm, sm, reader.getWidth(replacePixelsIndex), reader.getHeight(replacePixelsIndex));
int[] scaleSampleSize = sm.getSampleSize();
initializeScaleTables(scaleSampleSize);
// Determine whether bilevel.
this.isBilevel = ImageUtil.isBinary(image.getSampleModel());
// Check for photometric inversion.
this.isInverted = (nativePhotometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO && photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO) || (nativePhotometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO && photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO);
// Analyze image data suitability for direct copy.
this.isImageSimple = (isBilevel || (!isInverted && ImageUtil.imageIsContiguous(image))) && // no value rescaling
!isRescaling && // no subbanding
sourceBands == null && periodX == 1 && // no subsampling
periodY == 1 && colorConverter == null;
int minTileX = XToTileX(dstRect.x, 0, tileWidth);
int minTileY = YToTileY(dstRect.y, 0, tileLength);
int maxTileX = XToTileX(dstRect.x + dstRect.width - 1, 0, tileWidth);
int maxTileY = YToTileY(dstRect.y + dstRect.height - 1, 0, tileLength);
TIFFCompressor encoder = new TIFFNullCompressor();
encoder.setWriter(this);
encoder.setStream(stream);
encoder.setMetadata(this.imageMetadata);
Rectangle tileRect = new Rectangle();
for (int ty = minTileY; ty <= maxTileY; ty++) {
for (int tx = minTileX; tx <= maxTileX; tx++) {
int tileIndex = ty * tilesAcross + tx;
boolean isEmpty = replacePixelsByteCounts[tileIndex] == 0L;
WritableRaster raster;
if (isEmpty) {
SampleModel tileSM = sm.createCompatibleSampleModel(tileWidth, tileLength);
raster = Raster.createWritableRaster(tileSM, null);
} else {
BufferedImage tileImage = reader.readTile(replacePixelsIndex, tx, ty);
raster = tileImage.getRaster();
}
tileRect.setLocation(tx * tileWidth, ty * tileLength);
tileRect.setSize(raster.getWidth(), raster.getHeight());
raster = raster.createWritableTranslatedChild(tileRect.x, tileRect.y);
Rectangle replacementRect = tileRect.intersection(dstRect);
int srcMinX = (replacementRect.x - dstOffset.x) * subPeriodX + subOriginX;
int srcXmax = (replacementRect.x + replacementRect.width - 1 - dstOffset.x) * subPeriodX + subOriginX;
int srcWidth = srcXmax - srcMinX + 1;
int srcMinY = (replacementRect.y - dstOffset.y) * subPeriodY + subOriginY;
int srcYMax = (replacementRect.y + replacementRect.height - 1 - dstOffset.y) * subPeriodY + subOriginY;
int srcHeight = srcYMax - srcMinY + 1;
Rectangle srcTileRect = new Rectangle(srcMinX, srcMinY, srcWidth, srcHeight);
Raster replacementData = image.getData(srcTileRect);
if (subPeriodX == 1 && subPeriodY == 1 && subOriginX == 0 && subOriginY == 0) {
replacementData = replacementData.createChild(srcTileRect.x, srcTileRect.y, srcTileRect.width, srcTileRect.height, replacementRect.x, replacementRect.y, sourceBands);
} else {
replacementData = subsample(replacementData, sourceBands, subOriginX, subOriginY, subPeriodX, subPeriodY, dstOffset.x, dstOffset.y, replacementRect);
if (replacementData == null) {
continue;
}
}
raster.setRect(replacementData);
if (isEmpty) {
stream.seek(nextSpace);
} else {
stream.seek(replacePixelsTileOffsets[tileIndex]);
}
this.image = new SingleTileRenderedImage(raster, cm);
int numBytes = writeTile(tileRect, encoder);
if (isEmpty) {
// Update Strip/TileOffsets and
// Strip/TileByteCounts fields.
stream.mark();
stream.seek(replacePixelsOffsetsPosition + 4 * tileIndex);
stream.writeInt((int) nextSpace);
stream.seek(replacePixelsByteCountsPosition + 4 * tileIndex);
stream.writeInt(numBytes);
stream.reset();
// Increment location of next available space.
nextSpace += numBytes;
}
}
}
} catch (IOException e) {
throw e;
} finally {
stream.reset();
}
}
}
use of it.geosolutions.imageio.plugins.tiff.TIFFField in project imageio-ext by geosolutions-it.
the class TIFFT6Compressor method encode.
public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, int scanlineStride) throws IOException {
if (bitsPerSample.length != 1 || bitsPerSample[0] != 1) {
throw new IIOException("Bits per sample must be 1 for T6 compression!");
}
if (metadata instanceof TIFFImageMetadata) {
TIFFImageMetadata tim = (TIFFImageMetadata) metadata;
long[] options = new long[1];
options[0] = 0;
BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
TIFFField T6Options = new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_T6_OPTIONS), TIFFTag.TIFF_LONG, 1, options);
tim.rootIFD.addTIFFField(T6Options);
}
// See comment in TIFFT4Compressor
int maxBits = 9 * ((width + 1) / 2) + 2;
int bufSize = (maxBits + 7) / 8;
bufSize = height * (bufSize + 2) + 12;
byte[] compData = new byte[bufSize];
int bytes = encodeT6(b, scanlineStride, 8 * off, width, height, compData);
stream.write(compData, 0, bytes);
return bytes;
}
use of it.geosolutions.imageio.plugins.tiff.TIFFField in project imageio-ext by geosolutions-it.
the class TIFFYCbCrDecompressor method beginDecoding.
public void beginDecoding() {
if (decompressor != null) {
decompressor.beginDecoding();
}
TIFFImageMetadata tmetadata = (TIFFImageMetadata) metadata;
TIFFField f;
f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_SUBSAMPLING);
if (f != null) {
if (f.getCount() == 2) {
this.chromaSubsampleH = f.getAsInt(0);
this.chromaSubsampleV = f.getAsInt(1);
if (chromaSubsampleH != 1 && chromaSubsampleH != 2 && chromaSubsampleH != 4) {
warning("Y_CB_CR_SUBSAMPLING[0] has illegal value " + chromaSubsampleH + " (should be 1, 2, or 4), setting to 1");
chromaSubsampleH = 1;
}
if (chromaSubsampleV != 1 && chromaSubsampleV != 2 && chromaSubsampleV != 4) {
warning("Y_CB_CR_SUBSAMPLING[1] has illegal value " + chromaSubsampleV + " (should be 1, 2, or 4), setting to 1");
chromaSubsampleV = 1;
}
} else {
warning("Y_CB_CR_SUBSAMPLING count != 2, " + "assuming no subsampling");
}
}
f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_COEFFICIENTS);
if (f != null) {
if (f.getCount() == 3) {
this.LumaRed = f.getAsFloat(0);
this.LumaGreen = f.getAsFloat(1);
this.LumaBlue = f.getAsFloat(2);
} else {
warning("Y_CB_CR_COEFFICIENTS count != 3, " + "assuming default values for CCIR 601-1");
}
}
f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_REFERENCE_BLACK_WHITE);
if (f != null) {
if (f.getCount() == 6) {
this.referenceBlackY = f.getAsFloat(0);
this.referenceWhiteY = f.getAsFloat(1);
this.referenceBlackCb = f.getAsFloat(2);
this.referenceWhiteCb = f.getAsFloat(3);
this.referenceBlackCr = f.getAsFloat(4);
this.referenceWhiteCr = f.getAsFloat(5);
} else {
warning("REFERENCE_BLACK_WHITE count != 6, ignoring it");
}
} else {
warning("REFERENCE_BLACK_WHITE not found, assuming 0-255/128-255/128-255");
}
this.colorConvert = true;
float BCb = (2.0f - 2.0f * LumaBlue);
float RCr = (2.0f - 2.0f * LumaRed);
float GY = (1.0f - LumaBlue - LumaRed) / LumaGreen;
float GCb = 2.0f * LumaBlue * (LumaBlue - 1.0f) / LumaGreen;
float GCr = 2.0f * LumaRed * (LumaRed - 1.0f) / LumaGreen;
for (int i = 0; i < 256; i++) {
float fY = (i - referenceBlackY) * codingRangeY / (referenceWhiteY - referenceBlackY);
float fCb = (i - referenceBlackCb) * 127.0f / (referenceWhiteCb - referenceBlackCb);
float fCr = (i - referenceBlackCr) * 127.0f / (referenceWhiteCr - referenceBlackCr);
iYTab[i] = (int) (fY * FRAC_SCALE);
iCbTab[i] = (int) (fCb * BCb * FRAC_SCALE);
iCrTab[i] = (int) (fCr * RCr * FRAC_SCALE);
iGYTab[i] = (int) (fY * GY * FRAC_SCALE);
iGCbTab[i] = (int) (fCb * GCb * FRAC_SCALE);
iGCrTab[i] = (int) (fCr * GCr * FRAC_SCALE);
}
}
use of it.geosolutions.imageio.plugins.tiff.TIFFField in project imageio-ext by geosolutions-it.
the class TIFFJPEGDecompressor method beginDecoding.
/* XXX
private static class JPEGSPIFilter implements ServiceRegistry.Filter {
JPEGSPIFilter() {}
public boolean filter(Object provider) {
ImageReaderSpi readerSPI = (ImageReaderSpi)provider;
if(readerSPI.getPluginClassName().startsWith("com.sun.imageio")) {
String streamMetadataName =
readerSPI.getNativeStreamMetadataFormatName();
if(streamMetadataName != null) {
return streamMetadataName.indexOf("jpeg_stream") != -1;
} else {
return false;
}
}
return false;
}
}
*/
public void beginDecoding() {
// Initialize the JPEG reader if needed.
if (this.JPEGReader == null) {
if (DEBUG)
System.out.println("Initializing JPEGReader");
/* XXX
if(this.jpegReaderSPI != null) {
try {
this.JPEGReader = jpegReaderSPI.createReaderInstance();
} catch(Exception e) {
}
}
if(this.JPEGReader == null) {
*/
// Get all JPEG readers.
Iterator iter = ImageIO.getImageReadersByFormatName("jpeg");
if (!iter.hasNext()) {
// XXX The exception thrown should be an IIOException.
throw new IllegalStateException("No JPEG readers found!");
}
// Initialize reader to the first one.
this.JPEGReader = (ImageReader) iter.next();
String className = JPEGReader.getClass().getName();
if (DEBUG)
System.out.println("Using " + className);
if (className.equalsIgnoreCase(TURBO_JPEG_DECOMPRESSOR)) {
useTurbo = true;
}
this.JPEGParam = JPEGReader.getDefaultReadParam();
}
// Get the JPEGTables field.
TIFFImageMetadata tmetadata = (TIFFImageMetadata) metadata;
TIFFField f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_TABLES);
if (f != null) {
this.hasJPEGTables = true;
this.tables = f.getAsBytes();
} else {
this.hasJPEGTables = false;
}
}
use of it.geosolutions.imageio.plugins.tiff.TIFFField in project imageio-ext by geosolutions-it.
the class TIFFOldJPEGDecompressor method initialize.
//
// Intialize instance variables according to an analysis of the
// TIFF field content. See bug 4929147 for test image information.
//
// Case 1: Image contains a single strip or tile and the offset to
// that strip or tile points to an SOI marker.
//
// Example:
// "Visionshape Inc. Compression Software, version 2.5"
// ColorTiffWithBarcode.tif
// Color2.tif (pages 2-5 (indexes 1-4)
// color3.tif (pages 2-5 (indexes 1-4)
//
// "Kofax standard Multi-Page TIFF Storage Filter v2.01.000"
// 01.tif (pages 1 and 3(indexes 0 and 2))
//
// Instance variables set: JPEGStreamOffset
//
// Case 2: Image contains a single strip or tile and a
// JPEGInterchangeFormat field is present but the
// JPEGInterchangeFormatLength is erroneously missing.
//
// Example:
// "Kofax standard Multi-Page TIFF Storage Filter v2.01.000"
// 01.tif (pages 1 and 3(indexes 0 and 2))
// (but this example also satisfies case 1)
//
// Instance variables set: JPEGStreamOffset
//
// Case 3: Image contains a single strip or tile, the
// JPEGInterchangeFormat and JPEGInterchangeFormatLength
// fields are both present, the value of JPEGInterchangeFormat
// is less than the offset to the strip or tile, and the sum
// of the values of JPEGInterchangeFormat and
// JPEGInterchangeFormatLength is greater than the offset to
// the strip or tile.
//
// Instance variables set: JPEGStreamOffset
//
// Example:
// "HP IL v1.1"
// smallliz.tif from libtiff test data.
//
// Instance variables set: JPEGStreamOffset
//
// Cases 4-5 apply if none of cases 1-3 applies or the image has multiple
// strips or tiles.
//
// Case 4: JPEGInterchangeFormat and JPEGInterchangeFormatLength are
// present, the value of JPEGInterchangeFormatLength is at least 2,
// and the sum of the values of these two fields is at most the
// value of the offset to the first strip or tile.
//
// Instance variables set: tables, SOFPosition, SOSMarker
//
// Example:
// "Oi/GFS, writer v00.06.00P, (c) Wang Labs, Inc. 1990, 1991"
// 03.tif (pages 1 and 3(indexes 0 and 2))
//
// "Oi/GFS, writer v00.06.02"
// Color2.tif (page 1 (index 0))
// color3.tif (page 1 (index 0))
//
// Case 5: If none of the foregoing cases apply. For this case the
// JPEGQTables, JPEGACTables, and JPEGDCTables must be valid.
//
// Instance variables set: tables, SOFPosition, SOSMarker
//
// Example:
// "NeXT"
// zackthecat.tif from libtiff test data.
//
private synchronized void initialize() throws IOException {
if (isInitialized) {
return;
}
// Get the TIFF metadata object.
TIFFImageMetadata tim = (TIFFImageMetadata) metadata;
// Get the JPEGInterchangeFormat field.
TIFFField JPEGInterchangeFormatField = tim.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT);
// Get the tile or strip offsets.
TIFFField segmentOffsetField = tim.getTIFFField(BaselineTIFFTagSet.TAG_TILE_OFFSETS);
if (segmentOffsetField == null) {
segmentOffsetField = tim.getTIFFField(BaselineTIFFTagSet.TAG_STRIP_OFFSETS);
if (segmentOffsetField == null) {
segmentOffsetField = JPEGInterchangeFormatField;
}
}
long[] segmentOffsets = segmentOffsetField.getAsLongs();
// Determine whether the image has more than one strip or tile.
boolean isTiled = segmentOffsets.length > 1;
if (!isTiled) {
//
// If the image has only a single strip or tile and it looks
// as if a complete JPEG stream is present then set the value
// of JPEGStreamOffset to the offset of the JPEG stream;
// otherwise leave JPEGStreamOffset set to null.
//
stream.seek(offset);
stream.mark();
if (stream.read() == 0xff && stream.read() == SOI) {
// Tile or strip offset points to SOI.
JPEGStreamOffset = new Long(offset);
// Set initialization flag and return.
if (DEBUG)
System.out.println("OLD JPEG CASE 1");
((TIFFImageReader) reader).forwardWarningMessage("SOI marker detected at start of strip or tile.");
isInitialized = true;
stream.reset();
return;
}
stream.reset();
if (JPEGInterchangeFormatField != null) {
// Get the value of JPEGInterchangeFormat.
long jpegInterchangeOffset = JPEGInterchangeFormatField.getAsLong(0);
// Check that the value of JPEGInterchangeFormat points to SOI.
stream.mark();
stream.seek(jpegInterchangeOffset);
if (stream.read() == 0xff && stream.read() == SOI)
// JPEGInterchangeFormat offset points to SOI.
JPEGStreamOffset = new Long(jpegInterchangeOffset);
else
((TIFFImageReader) reader).forwardWarningMessage("JPEGInterchangeFormat does not point to SOI");
stream.reset();
// Get the JPEGInterchangeFormatLength field.
TIFFField JPEGInterchangeFormatLengthField = tim.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
if (JPEGInterchangeFormatLengthField == null) {
if (DEBUG)
System.out.println("OLD JPEG CASE 2");
((TIFFImageReader) reader).forwardWarningMessage("JPEGInterchangeFormatLength field is missing");
} else {
// Get the JPEGInterchangeFormatLength field's value.
long jpegInterchangeLength = JPEGInterchangeFormatLengthField.getAsLong(0);
if (jpegInterchangeOffset < segmentOffsets[0] && (jpegInterchangeOffset + jpegInterchangeLength) > segmentOffsets[0]) {
if (DEBUG)
System.out.println("OLD JPEG CASE 3");
} else {
if (DEBUG)
System.out.println("OLD JPEG CASE 3A");
((TIFFImageReader) reader).forwardWarningMessage("JPEGInterchangeFormatLength field value is invalid");
}
}
// Return if JPEGInterchangeFormat pointed to SOI.
if (JPEGStreamOffset != null) {
isInitialized = true;
return;
}
}
}
// Get the subsampling factors.
TIFFField YCbCrSubsamplingField = tim.getTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_SUBSAMPLING);
if (YCbCrSubsamplingField != null) {
subsamplingX = YCbCrSubsamplingField.getAsChars()[0];
subsamplingY = YCbCrSubsamplingField.getAsChars()[1];
}
//
if (JPEGInterchangeFormatField != null) {
// Get the value of JPEGInterchangeFormat.
long jpegInterchangeOffset = JPEGInterchangeFormatField.getAsLong(0);
// Get the JPEGInterchangeFormatLength field.
TIFFField JPEGInterchangeFormatLengthField = tim.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
if (JPEGInterchangeFormatLengthField != null) {
// Get the JPEGInterchangeFormatLength field's value.
long jpegInterchangeLength = JPEGInterchangeFormatLengthField.getAsLong(0);
if (jpegInterchangeLength >= 2 && jpegInterchangeOffset + jpegInterchangeLength <= segmentOffsets[0]) {
// Determine the length excluding any terminal EOI marker
// and allocate table memory.
stream.mark();
stream.seek(jpegInterchangeOffset + jpegInterchangeLength - 2);
if (stream.read() == 0xff && stream.read() == EOI) {
this.tables = new byte[(int) (jpegInterchangeLength - 2)];
} else {
this.tables = new byte[(int) jpegInterchangeLength];
}
stream.reset();
// Read the tables.
stream.mark();
stream.seek(jpegInterchangeOffset);
stream.readFully(tables);
stream.reset();
if (DEBUG)
System.out.println("OLD JPEG CASE 4");
((TIFFImageReader) reader).forwardWarningMessage("Incorrect JPEG interchange format: using JPEGInterchangeFormat offset to derive tables.");
} else {
((TIFFImageReader) reader).forwardWarningMessage("JPEGInterchangeFormat+JPEGInterchangeFormatLength > offset to first strip or tile.");
}
}
}
if (this.tables == null) {
//
// Create tables-only stream in tables[] consisting of
// SOI+DQTs+DHTs
//
ByteArrayOutputStream baos = // XXX length
new ByteArrayOutputStream();
// Save stream length;
long streamLength = stream.length();
// SOI
baos.write(0xff);
baos.write(SOI);
// Quantization Tables
TIFFField f = tim.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_Q_TABLES);
if (f == null) {
throw new IIOException("JPEGQTables field missing!");
}
long[] off = f.getAsLongs();
for (int i = 0; i < off.length; i++) {
// Marker ID
baos.write(0xff);
baos.write(DQT);
char markerLength = (char) 67;
// Length
baos.write((markerLength >>> 8) & 0xff);
baos.write(markerLength & 0xff);
// Table ID and precision
baos.write(i);
byte[] qtable = new byte[64];
if (streamLength != -1 && off[i] > streamLength) {
throw new IIOException("JPEGQTables offset for index " + i + " is not in the stream!");
}
stream.seek(off[i]);
stream.readFully(qtable);
// Table data
baos.write(qtable);
}
// Huffman Tables (k == 0 ? DC : AC).
for (int k = 0; k < 2; k++) {
int tableTagNumber = k == 0 ? BaselineTIFFTagSet.TAG_JPEG_DC_TABLES : BaselineTIFFTagSet.TAG_JPEG_AC_TABLES;
f = tim.getTIFFField(tableTagNumber);
String fieldName = tableTagNumber == BaselineTIFFTagSet.TAG_JPEG_DC_TABLES ? "JPEGDCTables" : "JPEGACTables";
if (f == null) {
throw new IIOException(fieldName + " field missing!");
}
off = f.getAsLongs();
for (int i = 0; i < off.length; i++) {
// Marker ID
baos.write(0xff);
baos.write(DHT);
byte[] blengths = new byte[16];
if (streamLength != -1 && off[i] > streamLength) {
throw new IIOException(fieldName + " offset for index " + i + " is not in the stream!");
}
stream.seek(off[i]);
stream.readFully(blengths);
int numCodes = 0;
for (int j = 0; j < 16; j++) {
numCodes += blengths[j] & 0xff;
}
char markerLength = (char) (19 + numCodes);
// Length
baos.write((markerLength >>> 8) & 0xff);
baos.write(markerLength & 0xff);
// Table ID and type
baos.write(i | (k << 4));
// Number of codes
baos.write(blengths);
byte[] bcodes = new byte[numCodes];
stream.readFully(bcodes);
// Codes
baos.write(bcodes);
}
}
// SOF0
// Marker identifier
baos.write((byte) 0xff);
baos.write((byte) SOF0);
// Length
short sval = (short) (8 + 3 * samplesPerPixel);
baos.write((byte) ((sval >>> 8) & 0xff));
baos.write((byte) (sval & 0xff));
// Data precision
baos.write((byte) 8);
// Tile/strip height
sval = (short) srcHeight;
baos.write((byte) ((sval >>> 8) & 0xff));
baos.write((byte) (sval & 0xff));
// Tile/strip width
sval = (short) srcWidth;
baos.write((byte) ((sval >>> 8) & 0xff));
baos.write((byte) (sval & 0xff));
// Number of components
baos.write((byte) samplesPerPixel);
if (samplesPerPixel == 1) {
// Component ID
baos.write((byte) 1);
// Subsampling factor
baos.write((byte) 0x11);
// Quantization table ID
baos.write((byte) 0);
} else {
// 3
for (int i = 0; i < 3; i++) {
// Component ID
baos.write((byte) (i + 1));
baos.write((i != 0) ? (byte) 0x11 : (byte) (((subsamplingX & 0x0f) << 4) | (subsamplingY & 0x0f)));
// Quantization table ID
baos.write((byte) i);
}
}
;
// DRI (optional).
f = tim.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_RESTART_INTERVAL);
if (f != null) {
char restartInterval = f.getAsChars()[0];
if (restartInterval != 0) {
// Marker identifier
baos.write((byte) 0xff);
baos.write((byte) DRI);
sval = 4;
// Length
baos.write((byte) ((sval >>> 8) & 0xff));
baos.write((byte) (sval & 0xff));
// RestartInterval
baos.write((byte) ((restartInterval >>> 8) & 0xff));
baos.write((byte) (restartInterval & 0xff));
}
}
tables = baos.toByteArray();
if (DEBUG)
System.out.println("OLD JPEG CASE 5");
}
//
// Check for presence of SOF marker and save its position.
//
int idx = 0;
int idxMax = tables.length - 1;
while (idx < idxMax) {
if ((tables[idx] & 0xff) == 0xff && (tables[idx + 1] & 0xff) == SOF0) {
SOFPosition = idx;
break;
}
idx++;
}
//
if (SOFPosition == -1) {
byte[] tmpTables = new byte[tables.length + 10 + 3 * samplesPerPixel];
System.arraycopy(tables, 0, tmpTables, 0, tables.length);
int tmpOffset = tables.length;
SOFPosition = tables.length;
tables = tmpTables;
// Marker identifier
tables[tmpOffset++] = (byte) 0xff;
tables[tmpOffset++] = (byte) SOF0;
// Length
short sval = (short) (8 + 3 * samplesPerPixel);
tables[tmpOffset++] = (byte) ((sval >>> 8) & 0xff);
tables[tmpOffset++] = (byte) (sval & 0xff);
// Data precision
tables[tmpOffset++] = (byte) 8;
// Tile/strip height
sval = (short) srcHeight;
tables[tmpOffset++] = (byte) ((sval >>> 8) & 0xff);
tables[tmpOffset++] = (byte) (sval & 0xff);
// Tile/strip width
sval = (short) srcWidth;
tables[tmpOffset++] = (byte) ((sval >>> 8) & 0xff);
tables[tmpOffset++] = (byte) (sval & 0xff);
// Number of components
tables[tmpOffset++] = (byte) samplesPerPixel;
if (samplesPerPixel == 1) {
// Component ID
tables[tmpOffset++] = (byte) 1;
// Subsampling factor
tables[tmpOffset++] = (byte) 0x11;
// Quantization table ID
tables[tmpOffset++] = (byte) 0;
} else {
// 3
for (int i = 0; i < 3; i++) {
// Component ID
tables[tmpOffset++] = (byte) (i + 1);
tables[tmpOffset++] = (i != 0) ? (byte) 0x11 : (byte) (((subsamplingX & 0x0f) << 4) | (subsamplingY & 0x0f));
// Quantization table ID
tables[tmpOffset++] = (byte) i;
}
}
;
}
//
// Initialize SOSMarker.
//
stream.mark();
stream.seek(segmentOffsets[0]);
if (stream.read() == 0xff && stream.read() == SOS) {
//
// If the first segment starts with an SOS marker save it.
//
int SOSLength = (stream.read() << 8) | stream.read();
SOSMarker = new byte[SOSLength + 2];
SOSMarker[0] = (byte) 0xff;
SOSMarker[1] = (byte) SOS;
SOSMarker[2] = (byte) ((SOSLength & 0xff00) >> 8);
SOSMarker[3] = (byte) (SOSLength & 0xff);
stream.readFully(SOSMarker, 4, SOSLength - 2);
} else {
//
// Manufacture an SOS marker.
//
SOSMarker = new byte[2 + 6 + 2 * samplesPerPixel];
int SOSMarkerIndex = 0;
// Marker identifier
SOSMarker[SOSMarkerIndex++] = (byte) 0xff;
SOSMarker[SOSMarkerIndex++] = (byte) SOS;
// Length
short sval = (short) (6 + 2 * samplesPerPixel);
SOSMarker[SOSMarkerIndex++] = (byte) ((sval >>> 8) & 0xff);
SOSMarker[SOSMarkerIndex++] = (byte) (sval & 0xff);
// Number of components in scan
SOSMarker[SOSMarkerIndex++] = (byte) samplesPerPixel;
if (samplesPerPixel == 1) {
// Component ID
SOSMarker[SOSMarkerIndex++] = (byte) 1;
// Huffman table ID
SOSMarker[SOSMarkerIndex++] = (byte) 0;
} else {
// 3
for (int i = 0; i < 3; i++) {
SOSMarker[SOSMarkerIndex++] = // Component ID
(byte) (i + 1);
SOSMarker[SOSMarkerIndex++] = // Huffman table IDs
(byte) ((i << 4) | i);
}
}
;
SOSMarker[SOSMarkerIndex++] = (byte) 0;
SOSMarker[SOSMarkerIndex++] = (byte) 0x3f;
SOSMarker[SOSMarkerIndex++] = (byte) 0;
}
stream.reset();
// Set initialization flag.
isInitialized = true;
}
Aggregations