今天在硬盘上挖出这个存放了几年的代码。又回忆起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所以可以使用更方便的方法替换颜色。
总之,再次感谢这位已经被我忘掉名字的大侠,关键代码是他写的,我只是修改整理而已。