Look into it ~

present
随笔 - 32, 文章 - 0, 评论 - 3, 引用 - 0
数据加载中……

修改png图的调色板

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

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

具体过程其实并不复杂,大家可以先搜索资料,先看看png图片的格式定义。这个算法正是找到调色板区,根据原有格式修改之后,生成新的crc校验码,然后替换原来的调色板。这样就可以用一个png图片,创建多个变色副本。
public class PalettedImage {
 
    
public Image getPalettedImage(byte[] data, int[] originalColors,
            
int[] palettedColors) {
        
byte[] tempData = new byte[data.length];
        System.arraycopy(data, 
0, tempData, 0, data.length);
        Image img 
= null;
        
int[] parameter = { 000 };
        analyze(tempData, parameter);
        
for (int i = 0; i < originalColors.length; i++) {
            replaceColor(tempData, parameter, originalColors[i],
                    palettedColors[i]);
        }
        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[offset + 4!= 0x50 || data[offset + 5!= 0x4c
                
|| data[offset + 6!= 0x54 || data[offset + 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[offset] & 0xFF<< 24)
                
| ((data[offset + 1& 0xFF<< 16)
                
| ((data[offset + 2& 0xFF<< 8| (data[offset + 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[offset] && gg == data[offset + 1]
                    
&& bb == data[offset + 2]) {
                data[offset] 
= (byte) ((newColor >> 16& 0xff);
                data[offset 
+ 1= (byte) ((newColor >> 8& 0xff);
                data[offset 
+ 2= (byte) (newColor & 0xff);
                
break;
            }
        }
    }
 
    
private void fillData(byte[] data, int[] para) {
        
int checksum = update_crc(data, para[0- 4, para[2* 3 + 4);
        data[para[
1]] = (byte) ((checksum >> 24& 0xff);
        data[para[
1+ 1= (byte) ((checksum >> 16& 0xff);
        data[para[
1+ 2= (byte) ((checksum >> 8& 0xff);
        data[para[
1+ 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[n] 
= xx;
        }
 
        
for (n = off; n < len + off; n++) {
            c 
= crc_table[(c ^ buf[n]) & 0xff^ (c >>> 8);
        }
        
return (c ^ 0xffffffff);
    }
 
}


接口就是getPalettedImage()函数,只需要输入原始图片的byte数组,以及需要替换颜色的颜色值还有目标颜色值就行了。因为可以同时替换多个颜色,所以输入参数是代表颜色的整形的数组。总之,要保证原始颜色与目标颜色一一对应就好了。方法简单实用。

欢迎大家使用并留下宝贵的意见。当然,也可以修改一下这个函数,做一些特殊的效果。这里就不多说了。
不过这个代码用处已经不大,因为现在的手机基本上都支持midp2.0所以可以使用更方便的方法替换颜色。

总之,再次感谢这位已经被我忘掉名字的大侠,关键代码是他写的,我只是修改整理而已。

posted on 2008-08-15 14:34 LukeW 阅读(600) 评论(0)  编辑  收藏 所属分类: Tips, Tricks, Hints & Code


只有注册用户登录后才能发表评论。


网站导航: