天天看點

将Image對像轉換為png格式的byte數組

将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測試成功