Methods Summary |
---|
private void | checkIndex(int imageIndex)
if (imageIndex < minIndex) {
throw new IndexOutOfBoundsException("imageIndex < minIndex!");
}
if (seekForwardOnly) {
minIndex = imageIndex;
}
|
private void | computeDecodeThisRow()
this.decodeThisRow =
(destY < destinationRegion.y + destinationRegion.height) &&
(streamY >= sourceRegion.y) &&
(streamY < sourceRegion.y + sourceRegion.height) &&
(((streamY - sourceRegion.y) % sourceYSubsampling) == 0);
|
private byte[] | concatenateBlocks()
byte[] data = new byte[0];
while (true) {
int length = stream.readUnsignedByte();
if (length == 0) {
break;
}
byte[] newData = new byte[data.length + length];
System.arraycopy(data, 0, newData, 0, data.length);
stream.readFully(newData, data.length, length);
data = newData;
}
return data;
|
private int | getCode(int codeSize, int codeMask)
if (bitPos + codeSize > 32) {
return eofCode; // No more data available
}
int code = (next32Bits >> bitPos) & codeMask;
bitPos += codeSize;
// Shift in a byte of new data at a time
while (bitPos >= 8 && !lastBlockFound) {
next32Bits >>>= 8;
bitPos -= 8;
// Check if current block is out of bytes
if (nextByte >= blockLength) {
// Get next block size
blockLength = stream.readUnsignedByte();
if (blockLength == 0) {
lastBlockFound = true;
return code;
} else {
int left = blockLength;
int off = 0;
while (left > 0) {
int nbytes = stream.read(block, off, left);
off += nbytes;
left -= nbytes;
}
nextByte = 0;
}
}
next32Bits |= block[nextByte++] << 24;
}
return code;
|
public javax.imageio.ImageReadParam | getDefaultReadParam()
return new ImageReadParam();
|
public int | getHeight(int imageIndex)
checkIndex(imageIndex);
int index = locateImage(imageIndex);
if (index != imageIndex) {
throw new IndexOutOfBoundsException();
}
readMetadata();
return imageMetadata.imageHeight;
|
public javax.imageio.metadata.IIOMetadata | getImageMetadata(int imageIndex)
checkIndex(imageIndex);
int index = locateImage(imageIndex);
if (index != imageIndex) {
throw new IndexOutOfBoundsException("Bad image index!");
}
readMetadata();
return imageMetadata;
|
public java.util.Iterator | getImageTypes(int imageIndex)
checkIndex(imageIndex);
int index = locateImage(imageIndex);
if (index != imageIndex) {
throw new IndexOutOfBoundsException();
}
readMetadata();
List l = new ArrayList(1);
byte[] colorTable;
if (imageMetadata.localColorTable != null) {
colorTable = imageMetadata.localColorTable;
} else {
colorTable = streamMetadata.globalColorTable;
}
// Normalize color table length to 2^1, 2^2, 2^4, or 2^8
int length = colorTable.length/3;
int bits;
if (length == 2) {
bits = 1;
} else if (length == 4) {
bits = 2;
} else if (length == 8 || length == 16) {
// Bump from 3 to 4 bits
bits = 4;
} else {
// Bump to 8 bits
bits = 8;
}
int lutLength = 1 << bits;
byte[] r = new byte[lutLength];
byte[] g = new byte[lutLength];
byte[] b = new byte[lutLength];
// Entries from length + 1 to lutLength - 1 will be 0
int rgbIndex = 0;
for (int i = 0; i < length; i++) {
r[i] = colorTable[rgbIndex++];
g[i] = colorTable[rgbIndex++];
b[i] = colorTable[rgbIndex++];
}
byte[] a = null;
if (imageMetadata.transparentColorFlag) {
a = new byte[lutLength];
Arrays.fill(a, (byte)255);
// Some files erroneously have a transparent color index
// of 255 even though there are fewer than 256 colors.
int idx = Math.min(imageMetadata.transparentColorIndex,
lutLength - 1);
a[idx] = (byte)0;
}
int[] bitsPerSample = new int[1];
bitsPerSample[0] = bits;
l.add(ImageTypeSpecifier.createIndexed(r, g, b, a, bits,
DataBuffer.TYPE_BYTE));
return l.iterator();
|
public int | getNumImages(boolean allowSearch)
if (stream == null) {
throw new IllegalStateException("Input not set!");
}
if (seekForwardOnly && allowSearch) {
throw new IllegalStateException
("seekForwardOnly and allowSearch can't both be true!");
}
if (numImages > 0) {
return numImages;
}
if (allowSearch) {
this.numImages = locateImage(Integer.MAX_VALUE) + 1;
}
return numImages;
|
public javax.imageio.metadata.IIOMetadata | getStreamMetadata()
readHeader();
return streamMetadata;
|
public int | getWidth(int imageIndex)
checkIndex(imageIndex);
int index = locateImage(imageIndex);
if (index != imageIndex) {
throw new IndexOutOfBoundsException();
}
readMetadata();
return imageMetadata.imageWidth;
|
private void | initNext32Bits()
next32Bits = block[0] & 0xff;
next32Bits |= (block[1] & 0xff) << 8;
next32Bits |= (block[2] & 0xff) << 16;
next32Bits |= block[3] << 24;
nextByte = 4;
|
public void | initializeStringTable(int[] prefix, byte[] suffix, byte[] initial, int[] length)
int numEntries = 1 << initCodeSize;
for (int i = 0; i < numEntries; i++) {
prefix[i] = -1;
suffix[i] = (byte)i;
initial[i] = (byte)i;
length[i] = 1;
}
// Fill in the entire table for robustness against
// out-of-sequence codes.
for (int i = numEntries; i < 4096; i++) {
prefix[i] = -1;
length[i] = 1;
}
// tableIndex = numEntries + 2;
// codeSize = initCodeSize + 1;
// codeMask = (1 << codeSize) - 1;
|
private int | locateImage(int imageIndex)
readHeader();
try {
// Find closest known index
int index = Math.min(imageIndex, imageStartPosition.size() - 1);
// Seek to that position
Long l = (Long)imageStartPosition.get(index);
stream.seek(l.longValue());
// Skip images until at desired index or last image found
while (index < imageIndex) {
if (!skipImage()) {
--index;
return index;
}
Long l1 = new Long(stream.getStreamPosition());
imageStartPosition.add(l1);
++index;
}
} catch (IOException e) {
throw new IIOException("Couldn't seek!", e);
}
if (currIndex != imageIndex) {
imageMetadata = null;
}
currIndex = imageIndex;
return imageIndex;
|
private void | outputPixels(byte[] string, int len)
if (interlacePass < sourceMinProgressivePass ||
interlacePass > sourceMaxProgressivePass) {
return;
}
for (int i = 0; i < len; i++) {
if (streamX >= sourceRegion.x) {
rowBuf[streamX - sourceRegion.x] = string[i];
}
// Process end-of-row
++streamX;
if (streamX == width) {
// Update IIOReadProgressListeners
++rowsDone;
processImageProgress(100.0F*rowsDone/height);
if (decodeThisRow) {
outputRow();
}
streamX = 0;
if (imageMetadata.interlaceFlag) {
streamY += interlaceIncrement[interlacePass];
if (streamY >= height) {
// Inform IIOReadUpdateListeners of end of pass
if (updateListeners != null) {
processPassComplete(theImage);
}
++interlacePass;
if (interlacePass > sourceMaxProgressivePass) {
return;
}
streamY = interlaceOffset[interlacePass];
startPass(interlacePass);
}
} else {
++streamY;
}
// Determine whether pixels from this row will
// be written to the destination
this.destY = destinationRegion.y +
(streamY - sourceRegion.y)/sourceYSubsampling;
computeDecodeThisRow();
}
}
|
private void | outputRow()
// Clip against ImageReadParam
int width = Math.min(sourceRegion.width,
destinationRegion.width*sourceXSubsampling);
int destX = destinationRegion.x;
if (sourceXSubsampling == 1) {
theTile.setDataElements(destX, destY, width, 1, rowBuf);
} else {
for (int x = 0; x < width; x += sourceXSubsampling, destX++) {
theTile.setSample(destX, destY, 0, rowBuf[x] & 0xff);
}
}
// Update IIOReadUpdateListeners, if any
if (updateListeners != null) {
int[] bands = { 0 };
// updateYStep will have been initialized if
// updateListeners is non-null
processImageUpdate(theImage,
destX, destY,
width, 1, 1, updateYStep,
bands);
}
|
public java.awt.image.BufferedImage | read(int imageIndex, javax.imageio.ImageReadParam param)
if (stream == null) {
throw new IllegalStateException("Input not set!");
}
checkIndex(imageIndex);
int index = locateImage(imageIndex);
if (index != imageIndex) {
throw new IndexOutOfBoundsException("imageIndex out of bounds!");
}
clearAbortRequest();
readMetadata();
// A null ImageReadParam means we use the default
if (param == null) {
param = getDefaultReadParam();
}
// Initialize the destination image
Iterator imageTypes = getImageTypes(imageIndex);
this.theImage = getDestination(param,
imageTypes,
imageMetadata.imageWidth,
imageMetadata.imageHeight);
this.theTile = theImage.getWritableTile(0, 0);
this.width = imageMetadata.imageWidth;
this.height = imageMetadata.imageHeight;
this.streamX = 0;
this.streamY = 0;
this.rowsDone = 0;
this.interlacePass = 0;
// Get source region, taking subsampling offsets into account,
// and clipping against the true source bounds
this.sourceRegion = new Rectangle(0, 0, 0, 0);
this.destinationRegion = new Rectangle(0, 0, 0, 0);
computeRegions(param, width, height, theImage,
sourceRegion, destinationRegion);
this.destinationOffset = new Point(destinationRegion.x,
destinationRegion.y);
this.sourceXSubsampling = param.getSourceXSubsampling();
this.sourceYSubsampling = param.getSourceYSubsampling();
this.sourceMinProgressivePass =
Math.max(param.getSourceMinProgressivePass(), 0);
this.sourceMaxProgressivePass =
Math.min(param.getSourceMaxProgressivePass(), 3);
this.destY = destinationRegion.y +
(streamY - sourceRegion.y)/sourceYSubsampling;
computeDecodeThisRow();
// Inform IIOReadProgressListeners of start of image
processImageStarted(imageIndex);
startPass(0);
this.rowBuf = new byte[width];
try {
// Read and decode the image data, fill in theImage
this.initCodeSize = stream.readUnsignedByte();
// Read first data block
this.blockLength = stream.readUnsignedByte();
int left = blockLength;
int off = 0;
while (left > 0) {
int nbytes = stream.read(block, off, left);
left -= nbytes;
off += nbytes;
}
this.bitPos = 0;
this.nextByte = 0;
this.lastBlockFound = false;
this.interlacePass = 0;
// Init 32-bit buffer
initNext32Bits();
this.clearCode = 1 << initCodeSize;
this.eofCode = clearCode + 1;
int code, oldCode = 0;
int[] prefix = new int[4096];
byte[] suffix = new byte[4096];
byte[] initial = new byte[4096];
int[] length = new int[4096];
byte[] string = new byte[4096];
initializeStringTable(prefix, suffix, initial, length);
int tableIndex = (1 << initCodeSize) + 2;
int codeSize = initCodeSize + 1;
int codeMask = (1 << codeSize) - 1;
while (!abortRequested()) {
code = getCode(codeSize, codeMask);
if (code == clearCode) {
initializeStringTable(prefix, suffix, initial, length);
tableIndex = (1 << initCodeSize) + 2;
codeSize = initCodeSize + 1;
codeMask = (1 << codeSize) - 1;
code = getCode(codeSize, codeMask);
if (code == eofCode) {
// Inform IIOReadProgressListeners of end of image
processImageComplete();
return theImage;
}
} else if (code == eofCode) {
// Inform IIOReadProgressListeners of end of image
processImageComplete();
return theImage;
} else {
int newSuffixIndex;
if (code < tableIndex) {
newSuffixIndex = code;
} else { // code == tableIndex
newSuffixIndex = oldCode;
if (code != tableIndex) {
// warning - code out of sequence
// possibly data corruption
processWarningOccurred("Out-of-sequence code!");
}
}
int ti = tableIndex;
int oc = oldCode;
prefix[ti] = oc;
suffix[ti] = initial[newSuffixIndex];
initial[ti] = initial[oc];
length[ti] = length[oc] + 1;
++tableIndex;
if ((tableIndex == (1 << codeSize)) &&
(tableIndex < 4096)) {
++codeSize;
codeMask = (1 << codeSize) - 1;
}
}
// Reverse code
int c = code;
int len = length[c];
for (int i = len - 1; i >= 0; i--) {
string[i] = suffix[c];
c = prefix[c];
}
outputPixels(string, len);
oldCode = code;
}
processReadAborted();
return theImage;
} catch (IOException e) {
e.printStackTrace();
throw new IIOException("I/O error reading image!", e);
}
|
private void | readHeader()
if (gotHeader) {
return;
}
if (stream == null) {
throw new IllegalStateException("Input not set!");
}
// Create an object to store the stream metadata
this.streamMetadata = new GIFStreamMetadata();
try {
stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
byte[] signature = new byte[6];
stream.readFully(signature);
StringBuffer version = new StringBuffer(3);
version.append((char)signature[3]);
version.append((char)signature[4]);
version.append((char)signature[5]);
streamMetadata.version = version.toString();
streamMetadata.logicalScreenWidth = stream.readUnsignedShort();
streamMetadata.logicalScreenHeight = stream.readUnsignedShort();
int packedFields = stream.readUnsignedByte();
boolean globalColorTableFlag = (packedFields & 0x80) != 0;
streamMetadata.colorResolution = ((packedFields >> 4) & 0x7) + 1;
streamMetadata.sortFlag = (packedFields & 0x8) != 0;
int numGCTEntries = 1 << ((packedFields & 0x7) + 1);
streamMetadata.backgroundColorIndex = stream.readUnsignedByte();
streamMetadata.pixelAspectRatio = stream.readUnsignedByte();
if (globalColorTableFlag) {
streamMetadata.globalColorTable = new byte[3*numGCTEntries];
stream.readFully(streamMetadata.globalColorTable);
} else {
streamMetadata.globalColorTable = null;
}
// Found position of metadata for image 0
imageStartPosition.add(new Long(stream.getStreamPosition()));
} catch (IOException e) {
throw new IIOException("I/O error reading header!", e);
}
gotHeader = true;
|
private void | readMetadata()
if (stream == null) {
throw new IllegalStateException("Input not set!");
}
try {
// Create an object to store the image metadata
this.imageMetadata = new GIFImageMetadata();
long startPosition = stream.getStreamPosition();
while (true) {
int blockType = stream.readUnsignedByte();
if (blockType == 0x2c) { // Image Descriptor
imageMetadata.imageLeftPosition =
stream.readUnsignedShort();
imageMetadata.imageTopPosition =
stream.readUnsignedShort();
imageMetadata.imageWidth = stream.readUnsignedShort();
imageMetadata.imageHeight = stream.readUnsignedShort();
int idPackedFields = stream.readUnsignedByte();
boolean localColorTableFlag =
(idPackedFields & 0x80) != 0;
imageMetadata.interlaceFlag = (idPackedFields & 0x40) != 0;
imageMetadata.sortFlag = (idPackedFields & 0x20) != 0;
int numLCTEntries = 1 << ((idPackedFields & 0x7) + 1);
if (localColorTableFlag) {
// Read color table if any
imageMetadata.localColorTable =
new byte[3*numLCTEntries];
stream.readFully(imageMetadata.localColorTable);
} else {
imageMetadata.localColorTable = null;
}
// Record length of this metadata block
this.imageMetadataLength =
(int)(stream.getStreamPosition() - startPosition);
// Now positioned at start of LZW-compressed pixels
return;
} else if (blockType == 0x21) { // Extension block
int label = stream.readUnsignedByte();
if (label == 0xf9) { // Graphics Control Extension
int gceLength = stream.readUnsignedByte(); // 4
int gcePackedFields = stream.readUnsignedByte();
imageMetadata.disposalMethod =
(gcePackedFields >> 2) & 0x3;
imageMetadata.userInputFlag =
(gcePackedFields & 0x2) != 0;
imageMetadata.transparentColorFlag =
(gcePackedFields & 0x1) != 0;
imageMetadata.delayTime = stream.readUnsignedShort();
imageMetadata.transparentColorIndex
= stream.readUnsignedByte();
int terminator = stream.readUnsignedByte();
} else if (label == 0x1) { // Plain text extension
int length = stream.readUnsignedByte();
imageMetadata.hasPlainTextExtension = true;
imageMetadata.textGridLeft =
stream.readUnsignedShort();
imageMetadata.textGridTop =
stream.readUnsignedShort();
imageMetadata.textGridWidth =
stream.readUnsignedShort();
imageMetadata.textGridHeight =
stream.readUnsignedShort();
imageMetadata.characterCellWidth =
stream.readUnsignedByte();
imageMetadata.characterCellHeight =
stream.readUnsignedByte();
imageMetadata.textForegroundColor =
stream.readUnsignedByte();
imageMetadata.textBackgroundColor =
stream.readUnsignedByte();
imageMetadata.text = concatenateBlocks();
} else if (label == 0xfe) { // Comment extension
byte[] comment = concatenateBlocks();
if (imageMetadata.comments == null) {
imageMetadata.comments = new ArrayList();
}
imageMetadata.comments.add(comment);
} else if (label == 0xff) { // Application extension
int blockSize = stream.readUnsignedByte();
byte[] applicationID = new byte[8];
stream.readFully(applicationID);
byte[] authCode = new byte[3];
stream.readFully(authCode);
byte[] applicationData = concatenateBlocks();
// Init lists if necessary
if (imageMetadata.applicationIDs == null) {
imageMetadata.applicationIDs = new ArrayList();
imageMetadata.authenticationCodes =
new ArrayList();
imageMetadata.applicationData = new ArrayList();
}
imageMetadata.applicationIDs.add(applicationID);
imageMetadata.authenticationCodes.add(authCode);
imageMetadata.applicationData.add(applicationData);
} else {
// Skip over unknown extension blocks
int length = 0;
do {
length = stream.readUnsignedByte();
stream.skipBytes(length);
} while (length > 0);
}
} else if (blockType == 0x3b) { // Trailer
throw new IndexOutOfBoundsException
("Attempt to read past end of image sequence!");
} else {
throw new IIOException("Unexpected block type " +
blockType + "!");
}
}
} catch (IIOException iioe) {
throw iioe;
} catch (IOException ioe) {
throw new IIOException("I/O error reading image metadata!", ioe);
}
|
public void | reset()Remove all settings including global settings such as
Locale s and listeners, as well as stream settings.
super.reset();
resetStreamSettings();
|
private void | resetStreamSettings()Remove local settings based on parsing of a stream.
gotHeader = false;
streamMetadata = null;
currIndex = -1;
imageMetadata = null;
imageStartPosition = new ArrayList();
numImages = -1;
// No need to reinitialize 'block'
blockLength = 0;
bitPos = 0;
nextByte = 0;
next32Bits = 0;
lastBlockFound = false;
theImage = null;
theTile = null;
width = -1;
height = -1;
streamX = -1;
streamY = -1;
rowsDone = 0;
interlacePass = 0;
|
public void | setInput(java.lang.Object input, boolean seekForwardOnly, boolean ignoreMetadata)
super.setInput(input, seekForwardOnly, ignoreMetadata);
if (input != null) {
if (!(input instanceof ImageInputStream)) {
throw new IllegalArgumentException
("input not an ImageInputStream!");
}
this.stream = (ImageInputStream)input;
} else {
this.stream = null;
}
// Clear all values based on the previous stream contents
resetStreamSettings();
|
private boolean | skipImage()
// Stream must be at the beginning of an image descriptor
// upon exit
try {
while (true) {
int blockType = stream.readUnsignedByte();
if (blockType == 0x2c) {
stream.skipBytes(8);
int packedFields = stream.readUnsignedByte();
if ((packedFields & 0x80) != 0) {
// Skip color table if any
int bits = (packedFields & 0x7) + 1;
stream.skipBytes(3*(1 << bits));
}
stream.skipBytes(1);
int length = 0;
do {
length = stream.readUnsignedByte();
stream.skipBytes(length);
} while (length > 0);
return true;
} else if (blockType == 0x3b) {
return false;
} else if (blockType == 0x21) {
int label = stream.readUnsignedByte();
int length = 0;
do {
length = stream.readUnsignedByte();
stream.skipBytes(length);
} while (length > 0);
} else if (blockType == 0x0) {
// EOF
return false;
} else {
int length = 0;
do {
length = stream.readUnsignedByte();
stream.skipBytes(length);
} while (length > 0);
}
}
} catch (EOFException e) {
return false;
} catch (IOException e) {
throw new IIOException("I/O error locating image!", e);
}
|
private void | startPass(int pass)
if (updateListeners == null) {
return;
}
int y = 0;
int yStep = 1;
if (imageMetadata.interlaceFlag) {
y = interlaceOffset[interlacePass];
yStep = interlaceIncrement[interlacePass];
}
int[] vals = ReaderUtil.
computeUpdatedPixels(sourceRegion,
destinationOffset,
destinationRegion.x,
destinationRegion.y,
destinationRegion.x +
destinationRegion.width - 1,
destinationRegion.y +
destinationRegion.height - 1,
sourceXSubsampling,
sourceYSubsampling,
0,
y,
destinationRegion.width,
(destinationRegion.height + yStep - 1)/yStep,
1,
yStep);
// Initialized updateMinY and updateYStep
this.updateMinY = vals[1];
this.updateYStep = vals[5];
// Inform IIOReadUpdateListeners of new pass
int[] bands = { 0 };
processPassStarted(theImage,
interlacePass,
sourceMinProgressivePass,
sourceMaxProgressivePass,
0,
updateMinY,
1,
updateYStep,
bands);
|