服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

关于游戏中高效的换色方法


    众所周知,我们可以使用getrgb()取得取得图片的rgb颜色数据,然后修改rgb颜色数据,再用image的静态方法creatergbimage()将修改后的rgb颜色数据生成新的png图片。但是这个方法效率低不说,而且就目前来说,如果要做中国市场,还得使用midp1.0。所以今天我想谈一下另外一种换色方式,通过修改调色板数据来达到换色的目的,记得以前我在论坛发过一篇关于换色和旋转图片的文章,但是那次仅仅限于讨论,这次要说的是我已经应用在实际游戏当中的换色方法

     首先,我们取得png图片的二进制数据,修改其中的调色板域(plte chunk)数据,再使用createimage(byte[] imagedata,int imageoffset,int imagelength)将修改后的二进制数据生成新的png对象。(换色是基于对图像格式的熟悉来进行的,所以你必须先了解png图片的格式,这个可以参考http://www.w3.org/tr/png/)


下面是获得图片调色板数据的方法(感谢飘飘白云的代码)


             /**
               * 修改png图片的调色板数据生成新的png图片
               * @param imagesrc png图片的二进制数据字节数组
               * @return 修改后的png图片
               */
              public image getpltemodifidimage(byte[] imagesrc)
              {
                            if (imagesrc == null || imagesrc.length <= 1)
                                          return null;
 
                            if (crctable == null)
                                          makecrctable();
 
                            // plte chunk数据域的类型标识
                            // see http://www.w3.org/tr/png/#11plte
                            string[] splte = {"50", "4c", "54", "45"};
 
                            int i,j;
                            int pos = 0,startpos = 0;
                            byte[] data = imagesrc;
                           
                            for (i = 0; i < data.length; i++)
                            {
                        if (integer.tohexstring(data[i]).equals(splte[0])
                                                  && integer.tohexstring(data[i + 1]).equals(splte[1])
                                                  && integer.tohexstring(data[i + 2]).equals(splte[2])
                    && integer.tohexstring(data[i + 3]).equals(splte[3]))
                        {
                                      pos = i;
                                      break;
                        }
                            }
                            pos -= 4;
                            startpos = pos;

                            // 取得plte chunk数据域的数据长度().
                            int imagenbcolors = (
                                                        ((data[pos] << 24) & 0xff000000)
                                                        | ((data[pos + 1] << 16) & 0x00ff0000)
                                                        | ((data[pos + 2] << 8 ) & 0x0000ff00)
                                                        | ((data[pos + 3]      ) & 0x000000ff));
                            // 计算的plte chunk数据个数(每个plte chunk数据由r,g,b三个字节数据组成)
                            imagenbcolors = imagenbcolors/3;
                            // 为整形的plte chunk data分配空间
                            int imagergbcolors[]    = new int[ imagenbcolors ];
     
                            //12 = 数据长度(4个字节) + 类型标识(4个字节) + 校验码(4个字节)
//                           for( i = pos,j = 0; i < pos + 12 + imagenbcolors * 3 ; i++,j++ ){
//                                          if( j >= 8 && (j - 8)%3 == 0 ) {
//                                                        println("");
//                                          }
//                                          system.out.print(" " + data[i]);
//                            }
                          
                           pos += 8;
//                           println("/n--------the number of plte chunks is " + imagenbcolors + "------------");
  
           
                            if (imagergbcolors == null)
                                          return null;
                           
                             // 生成整形的plte chunk data
                             for( i = 0; i < imagenbcolors; i++ )
                             {
                                           imagergbcolors[i] = (
                                                                       (data[pos + 0] & 0x000000ff) << 16)
                                                                       | ((data[pos + 1] & 0x000000ff) << 8)
                                                                       | ((data[pos + 2] & 0x000000ff));
                                                       
                                         


                                          pos += 3;
                            }
                           
                            // 修改 plte chunk data                   
                             
                                int l,r,g,b;
                                                        // gray
                             for (j = 1; j < imagenbcolors; j++) {
                                                                      r = imagergbcolors[j];
                                                                      g = (r & 0x00ff00) >> 8;
                                                                      b = r & 0x0000ff;
                                                                      r = (r & 0xff0000) >> 16;
             
                                                                      l = (b + g * 6 + r * 3) / 16;
             
                                                                      imagergbcolors[j] = l << 16 | l << 8 | l;
                                }
             
                                    break;
         
                            
                            // 生成新的 plte chunk data
                            pos = startpos + 8;
                            for( i = 0; i < imagenbcolors ;i++)
                            {
                                          data[pos ] = (byte)((imagergbcolors[i] >> 16) ) ;
                                          data[pos + 1 ] = (byte)((imagergbcolors[i] >> 8) );
                                          data[pos + 2] = (byte)(imagergbcolors[i] );
                                          pos += 3;
                            }
                            // 更新 crc 校验码
                           
                           
                            int crc = updatecrcchunk( data, startpos + 4, startpos + 4 + 4 + ( imagenbcolors * 3 ) );
                            data[pos + 0] = (byte)(crc >> 24 & 0x000000ff);
                            data[pos + 1] = (byte)(crc >> 16 & 0x000000ff);
                            data[pos + 2] = (byte)(crc >> 8 & 0x000000ff);
                            data[pos + 3] = (byte)(crc & 0x000000ff);
                           
                            pos = startpos;


                            return image.createimage(data,0,data.length);
              }

    其实这个方法只能简单得修改图片颜色,更好效率更高的方法是,做一个小工具将原图片的调色板数据提取出来,然后需要换的各种颜色,全部事先导成调色板数据文件,程序里面做的是只是根据需要合并这些数据组成各种图片。

欢迎大家继续探讨

原文地址:http://www.j2medev.com/blog/user1/15402/archives/2006/1753.html

扫描关注微信公众号