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

package com.ray.test.gif;import java.util.ArrayList;public class Gif {public class Frame {private int delayTime;private Bitmap image;private boolean userInput = false;public Frame(int delay, int[] color) {delayTime = delay;image = Bitmap.createBitmap(color, mWidth, mHeight, Config.RGB_565);}private Frame setUserInput() {userInput = true;return this;}public int getDelay() {return delayTime;}public Bitmap getImage() {return image;}public boolean isUserInput() {return userInput;}}private int mWidth;private int mHeight;private List<Frame> mFrames = new ArrayList<Frame>();public Gif(int width, int height) {mWidth = width;mHeight = height;}public int getWidth() {return mWidth;}public int getHeight() {return mHeight;}public void addFrame(int delay, int[] color, boolean userInput) {synchronized (mFrames) {if (!userInput)mFrames.add(new Frame(delay, color));elsemFrames.add(new Frame(delay, color).setUserInput());}}public int getFrameCount() {synchronized (mFrames) {return mFrames.size();}}public Frame getFrame(int idx) {synchronized (mFrames) {if (idx < 0 || idx >= mFrames.size())return null;return mFrames.get(idx);}}}

GifDecoder.java

package com.ray.test.gif;import java.io.File;public class GifDecoder {private static final String MYTAG = "Ray";private static final String CLASS_NAME = "GifDecoder";public interface DecodeResult {public void onDecodeFinished(int count);}private static Gif sGif;private static DecodeResult sListener;private static boolean sIsReady = false;static void decode(String filePath, DecodeResult result) throws FileNotFoundException {File f = new File(filePath);if (f.exists()) {sListener = result;sIsReady = false;sGif = null;WorkThread thread = new WorkThread(filePath);thread.start();} elsethrow new FileNotFoundException("can not find file:" + filePath);}static Gif getImage() {return sGif;}private static void onDecodeFinished(String count) {Log.d(MYTAG, CLASS_NAME + ": onDecodeFinished, count = " + count);int c = Integer.parseInt(count);getFrames(c);if(c == 0)mHandler.obtainMessage(c).sendToTarget();}private static void getFrames(int idx) {if(idx == 0)sGif = new Gif(getWidth(), getHeight());sGif.addFrame(getDelay(idx), getColors(idx), getUserInput(idx));}private static class WorkThread extends Thread {private String mPath;public WorkThread(String path) {mPath = path;}@Overridepublic void run() {doDecode(mPath);}}private static Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {sListener.onDecodeFinished(msg.what);}};private static native void doDecode(String path);private static native int getWidth();private static native int getHeight();private static native int getDelay(int index);private static native boolean getUserInput(int index);private static native int[] getColors(int index);}


GifVIewer.java

package com.ray.test.gif;import android.content.Context;public class GifView extends SurfaceView implements SurfaceHolder.Callback {private SurfaceHolder mHolder;private Gif mGif;private boolean isReady = false;private Rect mdRc;private Rect msRc;private Paint mPaint;GestureDetector mGestureDetector;private int mCurrentImage;public GifView(Context context) {super(context);mHolder = this.getHolder();mHolder.addCallback(this);mPaint = new Paint();mGestureDetector = new GestureDetector(gestureListener);}public void setImages(Gif gif) {this.mGif = gif;init();}private void init() {if (isReady && mGif != null) {msRc = new Rect(0, 0, mGif.getWidth(), mGif.getHeight());Rect vRc = new Rect();getLocalVisibleRect(vRc);mdRc = getDstRc(msRc, vRc);mHandler.removeCallbacksAndMessages(null);mHandler.sendEmptyMessage(0);}}private Rect getDstRc(Rect image, Rect view) {double xRate = view.width() * 1.0 / image.width();double yRate = view.height() * 1.0 / image.height();if (xRate > yRate) {return new Rect((int) (view.width() - image.width() * yRate) / 2, 0, (int) (image.width() * yRate) + (int) (view.width() - image.width() * yRate)/ 2, (int) (image.height() * yRate));} else {return new Rect(0, (int) (view.height() - image.height() * xRate) / 2, (int) (image.width() * xRate), (int) (image.height() * xRate)+ (int) (view.height() - image.height() * xRate) / 2);}}private Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {int idx = msg.what;if (idx < 0 || idx >= mGif.getFrameCount())idx = 0;mCurrentImage = idx;Frame f = mGif.getFrame(idx);if(f == null){Log.e("Ray", "f = null when idx = " + idx);this.sendEmptyMessageDelayed(idx, 100);return;}Rect rc = new Rect(mdRc);Canvas cv = mHolder.lockCanvas(rc);if (rc.equals(mdRc)) {cv.drawBitmap(f.getImage(), msRc, mdRc, mPaint);mHolder.unlockCanvasAndPost(cv);this.sendEmptyMessageDelayed(++idx, f.getDelay());} else {mHolder.unlockCanvasAndPost(cv);this.sendEmptyMessageDelayed(idx, 100);}}};@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {init();}@Overridepublic void surfaceCreated(SurfaceHolder holder) {isReady = true;init();this.setOnTouchListener(new OnTouchListener(){@Overridepublic boolean onTouch(View v, MotionEvent event) {return mGestureDetector.onTouchEvent(event);}});}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {isReady = false;mHandler.removeCallbacksAndMessages(null);}private GestureDetector.OnGestureListener gestureListener = new GestureDetector.OnGestureListener() {@Overridepublic boolean onSingleTapUp(MotionEvent e) {if(mGif.getFrame(mCurrentImage).isUserInput()){mHandler.removeMessages(mCurrentImage + 1);mHandler.handleMessage(mHandler.obtainMessage(mCurrentImage + 1));}return true;}@Overridepublic void onShowPress(MotionEvent e) {;}@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {return true;}@Overridepublic void onLongPress(MotionEvent e) {;}@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {return true;}@Overridepublic boolean onDown(MotionEvent e) {return true;}};}


