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; } }