?? pngfileformat.java
字號:
void setImageDataValues(byte[] data, ImageData imageData) { byte[] result = validateBitDepth(data); setPixelData(result, imageData);}/** * Read the image data from the data stream. This must handle * decoding the data, filtering, and interlacing. */void readPixelData(PngIdatChunk chunk, PngChunkReader chunkReader) { decodingStream = new PngDecodingDataStream(chunk, chunkReader); int interlaceMethod = headerChunk.getInterlaceMethod(); if (interlaceMethod == PngIhdrChunk.INTERLACE_METHOD_NONE) { readNonInterlacedImage(); } else { readInterlacedImage(); } decodingStream.assertImageDataAtEnd(); decodingStream.checkAdler();}/** * Answer the number of bytes in a word-aligned row of pixel data. */int getAlignedBytesPerRow() { return ((getBytesPerRow(headerChunk.getWidth()) + 3) / 4) * 4;}/** * Answer the number of bytes in each row of the image * data. Each PNG row is byte-aligned, so images with bit * depths less than a byte may have unused bits at the * end of each row. The value of these bits is undefined. */int getBytesPerRow() { return getBytesPerRow(headerChunk.getWidth());}/** * Answer the number of bytes needed to represent a pixel. * This value depends on the image's color type and bit * depth. * Note that this method rounds up if an image's pixel size * isn't byte-aligned. */int getBytesPerPixel() { int bitsPerPixel = headerChunk.getBitsPerPixel(); return (bitsPerPixel + 7) / 8; }/** * Answer the number of bytes in a row of the given pixel * width. Each row is byte-aligned, so images with bit * depths less than a byte may have unused bits at the * end of each row. The value of these bits is undefined. */int getBytesPerRow(int rowWidthInPixels) { int bitsPerPixel = headerChunk.getBitsPerPixel(); int bitsPerRow = bitsPerPixel * rowWidthInPixels; int bitsPerByte = 8; return (bitsPerRow + (bitsPerByte - 1)) / bitsPerByte;}/** * 1. Read one of the seven frames of interlaced data. * 2. Update the imageData. * 3. Notify the image loader's listeners of the frame load. */void readInterlaceFrame( int rowInterval, int columnInterval, int startRow, int startColumn, int frameCount) { int width = headerChunk.getWidth(); int alignedBytesPerRow = getAlignedBytesPerRow(); int height = headerChunk.getHeight(); if (startRow >= height || startColumn >= width) return; int pixelsPerRow = (width - startColumn + columnInterval - 1) / columnInterval; int bytesPerRow = getBytesPerRow(pixelsPerRow); byte[] row1 = new byte[bytesPerRow]; byte[] row2 = new byte[bytesPerRow]; byte[] currentRow = row1; byte[] lastRow = row2; for (int row = startRow; row < height; row += rowInterval) { byte filterType = decodingStream.getNextDecodedByte(); for (int col = 0; col < bytesPerRow; col++) { currentRow[col] = decodingStream.getNextDecodedByte(); } filterRow(currentRow, lastRow, filterType); if (headerChunk.getBitDepth() >= 8) { int bytesPerPixel = getBytesPerPixel(); int dataOffset = (row * alignedBytesPerRow) + (startColumn * bytesPerPixel); for (int rowOffset = 0; rowOffset < currentRow.length; rowOffset += bytesPerPixel) { for (int byteOffset = 0; byteOffset < bytesPerPixel; byteOffset++) { data[dataOffset + byteOffset] = currentRow[rowOffset + byteOffset]; } dataOffset += (columnInterval * bytesPerPixel); } } else { int bitsPerPixel = headerChunk.getBitDepth(); int pixelsPerByte = 8 / bitsPerPixel; int column = startColumn; int rowBase = row * alignedBytesPerRow; int valueMask = 0; for (int i = 0; i < bitsPerPixel; i++) { valueMask <<= 1; valueMask |= 1; } int maxShift = 8 - bitsPerPixel; for (int byteOffset = 0; byteOffset < currentRow.length; byteOffset++) { for (int bitOffset = maxShift; bitOffset >= 0; bitOffset -= bitsPerPixel) { if (column < width) { int dataOffset = rowBase + (column * bitsPerPixel / 8); int value = (currentRow[byteOffset] >> bitOffset) & valueMask; int dataShift = maxShift - (bitsPerPixel * (column % pixelsPerByte)); data[dataOffset] |= value << dataShift; } column += columnInterval; } } } currentRow = (currentRow == row1) ? row2 : row1; lastRow = (lastRow == row1) ? row2 : row1; } setImageDataValues(data, imageData); fireInterlacedFrameEvent(frameCount);}/** * Read the pixel data for an interlaced image from the * data stream. */void readInterlacedImage() { readInterlaceFrame(8, 8, 0, 0, 0); readInterlaceFrame(8, 8, 0, 4, 1); readInterlaceFrame(8, 4, 4, 0, 2); readInterlaceFrame(4, 4, 0, 2, 3); readInterlaceFrame(4, 2, 2, 0, 4); readInterlaceFrame(2, 2, 0, 1, 5); readInterlaceFrame(2, 1, 1, 0, 6);}/** * Fire an event to let listeners know that an interlaced * frame has been loaded. * finalFrame should be true if the image has finished * loading, false if there are more frames to come. */void fireInterlacedFrameEvent(int frameCount) { if (loader.hasListeners()) { ImageData image = (ImageData) imageData.clone(); boolean finalFrame = frameCount == 6; loader.notifyListeners(new ImageLoaderEvent(loader, image, frameCount, finalFrame)); }}/** * Read the pixel data for a non-interlaced image from the * data stream. * Update the imageData to reflect the new data. */void readNonInterlacedImage() { int dataOffset = 0; int alignedBytesPerRow = getAlignedBytesPerRow(); int bytesPerRow = getBytesPerRow(); byte[] row1 = new byte[bytesPerRow]; byte[] row2 = new byte[bytesPerRow]; byte[] currentRow = row1; byte[] lastRow = row2; for (int row = 0; row < headerChunk.getHeight(); row++) { byte filterType = decodingStream.getNextDecodedByte(); for (int col = 0; col < bytesPerRow; col++) { currentRow[col] = decodingStream.getNextDecodedByte(); } filterRow(currentRow, lastRow, filterType); System.arraycopy(currentRow, 0, data, dataOffset, bytesPerRow); dataOffset += alignedBytesPerRow; currentRow = (currentRow == row1) ? row2 : row1; lastRow = (lastRow == row1) ? row2 : row1; } setImageDataValues(data, imageData);}/** * SWT does not support 16-bit depth color formats. * Convert the 16-bit data to 8-bit data. * The correct way to do this is to multiply each * 16 bit value by the value: * (2^8 - 1) / (2^16 - 1). * The fast way to do this is just to drop the low * byte of the 16-bit value. */static void compress16BitDepthTo8BitDepth( byte[] source, int sourceOffset, byte[] destination, int destinationOffset, int numberOfValues) { //double multiplier = (Compatibility.pow2(8) - 1) / (Compatibility.pow2(16) - 1); for (int i = 0; i < numberOfValues; i++) { int sourceIndex = sourceOffset + (2 * i); int destinationIndex = destinationOffset + i; //int value = (source[sourceIndex] << 8) | source[sourceIndex + 1]; //byte compressedValue = (byte)(value * multiplier); byte compressedValue = source[sourceIndex]; destination[destinationIndex] = compressedValue; }}/** * SWT does not support 16-bit depth color formats. * Convert the 16-bit data to 8-bit data. * The correct way to do this is to multiply each * 16 bit value by the value: * (2^8 - 1) / (2^16 - 1). * The fast way to do this is just to drop the low * byte of the 16-bit value. */static int compress16BitDepthTo8BitDepth(int value) { //double multiplier = (Compatibility.pow2(8) - 1) / (Compatibility.pow2(16) - 1); //byte compressedValue = (byte)(value * multiplier); return value >> 8;}/** * PNG supports four filtering types. These types are applied * per row of image data. This method unfilters the given row * based on the filterType. */void filterRow(byte[] row, byte[] previousRow, int filterType) { int byteOffset = headerChunk.getFilterByteOffset(); switch (filterType) { case PngIhdrChunk.FILTER_NONE: break; case PngIhdrChunk.FILTER_SUB: for (int i = byteOffset; i < row.length; i++) { int current = row[i] & 0xFF; int left = row[i - byteOffset] & 0xFF; row[i] = (byte)((current + left) & 0xFF); } break; case PngIhdrChunk.FILTER_UP: for (int i = 0; i < row.length; i++) { int current = row[i] & 0xFF; int above = previousRow[i] & 0xFF; row[i] = (byte)((current + above) & 0xFF); } break; case PngIhdrChunk.FILTER_AVERAGE: for (int i = 0; i < row.length; i++) { int left = (i < byteOffset) ? 0 : row[i - byteOffset] & 0xFF; int above = previousRow[i] & 0xFF; int current = row[i] & 0xFF; row[i] = (byte)((current + ((left + above) / 2)) & 0xFF); } break; case PngIhdrChunk.FILTER_PAETH: for (int i = 0; i < row.length; i++) { int left = (i < byteOffset) ? 0 : row[i - byteOffset] & 0xFF; int aboveLeft = (i < byteOffset) ? 0 : previousRow[i - byteOffset] & 0xFF; int above = previousRow[i] & 0xFF; int a = Math.abs(above - aboveLeft); int b = Math.abs(left - aboveLeft); int c = Math.abs(left - aboveLeft + above - aboveLeft); int preductor = 0; if (a <= b && a <= c) { preductor = left; } else if (b <= c) { preductor = above; } else { preductor = aboveLeft; } int currentValue = row[i] & 0xFF; row[i] = (byte) ((currentValue + preductor) & 0xFF); } break; }}}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -