lukew 发表于 2013-1-27 04:43:18

修改png图的调色板

今天在硬盘上挖出这个存放了几年的代码。又回忆起3年前的那个j2me手机游戏程序员……

这个算法是参考一位高人的文章,直接读取并修改png格式图片的调色板,然后生成新的调色板替代原来的。
这样可以实现游戏中常见的变色效果,可以解决游戏容量有限,不能存放太多精灵图片的问题。

具体过程其实并不复杂,大家可以先搜索资料,先看看png图片的格式定义。这个算法正是找到调色板区,根据原有格式修改之后,生成新的crc校验码,然后替换原来的调色板。这样就可以用一个png图片,创建多个变色副本。
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!---->public class PalettedImage {
 
    public Image getPalettedImage(byte[] data, int[] originalColors,
            int[] palettedColors) {
        byte[] tempData = new byte;
        System.arraycopy(data, 0, tempData, 0, data.length);
        Image img = null;
        int[] parameter = { 0, 0, 0 };
        analyze(tempData, parameter);
        for (int i = 0; i < originalColors.length; i++) {
            replaceColor(tempData, parameter, originalColors,
                    palettedColors);
        }
        fillData(tempData, parameter);
        try {
            img = Image.createImage(tempData, 0, data.length);
        } catch (Exception e) {
            System.out.println("getPalettedImage  &&  " + e.toString());
        }
        return img;
    }
 
    private void analyze(byte[] data, int[] para) {
        int offset = 8;
        int chunkLen = 0;
        while (data+ 4] != 0x50 || data+ 5] != 0x4c
                || data+ 6] != 0x54 || data+ 7] != 0x45) {
            chunkLen = readInt(data, offset);
            offset += (4 + 4 + chunkLen + 4);
        }
        chunkLen = readInt(data, offset);
        para[2] = chunkLen / 3;
        para[0] = offset + 8;
        para[1] = offset + 8 + chunkLen;
    }
 
    private int readInt(byte[] data, int offset) {
        return ((data & 0xFF) << 24)
                | ((data+ 1] & 0xFF) << 16)
                | ((data+ 2] & 0xFF) << 8) | (data+ 3] & 0xFF);
    }
 
    private void replaceColor(byte[] data, int[] para, int oldColor,
            int newColor) {
        byte rr = (byte) ((oldColor >> 16) & 0xff);
        byte gg = (byte) ((oldColor >> 8) & 0xff);
        byte bb = (byte) (oldColor & 0xff);
        for (int i = 0, offset = para[0], temp = 0; i < para[2]; i++, offset += 3) {
            if (rr == data && gg == data+ 1]
                    && bb == data+ 2]) {
                data = (byte) ((newColor >> 16) & 0xff);
                data+ 1] = (byte) ((newColor >> 8) & 0xff);
                data+ 2] = (byte) (newColor & 0xff);
                break;
            }
        }
    }
 
    private void fillData(byte[] data, int[] para) {
        int checksum = update_crc(data, para[0] - 4, para[2] * 3 + 4);
        data1]] = (byte) ((checksum >> 24) & 0xff);
        data1] + 1] = (byte) ((checksum >> 16) & 0xff);
        data1] + 2] = (byte) ((checksum >> 8) & 0xff);
        data1] + 3] = (byte) ((checksum) & 0xff);
    }
 
    private int update_crc(byte[] buf, int off, int len) {
        int c = 0xffffffff;
        int n, k;
        int xx;
        int[] crc_table = new int[256];
        for (n = 0; n < 256; n++) {
            xx = n;
            for (k = 0; k < 8; k++) {
                if ((xx & 1) == 1) {
                    xx = 0xedb88320 ^ (xx >>> 1);
                } else {
                    xx = xx >>> 1;
                }
            }
            crc_table = xx;
        }
 
        for (n = off; n < len + off; n++) {
            c = crc_table[(c ^ buf) & 0xff] ^ (c >>> 8);
        }
        return (c ^ 0xffffffff);
    }
 
}

页: [1]
查看完整版本: 修改png图的调色板