📄 pngimagereader.java
字号:
private static void decodeSubFilter(byte[] curr, int coff, int count, int bpp) { for (int i = bpp; i < count; i++) { int val; val = curr[i + coff] & 0xff; val += curr[i + coff - bpp] & 0xff; curr[i + coff] = (byte)val; } } private static void decodeUpFilter(byte[] curr, int coff, byte[] prev, int poff, int count) { for (int i = 0; i < count; i++) { int raw = curr[i + coff] & 0xff; int prior = prev[i + poff] & 0xff; curr[i + coff] = (byte)(raw + prior); } } private static void decodeAverageFilter(byte[] curr, int coff, byte[] prev, int poff, int count, int bpp) { int raw, priorPixel, priorRow; for (int i = 0; i < bpp; i++) { raw = curr[i + coff] & 0xff; priorRow = prev[i + poff] & 0xff; curr[i + coff] = (byte)(raw + priorRow/2); } for (int i = bpp; i < count; i++) { raw = curr[i + coff] & 0xff; priorPixel = curr[i + coff - bpp] & 0xff; priorRow = prev[i + poff] & 0xff; curr[i + coff] = (byte)(raw + (priorPixel + priorRow)/2); } } private static int paethPredictor(int a, int b, int c) { int p = a + b - c; int pa = Math.abs(p - a); int pb = Math.abs(p - b); int pc = Math.abs(p - c); if ((pa <= pb) && (pa <= pc)) { return a; } else if (pb <= pc) { return b; } else { return c; } } private static void decodePaethFilter(byte[] curr, int coff, byte[] prev, int poff, int count, int bpp) { int raw, priorPixel, priorRow, priorRowPixel; for (int i = 0; i < bpp; i++) { raw = curr[i + coff] & 0xff; priorRow = prev[i + poff] & 0xff; curr[i + coff] = (byte)(raw + priorRow); } for (int i = bpp; i < count; i++) { raw = curr[i + coff] & 0xff; priorPixel = curr[i + coff - bpp] & 0xff; priorRow = prev[i + poff] & 0xff; priorRowPixel = prev[i + poff - bpp] & 0xff; 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; // Read the image row-by-row for (int srcY = 0; srcY < passHeight; srcY++) { // Skip filter byte and the remaining row bytes pixelStream.skipBytes(1 + bytesPerRow); // If read has been aborted, just return // processReadAborted will be called later if (abortRequested()) { return; } } } 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 = ReaderUtil.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); // Skip filter byte and the remaining row bytes 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 updateImageProgress(passWidth); // Read the filter type byte and a row of data int filter = pixelStream.read(); try { // Swap curr and prior byte[] tmp = prior; prior = curr; curr = tmp; pixelStream.readFully(curr, 0, bytesPerRow); } catch (java.util.zip.ZipException ze) { // TODO - throw a more meaningful exception throw ze; } switch (filter) { case PNG_FILTER_NONE: break; case PNG_FILTER_SUB: decodeSubFilter(curr, 0, bytesPerRow, bytesPerPixel); break; case PNG_FILTER_UP: decodeUpFilter(curr, 0, prior, 0, bytesPerRow); break; case PNG_FILTER_AVERAGE: decodeAverageFilter(curr, 0, prior, 0, bytesPerRow, bytesPerPixel); break; case PNG_FILTER_PAETH: decodePaethFilter(curr, 0, prior, 0, bytesPerRow, bytesPerPixel); break; default: throw new IIOException("Unknown row filter type (= " + filter + ")!"); } // Copy data into passRow byte by byte if (bitDepth < 16) { System.arraycopy(curr, 0, byteData, 0, bytesPerRow); } else { int idx = 0; for (int j = 0; j < eltsPerRow; j++) { shortData[j] = (short)((curr[idx] << 8) | (curr[idx + 1] & 0xff)); idx += 2; } } // True Y position in source int sourceY = srcY*yStep + yStart; if ((sourceY >= sourceRegion.y) && (sourceY < sourceRegion.y + sourceRegion.height) && (((sourceY - sourceRegion.y) % sourceYSubsampling) == 0)) { int dstY = destinationOffset.y + (sourceY - sourceRegion.y)/sourceYSubsampling; if (dstY < dstMinY) { continue; } if (dstY > dstMaxY) { break; } if (useSetRect) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -