引用: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解码。
以下是我参考的资料:
解码的算法是直接抄袭了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));
- else
- mFrames.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();
- } else
- throw 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;
- }
- @Override
- public void run() {
- doDecode(mPath);
- }
- }
- private static Handler mHandler = new Handler() {
- @Override
- public 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() {
- @Override
- public 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);
- }
- }
- };
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- init();
- }
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- isReady = true;
- init();
- this.setOnTouchListener(new OnTouchListener(){
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- return mGestureDetector.onTouchEvent(event);
- }});
- }
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- isReady = false;
- mHandler.removeCallbacksAndMessages(null);
- }
- private GestureDetector.OnGestureListener gestureListener = new GestureDetector.OnGestureListener() {
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- if(mGif.getFrame(mCurrentImage).isUserInput())
- {
- mHandler.removeMessages(mCurrentImage + 1);
- mHandler.handleMessage(mHandler.obtainMessage(mCurrentImage + 1));
- }
- return true;
- }
- @Override
- public void onShowPress(MotionEvent e) {
- ;
- }
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- return true;
- }
- @Override
- public void onLongPress(MotionEvent e) {
- ;
- }
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- return true;
- }
- @Override
- public 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];
- else
- bgColor = 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);
- else
- this->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();
- } else
- this->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);
- else
- this->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的解码无关,只是写代码时的中间产物。