两种修改png图片颜色方法的对比/游戏帧速度处理/J2me中实现淡入淡出效果

  两种修改 png 图片颜色方法的对比
在手机游戏开发中,为了节省资源,我们常常修改png图片以实现一张图片多种显示效果。有两种办法可以实现这个功能:
 
第一种是装载png图片,使用getRGB()取得取得图片的RGB颜色数据,然后修改RGB颜色数据,再用Image的静态方法createRGBImage()将修改后的RGB颜色数据生成新的png图片。示例代码:testImage为测试的Image对象,imgW,imgH为其宽和高
// 取得图片的RGB数据--这个数组是比较大的,因此修改RGB数据生成新的图片效率很低
rgbData = new int[imgW * imgH];
testImage.getRGB(rgbData,0,imgW,0,0,imgW,imgH);
// 修改RGB数据并生成新的图片
rgbImage = Image.createRGBImage(changeRGBData(rgbData),imgW,imgH,true);
 
第二中方法是取得png图片的二进制数据,修改其中的调色板域(PLTE chunk)数据,再使用
Image的静态对象createImage(byte[] imageData,int imageOffset,int imageLength)将修改后的二进制数据生成新的png对象。示例代码:查看代码中的getPLTEModifidImage()函数。
 
如果对png的数据格式组成不熟悉,可以查阅: http://www.w3.org/TR/PNG/
或者(不错的中文介绍): http://www.ismyway.com/png/png-struct1.htm
 
通常,图片的RGB颜色数据是比较大的,而调色板数据远比RGB颜色数据要少的多,修改RGB颜色数据效率要高的多。下面我使用一张大小为52*28的png图片作为测试图片,从以下测试中打印的数据就可看出(1456对比144):
Load file Gold total data is 1084 ――――――――图片的二进制字节数据个数
--------RGB data length is 1456―――――――――RGB颜色字节数据个数
--------The number of PLTE chunks is 48―――调色板数据块个数(实际字节数据为 48*3
 
效果图:
 
附测试的源代码:
//-----------------------------------------------------Code--START------------------------------------------------
/**
 * Dicription        : Create png image by modifying PLTE chunk.
 * Author            : 飘飘白云
 * Created date      : 2006-07-03
 * Modified history :
 */
 
import java.io.DataInputStream;
import java.io.IOException;
 
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
 
public class CreatePNG extends MIDlet
{
    GameCanvas canvas;
    Display display;
              public CreatePNG()
              {
                            super();
                            // TODO Auto-generated constructor stub
                            try {
            display = Display.getDisplay(this);
            canvas = new GameCanvas(this);
        } catch (Exception e) {}
              }
 
              protected void startApp() throws MIDletStateChangeException
              {
                            // TODO Auto-generated method stub
                            if( canvas != null ){
                                          display.setCurrent(canvas);
                                          canvas.start();
                            }
              }
 
              protected void pauseApp()
              {
                            // TODO Auto-generated method stub
                            canvas.beExit = true;
              }
 
              protected void destroyApp( boolean arg0) throws MIDletStateChangeException
              {
                            // TODO Auto-generated method stub
              }
 
}
 
class GameCanvas extends Canvas implements Runnable
{
              CreatePNG app;
              Thread mainThread;
             
              Image                                                            offImage              = null;
              public Graphics                               g                                        = null;
             
              public boolean beExit = false;
              long sleepTime = 30;
             
              int scrW;
              int scrH;
              Font font;
              int fontH;
              int fontW;
             
              //-------------------------------------
              int gameMode;
              int subMode;
             
              static final int smInit = 0;
              static final int smProc = 1;
              static final int smEnd = 2;
             
              static final int gmStart = 0;
              static final int gmProcPNGData = 1;
             
              //--------------------------------------
              Image testImage = null;
              Image rgbImage = null;
              Image plteImage = null;
              int imgW;
              int imgH;
              int[] rgbData = null;
              byte[] imgData = null;
              String testFile = "Gold";
             
              public GameCanvas(MIDlet midlet)
              {
                            app = (CreatePNG)midlet;
 
              }
 
              public void start()
              {
                            changeGameMode(gmStart);
                           
                            mainThread = new Thread(this);
                            mainThread.start();
              }
             
              public void changeGameMode(int gm)
              {
                            gameMode = gm;
                            subMode = smInit;
              }
             
              protected void paint( Graphics _g)
              {
                            // TODO Auto-generated method stub
                            if( offImage != null)
                                          _g.drawImage(offImage, 0, 0, 0);
              }
 
 
              public void run()
              {
                            // TODO Auto-generated method stub
                            gameInit();
                            while( !beExit )
                            {
                                          gameMain();
                                          gameDraw();
                                          repaint();
                                          gcWait(sleepTime);
                            }
                           
                            if( beExit ) {
                                          try {
                                                        app.destroyApp(true);
                                          }
                                          catch ( MIDletStateChangeException e ) {
                                                        // TODO Auto-generated catch block
                                                        e.printStackTrace();
                                          }
                            }
              }
             
              void gcWait(long tm)
              {
                            System.gc();
                            try {
                                          Thread.sleep(tm);
                            }
                            catch ( InterruptedException e ) {
                                          // TODO Auto-generated catch block
                                          e.printStackTrace();
                            }
              }
             
              void println(String str)
              {
                            System.out.println( str );
              }
              void print(String str)
              {
                            System.out.print( str );
              }
             
              void gameInit()
              {
                            scrW = getWidth();
                            scrH = getHeight();
 
                            if(g == null || offImage == null) {
                                          offImage = Image.createImage(scrW, scrH);
                                g = offImage.getGraphics();
                                          g.translate(0,0);
                            }
                            repaint();
                           
                            font       = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_PLAIN,Font.SIZE_MEDIUM);
                            g.setFont(font);
                 
                  changeGameMode( gmStart );
              }
             
              /**
               * 装载图片
               * @param fileName 图片名称
               * @return image 对象
               */
              Image loadImage( String fileName)
              {
 
                            Image tmp = null;
                            try {
                                          tmp = Image.createImage("/" + fileName + ".png");
                            }
                            catch ( IOException e ) {
                                          println("[Error] >> loadImage(): " + fileName + " Failed!");
                                          e.printStackTrace();
                            }
 
                            if( tmp == null ) {
                                          println("[Error] >> loadImage(): " + fileName + " Failed!");
                            }
                            return tmp;
              }
             
              /**
               * 读取文件的二进制数据
               * @param fileName 文件名
               * @return 文件二进制数据的字节数组.
               */
              byte[] loadFile(String fileName)
              {
                            DataInputStream isr = null;
                            byte[] bData;
                            try {
 
                                          try {
                                                        isr = new DataInputStream(getClass().getResourceAsStream("/" + fileName + ".png"));
                                          }
                                          catch (Exception e) {
                                          }
                                         
                                          int res_size = 0;
                                          while (isr.read() != -1)
                                                        res_size++;
                                          if (isr.markSupported())
                                                        isr.reset();
                                          else {
                                                        isr.close();
                                                        isr = new DataInputStream(getClass().getResourceAsStream("/" + fileName + ".png"));
                                          }
                                          bData = new byte[res_size];
                                          int read_bytes = isr.read(bData, 0, res_size);
                                          isr.close();
                                          System.gc();
                                          println("Load file " + fileName + " total data is " + read_bytes);
                                          return bData;
                            }
                            catch (Exception e) {
                                          println("Error>>loadFile " + fileName);
                                          return null;
                            }
              }
             
             
              void gameMain()
              {
                            if( gameMode == gmStart )
                            {
                                          if( subMode == smInit )
                                          {
                                                        // 装载图片
                                                        testImage = loadImage(testFile);
                                                        imgW = testImage.getWidth();
                                                        imgH = testImage.getHeight();
                                                        subMode = smProc ;
                                          }
                                         
                                          else if( subMode == smProc )
                                          {
                                                        // 取得图片的RGB数据--这个数组是比较大的,因此修改RGB数据生成新的图片效率很低
                                                        rgbData = new int[imgW * imgH];
                                                        testImage.getRGB(rgbData,0,imgW,0,0,imgW,imgH);
                                                       
                                                        println("--------RGB data length is - " + rgbData.length);
                                                        changeGameMode(gmProcPNGData);
                                          }
                            }
                           
                            else if( gameMode == gmProcPNGData )
                            {
                                          if( subMode == smInit )
                                          {
                                                        // 取得图片的二进制数据
                                                        imgData = loadFile(testFile);
 
                                                        subMode = smProc ;
                                                        println("----Start---All Image Data--length-" + imgData.length);
                                                        for( int i = 0; i< imgData.length; i++ ){
                                                                      if( i% 10 == 0 )
                                                                                    println("");
                                                                      System.out.print(" " + imgData[i]);
                                                        }
                                                        println("/n----End---All Image Data--length-" + imgData.length);
                                                        // 修改调色板数据,改变图片颜色,这种方法修改的数据远比修改RGB数据要少,效率高很多
                                                        plteImage = getPLTEModifidImage(imgData,3);
                                          }
                                         
                                          else if( subMode == smProc )
                                          {            
                                                        // 修改RGB数据生成新的图片,非常低效
                                                        rgbImage = Image.createRGBImage(changeRGBData(rgbData),imgW,imgH,true);
                                                        subMode = smEnd;
                                          }
                                          else if( subMode == smEnd )
                                          {
 
                                          }
                            }
              }
             
              void gameDraw()
              {
                            if( gameMode == gmStart )
                            {
                                          if( subMode == smProc ){
                                                        // 描绘原始图片
                                                        g.drawImage(testImage,20,20,0);
                                          }
                            }
                            else if( gameMode == gmProcPNGData )
                            {
                                          if( subMode == smProc ){
                                                        // 描绘修改调试板数据生成的图片
                                                        g.drawImage(plteImage,20,80,0);
                                          }
                                          else if( subMode == smEnd ) {
                                                        // 描绘修改RGB数据生成的图片,也可以使用drawRGB()直接描绘RGB数据,不过要注意透明问题.
                                                        g.drawImage(rgbImage,20,140,0);
                                          }
                            }
              }
 
              /**
               * 修改png图片的调色板数据生成新的png图片
               * @param imageSrc png图片的二进制数据字节数组
               * @param type 修改策略
               * @return 新的png图片
               */
              public Image getPLTEModifidImage(byte[] imageSrc , int type)
              {
                            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;
                            println("/n======================start Palette data process========================");
                            println("-------------Palette chunk start pos = " + 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));
                                                       
                                         
                                          if( i % 10 == 0 && i != 0) {
                                                        println("");
                                          }
                                          print(" " + imageRGBColors[i]);
                                          pos += 3;
                            }
                           
                            // 修改 PLTE chunk data
                            switch (type)
                            {
                                          case 0:
                                                        // don't modify
                                                        break;
                                                       
                                          case 1: {
                                                        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;
                                          }
             
                                          case 2: {
                                                        // white
                                                        for (j = 1; j < imageNbColors; j++)
                                                                      imageRGBColors[j] = 0xFFFFFF;
             
                                                        break;
                                          }
             
                                          case 3: {
                                                        int l,r,g,b;
                                                        // red
                                                        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) / 10;
             
                                                                      imageRGBColors[j] = l << 16;
                                                        }
             
                                                        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;
                            println("/n---------------------New plte data crc " + crc +"--------------------------------");
                            for( i = 0; i < 4 + 4 + ( imageNbColors * 3 ) + 4; i++ )
                            {
                                          if( i >= 8 && (i - 8)%3 == 0 ) {
                                                        println("");
                                          }
 
                                          print(" " + data[pos + i]);
                            }
                            println("/n=========================End plte data-=================================");
                           
                            return Image.createImage(data,0,data.length);
              }
             
 
              /**
               * 修改png图片的RGB数据
               * @param rgbSrc png图片的RGB数据的字节数组
               * @return 新的RGB数据的字节数组
               */
              public int[] changeRGBData(int[] rgbSrc)
              {
                            int len = rgbSrc.length;
                            int[] ret = new int[len];
                           
                            int a,r,g,b;
                            int tmp;
                           
                            for( int i = 0; i < len; i++ )
                            {
                                          b = rgbSrc[i];
                                         
                                          a = ((b & 0xff000000) >> 24);
                                          r = ((b & 0x00ff0000) >> 16);
                                          g = ((b & 0x0000ff00) >> 8);
                                          b = ((b & 0x000000ff) >> 0);
                                         
                                          // exchange red and blue
                                          tmp = r;
                                          r = b;
                                          b = tmp;
                                         
                                          ret[i] = (a << 24) | (r << 16) | (g << 8) | b;
                            }
                           
                            return ret;
              }
 
             
              // CRC校验表,加速CRC计算
              static long crcTable[];
              static public void makeCrcTable()
              {
                            long c;
                            int n, k;
                            crcTable = new long[256];
 
                            for (n = 0; n < 256; n++) {
                                          c = (long) n;
 
                                          for (k = 0; k < 8; k++) {
                                                        if ((c & 1) == 1) {
                                                                      c = 0xEDB88320L ^ (c >> 1);
                                                        }
                                                        else {
                                                                      c = c >> 1;
                                                        }
                                          }
                                          crcTable[n] = c;
                            }
              }
 
              /**
               * 计算CRC校验码
               */
              static public int updateCrcChunk(byte[] buf, int dataOffsetStart,int dataOffsetEnd)
              {
                            long c = 0xFFFFFFFFL;
 
                            for (int i = dataOffsetStart; i < dataOffsetEnd; i++)
                                          c = (crcTable[(int) ((c ^ buf[i]) & 0xFF)] ^ (c >> 8));
 
                            return (int) (c ^ 0xFFFFFFFFL);
              }
}
//-----------------------------------------------------Code------END----------------------------------------------
//2
 游戏帧速度处理