GifUtils.cpp

#include "../head/GifUtils.h"#include <cstring>#include <iostream>#include <typeinfo>extern void showIntLog(string str, int num);extern void showStringLog(string text);extern void decodeFinished(int count);unsigned short getShort(char* data, int idx) {return *((unsigned short*) (data + idx));}GifUtils::GifUtils(string path) {this->mInStream.open(path.c_str());this->mFileSize = mInStream.gcount();}GifUtils::~GifUtils() {if (this->mGlobalColorTable != NULL) {delete[] this->mGlobalColorTable;this->mGlobalColorTable = NULL;}}void GifUtils::doWork(){showStringLog("Start decode");this->readFile();showStringLog("end decode");}int GifUtils::readShort() {return (unsigned short) (this->mInStream.get() | this->mInStream.get() << 8);}void GifUtils::readFile() {this->mStatus = DECODING;this->readHead();if (!this->is89) //本类只支持gif89版本return;this->readLogicalScreenDescriptor();int imageId = 0;while (this->mStatus == DECODING) {char flag = this->mInStream.get();if (flag == BLOCK_FLAG_IMAGE_DESCRIPTOR){this->readImageDescriptor();} else if (((unsigned char) flag) == BLOCK_FLAG_EXTENSION) {flag = this->mInStream.get();switch (flag) {case EXTENSION_FLAG_CONTROL:this->readControlExtension(imageId);imageId++;break;case EXTENSION_FLAG_COMMEMT:this->readCommentExtension();break;case EXTENSION_FLAG_TEXT:this->readTextExtension();break;case EXTENSION_FLAG_APPLICATION:this->readApplicationExtension();break;default:cout << "invalidate EXTENSION FLAG" << endl;this->mStatus = DATA_ERROR;break;}} else if (flag == BLOCK_FLAG_END) {this->mStatus = FINISHED;break;} else {cout << "invalidate block head" << endl;this->mStatus = DATA_ERROR;break;}}for(int i = 0; i < this->mFrames.size(); i++){delete[] this->mFrames[i].getColors();}}/** * 读取头文件 */void GifUtils::readHead() {char head[6];for (int i = 0; i < 6; i++)mInStream >> head[i];if (0 == strcmp(head, FILE_HEAD_GIF_89A)) {this->is89 = true;} else {this->is89 = false;}}/** * 读取逻辑屏幕标识符 */void GifUtils::readLogicalScreenDescriptor() {char data[7];this->mInStream.read(data, 7);this->mGlobalWidth = getShort(data, 0);this->mGlobalHeight = getShort(data, 2);this->mHasGlobalColorTable = (data[4] & 0x80);this->mColorResolution = ((data[4] & 0x70) >> 4) + 1;this->mSortFlag = data[4] & 8;this->mGlobalColorTableSize = 2 << (data[4] & 7);this->mGlobalBackGroundColorIndex = data[5];this->mRateOfHeightWithWidth = data[6];if (this->mHasGlobalColorTable)this->readGlobalColorTable();}/** * 读取全局调色板 */void GifUtils::readGlobalColorTable() {int* table = new int[this->mGlobalColorTableSize];for (int i = 0; i < this->mGlobalColorTableSize; i++) {table[i] = (unsigned char) this->mInStream.get();table[i] <<= 8;table[i] += (unsigned char) this->mInStream.get();table[i] <<= 8;table[i] += (unsigned char) this->mInStream.get();table[i] |= 0xFF000000;}this->mGlobalColorTable = table;}unsigned char GifUtils::readOneBlock(char* &data) {unsigned char length = this->mInStream.get();if (length != 0) {data = new char[length];this->mInStream.read(data, length);}return length;}/** * 读取局部调色板 */void GifUtils::readLocalColorTable(FrameInfo& frame) {int size = frame.getLocalColorTableSize();int* table = new int[size];for (int i = 0; i < size; i++) {table[i] = (unsigned char) this->mInStream.get();table[i] <<= 8;table[i] += (unsigned char) this->mInStream.get();table[i] <<= 8;table[i] += (unsigned char) this->mInStream.get();table[i] |= 0xFF000000;}frame.setLocalColorTable(table);}int* cloneColors(int* colors, int length) {int* data = new int[length];if (colors == NULL) {memset(data, length*4, 0);} else {for (int i = 0; i < length; i++)data[i] = colors[i];}return data;}/** * 读取图像标识符 */void GifUtils::readImageDescriptor() {FrameInfo frame = this->mFrames.back();this->mFrames.pop_back();frame.setXoffset(this->readShort());frame.setYOffset(this->readShort());frame.setWidth(this->readShort());frame.setHeight(this->readShort());char flag = this->mInStream.get();frame.setInterlaceFlag(flag & 0x40);frame.setSortFlag(flag & 0x20);if (flag & 0x80) {frame.setLocalColorTableSize(2 << (flag & 7));this->readLocalColorTable(frame);}int codeSize = this->mInStream.get();vector<char> data;char* block = NULL;int blockSize = this->readOneBlock(block);while (blockSize) {for (int i = 0; i < blockSize; i++)data.push_back(block[i]);delete[] block;blockSize = this->readOneBlock(block);}int length = this->mGlobalHeight * this->mGlobalWidth;int* lastColors = NULL;if (frame.getAction() == FrameInfo::RETURN_PRE&& this->mFrames.size() > 1) {lastColors = cloneColors(this->mFrames[this->mFrames.size() - 2].getColors(), length);} else if (frame.getAction() == FrameInfo::NONE|| frame.getAction() == FrameInfo::REMOVE_IMAGE) {if (!this->mFrames.empty())lastColors = cloneColors(this->mFrames[this->mFrames.size() - 1].getColors(),length);} else if (frame.getAction() == FrameInfo::RETURN_BG) {if (!this->mFrames.empty()) {lastColors = cloneColors(this->mFrames[this->mFrames.size() - 1].getColors(),length);int bgColor = 0;if (frame.hasTransparentIdx()) {int transparentIdx = frame.getTransparentIdx();if (frame.hasLocalColorTable())bgColor = frame.getLocalColorTable()[transparentIdx];elsebgColor = this->mGlobalColorTable[transparentIdx];}int yStart = frame.getOffsetY();int yEnd = yStart + frame.getHeight();int y = yStart, xStart, xEnd, x;while (y < yEnd) {xStart = this->mGlobalWidth * y + frame.getOffsetX();xEnd = xStart + frame.getWidth();x = xStart;while (x < xEnd) {lastColors[x] = bgColor;}}}}if (lastColors == NULL)lastColors = cloneColors(NULL, length);frame.decocde(this->mGlobalColorTable, this->mGlobalColorTableSize,this->mGlobalBackGroundColorIndex, codeSize, &data[0], data.size(),lastColors, this->mGlobalWidth, this->mGlobalHeight);this->mFrames.push_back(frame);decodeFinished(this->mFrames.size()-1);showIntLog("Image Ready :", this->mFrames.size());}void GifUtils::readControlExtension(int idx) {char* data = NULL;this->readOneBlock(data);char tmp[10] = { 0 };sprintf(tmp, "%d", idx);FrameInfo frame(tmp);frame.setAction((data[0] & 0x3C) >> 2);frame.setUserInput(data[0] & 2);if (data[0] & 1)frame.setTransparentIndex(data[3]);frame.setDelayTime(getShort(data, 1));if (!this->mInStream.get())this->mFrames.push_back(frame);elsethis->mStatus = DATA_ERROR;}void GifUtils::readCommentExtension() {int blockSize = 1;char * data = NULL;while (blockSize) {if (data != NULL)delete[] data;blockSize = this->readOneBlock(data);}}void GifUtils::readTextExtension() {this->readCommentExtension();//unsigned char blockSize = this->mInStream.get();//unsigned short locationX = this->readShort();//unsigned short locationY = this->readShort();//unsigned short width = this->readShort();//unsigned short height = this->readShort();//char cellWidth = this->mInStream.get();//char cellHeight = this->mInStream.get();//char foreColorIdx = this->mInStream.get();//char bgColorIdx = this->mInStream.get();//char * data = NULL;//while(blockSize){//if(data != NULL)//delete[] data;//blockSize = this->readOneBlock(data);//}}void GifUtils::readNETSCAPFile() {unsigned char blockSize;char* data = NULL;blockSize = this->readOneBlock(data);while (blockSize != 0) {if (data[0] == 1)this->mLoopCount = getShort(data, 1);delete[] data;data = NULL;blockSize = this->readOneBlock(data);}}void GifUtils::skip() {unsigned char blockSize;char* data = NULL;blockSize = this->readOneBlock(data);while (blockSize != 0) {delete[] data;data = NULL;blockSize = this->readOneBlock(data);}}void GifUtils::readApplicationExtension() {char * data = NULL;this->readOneBlock(data);char applicationIdentifier[8]; //应用程序标志符for (int i = 0; i < 8; i++)applicationIdentifier[i] = data[i];char applicationAuthenticationCode[3]; //应用程序验证码for (int i = 0; i < 3; i++)applicationAuthenticationCode[i] = data[i + 8];delete[] data;data = NULL;bool ap = strcmp(applicationIdentifier, "NETSCAPE");bool code = strcmp(applicationAuthenticationCode, "2.0");if (!ap && !code) {this->readNETSCAPFile();} elsethis->skip();}/** * 获得图片帧数 */int GifUtils::getImageCount() {return this->mFrames.size();}/** * 获得X方向偏移量 */int GifUtils::getOffsetX(int idx) {int re = this->mFrames[idx].getOffsetX();return re;}/** * 获得Y方向偏移量 */int GifUtils::getOffsetY(int idx) {return this->mFrames[idx].getOffsetY();}/** * 获得宽度 */int GifUtils::getWidth(int idx) {return this->mFrames[idx].getWidth();}/** * 获得高度 */int GifUtils::getHeight(int idx) {return this->mFrames[idx].getHeight();}/** * 获得等待时间 */int GifUtils::getDelayTime(int idx) {return this->mFrames[idx].getDelayTime();}/** * 获得动作 */int GifUtils::getAction(int idx) {return this->mFrames[idx].getAction();}/** * 获得用户操作 */bool GifUtils::getUserInput(int idx){return this->mFrames[idx].getUserInput();}/** * 获得颜色数据 */int* GifUtils::getColors(int idx) {return this->mFrames[idx].getColors();}int GifUtils::getGlobalWidth(){return this->mGlobalWidth;}int GifUtils::getGlobalHeight(){return this->mGlobalHeight;}


