Android中Gif图片的显示

来源:互联网 发布:防网络上瘾安全教育 编辑:程序博客网 时间:2024/05/17 03:34

Android中Gif图片的显示

分类: android 1620人阅读 评论(2) 收藏 举报
androidtableextensionstringdelete

         最近闲来无事,折腾了一下关于gif图片在Android上的显示(大家都知道,Android本身不支持gif图片的显示,当然通过Media还是能够实现gif的播放的)。网上找到的实现gif图片展示的主要是两种方式:使用java实现解码,或者使用编辑工具将gif图片拆分为多张图片,并编写xml文件,以帧动画的形式播放,另外还有个牛人,直接修改了Android框架层的源码,让android系统支持gif解码的。

        最后,我参考了一个android的开源项目,gifView,实现了一个基于native层的gif解码。

        以下是我参考的资料:

         gif文件格式说明

         LZW编码

         LZW算法和GIF数据压缩

         gifView项目

          解码的算法是直接抄袭了GifView,基本上就是C++语言重新实现了一下,解码重写了一下SurfaceView控件来实现gif的播放。以下贴上部分的核心代码:

          Gif.java

[java] view plaincopy
  1. package com.ray.test.gif;  
  2.   
  3. import java.util.ArrayList;  
  4.   
  5. public class Gif {  
  6.     public class Frame {  
  7.         private int delayTime;  
  8.         private Bitmap image;  
  9.         private boolean userInput = false;  
  10.   
  11.         public Frame(int delay, int[] color) {  
  12.             delayTime = delay;  
  13.             image = Bitmap.createBitmap(color, mWidth, mHeight, Config.RGB_565);  
  14.         }  
  15.   
  16.         private Frame setUserInput() {  
  17.             userInput = true;  
  18.             return this;  
  19.         }  
  20.   
  21.         public int getDelay() {  
  22.             return delayTime;  
  23.         }  
  24.   
  25.         public Bitmap getImage() {  
  26.             return image;  
  27.         }  
  28.   
  29.         public boolean isUserInput() {  
  30.             return userInput;  
  31.         }  
  32.     }  
  33.   
  34.     private int mWidth;  
  35.     private int mHeight;  
  36.     private List<Frame> mFrames = new ArrayList<Frame>();  
  37.   
  38.     public Gif(int width, int height) {  
  39.         mWidth = width;  
  40.         mHeight = height;  
  41.     }  
  42.   
  43.     public int getWidth() {  
  44.         return mWidth;  
  45.     }  
  46.   
  47.     public int getHeight() {  
  48.         return mHeight;  
  49.     }  
  50.   
  51.     public void addFrame(int delay, int[] color, boolean userInput) {  
  52.         synchronized (mFrames) {  
  53.             if (!userInput)  
  54.                 mFrames.add(new Frame(delay, color));  
  55.             else  
  56.                 mFrames.add(new Frame(delay, color).setUserInput());  
  57.         }  
  58.     }  
  59.   
  60.     public int getFrameCount() {  
  61.         synchronized (mFrames) {  
  62.             return mFrames.size();  
  63.         }  
  64.     }  
  65.   
  66.     public Frame getFrame(int idx) {  
  67.         synchronized (mFrames) {  
  68.             if (idx < 0 || idx >= mFrames.size())  
  69.                 return null;  
  70.             return mFrames.get(idx);  
  71.         }  
  72.     }  
  73. }  

GifDecoder.java

[java] view plaincopy
  1. package com.ray.test.gif;  
  2.   
  3. import java.io.File;  
  4.   
  5. public class GifDecoder {  
  6.   
  7.     private static final String MYTAG = "Ray";  
  8.     private static final String CLASS_NAME = "GifDecoder";  
  9.   
  10.     public interface DecodeResult {  
  11.         public void onDecodeFinished(int count);  
  12.     }  
  13.   
  14.     private static Gif sGif;  
  15.     private static DecodeResult sListener;  
  16.     private static boolean sIsReady = false;  
  17.   
  18.     static void decode(String filePath, DecodeResult result) throws FileNotFoundException {  
  19.         File f = new File(filePath);  
  20.         if (f.exists()) {  
  21.             sListener = result;  
  22.             sIsReady = false;  
  23.             sGif = null;  
  24.             WorkThread thread = new WorkThread(filePath);  
  25.             thread.start();  
  26.         } else  
  27.             throw new FileNotFoundException("can not find file:" + filePath);  
  28.     }  
  29.   
  30.     static Gif getImage() {  
  31.         return sGif;  
  32.     }  
  33.   
  34.     private static void onDecodeFinished(String count) {  
  35.         Log.d(MYTAG, CLASS_NAME + ": onDecodeFinished, count = " + count);  
  36.         int c = Integer.parseInt(count);  
  37.         getFrames(c);  
  38.         if(c == 0)  
  39.             mHandler.obtainMessage(c).sendToTarget();  
  40.     }  
  41.   
  42.     private static void getFrames(int idx) {  
  43.         if(idx == 0)  
  44.             sGif = new Gif(getWidth(), getHeight());  
  45.         sGif.addFrame(getDelay(idx), getColors(idx), getUserInput(idx));  
  46.     }  
  47.   
  48.     private static class WorkThread extends Thread {  
  49.         private String mPath;  
  50.   
  51.         public WorkThread(String path) {  
  52.             mPath = path;  
  53.         }  
  54.   
  55.         @Override  
  56.         public void run() {  
  57.             doDecode(mPath);  
  58.         }  
  59.     }  
  60.   
  61.     private static Handler mHandler = new Handler() {  
  62.         @Override  
  63.         public void handleMessage(Message msg) {  
  64.             sListener.onDecodeFinished(msg.what);  
  65.         }  
  66.     };  
  67.   
  68.     private static native void doDecode(String path);  
  69.   
  70.     private static native int getWidth();  
  71.   
  72.     private static native int getHeight();  
  73.   
  74.     private static native int getDelay(int index);  
  75.   
  76.     private static native boolean getUserInput(int index);  
  77.   
  78.     private static native int[] getColors(int index);  
  79. }  


GifVIewer.java

[java] view plaincopy
  1. package com.ray.test.gif;  
  2.   
  3. import android.content.Context;  
  4.   
  5. public class GifView extends SurfaceView implements SurfaceHolder.Callback {  
  6.   
  7.     private SurfaceHolder mHolder;  
  8.     private Gif mGif;  
  9.     private boolean isReady = false;  
  10.     private Rect mdRc;  
  11.     private Rect msRc;  
  12.     private Paint mPaint;  
  13.     GestureDetector mGestureDetector;  
  14.     private int mCurrentImage;  
  15.   
  16.     public GifView(Context context) {  
  17.         super(context);  
  18.         mHolder = this.getHolder();  
  19.         mHolder.addCallback(this);  
  20.         mPaint = new Paint();  
  21.         mGestureDetector = new GestureDetector(gestureListener);  
  22.     }  
  23.   
  24.     public void setImages(Gif gif) {  
  25.         this.mGif = gif;  
  26.         init();  
  27.     }  
  28.   
  29.     private void init() {  
  30.         if (isReady && mGif != null) {  
  31.             msRc = new Rect(00, mGif.getWidth(), mGif.getHeight());  
  32.             Rect vRc = new Rect();  
  33.             getLocalVisibleRect(vRc);  
  34.             mdRc = getDstRc(msRc, vRc);  
  35.             mHandler.removeCallbacksAndMessages(null);  
  36.             mHandler.sendEmptyMessage(0);  
  37.         }  
  38.     }  
  39.   
  40.     private Rect getDstRc(Rect image, Rect view) {  
  41.         double xRate = view.width() * 1.0 / image.width();  
  42.         double yRate = view.height() * 1.0 / image.height();  
  43.         if (xRate > yRate) {  
  44.             return new Rect((int) (view.width() - image.width() * yRate) / 20, (int) (image.width() * yRate) + (int) (view.width() - image.width() * yRate)  
  45.                     / 2, (int) (image.height() * yRate));  
  46.         } else {  
  47.             return new Rect(0, (int) (view.height() - image.height() * xRate) / 2, (int) (image.width() * xRate), (int) (image.height() * xRate)  
  48.                     + (int) (view.height() - image.height() * xRate) / 2);  
  49.         }  
  50.     }  
  51.   
  52.     private Handler mHandler = new Handler() {  
  53.         @Override  
  54.         public void handleMessage(Message msg) {  
  55.             int idx = msg.what;  
  56.             if (idx < 0 || idx >= mGif.getFrameCount())  
  57.                 idx = 0;  
  58.             mCurrentImage = idx;  
  59.             Frame f = mGif.getFrame(idx);  
  60.             if(f == null){  
  61.                 Log.e("Ray""f = null when idx = " + idx);  
  62.                 this.sendEmptyMessageDelayed(idx, 100);  
  63.                 return;  
  64.             }  
  65.             Rect rc = new Rect(mdRc);  
  66.             Canvas cv = mHolder.lockCanvas(rc);  
  67.             if (rc.equals(mdRc)) {  
  68.                 cv.drawBitmap(f.getImage(), msRc, mdRc, mPaint);  
  69.                 mHolder.unlockCanvasAndPost(cv);  
  70.                 this.sendEmptyMessageDelayed(++idx, f.getDelay());  
  71.             } else {  
  72.                 mHolder.unlockCanvasAndPost(cv);  
  73.                 this.sendEmptyMessageDelayed(idx, 100);  
  74.             }  
  75.         }  
  76.     };  
  77.   
  78.     @Override  
  79.     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {  
  80.         init();  
  81.     }  
  82.   
  83.     @Override  
  84.     public void surfaceCreated(SurfaceHolder holder) {  
  85.         isReady = true;  
  86.         init();  
  87.         this.setOnTouchListener(new OnTouchListener(){  
  88.   
  89.             @Override  
  90.             public boolean onTouch(View v, MotionEvent event) {  
  91.                 return mGestureDetector.onTouchEvent(event);  
  92.             }});  
  93.     }  
  94.   
  95.     @Override  
  96.     public void surfaceDestroyed(SurfaceHolder holder) {  
  97.         isReady = false;  
  98.         mHandler.removeCallbacksAndMessages(null);  
  99.     }  
  100.       
  101.     private GestureDetector.OnGestureListener gestureListener = new GestureDetector.OnGestureListener() {  
  102.           
  103.         @Override  
  104.         public boolean onSingleTapUp(MotionEvent e) {  
  105.             if(mGif.getFrame(mCurrentImage).isUserInput())  
  106.             {  
  107.                 mHandler.removeMessages(mCurrentImage + 1);  
  108.                 mHandler.handleMessage(mHandler.obtainMessage(mCurrentImage + 1));  
  109.             }  
  110.             return true;  
  111.         }  
  112.           
  113.         @Override  
  114.         public void onShowPress(MotionEvent e) {  
  115.             ;  
  116.         }  
  117.           
  118.         @Override  
  119.         public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {  
  120.             return true;  
  121.         }  
  122.           
  123.         @Override  
  124.         public void onLongPress(MotionEvent e) {      
  125.             ;  
  126.         }  
  127.           
  128.         @Override  
  129.         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {  
  130.             return true;  
  131.         }  
  132.           
  133.         @Override  
  134.         public boolean onDown(MotionEvent e) {  
  135.             return true;  
  136.         }  
  137.     };  
  138. }  


GifUtils.cpp

[cpp] view plaincopy
  1. #include "../head/GifUtils.h"  
  2. #include <cstring>  
  3. #include <iostream>  
  4. #include <typeinfo>  
  5.   
  6. extern void showIntLog(string str, int num);  
  7.   
  8. extern void showStringLog(string text);  
  9.   
  10. extern void decodeFinished(int count);  
  11.   
  12. unsigned short getShort(char* data, int idx) {  
  13.     return *((unsigned short*) (data + idx));  
  14. }  
  15.   
  16. GifUtils::GifUtils(string path) {  
  17.     this->mInStream.open(path.c_str());  
  18.     this->mFileSize = mInStream.gcount();  
  19. }  
  20.   
  21. GifUtils::~GifUtils() {  
  22.     if (this->mGlobalColorTable != NULL) {  
  23.         delete[] this->mGlobalColorTable;  
  24.         this->mGlobalColorTable = NULL;  
  25.     }  
  26. }  
  27.   
  28. void GifUtils::doWork(){  
  29.     showStringLog("Start decode");  
  30.     this->readFile();  
  31.     showStringLog("end decode");  
  32. }  
  33.   
  34. int GifUtils::readShort() {  
  35.     return (unsigned short) (this->mInStream.get() | this->mInStream.get() << 8);  
  36. }  
  37.   
  38. void GifUtils::readFile() {  
  39.     this->mStatus = DECODING;  
  40.     this->readHead();  
  41.     if (!this->is89) //本类只支持gif89版本  
  42.         return;  
  43.     this->readLogicalScreenDescriptor();  
  44.   
  45.     int imageId = 0;  
  46.     while (this->mStatus == DECODING) {  
  47.         char flag = this->mInStream.get();  
  48.         if (flag == BLOCK_FLAG_IMAGE_DESCRIPTOR)  
  49.         {  
  50.             this->readImageDescriptor();  
  51.         } else if (((unsigned char) flag) == BLOCK_FLAG_EXTENSION) {  
  52.             flag = this->mInStream.get();  
  53.             switch (flag) {  
  54.             case EXTENSION_FLAG_CONTROL:  
  55.                 this->readControlExtension(imageId);  
  56.                 imageId++;  
  57.                 break;  
  58.             case EXTENSION_FLAG_COMMEMT:  
  59.                 this->readCommentExtension();  
  60.                 break;  
  61.             case EXTENSION_FLAG_TEXT:  
  62.                 this->readTextExtension();  
  63.                 break;  
  64.             case EXTENSION_FLAG_APPLICATION:  
  65.                 this->readApplicationExtension();  
  66.                 break;  
  67.             default:  
  68.                 cout << "invalidate EXTENSION FLAG" << endl;  
  69.                 this->mStatus = DATA_ERROR;  
  70.                 break;  
  71.             }  
  72.         } else if (flag == BLOCK_FLAG_END) {  
  73.             this->mStatus = FINISHED;  
  74.             break;  
  75.         } else {  
  76.             cout << "invalidate block head" << endl;  
  77.             this->mStatus = DATA_ERROR;  
  78.             break;  
  79.         }  
  80.     }  
  81.   
  82.     for(int i = 0; i < this->mFrames.size(); i++){  
  83.         delete[] this->mFrames[i].getColors();  
  84.     }  
  85. }  
  86.   
  87. /** 
  88.  * 读取头文件 
  89.  */  
  90. void GifUtils::readHead() {  
  91.     char head[6];  
  92.     for (int i = 0; i < 6; i++)  
  93.         mInStream >> head[i];  
  94.     if (0 == strcmp(head, FILE_HEAD_GIF_89A)) {  
  95.         this->is89 = true;  
  96.     } else {  
  97.         this->is89 = false;  
  98.     }  
  99. }  
  100.   
  101. /** 
  102.  * 读取逻辑屏幕标识符 
  103.  */  
  104. void GifUtils::readLogicalScreenDescriptor() {  
  105.     char data[7];  
  106.     this->mInStream.read(data, 7);  
  107.     this->mGlobalWidth = getShort(data, 0);  
  108.     this->mGlobalHeight = getShort(data, 2);  
  109.     this->mHasGlobalColorTable = (data[4] & 0x80);  
  110.     this->mColorResolution = ((data[4] & 0x70) >> 4) + 1;  
  111.     this->mSortFlag = data[4] & 8;  
  112.     this->mGlobalColorTableSize = 2 << (data[4] & 7);  
  113.     this->mGlobalBackGroundColorIndex = data[5];  
  114.     this->mRateOfHeightWithWidth = data[6];  
  115.     if (this->mHasGlobalColorTable)  
  116.         this->readGlobalColorTable();  
  117. }  
  118.   
  119. /** 
  120.  * 读取全局调色板 
  121.  */  
  122. void GifUtils::readGlobalColorTable() {  
  123.     int* table = new int[this->mGlobalColorTableSize];  
  124.     for (int i = 0; i < this->mGlobalColorTableSize; i++) {  
  125.         table[i] = (unsigned charthis->mInStream.get();  
  126.         table[i] <<= 8;  
  127.         table[i] += (unsigned charthis->mInStream.get();  
  128.         table[i] <<= 8;  
  129.         table[i] += (unsigned charthis->mInStream.get();  
  130.         table[i] |= 0xFF000000;  
  131.     }  
  132.     this->mGlobalColorTable = table;  
  133. }  
  134.   
  135. unsigned char GifUtils::readOneBlock(char* &data) {  
  136.     unsigned char length = this->mInStream.get();  
  137.     if (length != 0) {  
  138.         data = new char[length];  
  139.         this->mInStream.read(data, length);  
  140.     }  
  141.     return length;  
  142. }  
  143.   
  144. /** 
  145.  * 读取局部调色板 
  146.  */  
  147. void GifUtils::readLocalColorTable(FrameInfo& frame) {  
  148.     int size = frame.getLocalColorTableSize();  
  149.     int* table = new int[size];  
  150.     for (int i = 0; i < size; i++) {  
  151.         table[i] = (unsigned charthis->mInStream.get();  
  152.         table[i] <<= 8;  
  153.         table[i] += (unsigned charthis->mInStream.get();  
  154.         table[i] <<= 8;  
  155.         table[i] += (unsigned charthis->mInStream.get();  
  156.         table[i] |= 0xFF000000;  
  157.     }  
  158.     frame.setLocalColorTable(table);  
  159. }  
  160.   
  161. int* cloneColors(int* colors, int length) {  
  162.     int* data = new int[length];  
  163.     if (colors == NULL) {  
  164.         memset(data, length*4, 0);  
  165.     } else {  
  166.         for (int i = 0; i < length; i++)  
  167.             data[i] = colors[i];  
  168.     }  
  169.     return data;  
  170. }  
  171.   
  172. /** 
  173.  * 读取图像标识符 
  174.  */  
  175. void GifUtils::readImageDescriptor() {  
  176.     FrameInfo frame = this->mFrames.back();  
  177.     this->mFrames.pop_back();  
  178.     frame.setXoffset(this->readShort());  
  179.     frame.setYOffset(this->readShort());  
  180.     frame.setWidth(this->readShort());  
  181.     frame.setHeight(this->readShort());  
  182.   
  183.     char flag = this->mInStream.get();  
  184.     frame.setInterlaceFlag(flag & 0x40);  
  185.     frame.setSortFlag(flag & 0x20);  
  186.     if (flag & 0x80) {  
  187.         frame.setLocalColorTableSize(2 << (flag & 7));  
  188.         this->readLocalColorTable(frame);  
  189.     }  
  190.   
  191.     int codeSize = this->mInStream.get();  
  192.     vector<char> data;  
  193.     char* block = NULL;  
  194.     int blockSize = this->readOneBlock(block);  
  195.     while (blockSize) {  
  196.         for (int i = 0; i < blockSize; i++)  
  197.             data.push_back(block[i]);  
  198.         delete[] block;  
  199.         blockSize = this->readOneBlock(block);  
  200.     }  
  201.   
  202.     int length = this->mGlobalHeight * this->mGlobalWidth;  
  203.     int* lastColors = NULL;  
  204.     if (frame.getAction() == FrameInfo::RETURN_PRE  
  205.             && this->mFrames.size() > 1) {  
  206.         lastColors = cloneColors(  
  207.                 this->mFrames[this->mFrames.size() - 2].getColors(), length);  
  208.     } else if (frame.getAction() == FrameInfo::NONE  
  209.             || frame.getAction() == FrameInfo::REMOVE_IMAGE) {  
  210.         if (!this->mFrames.empty())  
  211.             lastColors = cloneColors(  
  212.                     this->mFrames[this->mFrames.size() - 1].getColors(),  
  213.                     length);  
  214.     } else if (frame.getAction() == FrameInfo::RETURN_BG) {  
  215.         if (!this->mFrames.empty()) {  
  216.             lastColors = cloneColors(  
  217.                     this->mFrames[this->mFrames.size() - 1].getColors(),  
  218.                     length);  
  219.             int bgColor = 0;  
  220.             if (frame.hasTransparentIdx()) {  
  221.                 int transparentIdx = frame.getTransparentIdx();  
  222.                 if (frame.hasLocalColorTable())  
  223.                     bgColor = frame.getLocalColorTable()[transparentIdx];  
  224.                 else  
  225.                     bgColor = this->mGlobalColorTable[transparentIdx];  
  226.             }  
  227.   
  228.             int yStart = frame.getOffsetY();  
  229.             int yEnd = yStart + frame.getHeight();  
  230.             int y = yStart, xStart, xEnd, x;  
  231.             while (y < yEnd) {  
  232.                 xStart = this->mGlobalWidth * y + frame.getOffsetX();  
  233.                 xEnd = xStart + frame.getWidth();  
  234.                 x = xStart;  
  235.                 while (x < xEnd) {  
  236.                     lastColors[x] = bgColor;  
  237.                 }  
  238.             }  
  239.         }  
  240.     }  
  241.   
  242.     if (lastColors == NULL  
  243.         )  
  244.         lastColors = cloneColors(NULL, length);  
  245.   
  246.     frame.decocde(this->mGlobalColorTable, this->mGlobalColorTableSize,  
  247.             this->mGlobalBackGroundColorIndex, codeSize, &data[0], data.size(),  
  248.             lastColors, this->mGlobalWidth, this->mGlobalHeight);  
  249.     this->mFrames.push_back(frame);  
  250.     decodeFinished(this->mFrames.size()-1);  
  251.     showIntLog("Image Ready :"this->mFrames.size());  
  252. }  
  253.   
  254. void GifUtils::readControlExtension(int idx) {  
  255.     char* data = NULL;  
  256.     this->readOneBlock(data);  
  257.     char tmp[10] = { 0 };  
  258.     sprintf(tmp, "%d", idx);  
  259.     FrameInfo frame(tmp);  
  260.     frame.setAction((data[0] & 0x3C) >> 2);  
  261.     frame.setUserInput(data[0] & 2);  
  262.     if (data[0] & 1)  
  263.         frame.setTransparentIndex(data[3]);  
  264.     frame.setDelayTime(getShort(data, 1));  
  265.     if (!this->mInStream.get())  
  266.         this->mFrames.push_back(frame);  
  267.     else  
  268.         this->mStatus = DATA_ERROR;  
  269. }  
  270.   
  271. void GifUtils::readCommentExtension() {  
  272.     int blockSize = 1;  
  273.     char * data = NULL;  
  274.     while (blockSize) {  
  275.         if (data != NULL  
  276.             )  
  277.             delete[] data;  
  278.         blockSize = this->readOneBlock(data);  
  279.     }  
  280.   
  281. }  
  282.   
  283. void GifUtils::readTextExtension() {  
  284.     this->readCommentExtension();  
  285.   
  286. //  unsigned char blockSize = this->mInStream.get();  
  287. //  unsigned short locationX = this->readShort();  
  288. //  unsigned short locationY = this->readShort();  
  289. //  unsigned short width = this->readShort();  
  290. //  unsigned short height = this->readShort();  
  291. //  char cellWidth = this->mInStream.get();  
  292. //  char cellHeight = this->mInStream.get();  
  293. //  char foreColorIdx = this->mInStream.get();  
  294. //  char bgColorIdx = this->mInStream.get();  
  295. //  char * data = NULL;  
  296. //  while(blockSize){  
  297. //      if(data != NULL)  
  298. //          delete[] data;  
  299. //      blockSize = this->readOneBlock(data);  
  300. //  }  
  301. }  
  302.   
  303. void GifUtils::readNETSCAPFile() {  
  304.     unsigned char blockSize;  
  305.     char* data = NULL;  
  306.     blockSize = this->readOneBlock(data);  
  307.     while (blockSize != 0) {  
  308.         if (data[0] == 1)  
  309.             this->mLoopCount = getShort(data, 1);  
  310.         delete[] data;  
  311.         data = NULL;  
  312.         blockSize = this->readOneBlock(data);  
  313.     }  
  314. }  
  315.   
  316. void GifUtils::skip() {  
  317.     unsigned char blockSize;  
  318.     char* data = NULL;  
  319.     blockSize = this->readOneBlock(data);  
  320.     while (blockSize != 0) {  
  321.         delete[] data;  
  322.         data = NULL;  
  323.         blockSize = this->readOneBlock(data);  
  324.     }  
  325. }  
  326.   
  327. void GifUtils::readApplicationExtension() {  
  328.     char * data = NULL;  
  329.     this->readOneBlock(data);  
  330.     char applicationIdentifier[8]; //应用程序标志符  
  331.     for (int i = 0; i < 8; i++)  
  332.         applicationIdentifier[i] = data[i];  
  333.     char applicationAuthenticationCode[3]; //应用程序验证码  
  334.     for (int i = 0; i < 3; i++)  
  335.         applicationAuthenticationCode[i] = data[i + 8];  
  336.     delete[] data;  
  337.     data = NULL;  
  338.   
  339.     bool ap = strcmp(applicationIdentifier, "NETSCAPE");  
  340.     bool code = strcmp(applicationAuthenticationCode, "2.0");  
  341.     if (!ap && !code) {  
  342.         this->readNETSCAPFile();  
  343.     } else  
  344.         this->skip();  
  345. }  
  346.   
  347. /** 
  348.  * 获得图片帧数 
  349.  */  
  350. int GifUtils::getImageCount() {  
  351.     return this->mFrames.size();  
  352. }  
  353.   
  354. /** 
  355.  * 获得X方向偏移量 
  356.  */  
  357. int GifUtils::getOffsetX(int idx) {  
  358.     int re = this->mFrames[idx].getOffsetX();  
  359.     return re;  
  360. }  
  361.   
  362. /** 
  363.  * 获得Y方向偏移量 
  364.  */  
  365. int GifUtils::getOffsetY(int idx) {  
  366.     return this->mFrames[idx].getOffsetY();  
  367. }  
  368.   
  369. /** 
  370.  * 获得宽度 
  371.  */  
  372. int GifUtils::getWidth(int idx) {  
  373.     return this->mFrames[idx].getWidth();  
  374. }  
  375.   
  376. /** 
  377.  * 获得高度 
  378.  */  
  379. int GifUtils::getHeight(int idx) {  
  380.     return this->mFrames[idx].getHeight();  
  381. }  
  382.   
  383. /** 
  384.  * 获得等待时间 
  385.  */  
  386. int GifUtils::getDelayTime(int idx) {  
  387.     return this->mFrames[idx].getDelayTime();  
  388. }  
  389.   
  390. /** 
  391.  * 获得动作 
  392.  */  
  393. int GifUtils::getAction(int idx) {  
  394.     return this->mFrames[idx].getAction();  
  395. }  
  396.   
  397. /** 
  398.  * 获得用户操作 
  399.  */  
  400. bool GifUtils::getUserInput(int idx){  
  401.     return this->mFrames[idx].getUserInput();  
  402. }  
  403. /** 
  404.  * 获得颜色数据 
  405.  */  
  406. int* GifUtils::getColors(int idx) {  
  407.     return this->mFrames[idx].getColors();  
  408. }  
  409.   
  410. int GifUtils::getGlobalWidth(){  
  411.     return this->mGlobalWidth;  
  412. }  
  413.   
  414. int GifUtils::getGlobalHeight(){  
  415.     return this->mGlobalHeight;  
  416. }  


FrameInfo.cpp

[cpp] view plaincopy
  1. #include "../head/FrameInfo.h"  
  2. #include "../head/LZWDecoder.h"  
  3. //#include "../head/Bitmap.h"  
  4. #include <iostream>  
  5. #include <cstring>  
  6. #include <cstdio>  
  7.   
  8. FrameInfo::FrameInfo(string name) {  
  9.     this->mName = name;  
  10.     this->mTransparentFlag = false;  
  11.     this->mHasLocalColorTable = false;  
  12. }  
  13.   
  14. void FrameInfo::setAction(char action) {  
  15.     if (action < 4)  
  16.         this->mAction = FRAME_ACTION(action);  
  17.     else  
  18.         this->mAction = OTHER;  
  19. }  
  20.   
  21. void FrameInfo::setUserInput(bool flag) {  
  22.     this->mUserInputFlag = flag;  
  23. }  
  24.   
  25. void FrameInfo::setDelayTime(unsigned char delay) {  
  26.     this->mDelayTime = delay;  
  27. }  
  28.   
  29. void FrameInfo::setTransparentIndex(unsigned char idx) {  
  30.     this->mTransparentFlag = true;  
  31.     this->mTransparentColorIndex = idx;  
  32. }  
  33.   
  34. bool FrameInfo::isUserInput() {  
  35.     return this->mUserInputFlag;  
  36. }  
  37.   
  38. bool FrameInfo::hasTransparentIdx() {  
  39.     return this->mTransparentFlag;  
  40. }  
  41.   
  42. bool FrameInfo::hasLocalColorTable() {  
  43.     return this->mHasLocalColorTable;  
  44. }  
  45.   
  46. int FrameInfo::getLocalColorTableSize() {  
  47.     return this->mLocalColorTableSize;  
  48. }  
  49.   
  50. int* FrameInfo::getLocalColorTable() {  
  51.     return this->mLocalColorTable;  
  52. }  
  53.   
  54. unsigned char FrameInfo::getTransparentIdx() {  
  55.     return this->mTransparentColorIndex;  
  56. }  
  57.   
  58. void FrameInfo::setXoffset(int x) {  
  59.     this->mXoffset = x;  
  60. }  
  61.   
  62. void FrameInfo::setYOffset(int y) {  
  63.     this->mYoffset = y;  
  64. }  
  65.   
  66. void FrameInfo::setWidth(int width) {  
  67.     this->mWidth = width;  
  68. }  
  69.   
  70. void FrameInfo::setHeight(int height) {  
  71.     this->mHeight = height;  
  72. }  
  73.   
  74. void FrameInfo::setInterlaceFlag(bool interlace) {  
  75.     this->mInterlaceFlag = interlace;  
  76. }  
  77.   
  78. void FrameInfo::setSortFlag(bool sort) {  
  79.     this->mSortFlag = sort;  
  80. }  
  81.   
  82. void FrameInfo::setLocalColorTableSize(int size) {  
  83.     this->mHasLocalColorTable = true;  
  84.     this->mLocalColorTableSize = size;  
  85. }  
  86.   
  87. void FrameInfo::setLocalColorTable(int* table) {  
  88.     this->mLocalColorTable = table;  
  89. }  
  90.   
  91. void FrameInfo::decocde(int* globalColorTable, int tableSize, int bgIdx,  
  92.         unsigned char codeSize, char* data, int length, int* lastColors,  
  93.         int gWidth, int gHeight) {  
  94.   
  95.     LZWDecoder decoder(codeSize, this->mWidth, this->mHeight);  
  96.     decoder.setData(data, length);  
  97.     unsigned char* decodedData = decoder.doDecode();  
  98.   
  99. //  char tmp[10];  
  100. //  int dataSize = this->mWidth * this->mHeight;  
  101. //  string decoded = "decoded " + this->mName;  
  102. //  FILE* file1 = fopen(decoded.c_str(), "w+");  
  103. //  for(int i = 0; i < dataSize; i++)  
  104. //  {  
  105. //      sprintf(tmp,"%d ", decodedData[i]);  
  106. //      fwrite(tmp,1,strlen(tmp), file1);  
  107. //  }  
  108. //  fflush(file1);  
  109. //  fclose(file1);  
  110. //  file1 = NULL;  
  111.   
  112.     int* activeColorTable =  
  113.             this->mHasLocalColorTable ?  
  114.                     this->mLocalColorTable : globalColorTable;  
  115.     int activeColorTableSize =  
  116.             this->mHasLocalColorTable ? this->mLocalColorTableSize : tableSize;  
  117.   
  118.     int savedColor;  
  119.     if (this->mTransparentFlag) {  
  120.         savedColor = activeColorTable[this->mTransparentColorIndex];  
  121.         if (!strcmp(this->mName.c_str(), "0")) {  
  122.             activeColorTable[this->mTransparentColorIndex] = activeColorTable[bgIdx];  
  123.         } else {  
  124.             activeColorTable[this->mTransparentColorIndex] = 0;  
  125.         }  
  126.     }  
  127.   
  128.     //make bitmap below  
  129. //  this->mColors = new int[this->mWidth * this->mHeight];  
  130. //  char picData[this->mWidth * this->mHeight];  
  131.     this->mColors = lastColors;  
  132.   
  133.     int pass = 1;  
  134.     int inc = 8;  
  135.     int iline = 0, line = 0;  
  136.     for (int i = 0; i < this->mHeight; i++) {  
  137.         line = i;  
  138.         if (this->mInterlaceFlag) {  
  139.             if (iline >= this->mHeight) {  
  140.                 pass++;  
  141.                 switch (pass) {  
  142.                 case 2:  
  143.                     iline = 4;  
  144.                     break;  
  145.                 case 3:  
  146.                     iline = 2;  
  147.                     inc = 4;  
  148.                     break;  
  149.                 case 4:  
  150.                     iline = 1;  
  151.                     inc = 2;  
  152.                     break;  
  153.                 }  
  154.             }  
  155.             line = iline;  
  156.             iline += inc;  
  157.         }  
  158.         int sIdx = i * this->mWidth;  
  159.         int dIdx = (this->getOffsetY() + line) * gWidth + this->getOffsetX();  
  160.         for (int x = 0; x < this->mWidth; x++) {  
  161. //          picData[dIdx + x] = decodedData[sIdx + x];  
  162.             if(activeColorTable[decodedData[sIdx + x]] != 0)  
  163.             this->mColors[dIdx + x] = activeColorTable[decodedData[sIdx + x]];  
  164.         }  
  165.     }  
  166. //  FILE* file = fopen(this->mName.c_str(), "w+");  
  167. //  fwrite(this->mColors, 4, this->mWidth * this->mHeight, file);  
  168. //  fflush(file);  
  169. //  fclose(file);  
  170.   
  171. //  BitmapUtils bitmap(this->mWidth, this->mHeight);  
  172. //  bitmap.setColorTable(activeColorTable, activeColorTableSize);  
  173. //  bitmap.addData(picData, (int) (this->mWidth * this->mHeight));  
  174. //  bitmap.save(this->mName);  
  175.   
  176.     if (this->mTransparentFlag && !this->mHasLocalColorTable)  
  177.         globalColorTable[this->mTransparentColorIndex] = savedColor;  
  178. }  
  179. /** 
  180.  * 获得X方向偏移量 
  181.  */  
  182. int FrameInfo::getOffsetX() {  
  183.     return this->mXoffset;  
  184. }  
  185.   
  186. /** 
  187.  * 获得Y方向偏移量 
  188.  */  
  189. int FrameInfo::getOffsetY() {  
  190.     return this->mYoffset;  
  191. }  
  192.   
  193. /** 
  194.  *  获得宽度 
  195.  */  
  196. int FrameInfo::getWidth() {  
  197.     return this->mWidth;  
  198. }  
  199.   
  200. /** 
  201.  * 获得高度 
  202.  */  
  203. int FrameInfo::getHeight() {  
  204.     return this->mHeight;  
  205. }  
  206.   
  207. /** 
  208.  * 获得延迟时间 
  209.  */  
  210. int FrameInfo::getDelayTime() {  
  211.     return (intthis->mDelayTime * 10;  
  212. }  
  213.   
  214. /** 
  215.  * 获取帧动作 
  216.  */  
  217. int FrameInfo::getAction() {  
  218.     return this->mAction;  
  219. }  
  220.   
  221. /** 
  222.  * 是否接受用户输入 
  223.  */  
  224. bool FrameInfo::getUserInput(){  
  225.     return this->mUserInputFlag;  
  226. }  
  227.   
  228. /** 
  229.  * 获取色彩数据 
  230.  */  
  231. int* FrameInfo::getColors() {  
  232.     return this->mColors;  
  233. }  


LZWDecoder.cpp

[cpp] view plaincopy
  1. #include "../head/LZWDecoder.h"  
  2. #include <stdio.h>  
  3. #include <cstring>  
  4. #include <cstdlib>  
  5. #include <iostream>  
  6. using namespace std;  
  7.   
  8. LZWDecoder::LZWDecoder(unsigned char codeSize, int width, int height) {  
  9.     this->mOrignalCodeSize = codeSize + 1;  
  10.     int orignalCodeTableSize = 1 << codeSize;  
  11.     this->mIdxClear = orignalCodeTableSize;  
  12.     this->mIdxEnd = orignalCodeTableSize + 1;  
  13.   
  14.     this->mOutData = new unsigned char[width * height];this  
  15.     ->mCodeTable = new unsigned char*[MAX_CODE_TABLE_SIZE];  
  16.     for (int i = 0; i < MAX_CODE_TABLE_SIZE; i++)  
  17.         this->mCodeTable[i] = NULL;  
  18.     for (int i = 0; i < orignalCodeTableSize; i++) {  
  19.         this->mCodeTable[i] = new unsigned char[2];  
  20.         this->mCodeTable[i][0] = 1;  
  21.         this->mCodeTable[i][1] = i;  
  22.     }  
  23.     this->mFinishedNumber = 0;  
  24. }  
  25.   
  26. /** 
  27.  * 设定待解码的数据 
  28.  */  
  29. void LZWDecoder::setData(char* data, int length) {  
  30.     this->mInData = data;  
  31.     this->mDataLength = length;  
  32. }  
  33.   
  34. unsigned char* LZWDecoder::doDecode() {  
  35.   
  36.     int codeSize = this->mOrignalCodeSize;  
  37.     int codeMask = (1 << codeSize) - 1;  
  38.     int availableIdx = this->mIdxClear + 2;  
  39.     int preCode = NULL_CODE, inCode = 0, code = 0;  
  40.     int readedBits = 0, readedCode = 0;  
  41.     int readBytes = 0, top = 0, first = 0;  
  42.   
  43.     unsigned short* prefix = new unsigned short[MAX_CODE_TABLE_SIZE];  
  44.     unsigned char* suffix = new unsigned char[MAX_CODE_TABLE_SIZE];  
  45.     unsigned char* pixelStack = new unsigned char[MAX_CODE_TABLE_SIZE + 1];  
  46.     for(int i =0; i < this->mIdxClear; i++){  
  47.         prefix[i] = 0;  
  48.         suffix[i] = i & 0xFF;  
  49.     }  
  50.   
  51.     while (readBytes < this->mDataLength) {  
  52.         if (!top) {  
  53.             if (readedBits < codeSize) { //如果现有的数据长度不足已构成一个编码,那么继续读取  
  54.                 readedCode += (((intthis->mInData[readBytes]) & 0xFF)  
  55.                         << readedBits;  
  56.                 readedBits += 8;  
  57.                 readBytes++;  
  58.                 continue;  
  59.             }  
  60.   
  61.             //从读取的数据中获取一个编码  
  62.             inCode = readedCode & codeMask;  
  63.             readedCode >>= codeSize;  
  64.             readedBits -= codeSize;  
  65.   
  66.             if (inCode > availableIdx || inCode == this->mIdxEnd) {  
  67.                 break;  
  68.             }  
  69.   
  70.             if (inCode == this->mIdxClear) {  
  71.                 codeSize = this->mOrignalCodeSize;  
  72.                 codeMask = (1 << codeSize) - 1;  
  73.                 availableIdx = this->mIdxClear + 2;  
  74.                 preCode = NULL_CODE;  
  75.                 continue;  
  76.             }  
  77.   
  78.             if (preCode == NULL_CODE) {  
  79.                 pixelStack[top++] = suffix[inCode];  
  80.                 preCode = inCode;  
  81.                 first = inCode;  
  82.                 continue;  
  83.             }  
  84.             code = inCode;  
  85.             if (inCode == availableIdx) {  
  86.                 pixelStack[top++] = first;  
  87.                 inCode = preCode;  
  88.             }  
  89.   
  90.             while (inCode > this->mIdxClear) {  
  91.                 pixelStack[top++] = suffix[inCode];  
  92.                 inCode = prefix[inCode];  
  93.             }  
  94.   
  95.             first = suffix[inCode];  
  96.             if (availableIdx >= MAX_CODE_TABLE_SIZE) {  
  97.                 cout << "availableIdx = MAX_CODE_TABLE_SIZE" << endl;  
  98.                 break;  
  99.             }  
  100.   
  101.             pixelStack[top++] = first;  
  102.             prefix[availableIdx] = preCode;  
  103.             suffix[availableIdx] = first;  
  104.             availableIdx++;  
  105.   
  106.             if (((availableIdx & codeMask) == 0)  
  107.                     && availableIdx < MAX_CODE_TABLE_SIZE) {  
  108.                 codeSize++;  
  109.                 codeMask += availableIdx;  
  110.             }  
  111.             preCode = code;  
  112.         }  
  113.         top--;  
  114.         this->mOutData[this->mFinishedNumber++] = pixelStack[top];  
  115.     }  
  116.     delete[] prefix;  
  117.     delete[] suffix;  
  118.     delete[] pixelStack;  
  119.     return this->mOutData;  
  120. }  



       经过我自己的初步测试,使用C++实现的解码器,比起JAVA的实现,基本上可以节约1/3到1/2的解码时间,内存占用上稍有优势,但不明显。

       PS:源码中的Bitmap.h和BitmapUtils.cpp的作用是将解码出来的gif帧保存为bitmap文件,与gif的解码无关,只是写代码时的中间产物。

      点击下载源码