PngEncoder类的详细分析

PngEncoder类的详细分析

/*******************************************************
功能:可以把image对象转换成png byte[]但是image必须是黑白图片,而且宽度必须是8的整数被
png图像采用了简单结构无压缩存储,采用索引图像,图像只有黑白俩色,背景白,前景黑
转换后的png把原图的背景变换成白,其他颜色都变换成黑
png中只使用了一个IDAT图像信息块,所以图像大小不能超过56635byte 大概总面积不能超过720*720
时间:2006-08-10
********************************************************/
import java.io.*;
import java.util.*;
import javax.microedition.rms.*;
import javax.microedition.lcdui.*;

class PngEncoder {
private int backColor;//要转换的图片的背景颜色
int[] crc_table = new int[256];//crc校验数组

public PngEncoder(int bc) {
backColor=bc;
make_crc_table();//成生校验数组
}

public PngEncoder() {
backColor=0xFFFFFFFF;//默认图像背景为白
make_crc_table();//成生校验数组
}

//设置背景颜色
public void setBackColor(int bc){
backColor=bc;
}

//资源释放
public void Free(){
crc_table=null;
}

//成生校验数组
private void make_crc_table() {
int c;
for (int n = 0; n <= 255; n++) {
c = n;
for (int k = 0; k <= 7; k++) {
if ( (c & 1) == 1) {
c = 0xEDB88320 ^ ((c >> 1)&0x7FFFFFFF);
}
else {
c = (c >> 1)&0x7FFFFFFF;
}
}
crc_table[n] = c;
}
}

//获得一个byte b的crc校验码,c是上一次的crc校验码,第一次时带入0xFFFFFFFF
public int getByteCRC(int c, byte b) {
return crc_table[ (c ^ b) & 0x000000FF] ^ ((c >> 8)&0x00FFFFFF);
}

//把image转换成png byte[]
public byte[] ImageToPng(Image img){
if(img==null) return null;
byte[] LZ77=null,png=null;
byte bb=0;
int ii=0,crc=0,i=0,j=0,crc2=1,len=0,k=0,ip=0,rawIndex=0;
long s1=0, s2=0;
int wid=0,hei=0;
byte cd=1,ct=3,cc=2;//color depth, color type, color count
wid=img.getWidth(); hei=img.getHeight();//图片的宽度和高度
if ((wid % 8)!=0){wid=(wid / 8 + 1)*8;}//宽度必须是8的整数被
len=(1+(wid*cd) / 8)*hei;//图像数据长度,每行前加0所以每行上多出一个字节,cd是一个像素用几个bit表示的意思
if(len>0xFFFF) return null;//图太大,无法构造,必须使用多重IDAT图像信息块才可以实现,目前没有实现
//对于现在的应用足够了。
LZ77=new byte[len+11];//这里临时存放图像信息,11是辅助位的长度,3个标示,4个长度,4个alter校验位
png =new byte[len+86];//这里存放最终的png格式图片 86是除图像信息以外的所有位的长度,固定为86个
int raw[] = new int[wid*hei];//image的RGB信息,数租中的一个值对应实际图像的一个像素,用0xAARRGGBB的形式存储
img.getRGB(raw, 0, wid, 0, 0, wid, hei);
//PNG文件的标识------------------------------------------
png[ip]=(byte)0x89; ip++;
png[ip]=(byte)0x50; ip++;
png[ip]=(byte)0x4E; ip++;
png[ip]=(byte)0x47; ip++;
png[ip]=(byte)0x0D; ip++;
png[ip]=(byte)0x0A; ip++;
png[ip]=(byte)0x1A; ip++;
png[ip]=(byte)0x0A; ip++;
//------------------------------------------------------

//开始写IHDR头部信息快-------------------------------------
//长度
bb=0; png[ip]=bb; ip++;
bb=0; png[ip]=bb; ip++;
bb=0; png[ip]=bb; ip++;
bb=13; png[ip]=bb; ip++;
//标识
crc=0xFFFFFFFF;
bb=0x49; png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=0x48; png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=0x44; png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=0x52; png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
//宽度
ii=wid;
bb=(byte)((ii >> 24) & 0x000000FF); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=(byte)((ii >> 16) & 0x000000FF); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=(byte)((ii >> 8) & 0x000000FF); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=(byte)((ii >> 0) & 0x000000FF); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
//高度
ii=hei;
bb=(byte)((ii >> 24) & 0x000000FF); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=(byte)((ii >> 16) & 0x000000FF); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=(byte)((ii >> 8) & 0x000000FF); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=(byte)((ii >> 0) & 0x000000FF); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
//颜色深度
bb=cd; png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
//颜色类型
bb=ct; png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=0; png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=0; png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=0; png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
//CRC
ii=crc ^ 0xFFFFFFFF;
bb=(byte)((ii >> 24) & 0x000000FF); png[ip]=bb; ip++;
bb=(byte)((ii >> 16) & 0x000000FF); png[ip]=bb; ip++;
bb=(byte)((ii >> 8) & 0x000000FF); png[ip]=bb; ip++;
bb=(byte)((ii >> 0) & 0x000000FF); png[ip]=bb; ip++;
//------------------------------------------------------

//PLTE调色板信息-----------------------------------------
//长度
ii=cc*3;
bb=(byte)((ii >> 24) & 0x000000FF); png[ip]=bb; ip++;
bb=(byte)((ii >> 16) & 0x000000FF); png[ip]=bb; ip++;
bb=(byte)((ii >> 8) & 0x000000FF); png[ip]=bb; ip++;
bb=(byte)((ii >> 0) & 0x000000FF); png[ip]=bb; ip++;
//标识
crc=0xFFFFFFFF;
bb=(byte)(0x50); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=(byte)(0x4C); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=(byte)(0x54); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=(byte)(0x45); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
//颜色0黑
bb=(byte)(0x00); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);//R
bb=(byte)(0x00); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);//G
bb=(byte)(0x00); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);//B
//颜色1白
bb=(byte)(0xFF); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);//R
bb=(byte)(0xFF); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);//G
bb=(byte)(0xFF); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);//B
//CRC
ii=crc ^ 0xFFFFFFFF;
bb=(byte)((ii >> 24) & 0x000000FF); png[ip]=bb; ip++;
bb=(byte)((ii >> 16) & 0x000000FF); png[ip]=bb; ip++;
bb=(byte)((ii >> 8) & 0x000000FF); png[ip]=bb; ip++;
bb=(byte)((ii >> 0) & 0x000000FF); png[ip]=bb; ip++;


//IDAT图像信息-------------------------------------------------
//长度
ii=len+11;
bb=(byte)((ii >> 24) & 0x000000FF); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=(byte)((ii >> 16) & 0x000000FF); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=(byte)((ii >> 8) & 0x000000FF); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=(byte)((ii >> 0) & 0x000000FF); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
//标识
crc=0xFFFFFFFF;
bb=(byte)(0x49); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=(byte)(0x44); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=(byte)(0x41); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
bb=(byte)(0x54); png[ip]=bb; ip++; crc=getByteCRC(crc,bb);
//无压缩数据
LZ77[0]=(byte)(0x78); LZ77[1]=(byte)(0xDA); LZ77[2]=(byte)(0x01); //LZ77标识
LZ77[3]=(byte)(len & 0x000000FF); LZ77[4]=(byte)((len >> 8) & 0x000000FF);//无压缩数据长度1*8==8 低字节在前
LZ77[5]=(byte)(LZ77[3] ^ 0xFF); LZ77[6]=(byte)(LZ77[4] ^ 0xFF);//无压缩数据长度补码
//图像信息
j=7;
for(i=1; i<=hei; i++)
{
LZ77[j]=(byte)(0x00); j++;
for(k=1; k<=wid / 8; k++)
{
bb=0;
for(int m=0; m<=7;m++){
if(raw[rawIndex+m]==backColor)//白
bb=(byte)(bb|((0x80>>m)&0x000000FF));
}
rawIndex+=8;
LZ77[j]=(byte)(bb); j++;
}
}
crc2=1;//LZ77的Adler32校验位 只校验图像信息部分,其他的不包括到校验位中
s1 = crc2 & 0x0000FFFF;
s2 = (crc2 >> 16) & 0x0000FFFF;
if (len > 0)
{
k = len;
j=7;
while (k > 0){
s1+=(LZ77[j]&0x000000FF); s2+=s1; j++; k--;
}
s1 = s1 % 65521; s2 = s2 % 65521;
}
crc2 = (int)((s2 << 16)&0xFFFF0000) | (int)(s1&0x0000FFFF);
//校验位保存
ii=crc2;
bb=(byte)((ii >> 24) & 0x000000FF); LZ77[len+7]=bb;
bb=(byte)((ii >> 16) & 0x000000FF); LZ77[len+8]=bb;
bb=(byte)((ii >> 8) & 0x000000FF); LZ77[len+9]=bb;
bb=(byte)((ii >> 0) & 0x000000FF); LZ77[len+10]=bb;
//CRC IDAT的校验位
for(i=0; i<=len+10; i++)
{
bb=LZ77[i];
png[ip]=bb; ip++;
crc=getByteCRC(crc,bb);
}
ii=crc ^ 0xFFFFFFFF;
bb=(byte)((ii >> 24) & 0x000000FF); png[ip]=bb; ip++;
bb=(byte)((ii >> 16) & 0x000000FF); png[ip]=bb; ip++;
bb=(byte)((ii >> 8) & 0x000000FF); png[ip]=bb; ip++;
bb=(byte)((ii >> 0) & 0x000000FF); png[ip]=bb; ip++;
//--------------------------------------------------------

//结束数据块-----------------------------------------------
bb=(byte)(0x00); png[ip]=bb; ip++;
bb=(byte)(0x00); png[ip]=bb; ip++;
bb=(byte)(0x00); png[ip]=bb; ip++;
bb=(byte)(0x00); png[ip]=bb; ip++;
bb=(byte)(0x49); png[ip]=bb; ip++;
bb=(byte)(0x45); png[ip]=bb; ip++;
bb=(byte)(0x4E); png[ip]=bb; ip++;
bb=(byte)(0x44); png[ip]=bb; ip++;
bb=(byte)(0xAE); png[ip]=bb; ip++;
bb=(byte)(0x42); png[ip]=bb; ip++;
bb=(byte)(0x60); png[ip]=bb; ip++;
bb=(byte)(0x82); png[ip]=bb; ip++;
//--------------------------------------------------------
LZ77=null;
raw=null;
//System.out.println(png.length);
return png;
}
}