H5W3
当前位置:H5W3 > 其他技术问题 > 正文

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

    众所周知,我们可以使用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

本文地址:H5W3 » 关于游戏中高效的换色方法

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址