保持游戏在不同性能手机平台的流畅性很重要,这就需要针对不通硬件设置相应合适的帧速度。假设一般

手机用户能接受的游戏帧速为40/s 则相关参数和代码如下:

 //====================================================
 // 游戏帧速度调整
 //====================================================
    private long framerate= 1000/40; // 设置帧速为每秒40帧,(25 ms / frame)
     private long frameStart;  // 帧开始的时间time the frame begin        
     private long frameCount = 0; // 这一秒的帧数   
     private long elapsedTime;  // 一帧消耗的时间 
     private long totalElapsedTime = 0; // 多帧累计消耗的时间
     private long reportedFramerate; // 实际计算出来的帧速

 public void updateFrame()
 {
  frameStart = System.currentTimeMillis();
  repaint();
  elapsedTime = System.currentTimeMillis() - frameStart;
  
  //帧速同步
  try {
   if( elapsedTime < framerate ) {
    Thread.sleep(framerate - elapsedTime);
   }else {
    Thread.sleep(5);
   }
  }catch( Exception e ) {
   e.printStackTrace();
  }
  
  //更新实际的帧速
  ++ frameCount;
  totalElapsedTime +=  (System.currentTimeMillis() - frameStart);
  if( totalElapsedTime > 1000 ) {
   reportedFramerate = (long)((double)frameCount/(double)

totalElapsedTime*1000.0);
   //在调试时可屏幕中显示帧速
              //g.drawString("fps: " + reportedFramerate,x,y,0);
              frameCount = 0;
              totalElapsedTime = 0;
  }
 }

