分享
 
 
 

将Javaimage对象转换成PNG格式字节数组

王朝java/jsp·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

/**

* 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 {

if (i % width == 0)

{

scanLines[scanPos++] = (byte) filter;

startPos = scanPos;

}

scanLines[scanPos++] = (byte) ((pixels[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 );

}

}

出处 http://catcode.com进入讨论组讨论。

(出处:http://www.knowsky.com)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有