zoukankan      html  css  js  c++  java
  • android gif

    引用:http://blog.csdn.net/a220315410/article/details/6753999

       最近闲来无事,折腾了一下关于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

    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

    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

    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

    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

    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

    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的解码无关,只是写代码时的中间产物。

          点击下载源码

  • 相关阅读:
    10天掌握webpack 4.0 Html 插件
    10天掌握webpack 4.0 服务篇
    spring boot 国际化信息
    Java 编程下使用 Class.forName() 加载类
    Java 编程下正则表达式判断字符串是否包含中文
    Adb connection Error:远程主机强迫关闭了一个现有的连接 解决方法
    Java 编程下简介 Class 与类加载
    通过htaccess文件配置多个一级域名指向根目录的子文件夹
    apache httpd.conf
    composer安装laravel框架时未生成Vendor解决办法
  • 原文地址:https://www.cnblogs.com/sode/p/2760087.html
Copyright © 2011-2022 走看看