3

J2me 中实现淡入淡出效果
飘飘白云 (l_zhaohui@163.com)
 
      J2me 中实现淡入淡出效果,据我所知至少有三种方法。
第一种是取得需要变换图片的像素,依次 个象素的 alpha 通道 , 让它在 0~100 之间变化。
    第二种是修改图片的调色板数据,让其在调色板原始数据到 255 之间变化。
    第三种,其实也是利用上面的办法,先描画图片,然后在图片上覆盖一个黑色矩形,改变这个黑色矩形透明度就可以实现淡入淡出的效果。
    前两种方法相比较的话,第一种方法运算量是比较大的,而且第一种方法由于 midp1.0 不支持 alpha 通道,在一些手机上无法实现。
 
    下面给出第二种方法的示例,在我们开始之前,应该熟悉 png 文件格式,如果还不是很明白的话,可以 google 一下,或者查看前面的帖子中的相关连接。
    代码很清楚,下面是源代码:
 
------------CODE__START-----------------------
import java.io.DataInputStream;
import java.util.Timer;
import java.util.TimerTask;
 
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
 
/**
 * Discription      : 修改调色板数据实现淡入淡出效果
 * Author           : 飘飘白云 (l_zhaohui@163.com)
 * Created date     : 2006/07/13 18:06:39
 * Modified history :
 */
 
