将Image對像轉換為png格式的byte數組 <script language=javascript src="/eapd0921/200703/16.js"></script> <script type=text/javascript> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type=text/javascript> </script>
由于J2me中沒有ImageIO 導緻一些功能無法在J2me上實作.
導緻大家無法實作一些功能.
如繪圖軟體.大頭貼.截屏等.
貌私新版的jsr什麼什麼實作了将Image 輸出為png or jpg
但估計等到這種手機上市的時候以是幾年後的事情了.
其實在j2me上将Image 對象轉成png格式的數組并不是不可能的任務.
原理上說
1 擷取Image 的ARGB資料
2将ARGB轉換成PNG存儲用的的RGBA格式
3RGBA格式的資料還要做些小的處理每行後面加一個byte 0
4用LZ77方法将RGBA格式的數組壓縮
5附加正确格式PNG24檔案頭輸出即可包括IHEAD IHDR IEND IDAT外殼
但是使用LZ77壓縮手機上無論時間或空間都是不太能接受的
還好LZ77 存在一鐘無壓縮的壓縮方法本文的方法就是使用無壓縮的方式搞定資料壓縮的
參閱了jzlib 代碼
使用300行左右的代碼搞定了将Image對象轉png
import javax.microedition.lcdui.*;
import java.io.*;
import javax.microedition.io.file.FileConnection;
import javax.microedition.io.Connector;
public class CGame extends Canvas {
//Image2Bytes by AnderLu
//生成的byte[]數組可直接用于外部存儲為.png格式的圖檔檔案看圖軟體可直接打開
public static int IDATPOS;
public static byte[] HEADChunk = {
(byte) 0x89, (byte) 0x50,
(byte) 0x4E, (byte) 0x47,
(byte) 0x0D, (byte) 0x0A,
(byte) 0x1A, (byte) 0x0A,
};
public static byte[] tRNSChunk = {
(byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x01,
(byte) 0x74, (byte) 0x52,
(byte) 0x4E, (byte) 0x53,
(byte) 0x00,
(byte) 0x40, (byte) 0xE6,
(byte) 0xD8, (byte) 0x66,
};
public static byte[] IENDChunk = {
//PNGIEND
(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 img;
public CGame() {
Image img = null;
try {
img = Image.createImage("/cap.png");
} catch (IOException ex) {
ex.printStackTrace();
}
byte data[] = Image2Bytes(img);
this.img = Image.createImage(data, 0, data.length);
saveFile("file:///e:/a.png", data);
}
protected void paint(Graphics g) {
g.setColor(0xffffff);
g.fillRect(0, 0, 240, 320);
g.drawImage(img, 0, 0, 0);
}
public int saveFile(String path, byte[] fileData) {
FileConnection fc = null;
try {
fc = (FileConnection) Connector.open(path, Connector.READ_WRITE);
if (!fc.exists()) {
fc.create();
}
OutputStream os = fc.openOutputStream();
os.write(fileData);
os.flush();
os.close();
fc.close();
return 1;
} catch (IOException ex) {
ex.printStackTrace();
return 0;
}
}
public byte[] Image2Bytes(Image img) {
try {
int w = img.getWidth();
int h = img.getHeight();
int offset = 0;
byte buffer[] = new byte[(w * 4 + 1) * h + offset];
getImageBufferForImageARGB8888(img, buffer, w, h, offset);
System.gc();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(baos);
WritePng(dout, w, h, buffer, null, false, offset);
byte[] data = baos.toByteArray();
writeCRC(data, 8); //更新IHDR CRC
writeCRC(data, 33); //更新PLTE CRC
writeCRC(data, IDATPOS); //更新IDAT CRC
buffer = null;
System.gc();
return data;
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
}
public static void writeCRC(byte[] data, int chunkpos) {
int chunklen = ((data[chunkpos] & 0xFF) << 24)
| ((data[chunkpos + 1] & 0xFF) << 16)
| ((data[chunkpos + 2] & 0xFF) << 8)
| (data[chunkpos + 3] & 0xFF);
int sum = CRCChecksum(data, chunkpos + 4, 4 + chunklen) ^ 0xffffffff;
int val = sum;
int pos = chunkpos + 8 + chunklen;
data[pos] = (byte) ((val & 0xFF000000) >> 24);
data[pos + 1] = (byte) ((val & 0xFF0000) >> 16);
data[pos + 2] = (byte) ((val & 0xFF00) >> 8);
data[pos + 3] = (byte) (val & 0xFF);
}
public static int[] crc_table; //CRC 表
public static int CRCChecksum(byte[] buf, int off, int len) {
int c = 0xffffffff;
int n;
if (crc_table == null) {
int mkc;
int mkn, mkk;
crc_table = new int[256];
for (mkn = 0; mkn < 256; mkn++) {
mkc = mkn;
for (mkk = 0; mkk < 8; mkk++) {
if ((mkc & 1) == 1) {
mkc = 0xedb88320 ^ (mkc >>> 1);
} else {
mkc = mkc >>> 1;
}
}
crc_table[mkn] = mkc;
}
}
for (n = off; n < len + off; n++) {
c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >>> 8);
}
return c;
}
public static long adler32(long adler, byte[] buf, int index, int len) {
int BASE = 65521;
int NMAX = 5552;
//TODO remove this function at all
if (buf == null) {
return 1L;
}
long s1 = adler & 0xffff;
long s2 = (adler >> 16) & 0xffff;
int k;
while (len > 0) {
k = len < NMAX ? len : NMAX;
len -= k;
while (k >= 16) {
s1 += buf[index++] & 0xff;
s2 += s1;
s1 += buf[index++] & 0xff;
s2 += s1;
s1 += buf[index++] & 0xff;
s2 += s1;
s1 += buf[index++] & 0xff;
s2 += s1;
s1 += buf[index++] & 0xff;
s2 += s1;
s1 += buf[index++] & 0xff;
s2 += s1;
s1 += buf[index++] & 0xff;
s2 += s1;
s1 += buf[index++] & 0xff;
s2 += s1;
s1 += buf[index++] & 0xff;
s2 += s1;
s1 += buf[index++] & 0xff;
s2 += s1;
s1 += buf[index++] & 0xff;
s2 += s1;
s1 += buf[index++] & 0xff;
s2 += s1;
s1 += buf[index++] & 0xff;
s2 += s1;
s1 += buf[index++] & 0xff;
s2 += s1;
s1 += buf[index++] & 0xff;
s2 += s1;
s1 += buf[index++] & 0xff;
s2 += s1;
k -= 16;
}
if (k != 0) {
do {
s1 += buf[index++] & 0xff;
s2 += s1;
} while (--k != 0);
}
s1 %= BASE;
s2 %= BASE;
}
return (s2 << 16) | s1;
}
public static void WritePng(DataOutputStream output, int width, int height,
byte[] buffer, byte[] colors,
boolean Transparent, int offset) throws
IOException {
int adler = (int) adler32(1l, buffer, offset, buffer.length - offset);
byte[] lenNlen = { //壓縮塊的LEN和NLEN資訊
(byte) 0,
(byte) 0xfa, (byte) 0x7e,
(byte) 0x05, (byte) 0x81
};
IDATPOS = 0;
output.write(HEADChunk);
IDATPOS += HEADChunk.length;
//寫IHDR
output.writeInt(13); //len
output.writeInt(1229472850); //IHDR type code
output.writeInt(width); //寫寬度
output.writeInt(height); //寫高度
output.writeByte(8); //1Bitdepth
if (colors == null) {
output.writeByte(6); //2ColorType
} else {
output.writeByte(3); //2ColorType
}
output.writeByte(0); //3CompressionMethod
output.writeByte(0); //4Filter method
output.writeByte(0); //5Interlace method
output.writeInt(0); //寫crc
IDATPOS += 25;
//寫PLTE
if (colors != null) {
output.writeInt(colors.length); //len
output.writeInt(1347179589); //type code
output.write(colors); //data
output.writeInt(0); //crc
IDATPOS += colors.length + 12;
}
//寫TRNS
if (Transparent) {
output.write(tRNSChunk);
IDATPOS += tRNSChunk.length;
}
//寫IDAT
byte[] dpixels = buffer;
int bufferlen = dpixels.length - offset;
int blocklen = 32506;
int blocknum = 1;
if ((dpixels.length % blocklen) == 0) {
blocknum = bufferlen / blocklen;
} else {
blocknum = (bufferlen / blocklen) + 1;
}
int IDATChunkLen = (bufferlen + 6 + blocknum * 5);
output.writeInt(IDATChunkLen); //len
output.writeInt(1229209940); //idat type code
output.writeShort((short) 0x78da); //78da
for (int i = 0; i < blocknum; i++) {
int off = i * blocklen;
int len = bufferlen - off;
if (len >= blocklen) {
len = blocklen;
lenNlen[0] = (byte) 0;
} else {
lenNlen[0] = (byte) 1;
}
int msb = (len & 0xff);
int lsb = (len >>> 8);
lenNlen[1] = (byte) msb;
lenNlen[2] = (byte) lsb;
lenNlen[3] = (byte) (msb ^ 0xff);
lenNlen[4] = (byte) (lsb ^ 0xff);
output.write(lenNlen);
output.write(dpixels, off + offset, len);
}
output.writeInt(adler); //IDAT adler
output.writeInt(0); //IDAT crc
output.write(IENDChunk);
}
public static void getImageBufferForImageARGB8888(Image img, byte[] rawByte,
int w, int h, int off) {
int n = off;
int[] raw = new int[w];
for (int j = 0; j < h; j++) {
img.getRGB(raw, 0, w, 0, j, w, 1);
for (int i = 0; i < raw.length; i++) {
int ARGB = raw[i];
int a = (ARGB & 0xff000000) >> 24;
int r = (ARGB & 0xff0000) >> 16;
int g = (ARGB & 0xff00) >> 8;
int b = ARGB & 0xff;
if (i % w == 0) {
n += 1;
}
rawByte[n] = (byte) r;
rawByte[n + 1] = (byte) g;
rawByte[n + 2] = (byte) b;
rawByte[n + 3] = (byte) a;
n += 4;
}
}
raw = null;
System.gc();
}
}
附件zip可改名為jar在手機上直接執行
内附有源代碼
需要手機支援JSR75有E盤(就是存儲卡)生成的檔案為a.png
可使用任意的看圖軟體打開
N73,6270測試成功