gifimagereader.java
来自「JAVA的一些源码 JAVA2 STANDARD EDITION DEVELO」· Java 代码 · 共 1,146 行 · 第 1/3 页
JAVA
1,146 行
// attempt to analyze the congruences. If passPeriod and // sourceSubsamling are relatively prime, the period will be // their product. If they share a common factor, either the // period will be equal to the larger value, or the sequences // will be completely disjoint, depending on the relationship // between passStart and sourceOffset. Since we only have to do this // twice per image (once each for X and Y), it seems cheap enough // to do it the straightforward way. boolean gotPixel = false; int firstDst = -1; int secondDst = -1; int lastDst = -1; for (int i = 0; i < passExtent; i++) { int src = passStart + i*passPeriod; if (src < sourceOffset) { continue; } if ((src - sourceOffset) % sourceSubsampling != 0) { continue; } if (src >= sourceOffset + sourceExtent) { break; } int dst = destinationOffset + (src - sourceOffset)/sourceSubsampling; if (dst < dstMin) { continue; } if (dst > dstMax) { break; } if (!gotPixel) { firstDst = dst; // Record smallest valid pixel gotPixel = true; } else if (secondDst == -1) { secondDst = dst; // Record second smallest valid pixel } lastDst = dst; // Record largest valid pixel } vals[offset] = firstDst; // If we never saw a valid pixel, set width to 0 if (!gotPixel) { vals[offset + 2] = 0; } else { vals[offset + 2] = lastDst - firstDst + 1; } // The period is given by the difference of any two adjacent pixels vals[offset + 4] = Math.max(secondDst - firstDst, 1); } /** * A utility method that computes the exact set of destination * pixels that will be written during a particular decoding pass. * The intent is to simplify the work done by readers in combining * the source region, source subsampling, and destination offset * information obtained from the <code>ImageReadParam</code> with * the offsets and periods of a progressive or interlaced decoding * pass. * * @param sourceRegion a <code>Rectangle</code> containing the * source region being read, offset by the source subsampling * offsets, and clipped against the source bounds, as returned by * the <code>getSourceRegion</code> method. * @param destinationOffset a <code>Point</code> containing the * coordinates of the upper-left pixel to be written in the * destination. * @param dstMinX the smallest X coordinate (inclusive) of the * destination <code>Raster</code>. * @param dstMinY the smallest Y coordinate (inclusive) of the * destination <code>Raster</code>. * @param dstMaxX the largest X coordinate (inclusive) of the destination * <code>Raster</code>. * @param dstMaxY the largest Y coordinate (inclusive) of the destination * <code>Raster</code>. * @param sourceXSubsampling the X subsampling factor. * @param sourceYSubsampling the Y subsampling factor. * @param passXStart the smallest source X coordinate (inclusive) * of the current progressive pass. * @param passYStart the smallest source Y coordinate (inclusive) * of the current progressive pass. * @param passWidth the width in pixels of the current progressive * pass. * @param passHeight the height in pixels of the current progressive * pass. * @param passPeriodX the X period (horizontal spacing between * pixels) of the current progressive pass. * @param passPeriodY the Y period (vertical spacing between * pixels) of the current progressive pass. * * @return an array of 6 <code>int</code>s containing the * destination min X, min Y, width, height, X period and Y period * of the region that will be updated. */ private static int[] computeUpdatedPixels(Rectangle sourceRegion, Point destinationOffset, int dstMinX, int dstMinY, int dstMaxX, int dstMaxY, int sourceXSubsampling, int sourceYSubsampling, int passXStart, int passYStart, int passWidth, int passHeight, int passPeriodX, int passPeriodY) { int[] vals = new int[6]; computeUpdatedPixels(sourceRegion.x, sourceRegion.width, destinationOffset.x, dstMinX, dstMaxX, sourceXSubsampling, passXStart, passWidth, passPeriodX, vals, 0); computeUpdatedPixels(sourceRegion.y, sourceRegion.height, destinationOffset.y, dstMinY, dstMaxY, sourceYSubsampling, passYStart, passHeight, passPeriodY, vals, 1); return vals; } 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 = 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); } public BufferedImage read(int imageIndex, ImageReadParam param) throws IIOException { 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); } } /** * Remove all settings including global settings such as * <code>Locale</code>s and listeners, as well as stream settings. */ public void reset() { super.reset(); resetStreamSettings(); } /** * Remove local settings based on parsing of a stream. */ private void resetStreamSettings() { 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; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?