Image对象转成PNG格式字节 。没有做LZ77压。
共三个文件。
pngtools.java image转png格式工具类
bytestools.java byte操作类
crcutil crc校验类
转载请注明出处,可自由使用,无使用限,但商用请通知我。
pngtools.java
/**
* @功能:image 生成 png 字节
* @作者: imuse
* @MAIL: postzhu@hotmail.com
* @blog: http://blog.csdn.net/imuse
* @注 可自由使用,无使用限制。如商用请通知我
*/
import javax.microedition.lcdui.Image;
public class PngTools {
public static final int BIT4 = 4;
public static final int BIT8 = 8;
/** PNG tag. */
private static final byte PNG[] = {-119, 80, 78, 71, 13, 10, 26, 10};
/** IHDR tag. */
private static final byte IHDR[] = {73, 72, 68, 82};
/** PLTE tag. */
private static final byte PLTE[] = {0x50,0x4C,0x54,0x45};
/** IDAT tag. */
private static final byte IDAT[] = {73, 68, 65, 84};
/** LZ77 tag. */
private static final byte LZ77[] = {0x78, (byte)0xDA, 0x01};
/** IEND tag. */
private static final byte IEND[] = {(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x49, (byte) 0x45, (byte) 0x4E, (byte) 0x44, (byte) 0xAE, (byte) 0x42, (byte) 0x60, (byte) 0x82};
/**
* @功能 Image转成PNG字节
* @参数 Image srcImage 原图<br>int bit色深<br>
* @返回值 转换后的图片
* */
public static byte[] imageToPng(Image srcImg, int bit){
int srcW = srcImg.getWidth();
int srcH = srcImg.getHeight();
int[] srcRGB = new int[srcW];
int[] nColorArr = new int[0];
//取出图片中所用到的所有颜色
for (int i = 0; i < srcH; i++) {
//取一行颜色
srcImg.getRGB(srcRGB, 0, srcW, 0, i, srcW, 1);
//取一行颜色中的不同值
int[] temp = GetColorArr(srcRGB);
//将本行与上一次的结果连接
int[] count = new int[nColorArr.length+temp.length];
System.arraycopy(nColorArr, 0, count, 0, nColorArr.length);
System.arraycopy(temp, 0, count, nColorArr.length, temp.length);
//取连接后的结果再次取不同颜色
nColorArr = GetColorArr(count);
}
//如果没找到颜色则返回空
if(nColorArr.length==0){
return null;
}
int nPosCRC = 0;
byte[] bRet;
//固定头
bRet = BytesTools.appendBytes(null, PNG);
//固定头长度
bRet = BytesTools.appendBytes(bRet, BytesTools.intToBytes(13));
nPosCRC = bRet.length;
//IHDR
bRet = BytesTools.appendBytes(bRet, IHDR);
//宽
bRet = BytesTools.appendBytes(bRet, BytesTools.intToBytes(srcW));
//高
bRet = BytesTools.appendBytes(bRet, BytesTools.intToBytes(srcH));
//色深
bRet = BytesTools.appendBytes(bRet, (byte)bit);
//颜色类型
bRet = BytesTools.appendBytes(bRet, 0x03);
//规定此处总为0
bRet = BytesTools.appendBytes(bRet, 0x00);
//同上
bRet = BytesTools.appendBytes(bRet, 0x00);
//非隔行扫描
bRet = BytesTools.appendBytes(bRet, 0x00);
//头信息CRC
int nCRC = CRCUtil.checksum(bRet, nPosCRC, bRet.length-nPosCRC);
bRet = BytesTools.appendBytes(bRet, BytesTools.intToBytes(nCRC));
//颜色总数
int nColorLen = nColorArr.length;
bRet = BytesTools.appendBytes(bRet, BytesTools.intToBytes(nColorLen*3));
nPosCRC = bRet.length;
//PLTE
bRet = BytesTools.appendBytes(bRet, PLTE);
for (int i = 0; i < nColorLen; i++) {
bRet = BytesTools.appendBytes(bRet, intToRGBBytes(nColorArr[i]));
}
//CRC PLTE
nCRC = CRCUtil.checksum(bRet, nPosCRC, bRet.length-nPosCRC);
bRet = BytesTools.appendBytes(bRet, BytesTools.intToBytes(nCRC));
//IDTA长度
int nIdtaLen = 0;
if(bit==BIT4){
nIdtaLen = (srcW/2+1)*srcH;
}else if(bit==BIT8){
nIdtaLen = (srcW+1)*srcH;
}
int nLen = 4+LZ77.length+4+nIdtaLen;
bRet = BytesTools.appendBytes(bRet, BytesTools.intToBytes(nLen));
nPosCRC = bRet.length;
//IDAT
bRet = BytesTools.appendBytes(bRet, IDAT);
//无压缩的LZ77压缩块
bRet = BytesTools.appendBytes(bRet, LZ77);
//长度
bRet = BytesTools.appendBytes(bRet, getIDATLen(nIdtaLen));
//数据区域
int nAl = bRet.length;
if(bit==BIT4){
bRet = BytesTools.appendBytes(bRet, getPngBytes(srcImg, nColorArr));
}else if(bit==BIT8){
bRet = BytesTools.appendBytes(bRet, getPngBytes8(srcImg, nColorArr));
}
//Adler32
bRet = BytesTools.appendBytes(bRet, Adler(bRet, nAl, bRet.length-nAl));
//CRC
nCRC = CRCUtil.checksum(bRet, nPosCRC, bRet.length-nPosCRC);
bRet = BytesTools.appendBytes(bRet, BytesTools.intToBytes(nCRC));
//IEND
bRet = BytesTools.appendBytes(bRet, IEND);
return bRet;
}
//Adler校验
private static byte[] Adler(byte[] bData, int nStart, int nLen){
int adler1=1;
int adler2=0;
nLen += nStart;
for(int i=nStart;i<nLen;i++)
{
adler1=adler1+((int)bData[i]&0xff);
adler2=adler1+adler2;
adler1%=65521;
adler2%=65521;
}
int nRet = (adler2<<16) | adler1 ;
return BytesTools.intToBytes(nRet);
}
//8位色深IDAT数据
private static byte[] getPngBytes8(Image srcImg, int[] nColorArr){
int srcW = srcImg.getWidth();
int srcH = srcImg.getHeight();
int[] srcRGB = new int[srcW];
byte[] bRet = new byte[(srcW+1)*srcH];
int nPos = 0;
for (int i = 0; i < srcH; i++) {
srcImg.getRGB(srcRGB, 0, srcW, 0, i, srcW, 1);
nPos = i;
bRet[i*srcW+nPos] = 0;
for (int j = 0; j < srcW; j++) {
bRet[i*srcW+nPos+j+1] = (byte)(getColorIndex(srcRGB[j], nColorArr)&0xFF);
}
}
return bRet;
}
//4位色深IDAT数据
private static byte[] getPngBytes(Image srcImg, int[] nColorArr){
int srcW = srcImg.getWidth();
int srcH = srcImg.getHeight();
int[] srcRGB = new int[srcW];
byte[] bRet = new byte[(srcW/2+1)*srcH];
int nPos = 0;
for (int i = 0; i < srcH; i++) {
srcImg.getRGB(srcRGB, 0, srcW, 0, i, srcW, 1);
nPos = i;
bRet[i*srcW/2+nPos] = 0;
int nIndex = 0;
for (int j = 0; j < srcW; j++) {
if(j%2==1 && j!=0){
nIndex = nIndex | (getColorIndex(srcRGB[j], nColorArr)&0xFF);
bRet[i*srcW/2+j/2+1+nPos] = (byte)nIndex;
}else{
nIndex = (getColorIndex(srcRGB[j], nColorArr)&0xFF)<<4;
}
}
}
return bRet;
}
//取颜色索引
private static int getColorIndex(int nColor, int[] nColorArr){
int nLen = nColorArr.length;
int nIndex = -1;
for (int i = 0; i < nLen; i++) {
if(nColor==nColorArr[i]){
nIndex = i;
break;
}
}
return nIndex;
}
//将一个int color转红绿蓝byte数组
private static byte[] intToRGBBytes(int nColor){
byte[] bColor = new byte[3];
//红
bColor[0] = (byte)(nColor>>16&0xFF);
//绿
bColor[1] = (byte)(nColor>>8&0xFF);
//蓝
bColor[2] = (byte)(nColor&0xFF);
return bColor;
}
//IDAT数据的长度,格式为:前两字节为IDAT长度,低字节在前,后两字节为前两字节的^值.
private static byte[] getIDATLen(int nLen){
byte[] bRet = new byte[4];
bRet[0] = (byte)(nLen & 0xFF);
bRet[1] = (byte)(nLen >> 8 & 0xFF);
bRet[2] = (byte)(bRet[0] ^ 0xFF);
bRet[3] = (byte)(bRet[1] ^ 0xFF);
return bRet;
}
//从一个int数据中取出不同的int值
private static int[] GetColorArr(int[] nArr){
int nLen = nArr.length;
int nRet[] = new int[0];
for (int i = 0; i < nLen; i++) {
int nrLen = nRet.length;
boolean is = true;
for (int j = 0; j < nrLen; j++) {
if(nArr[i]==nRet[j]){
is = false;
break;
}
}
if(is){
int[] temp = new int[nrLen+1];
System.arraycopy(nRet, 0, temp, 0, nrLen);
temp[nrLen] = nArr[i];
nRet = temp;
}
}
return nRet;
}
}
bytestools.java
/**
* @功能:字节工具类
* @作者: imuse
* @MAIL: postzhu@hotmail.com
* @blog: http://blog.csdn.net/imuse
* @注 可自由使用,无使用限制。如商用请通知我
*/
public class BytesTools {
/**
* @功能: 将一个int值转为byte数组
* @参数: int nNum 要转的int值
* @返回值: byte[] bytesRet 转后的byte数组
*/
public static byte[] intToBytes(int nNum) {
byte[] bytesRet = new byte[4];
bytesRet[0] = (byte) ((nNum >> 24) & 0xFF);
bytesRet[1] = (byte) ((nNum >> 16) & 0xFF);
bytesRet[2] = (byte) ((nNum >> 8) & 0xFF);
bytesRet[3] = (byte) (nNum & 0xFF);
return bytesRet;
}
/**
* @功能: 将一个长度为4 byte数组转为int
* @参数: byte[] bNum要转的字节数组
* @返回值: int retInt 转后的int值
*/
public static int bytesToInt(byte[] bNum) {
return bytesToInt(bNum, 0);
}
/**
* @功能: 将一个长度为4 byte数组转为int
* @参数: byte[] bNum要转的字节数组<br>int nStartPos起始位置
* @返回值: int retInt 转后的int值
*/
public static int bytesToInt(byte[] bNum, int nStartPos) {
int retInt = 0;
retInt = ((bNum[nStartPos++] & 0xFF) << 24);
retInt += (bNum[nStartPos++] & 0xFF) << 16;
retInt += (bNum[nStartPos++] & 0xFF) << 8;
retInt += bNum[nStartPos] & 0xFF;
return retInt;
}
/**
* @功能: 将一个INT的转为byte数组后追加到指定数组后
* @参数: byte[] bDes追加目标<br>int bSrc要追加的int
* @返回值: byte[] 追加后的字节数组
*/
public static byte[] appendBytes(byte[] bDes, int bSrc) {
return appendBytes(bDes, new byte[]{(byte)bSrc});
}
/**
* @功能: 将一个byte 数组追加到指定数组后
* @参数: byte[] bDes追加目标<br>byte[] bSrc要追加的字节数组
* @返回值: byte[] 追加后的字节数组
*/
public static byte[] appendBytes(byte[] bDes, byte[] bSrc) {
byte[] ret = null;
if (bDes == null) {
ret = bSrc;
}
if (bSrc == null) {
ret = bDes;
}
if (bDes != null && bSrc != null) {
ret = new byte[bDes.length + bSrc.length];
System.arraycopy(bDes, 0, ret, 0, bDes.length);
System.arraycopy(bSrc, 0, ret, bDes.length, bSrc.length);
}
return ret;
}
/**
* @功能: 截取指定byte 数组中的字节数组
* @参数: byte[] bSrc原字节数组<br>int nStartPos原字节数组起始位置<br>int nLen截取长度
* @返回值: byte[] 截取后的字节数组
*/
public static byte[] subBytes(byte[] bSrc, int nStartPos, int nLen) {
byte[] ret = null;
if (bSrc != null) {
ret = new byte[nLen];
if((nStartPos+nLen)<=bSrc.length){
System.arraycopy(bSrc, nStartPos, ret, 0, nLen);
}
}
return ret;
}
/**
* @功能: 查找子字节数组在父字节数组中的位置
* @参数: byte[] bSrc父字节数组<br>byte[] bSub子字节数组
* @返回值: int 在父字节数组中的位置,如未找到则返回-1
*/
public static int findSubBytesPos(byte[] bSrc, byte[] bSub){
int ret = -1;
int nSubLen = bSub.length;
int nLen = bSrc.length-nSubLen;
boolean b=true;
for(int i=0; i<=nLen; i++){
b = true;
for (int j = 0; j < nSubLen; j++) {
if(bSrc[i+j]!=bSub[j]){
b = false;
break;
}
}
if(b){
ret = i;
break;
}
}
return ret;
}
}
crcutil.java
/**
* @功能:CRC校验
* @作者: imuse
* @MAIL: postzhu@hotmail.com
* @blog: http://blog.csdn.net/imuse
* @注 可自由使用,无使用限制。如商用请通知我
*/
public class CRCUtil {
private static int[] crc_table;
private static void make_crc_table() {
int c;
int n, k;
crc_table = new int[256];
for (n = 0; n < 256; n++) {
c = n;
for (k = 0; k < 8; k++) {
if ((c & 1) == 1)
c = 0xedb88320 ^ (c >>> 1);
else
c = c >>> 1;
}
crc_table[n] = c;
}
}
private static int update_crc(byte[] buf, int nStart, int nLen) {
int c = 0xffffffff;
int n;
if (crc_table == null) {
make_crc_table();
}
for (n = nStart; n < nLen + nStart; n++) {
c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >>> 8);
}
return c;
}
/**
* @功能: 生成CRC校验码
* @参数: byte[] buf数据区域<br>int nStart起始位置<br>int nLen计算长度<br>
* @返回值: int CRC校验码
* */
public static int checksum(byte[] buf, int nStart, int nLen) {
return update_crc(buf, nStart, nLen) ^ 0xffffffff;
}
}