FrameInfo.cpp

#include "../head/FrameInfo.h"#include "../head/LZWDecoder.h"//#include "../head/Bitmap.h"#include <iostream>#include <cstring>#include <cstdio>FrameInfo::FrameInfo(string name) {this->mName = name;this->mTransparentFlag = false;this->mHasLocalColorTable = false;}void FrameInfo::setAction(char action) {if (action < 4)this->mAction = FRAME_ACTION(action);elsethis->mAction = OTHER;}void FrameInfo::setUserInput(bool flag) {this->mUserInputFlag = flag;}void FrameInfo::setDelayTime(unsigned char delay) {this->mDelayTime = delay;}void FrameInfo::setTransparentIndex(unsigned char idx) {this->mTransparentFlag = true;this->mTransparentColorIndex = idx;}bool FrameInfo::isUserInput() {return this->mUserInputFlag;}bool FrameInfo::hasTransparentIdx() {return this->mTransparentFlag;}bool FrameInfo::hasLocalColorTable() {return this->mHasLocalColorTable;}int FrameInfo::getLocalColorTableSize() {return this->mLocalColorTableSize;}int* FrameInfo::getLocalColorTable() {return this->mLocalColorTable;}unsigned char FrameInfo::getTransparentIdx() {return this->mTransparentColorIndex;}void FrameInfo::setXoffset(int x) {this->mXoffset = x;}void FrameInfo::setYOffset(int y) {this->mYoffset = y;}void FrameInfo::setWidth(int width) {this->mWidth = width;}void FrameInfo::setHeight(int height) {this->mHeight = height;}void FrameInfo::setInterlaceFlag(bool interlace) {this->mInterlaceFlag = interlace;}void FrameInfo::setSortFlag(bool sort) {this->mSortFlag = sort;}void FrameInfo::setLocalColorTableSize(int size) {this->mHasLocalColorTable = true;this->mLocalColorTableSize = size;}void FrameInfo::setLocalColorTable(int* table) {this->mLocalColorTable = table;}void FrameInfo::decocde(int* globalColorTable, int tableSize, int bgIdx,unsigned char codeSize, char* data, int length, int* lastColors,int gWidth, int gHeight) {LZWDecoder decoder(codeSize, this->mWidth, this->mHeight);decoder.setData(data, length);unsigned char* decodedData = decoder.doDecode();//char tmp[10];//int dataSize = this->mWidth * this->mHeight;//string decoded = "decoded " + this->mName;//FILE* file1 = fopen(decoded.c_str(), "w+");//for(int i = 0; i < dataSize; i++)//{//sprintf(tmp,"%d ", decodedData[i]);//fwrite(tmp,1,strlen(tmp), file1);//}//fflush(file1);//fclose(file1);//file1 = NULL;int* activeColorTable =this->mHasLocalColorTable ?this->mLocalColorTable : globalColorTable;int activeColorTableSize =this->mHasLocalColorTable ? this->mLocalColorTableSize : tableSize;int savedColor;if (this->mTransparentFlag) {savedColor = activeColorTable[this->mTransparentColorIndex];if (!strcmp(this->mName.c_str(), "0")) {activeColorTable[this->mTransparentColorIndex] = activeColorTable[bgIdx];} else {activeColorTable[this->mTransparentColorIndex] = 0;}}//make bitmap below//this->mColors = new int[this->mWidth * this->mHeight];//char picData[this->mWidth * this->mHeight];this->mColors = lastColors;int pass = 1;int inc = 8;int iline = 0, line = 0;for (int i = 0; i < this->mHeight; i++) {line = i;if (this->mInterlaceFlag) {if (iline >= this->mHeight) {pass++;switch (pass) {case 2:iline = 4;break;case 3:iline = 2;inc = 4;break;case 4:iline = 1;inc = 2;break;}}line = iline;iline += inc;}int sIdx = i * this->mWidth;int dIdx = (this->getOffsetY() + line) * gWidth + this->getOffsetX();for (int x = 0; x < this->mWidth; x++) {//picData[dIdx + x] = decodedData[sIdx + x];if(activeColorTable[decodedData[sIdx + x]] != 0)this->mColors[dIdx + x] = activeColorTable[decodedData[sIdx + x]];}}//FILE* file = fopen(this->mName.c_str(), "w+");//fwrite(this->mColors, 4, this->mWidth * this->mHeight, file);//fflush(file);//fclose(file);//BitmapUtils bitmap(this->mWidth, this->mHeight);//bitmap.setColorTable(activeColorTable, activeColorTableSize);//bitmap.addData(picData, (int) (this->mWidth * this->mHeight));//bitmap.save(this->mName);if (this->mTransparentFlag && !this->mHasLocalColorTable)globalColorTable[this->mTransparentColorIndex] = savedColor;}/** * 获得X方向偏移量 */int FrameInfo::getOffsetX() {return this->mXoffset;}/** * 获得Y方向偏移量 */int FrameInfo::getOffsetY() {return this->mYoffset;}/** *获得宽度 */int FrameInfo::getWidth() {return this->mWidth;}/** * 获得高度 */int FrameInfo::getHeight() {return this->mHeight;}/** * 获得延迟时间 */int FrameInfo::getDelayTime() {return (int) this->mDelayTime * 10;}/** * 获取帧动作 */int FrameInfo::getAction() {return this->mAction;}/** * 是否接受用户输入 */bool FrameInfo::getUserInput(){return this->mUserInputFlag;}/** * 获取色彩数据 */int* FrameInfo::getColors() {return this->mColors;}


