in src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderStrips.java [230:335]
public ImageBuilder readImageData(final Rectangle subImageSpecification, final boolean hasAlpha, final boolean isAlphaPreMultiplied)
throws IOException, ImagingException {
final Rectangle subImage;
if (subImageSpecification == null) {
// configure subImage to read entire image
subImage = new Rectangle(0, 0, width, height);
} else {
subImage = subImageSpecification;
}
// the legacy code is optimized to the reading of whole
// strips (except for the last strip in the image, which can
// be a partial). So create a working image with compatible
// dimensions and read that. Later on, the working image
// will be sub-imaged to the proper size.
// strip0 and strip1 give the indices of the strips containing
// the first and last rows of pixels in the subimage
final int strip0 = subImage.y / rowsPerStrip;
final int strip1 = (subImage.y + subImage.height - 1) / rowsPerStrip;
final int workingHeight = (strip1 - strip0 + 1) * rowsPerStrip;
// the legacy code uses a member element "y" to keep track
// of the row index of the output image that is being processed
// by interpretStrip. y is set to zero before the first
// call to interpretStrip. y0 will be the index of the first row
// in the full image (the source image) that will be processed.
final int y0 = strip0 * rowsPerStrip;
final int yLimit = subImage.y - y0 + subImage.height;
// When processing a subimage, the workingBuilder height is set
// to be an integral multiple of the rowsPerStrip and
// the full width of the strips. So the working image may be larger than
// the specified size of the subimage. If necessary, the subimage
// is extracted from the workingBuilder at the end of this method.
// This approach avoids the need for the interpretStrips method
// to implement bounds checking for a subimage.
final ImageBuilder workingBuilder = new ImageBuilder(width, workingHeight, hasAlpha, isAlphaPreMultiplied);
// the following statement accounts for cases where planar configuration
// is not specified and the default (CHUNKY) is assumed.
final boolean interleaved = planarConfiguration != TiffPlanarConfiguration.PLANAR;
if (interleaved) {
// Pixel definitions are organized in an interleaved format
// For example, red-green-blue values for each pixel
// would appear contiguous in input sequence.
for (int strip = strip0; strip <= strip1; strip++) {
final long rowsPerStripLong = 0xFFFFffffL & rowsPerStrip;
final long rowsRemaining = height - strip * rowsPerStripLong;
final long rowsInThisStrip = Math.min(rowsRemaining, rowsPerStripLong);
final long bytesPerRow = (bitsPerPixel * width + 7) / 8;
final long bytesPerStrip = rowsInThisStrip * bytesPerRow;
final long pixelsPerStrip = rowsInThisStrip * width;
final byte[] compressed = imageData.getImageData(strip).getData();
if (compression == COMPRESSION_JPEG) {
final int yBlock = strip * rowsPerStrip;
final int yWork = yBlock - y0;
DataInterpreterJpeg.intepretBlock(directory, workingBuilder, 0, yWork, width, (int) rowsInThisStrip, compressed);
continue;
}
final byte[] decompressed = decompress(compressed, compression, (int) bytesPerStrip, width, (int) rowsInThisStrip);
interpretStrip(workingBuilder, decompressed, (int) pixelsPerStrip, yLimit);
}
} else {
// pixel definitions are organized in a 3 separate sections of input
// sequence. For example, red-green-blue values would be given as
// red values for all pixels, followed by green values for all pixels,
// etc.
if (compression == COMPRESSION_JPEG) {
throw new ImagingException("TIFF file in non-supported configuration: JPEG compression used in planar configuration.");
}
final int nStripsInPlane = imageData.getImageDataLength() / 3;
for (int strip = strip0; strip <= strip1; strip++) {
final long rowsPerStripLong = 0xFFFFffffL & rowsPerStrip;
final long rowsRemaining = height - strip * rowsPerStripLong;
final long rowsInThisStrip = Math.min(rowsRemaining, rowsPerStripLong);
final long bytesPerRow = (bitsPerPixel * width + 7) / 8;
final long bytesPerStrip = rowsInThisStrip * bytesPerRow;
final long pixelsPerStrip = rowsInThisStrip * width;
final byte[] b = Allocator.byteArray((int) bytesPerStrip);
for (int iPlane = 0; iPlane < 3; iPlane++) {
final int planeStrip = iPlane * nStripsInPlane + strip;
final byte[] compressed = imageData.getImageData(planeStrip).getData();
final byte[] decompressed = decompress(compressed, compression, (int) bytesPerStrip, width, (int) rowsInThisStrip);
int index = iPlane;
for (final byte element : decompressed) {
b[index] = element;
index += 3;
}
}
interpretStrip(workingBuilder, b, (int) pixelsPerStrip, height);
}
}
if (subImage.x == 0 && subImage.y == y0 && subImage.width == width && subImage.height == workingHeight) {
// the subimage exactly matches the ImageBuilder bounds
// so we can return that.
return workingBuilder;
}
return workingBuilder.getSubset(subImage.x, subImage.y - y0, subImage.width, subImage.height);
}