From b596014c8152fbd96541cbf8b421cf06f7733d80 Mon Sep 17 00:00:00 2001 From: stfm Date: Sat, 23 Jun 2012 13:58:25 +0200 Subject: [PATCH] removed PngEncoder sources, added PngEncoder lib as maven dependency --- pom.xml | 8 + src/main/java/com/keypoint/PngEncoder.java | 621 -------------------- src/main/java/com/keypoint/PngEncoderB.java | 415 ------------- 3 files changed, 8 insertions(+), 1036 deletions(-) delete mode 100755 src/main/java/com/keypoint/PngEncoder.java delete mode 100755 src/main/java/com/keypoint/PngEncoderB.java diff --git a/pom.xml b/pom.xml index 44bf20f..aa8e814 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,14 @@ TeXDoclet + + + + com.keypoint + png-encoder + 1.5 + + diff --git a/src/main/java/com/keypoint/PngEncoder.java b/src/main/java/com/keypoint/PngEncoder.java deleted file mode 100755 index d3e1888..0000000 --- a/src/main/java/com/keypoint/PngEncoder.java +++ /dev/null @@ -1,621 +0,0 @@ -package com.keypoint; - -/** - * PngEncoder takes a Java Image object and creates a byte string which can be saved as a PNG file. - * The Image is presumed to use the DirectColorModel. - * - * Thanks to Jay Denny at KeyPoint Software - * http://www.keypoint.com/ - * who let me develop this code on company time. - * - * You may contact me with (probably very-much-needed) improvements, - * comments, and bug fixes at: - * - * david@catcode.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * A copy of the GNU LGPL may be found at - * http://www.gnu.org/copyleft/lesser.html, - * - * @author J. David Eisenberg - * @version 1.4, 31 March 2000 - */ - -import java.awt.*; -import java.awt.image.*; -import java.util.*; -import java.util.zip.*; -import java.io.*; - -public class PngEncoder extends Object -{ - /** Constant specifying that alpha channel should be encoded. */ - public static final boolean ENCODE_ALPHA=true; - /** Constant specifying that alpha channel should not be encoded. */ - public static final boolean NO_ALPHA=false; - /** Constants for filters */ - public static final int FILTER_NONE = 0; - public static final int FILTER_SUB = 1; - public static final int FILTER_UP = 2; - public static final int FILTER_LAST = 2; - - protected byte[] pngBytes; - protected byte[] priorRow; - protected byte[] leftBytes; - protected Image image; - protected int width, height; - protected int bytePos, maxPos; - protected int hdrPos, dataPos, endPos; - protected CRC32 crc = new CRC32(); - protected long crcValue; - protected boolean encodeAlpha; - protected int filter; - protected int bytesPerPixel; - protected int compressionLevel; - - /** - * Class constructor - * - */ - public PngEncoder() - { - this( null, false, FILTER_NONE, 0 ); - } - - /** - * Class constructor specifying Image to encode, with no alpha channel encoding. - * - * @param image A Java Image object which uses the DirectColorModel - * @see java.awt.Image - */ - public PngEncoder( Image image ) - { - this(image, false, FILTER_NONE, 0); - } - - /** - * Class constructor specifying Image to encode, and whether to encode alpha. - * - * @param image A Java Image object which uses the DirectColorModel - * @param encodeAlpha Encode the alpha channel? false=no; true=yes - * @see java.awt.Image - */ - public PngEncoder( Image image, boolean encodeAlpha ) - { - this(image, encodeAlpha, FILTER_NONE, 0); - } - - /** - * Class constructor specifying Image to encode, whether to encode alpha, and filter to use. - * - * @param image A Java Image object which uses the DirectColorModel - * @param encodeAlpha Encode the alpha channel? false=no; true=yes - * @param whichFilter 0=none, 1=sub, 2=up - * @see java.awt.Image - */ - public PngEncoder( Image image, boolean encodeAlpha, int whichFilter ) - { - this( image, encodeAlpha, whichFilter, 0 ); - } - - - /** - * Class constructor specifying Image source to encode, whether to encode alpha, filter to use, and compression level. - * - * @param image A Java Image object - * @param encodeAlpha Encode the alpha channel? false=no; true=yes - * @param whichFilter 0=none, 1=sub, 2=up - * @param compLevel 0..9 - * @see java.awt.Image - */ - public PngEncoder( Image image, boolean encodeAlpha, int whichFilter, - int compLevel) - { - this.image = image; - this.encodeAlpha = encodeAlpha; - setFilter( whichFilter ); - if (compLevel >=0 && compLevel <=9) - { - this.compressionLevel = compLevel; - } - } - - /** - * Set the image to be encoded - * - * @param image A Java Image object which uses the DirectColorModel - * @see java.awt.Image - * @see java.awt.image.DirectColorModel - */ - public void setImage( Image image ) - { - this.image = image; - pngBytes = null; - } - - /** - * Creates an array of bytes that is the PNG equivalent of the current image, specifying whether to encode alpha or not. - * - * @param encodeAlpha boolean false=no alpha, true=encode alpha - * @return an array of bytes, or null if there was a problem - */ - public byte[] pngEncode( boolean encodeAlpha ) - { - byte[] pngIdBytes = { -119, 80, 78, 71, 13, 10, 26, 10 }; - int i; - - if (image == null) - { - return null; - } - width = image.getWidth( null ); - height = image.getHeight( null ); - this.image = image; - - /* - * start with an array that is big enough to hold all the pixels - * (plus filter bytes), and an extra 200 bytes for header info - */ - pngBytes = new byte[((width+1) * height * 3) + 200]; - - /* - * keep track of largest byte written to the array - */ - maxPos = 0; - - bytePos = writeBytes( pngIdBytes, 0 ); - hdrPos = bytePos; - writeHeader(); - dataPos = bytePos; - if (writeImageData()) - { - writeEnd(); - pngBytes = resizeByteArray( pngBytes, maxPos ); - } - else - { - pngBytes = null; - } - return pngBytes; - } - - /** - * Creates an array of bytes that is the PNG equivalent of the current image. - * Alpha encoding is determined by its setting in the constructor. - * - * @return an array of bytes, or null if there was a problem - */ - public byte[] pngEncode() - { - return pngEncode( encodeAlpha ); - } - - /** - * Set the alpha encoding on or off. - * - * @param encodeAlpha false=no, true=yes - */ - public void setEncodeAlpha( boolean encodeAlpha ) - { - this.encodeAlpha = encodeAlpha; - } - - /** - * Retrieve alpha encoding status. - * - * @return boolean false=no, true=yes - */ - public boolean getEncodeAlpha() - { - return encodeAlpha; - } - - /** - * Set the filter to use - * - * @param whichFilter from constant list - */ - public void setFilter( int whichFilter ) - { - this.filter = FILTER_NONE; - if ( whichFilter <= FILTER_LAST ) - { - this.filter = whichFilter; - } - } - - /** - * Retrieve filtering scheme - * - * @return int (see constant list) - */ - public int getFilter() - { - return filter; - } - - /** - * Set the compression level to use - * - * @param level 0 through 9 - */ - public void setCompressionLevel( int level ) - { - if ( level >= 0 && level <= 9) - { - this.compressionLevel = level; - } - } - - /** - * Retrieve compression level - * - * @return int in range 0-9 - */ - public int getCompressionLevel() - { - return compressionLevel; - } - - /** - * Increase or decrease the length of a byte array. - * - * @param array The original array. - * @param newLength The length you wish the new array to have. - * @return Array of newly desired length. If shorter than the - * original, the trailing elements are truncated. - */ - protected byte[] resizeByteArray( byte[] array, int newLength ) - { - byte[] newArray = new byte[newLength]; - int oldLength = array.length; - - System.arraycopy( array, 0, newArray, 0, - Math.min( oldLength, newLength ) ); - return newArray; - } - - /** - * Write an array of bytes into the pngBytes array. - * Note: This routine has the side effect of updating - * maxPos, the largest element written in the array. - * The array is resized by 1000 bytes or the length - * of the data to be written, whichever is larger. - * - * @param data The data to be written into pngBytes. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - */ - protected int writeBytes( byte[] data, int offset ) - { - maxPos = Math.max( maxPos, offset + data.length ); - if (data.length + offset > pngBytes.length) - { - pngBytes = resizeByteArray( pngBytes, pngBytes.length + - Math.max( 1000, data.length ) ); - } - System.arraycopy( data, 0, pngBytes, offset, data.length ); - return offset + data.length; - } - - /** - * Write an array of bytes into the pngBytes array, specifying number of bytes to write. - * Note: This routine has the side effect of updating - * maxPos, the largest element written in the array. - * The array is resized by 1000 bytes or the length - * of the data to be written, whichever is larger. - * - * @param data The data to be written into pngBytes. - * @param nBytes The number of bytes to be written. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - */ - protected int writeBytes( byte[] data, int nBytes, int offset ) - { - maxPos = Math.max( maxPos, offset + nBytes ); - if (nBytes + offset > pngBytes.length) - { - pngBytes = resizeByteArray( pngBytes, pngBytes.length + - Math.max( 1000, nBytes ) ); - } - System.arraycopy( data, 0, pngBytes, offset, nBytes ); - return offset + nBytes; - } - - /** - * Write a two-byte integer into the pngBytes array at a given position. - * - * @param n The integer to be written into pngBytes. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - */ - protected int writeInt2( int n, int offset ) - { - byte[] temp = { (byte)((n >> 8) & 0xff), - (byte) (n & 0xff) }; - return writeBytes( temp, offset ); - } - - /** - * Write a four-byte integer into the pngBytes array at a given position. - * - * @param n The integer to be written into pngBytes. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - */ - protected int writeInt4( int n, int offset ) - { - byte[] temp = { (byte)((n >> 24) & 0xff), - (byte) ((n >> 16) & 0xff ), - (byte) ((n >> 8) & 0xff ), - (byte) ( n & 0xff ) }; - return writeBytes( temp, offset ); - } - - /** - * Write a single byte into the pngBytes array at a given position. - * - * @param n The integer to be written into pngBytes. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - */ - protected int writeByte( int b, int offset ) - { - byte[] temp = { (byte) b }; - return writeBytes( temp, offset ); - } - - /** - * Write a string into the pngBytes array at a given position. - * This uses the getBytes method, so the encoding used will - * be its default. - * - * @param n The integer to be written into pngBytes. - * @param offset The starting point to write to. - * @return The next place to be written to in the pngBytes array. - * @see java.lang.String#getBytes() - */ - protected int writeString( String s, int offset ) - { - return writeBytes( s.getBytes(), offset ); - } - - /** - * Write a PNG "IHDR" chunk into the pngBytes array. - */ - protected void writeHeader() - { - int startPos; - - startPos = bytePos = writeInt4( 13, bytePos ); - bytePos = writeString( "IHDR", bytePos ); - width = image.getWidth( null ); - height = image.getHeight( null ); - bytePos = writeInt4( width, bytePos ); - bytePos = writeInt4( height, bytePos ); - bytePos = writeByte( 8, bytePos ); // bit depth - bytePos = writeByte( (encodeAlpha) ? 6 : 2, bytePos ); // direct model - bytePos = writeByte( 0, bytePos ); // compression method - bytePos = writeByte( 0, bytePos ); // filter method - bytePos = writeByte( 0, bytePos ); // no interlace - crc.reset(); - crc.update( pngBytes, startPos, bytePos-startPos ); - crcValue = crc.getValue(); - bytePos = writeInt4( (int) crcValue, bytePos ); - } - - /** - * Perform "sub" filtering on the given row. - * Uses temporary array leftBytes to store the original values - * of the previous pixels. The array is 16 bytes long, which - * will easily hold two-byte samples plus two-byte alpha. - * - * @param pixels The array holding the scan lines being built - * @param startPos Starting position within pixels of bytes to be filtered. - * @param width Width of a scanline in pixels. - */ - protected void filterSub( byte[] pixels, int startPos, int width ) - { - int i; - int offset = bytesPerPixel; - int actualStart = startPos + offset; - int nBytes = width * bytesPerPixel; - int leftInsert = offset; - int leftExtract = 0; - byte current_byte; - - for (i=actualStart; i < startPos + nBytes; i++) - { - leftBytes[leftInsert] = pixels[i]; - pixels[i] = (byte) ((pixels[i] - leftBytes[leftExtract]) % 256); - leftInsert = (leftInsert+1) % 0x0f; - leftExtract = (leftExtract + 1) % 0x0f; - } - } - - /** - * Perform "up" filtering on the given row. - * Side effect: refills the prior row with current row - * - * @param pixels The array holding the scan lines being built - * @param startPos Starting position within pixels of bytes to be filtered. - * @param width Width of a scanline in pixels. - */ - protected void filterUp( byte[] pixels, int startPos, int width ) - { - int i, nBytes; - byte current_byte; - - nBytes = width * bytesPerPixel; - - for (i=0; i < nBytes; i++) - { - current_byte = pixels[startPos + i]; - pixels[startPos + i] = (byte) ((pixels[startPos + i] - priorRow[i]) % 256); - priorRow[i] = current_byte; - } - } - - /** - * Write the image data into the pngBytes array. - * This will write one or more PNG "IDAT" chunks. In order - * to conserve memory, this method grabs as many rows as will - * fit into 32K bytes, or the whole image; whichever is less. - * - * - * @return true if no errors; false if error grabbing pixels - */ - protected boolean writeImageData() - { - int rowsLeft = height; // number of rows remaining to write - int startRow = 0; // starting row to process this time through - int nRows; // how many rows to grab at a time - - byte[] scanLines; // the scan lines to be compressed - int scanPos; // where we are in the scan lines - int startPos; // where this line's actual pixels start (used for filtering) - - byte[] compressedLines; // the resultant compressed lines - int nCompressed; // how big is the compressed area? - - int depth; // color depth ( handle only 8 or 32 ) - - PixelGrabber pg; - - bytesPerPixel = (encodeAlpha) ? 4 : 3; - - Deflater scrunch = new Deflater( compressionLevel ); - ByteArrayOutputStream outBytes = - new ByteArrayOutputStream(1024); - - DeflaterOutputStream compBytes = - new DeflaterOutputStream( outBytes, scrunch ); - try - { - while (rowsLeft > 0) - { - nRows = Math.min( 32767 / (width*(bytesPerPixel+1)), rowsLeft ); - // nRows = rowsLeft; - - int[] pixels = new int[width * nRows]; - - pg = new PixelGrabber(image, 0, startRow, - width, nRows, pixels, 0, width); - try { - pg.grabPixels(); - } - catch (Exception e) { - System.err.println("interrupted waiting for pixels!"); - return false; - } - if ((pg.getStatus() & ImageObserver.ABORT) != 0) { - System.err.println("image fetch aborted or errored"); - return false; - } - - /* - * Create a data chunk. scanLines adds "nRows" for - * the filter bytes. - */ - scanLines = new byte[width * nRows * bytesPerPixel + nRows]; - - if (filter == FILTER_SUB) - { - leftBytes = new byte[16]; - } - if (filter == FILTER_UP) - { - priorRow = new byte[width*bytesPerPixel]; - } - - scanPos = 0; - startPos = 1; - for (int i=0; i> 16) & 0xff); - scanLines[scanPos++] = (byte) ((pixels[i] >> 8) & 0xff); - scanLines[scanPos++] = (byte) ((pixels[i] ) & 0xff); - if (encodeAlpha) - { - scanLines[scanPos++] = (byte) ((pixels[i] >> 24) & 0xff ); - } - if ((i % width == width-1) && (filter != FILTER_NONE)) - { - if (filter == FILTER_SUB) - { - filterSub( scanLines, startPos, width ); - } - if (filter == FILTER_UP) - { - filterUp( scanLines, startPos, width ); - } - } - } - - /* - * Write these lines to the output area - */ - compBytes.write( scanLines, 0, scanPos ); - - - startRow += nRows; - rowsLeft -= nRows; - } - compBytes.close(); - - /* - * Write the compressed bytes - */ - compressedLines = outBytes.toByteArray(); - nCompressed = compressedLines.length; - - crc.reset(); - bytePos = writeInt4( nCompressed, bytePos ); - bytePos = writeString("IDAT", bytePos ); - crc.update("IDAT".getBytes()); - bytePos = writeBytes( compressedLines, nCompressed, bytePos ); - crc.update( compressedLines, 0, nCompressed ); - - crcValue = crc.getValue(); - bytePos = writeInt4( (int) crcValue, bytePos ); - scrunch.finish(); - return true; - } - catch (IOException e) - { - System.err.println( e.toString()); - return false; - } - } - - /** - * Write a PNG "IEND" chunk into the pngBytes array. - */ - protected void writeEnd() - { - bytePos = writeInt4( 0, bytePos ); - bytePos = writeString( "IEND", bytePos ); - crc.reset(); - crc.update("IEND".getBytes()); - crcValue = crc.getValue(); - bytePos = writeInt4( (int) crcValue, bytePos ); - } -} - diff --git a/src/main/java/com/keypoint/PngEncoderB.java b/src/main/java/com/keypoint/PngEncoderB.java deleted file mode 100755 index 6d127bb..0000000 --- a/src/main/java/com/keypoint/PngEncoderB.java +++ /dev/null @@ -1,415 +0,0 @@ -package com.keypoint; - -/** - * PngEncoderB takes a Java BufferedImage object and creates a byte string which can be saved as a PNG file. - * The encoder will accept BufferedImages with eight-bit samples - * or 4-byte ARGB samples. - * - * There is also code to handle 4-byte samples returned as - * one int per pixel, but that has not been tested. - * - * Thanks to Jay Denny at KeyPoint Software - * http://www.keypoint.com/ - * who let me develop this code on company time. - * - * You may contact me with (probably very-much-needed) improvements, - * comments, and bug fixes at: - * - * david@catcode.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * A copy of the GNU LGPL may be found at - * http://www.gnu.org/copyleft/lesser.html, - * - * @author J. David Eisenberg - * @version 1.4, 31 March 2000 - */ - -import java.awt.image.BufferedImage; -import java.awt.image.DataBuffer; -import java.awt.image.IndexColorModel; -import java.awt.image.WritableRaster; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.zip.Deflater; -import java.util.zip.DeflaterOutputStream; - -public class PngEncoderB extends PngEncoder { - protected BufferedImage image; - protected WritableRaster wRaster; - protected int tType; - - /** - * Class constructor - * - */ - public PngEncoderB() { - this(null, false, FILTER_NONE, 0); - } - - /** - * Class constructor specifying BufferedImage to encode, with no alpha - * channel encoding. - * - * @param image - * A Java BufferedImage object - */ - public PngEncoderB(BufferedImage image) { - this(image, false, FILTER_NONE, 0); - } - - /** - * Class constructor specifying BufferedImage to encode, and whether to - * encode alpha. - * - * @param image - * A Java BufferedImage object - * @param encodeAlpha - * Encode the alpha channel? false=no; true=yes - */ - public PngEncoderB(BufferedImage image, boolean encodeAlpha) { - this(image, encodeAlpha, FILTER_NONE, 0); - } - - /** - * Class constructor specifying BufferedImage to encode, whether to encode - * alpha, and filter to use. - * - * @param image - * A Java BufferedImage object - * @param encodeAlpha - * Encode the alpha channel? false=no; true=yes - * @param whichFilter - * 0=none, 1=sub, 2=up - */ - public PngEncoderB(BufferedImage image, boolean encodeAlpha, int whichFilter) { - this(image, encodeAlpha, whichFilter, 0); - } - - /** - * Class constructor specifying BufferedImage source to encode, whether to - * encode alpha, filter to use, and compression level - * - * @param image - * A Java BufferedImage object - * @param encodeAlpha - * Encode the alpha channel? false=no; true=yes - * @param whichFilter - * 0=none, 1=sub, 2=up - * @param compLevel - * 0..9 - */ - public PngEncoderB(BufferedImage image, boolean encodeAlpha, - int whichFilter, int compLevel) { - this.image = image; - this.encodeAlpha = encodeAlpha; - setFilter(whichFilter); - if (compLevel >= 0 && compLevel <= 9) { - this.compressionLevel = compLevel; - } - } - - /** - * Set the BufferedImage to be encoded - * - * @param BufferedImage - * A Java BufferedImage object - */ - public void setImage(BufferedImage image) { - this.image = image; - pngBytes = null; - } - - /** - * Creates an array of bytes that is the PNG equivalent of the current - * image, specifying whether to encode alpha or not. - * - * @param encodeAlpha - * boolean false=no alpha, true=encode alpha - * @return an array of bytes, or null if there was a problem - */ - @Override - public byte[] pngEncode(boolean encodeAlpha) { - byte[] pngIdBytes = { -119, 80, 78, 71, 13, 10, 26, 10 }; - int i; - - if (image == null) { - return null; - } - width = image.getWidth(null); - height = image.getHeight(null); - this.image = image; - - if (!establishStorageInfo()) { - return null; - } - - /* - * start with an array that is big enough to hold all the pixels (plus - * filter bytes), and an extra 200 bytes for header info - */ - pngBytes = new byte[((width + 1) * height * 3) + 200]; - - /* - * keep track of largest byte written to the array - */ - maxPos = 0; - - bytePos = writeBytes(pngIdBytes, 0); - hdrPos = bytePos; - writeHeader(); - dataPos = bytePos; - if (writeImageData()) { - writeEnd(); - pngBytes = resizeByteArray(pngBytes, maxPos); - } else { - pngBytes = null; - } - return pngBytes; - } - - /** - * Creates an array of bytes that is the PNG equivalent of the current - * image. Alpha encoding is determined by its setting in the constructor. - * - * @return an array of bytes, or null if there was a problem - */ - @Override - public byte[] pngEncode() { - return pngEncode(encodeAlpha); - } - - /** - * - * Get and set variables that determine how picture is stored. - * - * Retrieves the writable raster of the buffered image, as well its transfer - * type. - * - * Sets number of output bytes per pixel, and, if only eight-bit bytes, - * turns off alpha encoding. - * - * @return true if 1-byte or 4-byte data, false otherwise - */ - protected boolean establishStorageInfo() { - int dataBytes; - - wRaster = image.getRaster(); - dataBytes = wRaster.getNumDataElements(); - tType = wRaster.getTransferType(); - - if (((tType == DataBuffer.TYPE_BYTE) && (dataBytes == 4)) - || ((tType == DataBuffer.TYPE_INT) && (dataBytes == 1))) { - bytesPerPixel = (encodeAlpha) ? 4 : 3; - } else if ((tType == DataBuffer.TYPE_BYTE) && (dataBytes == 1)) { - bytesPerPixel = 1; - encodeAlpha = false; // one-byte samples - } else { - return false; - } - return true; - } - - /** - * Write a PNG "IHDR" chunk into the pngBytes array. - */ - @Override - protected void writeHeader() { - int startPos; - - startPos = bytePos = writeInt4(13, bytePos); - bytePos = writeString("IHDR", bytePos); - width = image.getWidth(null); - height = image.getHeight(null); - bytePos = writeInt4(width, bytePos); - bytePos = writeInt4(height, bytePos); - bytePos = writeByte(8, bytePos); // bit depth - if (bytesPerPixel != 1) { - bytePos = writeByte((encodeAlpha) ? 6 : 2, bytePos); // direct model - } else { - bytePos = writeByte(3, bytePos); // indexed - } - bytePos = writeByte(0, bytePos); // compression method - bytePos = writeByte(0, bytePos); // filter method - bytePos = writeByte(0, bytePos); // no interlace - crc.reset(); - crc.update(pngBytes, startPos, bytePos - startPos); - crcValue = crc.getValue(); - bytePos = writeInt4((int) crcValue, bytePos); - } - - protected void writePalette(IndexColorModel icm) { - byte[] redPal = new byte[256]; - byte[] greenPal = new byte[256]; - byte[] bluePal = new byte[256]; - byte[] allPal = new byte[768]; - int i; - - icm.getReds(redPal); - icm.getGreens(greenPal); - icm.getBlues(bluePal); - for (i = 0; i < 256; i++) { - allPal[i * 3] = redPal[i]; - allPal[i * 3 + 1] = greenPal[i]; - allPal[i * 3 + 2] = bluePal[i]; - } - bytePos = writeInt4(768, bytePos); - bytePos = writeString("PLTE", bytePos); - crc.reset(); - crc.update("PLTE".getBytes()); - bytePos = writeBytes(allPal, bytePos); - crc.update(allPal); - crcValue = crc.getValue(); - bytePos = writeInt4((int) crcValue, bytePos); - } - - /** - * Write the image data into the pngBytes array. This will write one or more - * PNG "IDAT" chunks. In order to conserve memory, this method grabs as many - * rows as will fit into 32K bytes, or the whole image; whichever is less. - * - * - * @return true if no errors; false if error grabbing pixels - */ - @Override - protected boolean writeImageData() { - int rowsLeft = height; // number of rows remaining to write - int startRow = 0; // starting row to process this time through - int nRows; // how many rows to grab at a time - - byte[] scanLines; // the scan lines to be compressed - int scanPos; // where we are in the scan lines - int startPos; // where this line's actual pixels start (used for - // filtering) - int readPos; // position from which source pixels are read - - byte[] compressedLines; // the resultant compressed lines - int nCompressed; // how big is the compressed area? - - byte[] pixels; // storage area for byte-sized pixels - int[] iPixels; // storage area for int-sized pixels - - Deflater scrunch = new Deflater(compressionLevel); - ByteArrayOutputStream outBytes = new ByteArrayOutputStream(1024); - - DeflaterOutputStream compBytes = new DeflaterOutputStream(outBytes, - scrunch); - - if (bytesPerPixel == 1) { - writePalette((IndexColorModel) image.getColorModel()); - } - - try { - while (rowsLeft > 0) { - nRows = Math.min(32767 / (width * (bytesPerPixel + 1)), - rowsLeft); - // nRows = rowsLeft; - - /* - * Create a data chunk. scanLines adds "nRows" for the filter - * bytes. - */ - scanLines = new byte[width * nRows * bytesPerPixel + nRows]; - - if (filter == FILTER_SUB) { - leftBytes = new byte[16]; - } - if (filter == FILTER_UP) { - priorRow = new byte[width * bytesPerPixel]; - } - - if (tType == DataBuffer.TYPE_BYTE) { - pixels = (byte[]) wRaster.getDataElements(0, startRow, - width, nRows, null); - iPixels = null; - } else { - iPixels = (int[]) wRaster.getDataElements(0, startRow, - width, nRows, null); - pixels = null; - } - - scanPos = 0; - readPos = 0; - startPos = 1; - for (int i = 0; i < width * nRows; i++) { - if (i % width == 0) { - scanLines[scanPos++] = (byte) filter; - startPos = scanPos; - } - - if (bytesPerPixel == 1) { - scanLines[scanPos++] = pixels[readPos++]; - } else if (tType == DataBuffer.TYPE_BYTE) { - scanLines[scanPos++] = pixels[readPos++]; - scanLines[scanPos++] = pixels[readPos++]; - scanLines[scanPos++] = pixels[readPos++]; - if (encodeAlpha) { - scanLines[scanPos++] = pixels[readPos++]; - } else { - readPos++; - } - } else { - scanLines[scanPos++] = (byte) ((iPixels[readPos] >> 16) & 0xff); - scanLines[scanPos++] = (byte) ((iPixels[readPos] >> 8) & 0xff); - scanLines[scanPos++] = (byte) ((iPixels[readPos]) & 0xff); - if (encodeAlpha) { - scanLines[scanPos++] = (byte) ((iPixels[readPos] >> 24) & 0xff); - } - readPos++; - } - if ((i % width == width - 1) && (filter != FILTER_NONE)) { - if (filter == FILTER_SUB) { - filterSub(scanLines, startPos, width); - } - if (filter == FILTER_UP) { - filterUp(scanLines, startPos, width); - } - } - } - - /* - * Write these lines to the output area - */ - compBytes.write(scanLines, 0, scanPos); - - startRow += nRows; - rowsLeft -= nRows; - } - compBytes.close(); - - /* - * Write the compressed bytes - */ - compressedLines = outBytes.toByteArray(); - nCompressed = compressedLines.length; - - crc.reset(); - bytePos = writeInt4(nCompressed, bytePos); - bytePos = writeString("IDAT", bytePos); - crc.update("IDAT".getBytes()); - bytePos = writeBytes(compressedLines, nCompressed, bytePos); - crc.update(compressedLines, 0, nCompressed); - - crcValue = crc.getValue(); - bytePos = writeInt4((int) crcValue, bytePos); - scrunch.finish(); - return true; - } catch (IOException e) { - System.err.println(e.toString()); - return false; - } - } - -}