gundumw100 发表于 2013-1-15 02:36:52

将Image对像转换为png格式的byte数组

原理上说

1 获取Image 的ARGB数据

2将ARGB转换成PNG存储用的的RGBA格式

3RGBA格式的数据还要做些小的处理每行后面加一个byte 0

4用LZ77方法将RGBA格式的数组压缩

5附加正确格式PNG24文件头输出即可包括IHEAD IHDR IEND IDAT外壳

但是使用LZ77压缩手机上无论时间或空间都是不太能接受的

还好LZ77 存在一钟无压缩的压缩方法本文的方法就是使用无压缩的方式搞定数据压缩的

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);    }    /**保存文件   * @path:路径   * @fileData:文件数据   * @return: 0:出现异常,1:保存成功   */    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 & 0xFF) << 24)                     | ((data & 0xFF) << 16)                     | ((data & 0xFF) << 8)                     | (data & 0xFF);      int sum = CRCChecksum(data, chunkpos + 4, 4 + chunklen) ^ 0xffffffff;      int val = sum;      int pos = chunkpos + 8 + chunklen;      data = (byte) ((val & 0xFF000000) >> 24);      data = (byte) ((val & 0xFF0000) >> 16);      data = (byte) ((val & 0xFF00) >> 8);      data = (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;            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 = mkc;            }      }      for (n = off; n < len + off; n++) {            c = crc_table[(c ^ buf) & 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 & 0xff;                s2 += s1;                s1 += buf & 0xff;                s2 += s1;                s1 += buf & 0xff;                s2 += s1;                s1 += buf & 0xff;                s2 += s1;                s1 += buf & 0xff;                s2 += s1;                s1 += buf & 0xff;                s2 += s1;                s1 += buf & 0xff;                s2 += s1;                s1 += buf & 0xff;                s2 += s1;                s1 += buf & 0xff;                s2 += s1;                s1 += buf & 0xff;                s2 += s1;                s1 += buf & 0xff;                s2 += s1;                s1 += buf & 0xff;                s2 += s1;                s1 += buf & 0xff;                s2 += s1;                s1 += buf & 0xff;                s2 += s1;                s1 += buf & 0xff;                s2 += s1;                s1 += buf & 0xff;                s2 += s1;                k -= 16;            }            if (k != 0) {                do {                  s1 += buf & 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 = (byte) 0;            } else {                lenNlen = (byte) 1;            }            int msb = (len & 0xff);            int lsb = (len >>> 8);            lenNlen = (byte) msb;            lenNlen = (byte) lsb;            lenNlen = (byte) (msb ^ 0xff);            lenNlen = (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;      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;                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 = (byte) r;                rawByte = (byte) g;                rawByte = (byte) b;                rawByte = (byte) a;                n += 4;            }      }      raw = null;      System.gc();    }}
附件zip可改名为jar在手机上直接执行

内附有源代码

需要手机支持JSR75有E盘(就是存储卡)生成的文件为a.png

可使用任意的看图软件打开

N73,6270测试成功
页: [1]
查看完整版本: 将Image对像转换为png格式的byte数组