修改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  =  {  0 0 0  };
        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所以可以使用更方便的方法替换颜色。

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

你可能感兴趣的:(Tips,Tricks,Hints,&,Code,游戏,算法,C,C++,C#)