public class PngFadeInOut extends MIDlet
{
                           GameCanvas canvas;
                  Display display;
                            public PngFadeInOut()
                            {
                                          super();
                                          try {
                          display = Display.getDisplay(this);
                          canvas = new GameCanvas(this);
                      } catch (Exception e) {}
                            }
 
                            protected void startApp() throws MIDletStateChangeException
                            {
                                          if( canvas != null ){
                                                        display.setCurrent(canvas);
                                                        canvas.start();
                                          }
                            }
 
                            protected void pauseApp()
                            {
                                          canvas.isExit = true;
                            }
 
                            protected void destroyApp( boolean arg0) throws MIDletStateChangeException
                            {
                            }
              }
 
              class GameCanvas extends Canvas
              {
                            static String imageName = "/fadeInOut.png";
                            public static final int    MAX_TARDINESS = 30;
                           
                            //---------------------------------------------------
                            PngFadeInOut app;
                            boolean isInited = false;
                            public boolean isExit = false;
 
                            Image offImage             = null;
                            public Graphics             g = null;
                            int scrW;
                            int scrH;
 
                            //---------------------------------------------------
                            int gameMode;
                            int subMode;
                           
                            static final int smInit = 0;
                            static final int smProc = 1;
                            static final int smEnd = 2;
                           
                            static final int gmStart = 0;
                           
                            //---------------------------------------------------
                            Image testImage = null;
                           
                            byte[] oldRGBData = null;
                            byte[] imgData = null;
                           
                            static final int FADE_IN = 0;
                            static final int FADE_OUT = 1;
                            static final int FADE_STEP = 1;
                           
                            static int fadeType = FADE_IN;
                           
                            //---------------------------------------------------
                            //---Timer process
                            //---------------------------------------------------
                            TimerTask task;
                            Timer timer;
                            int timerDelayTime;
                            public boolean isTimerRunning;
                           
                            void startTimer(int delayTime){
                                          timerDelayTime = delayTime;
                                          isTimerRunning = true;
                                         
                                          timer = new Timer();
                                          task = new ProcessingRunner();
                                          timer.scheduleAtFixedRate(task, 0, delayTime);
                            }
                           
                            public void stopTimer(){
                                          if( task != null )
                                                        task.cancel();
                                         
                                          isTimerRunning = false;
                                          timer = null;
                                          task = null;
                            }
                            //-----------------------------------------------------
                            class ProcessingRunner extends TimerTask
                            {
                                          public void run()
                                          {
                                                        if( isExit ) {
                                                                      stopTimer();
                                                                      app.notifyDestroyed();
                                                        }
                                                       
                                                        if (!isTimerRunning || System.currentTimeMillis() -
                                                                                    scheduledExecutionTime() >= timerDelayTime)
                                                        {
                                                                      return;
                                                        }
 
                                                        gameMain();
                                                        gameDraw();
                                                       
                                                        repaint();
                                                        serviceRepaints();
                                                        System.gc();
                                          }
                            }
                            //-------------------------------------------------
                           
                            public GameCanvas(MIDlet midlet)
                            {
                                          app = (PngFadeInOut)midlet;
                            }
 
             
                           
                            public void start()
                            {
                                          setFullScreenMode(true);
                                          while (!isShown())
                                                        ;
                                         
                                          if( !isInited ) {
                                                        gameInit();
                                                        isInited = true;
                                          }
 
                                          startTimer(MAX_TARDINESS);
                            }
                           
                            void gameInit()
                            {
                                          scrW = getWidth();
                                          scrH = getHeight();
 
                                          if(g == null || offImage == null) {
                                                        offImage = Image.createImage(scrW, scrH);
                                              g = offImage.getGraphics();
                                          }
                                         
                                          changeGameMode(gmStart);
                            }
 
                            public void changeGameMode(int gm){
                                          gameMode = gm;
                                          subMode = smInit;
                            }
                           
                            //---------------------------------------------------
                            // 游戏主逻辑处理
                            //---------------------------------------------------
                            void gameMain()
                            {
                                          if( gameMode == gmStart )
                                          {
                                                        if( subMode == smInit )
                                                        {
                                                                      // 取得图片的二进制数据
                                                                      imgData = loadFile(imageName);
                                                       
                                                                      // 保存原始图片的调色板 rgb 数据
                                                                      oldRGBData = getPlteRGBData(imgData);
                                                       
                                                                      if( fadeType == FADE_IN) {
                                                                                    // 设置调色板颜色为白色,淡入效果
                                                                                    for(int i = rgbDataStartPos; i < rgbDataStartPos + rgbDataLength;i++ ) {
                                                                                                  imgData[i] = (byte)255;
                                                                                    }
                                                                      }
                                                                      // 生成新的图片
                                                                      testImage = createFadeImage(imgData,rgbDataStartPos,rgbDataLength);
 
                                                                      subMode = smProc ;
                                                        }
                                                       
                                                        else if( subMode == smProc )
                                                        {
                                                                      try {
                                                                                    // 淡入淡出效果处理
                                                                                    fade(fadeType);
                                                                                    testImage = createFadeImage(imgData,rgbDataStartPos,rgbDataLength);
                                                                      }
                                                                      catch ( Exception e ) {
                                                                                    println("Create fade image error. /n" + e);
                                                                      }
                                                        }
                                          }
                            }
                           
                            //---------------------------------------------------
                            // 游戏描画处理
                            //---------------------------------------------------
                           
                            protected void paint( Graphics _g){
                                          if( offImage != null)
                                                        _g.drawImage(offImage, 0, 0, 0);
                            }
                           
                            void gameDraw()
                            {
                                          if( gameMode == gmStart )
                                          {
                                                        if( subMode == smProc ){
                                                                      g.setColor(0xffffff);
                                                                      g.fillRect(0,0,scrW,scrH);
                                                                      g.drawImage(testImage,20,140,0);
                                                        }
                                          }
                            }
                           
                            /**
                             * 淡入淡出效果处理
                             * @param type
                             */
                            public void fade( int type)
                            {
                                          int m = 0;
                                          int n = 0;
                                          // 淡入
                                          if ( type == FADE_IN ) {
                                                        for( int i = 0; i < rgbDataLength; i++ )
                                                        {
                                                                      m = imgData[rgbDataStartPos + i] & 0x000000ff;
                                                                      n = oldRGBData[i] & 0x000000ff;
                                                                      m = m < 0? m + 256 : m;
                                                                      n = n < 0? n + 256 : n;
                                                                     
                                                                      m = m > n ? m - FADE_STEP : n;
                                                                     
                                                                      imgData[rgbDataStartPos + i] = (byte)(m & 0xff);
                                                        }
                                          }
                                          // 淡出
                                          else if ( type == FADE_OUT ) {
                                                        for( int i = 0; i < rgbDataLength; i++ )
                                                        {
                                                                      m = imgData[rgbDataStartPos + i] & 0x000000ff;
                                                                      m = m < 0? m + 256 : m;
                                                                      m = m < 255 ? m + FADE_STEP : 255;
                                                                     
                                                                      imgData[rgbDataStartPos + i] = (byte)(m & 0xff);
                                                        }
                                          }
                            }
                           
                            /**
                             * 这里不是单纯创建一幅图片, crc32 校验码也在这个函数里更新
                             * @param data
                             * @param startPos 需要校验的数据的起始位置
                             * @return
                             */
                            public Image createFadeImage(byte[] data,int startPos,int length)
                            {
                                          if (crcTable == null)
                                                        makeCrcTable();
                                         
                                          int endPos = startPos + length ;
                                          int crc = updateCrcChunk( data, startPos -8,endPos );
                                          data[endPos + 0] = (byte)(crc >> 24 & 0x000000FF);
                                          data[endPos + 1] = (byte)(crc >> 16 & 0x000000FF);
                                          data[endPos + 2] = (byte)(crc >> 8 & 0x000000FF);
                                          data[endPos + 3] = (byte)(crc & 0x000000FF);
                                         
                                          return Image.createImage(data,0,data.length);
                            }
                           
                            static int rgbDataStartPos = 0;
                            static int rgbDataLength = 0;
                           
                            /**
                             * @param imgData png 图片的二进制数据
                             * @return 调色板颜色数据的字节数组
                             */
                            public byte[] getPlteRGBData(byte[] imgData)
                            {
                                          if (imgData == null || imgData.length <= 1)
                                                        return null;
 
                                          // PLTE chunk 数据域的类型标识
                                          // see http://www.w3.org/TR/PNG/#11PLTE
                                          String[] sPLTE = {"50", "4c", "54", "45"};
 
                                          int i;
                                          int pos = 0;
                                          // 定位调色板数据的位置
                                          for (i = 0; i < imgData.length; i++)
                                          {
                                     if (Integer.toHexString(imgData[i]).equals(sPLTE[0])
                                                              && Integer.toHexString(imgData[i + 1]).equals(sPLTE[1])
                                                              && Integer.toHexString(imgData[i + 2]).equals(sPLTE[2]) 
                                  && Integer.toHexString(imgData[i + 3]).equals(sPLTE[3]))
                                      {
                                                  pos = i;
                                                  break;
                                      }
                                          }
                                         
                                          pos -= 4;
 
                                          // 取得 PLTE chunk 的字节数据长度 .
                                          int imageNbColors = (
                                                                      ((imgData[pos] << 24) & 0xff000000)
                                                                      | ((imgData[pos + 1] << 16) & 0x00ff0000)
                                                                      | ((imgData[pos + 2] << 8 ) & 0x0000ff00)
                                                                      | ((imgData[pos + 3]      ) & 0x000000ff));
                           
                                          //8 = 数据长度 (4 个字节 ) + 类型标识 (4 个字节 )           
                                          pos += 8;
                                         
                                          // 设置全局变量
                                          rgbDataStartPos = pos;
                                          rgbDataLength = imageNbColors;
                                         
                                          // 复制数据
                                          byte[] data = new byte[rgbDataLength ];
                                          for( i = 0 ; i < rgbDataLength ; i++){
                                                        data[i] = imgData[i + rgbDataStartPos ];
                                          }
                                           
                                          return data;
                            }
                           
                            // CRC 校验查找表,加速 CRC32 运算
                            static long crcTable[];
                            static public void makeCrcTable()
                            {
                                          long c;
                                          int n, k;
                                          crcTable = new long[256];
 
                                          for (n = 0; n < 256; n++) {
                                                        c = (long) n;
 
                                                        for (k = 0; k < 8; k++) {
                                                                      if ((c & 1) == 1) {
                                                                                    c = 0xEDB88320L ^ (c >> 1);
                                                                      }
                                                                      else {
                                                                                    c = c >> 1;
                                                                      }
                                                        }
                                                        crcTable[n] = c;
                                          }
                            }
 
                            /**
                             * 计算 crc32 校验码
                             */
                            static public int updateCrcChunk(byte[] buf, int dataOffsetStart,int dataOffsetEnd)
                            {
                                          long c = 0xFFFFFFFFL;
 
                                          for (int i = dataOffsetStart; i < dataOffsetEnd; i++)
                                                        c = (crcTable[(int) ((c ^ buf[i]) & 0xFF)] ^ (c >> 8));
 
                                          return (int) (c ^ 0xFFFFFFFFL);
                            }
                           
                           
                            /**
                             * 读取文件的二进制数据
                             * @param fileName 文件名
                             * @return 文件二进制数据
                             */
                            byte[] loadFile(String fileName)
                            {
                                          DataInputStream isr = null;
                                          byte[] bData;
                                          try {
 
                                                        try {
                                                                      isr = new DataInputStream(getClass().getResourceAsStream(fileName));
                                                        }
                                                        catch (Exception e) {
                                                        }
                                                       
                                                        int res_size = 0;
                                                        while (isr.read() != -1)
                                                                      res_size++;
                                                        if (isr.markSupported())
                                                                      isr.reset();
                                                        else {
                                                                      isr.close();
                                                                      isr = new DataInputStream(getClass().getResourceAsStream(fileName));
                                                        }
                                                        bData = new byte[res_size];
                                                        int read_bytes = isr.read(bData, 0, res_size);
                                                        isr.close();
                                                        System.gc();
 
                                                        return bData;
                                          }
                                          catch (Exception e) {
                                                        println("Error>>loadFile " + fileName);
                                                        return null;
                                          }
                            }
                           
                            static void println(String str){
                                          System.out.println( str );
                            }
                           
              }
----------------------CODE__END-------------------------------
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值