登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

聊天机器

Chatbot's private blog

 
 
 

日志

 
 

Image转byte  

2009-02-25 15:27:03|  分类: 程序理论 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

由于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);

    }

    /**保存文件

     * @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[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测试成功

http://www.j2medev.com/bbs/viewFile.asp?BoardID=17&ID=2515

  评论这张
 
阅读(271)| 评论(1)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018