作者:hunhun1981
出自:http://blog.csdn.net/hunhun1981/
今天在硬盘上挖出这个存放了几年的代码。又回忆起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 );
}
}
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所以可以使用更方便的方法替换颜色。
总之,再次感谢这位已经被我忘掉名字的大侠,关键代码是他写的,我只是修改整理而已。
更多信息,请关注hunhun1981的专栏 。