LZWDecoder.cpp

#include "../head/LZWDecoder.h"#include <stdio.h>#include <cstring>#include <cstdlib>#include <iostream>using namespace std;LZWDecoder::LZWDecoder(unsigned char codeSize, int width, int height) {this->mOrignalCodeSize = codeSize + 1;int orignalCodeTableSize = 1 << codeSize;this->mIdxClear = orignalCodeTableSize;this->mIdxEnd = orignalCodeTableSize + 1;this->mOutData = new unsigned char[width * height];this->mCodeTable = new unsigned char*[MAX_CODE_TABLE_SIZE];for (int i = 0; i < MAX_CODE_TABLE_SIZE; i++)this->mCodeTable[i] = NULL;for (int i = 0; i < orignalCodeTableSize; i++) {this->mCodeTable[i] = new unsigned char[2];this->mCodeTable[i][0] = 1;this->mCodeTable[i][1] = i;}this->mFinishedNumber = 0;}/** * 设定待解码的数据 */void LZWDecoder::setData(char* data, int length) {this->mInData = data;this->mDataLength = length;}unsigned char* LZWDecoder::doDecode() {int codeSize = this->mOrignalCodeSize;int codeMask = (1 << codeSize) - 1;int availableIdx = this->mIdxClear + 2;int preCode = NULL_CODE, inCode = 0, code = 0;int readedBits = 0, readedCode = 0;int readBytes = 0, top = 0, first = 0;unsigned short* prefix = new unsigned short[MAX_CODE_TABLE_SIZE];unsigned char* suffix = new unsigned char[MAX_CODE_TABLE_SIZE];unsigned char* pixelStack = new unsigned char[MAX_CODE_TABLE_SIZE + 1];for(int i =0; i < this->mIdxClear; i++){prefix[i] = 0;suffix[i] = i & 0xFF;}while (readBytes < this->mDataLength) {if (!top) {if (readedBits < codeSize) { //如果现有的数据长度不足已构成一个编码,那么继续读取readedCode += (((int) this->mInData[readBytes]) & 0xFF)<< readedBits;readedBits += 8;readBytes++;continue;}//从读取的数据中获取一个编码inCode = readedCode & codeMask;readedCode >>= codeSize;readedBits -= codeSize;if (inCode > availableIdx || inCode == this->mIdxEnd) {break;}if (inCode == this->mIdxClear) {codeSize = this->mOrignalCodeSize;codeMask = (1 << codeSize) - 1;availableIdx = this->mIdxClear + 2;preCode = NULL_CODE;continue;}if (preCode == NULL_CODE) {pixelStack[top++] = suffix[inCode];preCode = inCode;first = inCode;continue;}code = inCode;if (inCode == availableIdx) {pixelStack[top++] = first;inCode = preCode;}while (inCode > this->mIdxClear) {pixelStack[top++] = suffix[inCode];inCode = prefix[inCode];}first = suffix[inCode];if (availableIdx >= MAX_CODE_TABLE_SIZE) {cout << "availableIdx = MAX_CODE_TABLE_SIZE" << endl;break;}pixelStack[top++] = first;prefix[availableIdx] = preCode;suffix[availableIdx] = first;availableIdx++;if (((availableIdx & codeMask) == 0)&& availableIdx < MAX_CODE_TABLE_SIZE) {codeSize++;codeMask += availableIdx;}preCode = code;}top--;this->mOutData[this->mFinishedNumber++] = pixelStack[top];}delete[] prefix;delete[] suffix;delete[] pixelStack;return this->mOutData;}



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

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

点击下载源码



更多相关文章

  1. Android Basic-xml的数据读取及保存
  2. android 使用https请求请求数据
  3. Android加载drawable中图片后自动缩放的原理
  4. Android仿人人客户端(v5.7.1)——对从服务器端(网络)获取的图片进行
  5. android实现wifi与移动数据的切换
  6. Android之等比例显示图片
  7. Android 将少量的数据文件保存在 data/data 目录下
  8. Android上使用OpenGLES2.0显示YUV数据

随机推荐

  1. Maven系列 7.文档和报告
  2. Android(安卓)优化电池使用时间 ——监控
  3. Android(安卓)UI 之WaterFall瀑布流效果
  4. Android(安卓)RePlugin 使用及源码分析(1)
  5. 2.2 窗口屏幕参数及UI样式---Display 和S
  6. Android(安卓)OpenGL相机视角
  7. Android(安卓)Studio实现简单的购物商城
  8. 为什么说枚举更占内存,枚举原理是什么?
  9. u3d android 优化
  10. Android使用SVG的一点小坑