📄 pngimagereader.java
字号:
curr[i + coff] = (byte)(raw + paethPredictor(priorPixel, priorRow, priorRowPixel)); } } private static final int[][] bandOffsets = { null, { 0 }, // G { 0, 1 }, // GA in GA order { 0, 1, 2 }, // RGB in RGB order { 0, 1, 2, 3 } // RGBA in RGBA order }; private WritableRaster createRaster(int width, int height, int bands, int scanlineStride, int bitDepth) { DataBuffer dataBuffer; WritableRaster ras = null; Point origin = new Point(0, 0); if ((bitDepth < 8) && (bands == 1)) { dataBuffer = new DataBufferByte(height*scanlineStride); ras = Raster.createPackedRaster(dataBuffer, width, height, bitDepth, origin); } else if (bitDepth <= 8) { dataBuffer = new DataBufferByte(height*scanlineStride); ras = Raster.createInterleavedRaster(dataBuffer, width, height, scanlineStride, bands, bandOffsets[bands], origin); } else { dataBuffer = new DataBufferUShort(height*scanlineStride); ras = Raster.createInterleavedRaster(dataBuffer, width, height, scanlineStride, bands, bandOffsets[bands], origin); } return ras; } private void skipPass(int passWidth, int passHeight) throws IOException, IIOException { if ((passWidth == 0) || (passHeight == 0)) { return; } int inputBands = inputBandsForColorType[metadata.IHDR_colorType]; int bytesPerRow = (inputBands*passWidth*metadata.IHDR_bitDepth + 7)/8; byte[] curr = new byte[bytesPerRow]; // Read the image row-by-row for (int srcY = 0; srcY < passHeight; srcY++) { // Read the filter type byte and a row of data int filter = pixelStream.read(); pixelStream.readFully(curr, 0, bytesPerRow); // If read has been aborted, just return // processReadAborted will be called later if (abortRequested()) { return; } } } // Helper for protected computeUpdatedPixels method private static void computeUpdatedPixels(int sourceOffset, int sourceExtent, int destinationOffset, int dstMin, int dstMax, int sourceSubsampling, int passStart, int passExtent, int passPeriod, int[] vals, int offset) { // We need to satisfy the congruences: // dst = destinationOffset + (src - sourceOffset)/sourceSubsampling // // src - passStart == 0 (mod passPeriod) // src - sourceOffset == 0 (mod sourceSubsampling) // // subject to the inequalities: // // src >= passStart // src < passStart + passExtent // src >= sourceOffset // src < sourceOffset + sourceExtent // dst >= dstMin // dst <= dstmax // // where // // dst = destinationOffset + (src - sourceOffset)/sourceSubsampling // // For now we use a brute-force approach although we could // 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 updateImageProgress(int newPixels) { pixelsDone += newPixels; processImageProgress(100.0F*pixelsDone/totalPixels); } private void decodePass(int passNum, int xStart, int yStart, int xStep, int yStep, int passWidth, int passHeight) throws IOException { if ((passWidth == 0) || (passHeight == 0)) { return; } WritableRaster imRas = theImage.getWritableTile(0, 0); int dstMinX = imRas.getMinX(); int dstMaxX = dstMinX + imRas.getWidth() - 1; int dstMinY = imRas.getMinY(); int dstMaxY = dstMinY + imRas.getHeight() - 1; // Determine which pixels will be updated in this pass int[] vals = computeUpdatedPixels(sourceRegion, destinationOffset, dstMinX, dstMinY, dstMaxX, dstMaxY, sourceXSubsampling, sourceYSubsampling, xStart, yStart, passWidth, passHeight, xStep, yStep); int updateMinX = vals[0]; int updateMinY = vals[1]; int updateWidth = vals[2]; int updateXStep = vals[4]; int updateYStep = vals[5]; int bitDepth = metadata.IHDR_bitDepth; int inputBands = inputBandsForColorType[metadata.IHDR_colorType]; int bytesPerPixel = (bitDepth == 16) ? 2 : 1; bytesPerPixel *= inputBands; int bytesPerRow = (inputBands*passWidth*bitDepth + 7)/8; int eltsPerRow = (bitDepth == 16) ? bytesPerRow/2 : bytesPerRow; // If no pixels need updating, just skip the input data if (updateWidth == 0) { for (int srcY = 0; srcY < passHeight; srcY++) { // Update count of pixels read updateImageProgress(passWidth); pixelStream.skipBytes(1 + bytesPerRow); } return; } // Backwards map from destination pixels // (dstX = updateMinX + k*updateXStep) // to source pixels (sourceX), and then // to offset and skip in passRow (srcX and srcXStep) int sourceX = (updateMinX - destinationOffset.x)*sourceXSubsampling + sourceRegion.x; int srcX = (sourceX - xStart)/xStep; // Compute the step factor in the source int srcXStep = updateXStep*sourceXSubsampling/xStep; byte[] byteData = null; short[] shortData = null; byte[] curr = new byte[bytesPerRow]; byte[] prior = new byte[bytesPerRow]; // Create a 1-row tall Raster to hold the data WritableRaster passRow = createRaster(passWidth, 1, inputBands, eltsPerRow, bitDepth); // Create an array suitable for holding one pixel int[] ps = passRow.getPixel(0, 0, (int[])null); DataBuffer dataBuffer = passRow.getDataBuffer(); int type = dataBuffer.getDataType(); if (type == DataBuffer.TYPE_BYTE) { byteData = ((DataBufferByte)dataBuffer).getData(); } else { shortData = ((DataBufferUShort)dataBuffer).getData(); } processPassStarted(theImage, passNum, sourceMinProgressivePass, sourceMaxProgressivePass, updateMinX, updateMinY, updateXStep, updateYStep, destinationBands); // Handle source and destination bands if (sourceBands != null) { passRow = passRow.createWritableChild(0, 0, passRow.getWidth(), 1, 0, 0, sourceBands); } if (destinationBands != null) { imRas = imRas.createWritableChild(0, 0, imRas.getWidth(), imRas.getHeight(), 0, 0, destinationBands); } // Determine if all of the relevant output bands have the // same bit depth as the source data boolean adjustBitDepths = false; int[] outputSampleSize = imRas.getSampleModel().getSampleSize(); int numBands = outputSampleSize.length; for (int b = 0; b < numBands; b++) { if (outputSampleSize[b] != bitDepth) { adjustBitDepths = true; break; } } // If the bit depths differ, create a lookup table per band to perform // the conversion int[][] scale = null; if (adjustBitDepths) { int maxInSample = (1 << bitDepth) - 1; int halfMaxInSample = maxInSample/2; scale = new int[numBands][]; for (int b = 0; b < numBands; b++) { int maxOutSample = (1 << outputSampleSize[b]) - 1; scale[b] = new int[maxInSample + 1]; for (int s = 0; s <= maxInSample; s++) { scale[b][s] = (s*maxOutSample + halfMaxInSample)/maxInSample; } } } // Limit passRow to relevant area for the case where we // will can setRect to copy a contiguous span boolean useSetRect = srcXStep == 1 && updateXStep == 1 && !adjustBitDepths; if (useSetRect) { passRow = passRow.createWritableChild(srcX, 0, updateWidth, 1, 0, 0, null); } // Decode the (sub)image row-by-row for (int srcY = 0; srcY < passHeight; srcY++) { // Update count of pixels read
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -