Gif动态图加载

来源:互联网 发布:淘宝彩票 编辑:程序博客网 时间:2024/04/27 22:40

【Android Demo】加载.gif格式图片

Android系统为了节省内存,一般不支持直接显示gif图片,即使你强制设置了,也只会显示图片的第一帧。

这个 Demo 是在网上看到的,是个思路,还是有些局限性,还是记录下,以后研究吧。

1.效果图:

2.实现原理:

通过解码gif图片形成多张静态图,然后通过线程和imageView来实现循环播放

 

3.准备GIF图片

 

4.详细代码

<1>工具类:CommonUtil.java

复制代码
package com.yanis.tools;import java.io.InputStream;import com.yanis.tools.GifHelper.GifFrame;public class CommonUtil {      /**      * 解码GIF图片      *       * @param is      * @return      */      public static GifFrame[] getGif(InputStream is) {          GifHelper gifHelper = new GifHelper();          if (GifHelper.STATUS_OK == gifHelper.read(is)) {              return gifHelper.getFrames();          }          return null;      }      /**      * 判断图片是否为GIF格式      * @param is      * @return      */      public static boolean isGif(InputStream is) {          GifHelper gifHelper = new GifHelper();          return gifHelper.isGif(is);      }  }
复制代码

<2>解码类:GifHelper.java

复制代码
package com.yanis.tools;import java.io.InputStream;import java.util.Vector;import android.graphics.Bitmap;import android.graphics.Bitmap.Config;//Handler for read & extract Bitmap from *.gif  public class GifHelper {    // to store *.gif data, Bitmap & delay    public static class GifFrame {        // to access image & delay w/o interface        public Bitmap image;        public int delay;        public GifFrame(Bitmap im, int del) {            image = im;            delay = del;        }    }    // to define some error type    public static final int STATUS_OK = 0;    public static final int STATUS_FORMAT_ERROR = 1;    public static final int STATUS_OPEN_ERROR = 2;    protected int status;    protected InputStream in;    protected int width; // full image width    protected int height; // full image height    protected boolean gctFlag; // global color table used    protected int gctSize; // size of global color table    protected int loopCount = 1; // iterations; 0 = repeat forever    protected int[] gct; // global color table    protected int[] lct; // local color table    protected int[] act; // active color table    protected int bgIndex; // background color index    protected int bgColor; // background color    protected int lastBgColor; // previous bg color    protected int pixelAspect; // pixel aspect ratio    protected boolean lctFlag; // local color table flag    protected boolean interlace; // interlace flag    protected int lctSize; // local color table size    protected int ix, iy, iw, ih; // current image rectangle    protected int lrx, lry, lrw, lrh;    protected Bitmap image; // current frame    protected Bitmap lastImage; // previous frame    protected int frameindex = 0;    public int getFrameindex() {        return frameindex;    }    public void setFrameindex(int frameindex) {        this.frameindex = frameindex;        if (frameindex > frames.size() - 1) {            frameindex = 0;        }    }    protected byte[] block = new byte[256]; // current data block    protected int blockSize = 0; // block size    // last graphic control extension info    protected int dispose = 0;    // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev    protected int lastDispose = 0;    protected boolean transparency = false; // use transparent color    protected int delay = 0; // delay in milliseconds    protected int transIndex; // transparent color index    protected static final int MaxStackSize = 4096;    // max decoder pixel stack size    // LZW decoder working arrays    protected short[] prefix;    protected byte[] suffix;    protected byte[] pixelStack;    protected byte[] pixels;    protected Vector<GifFrame> frames; // frames read from current file    protected int frameCount;    // to get its Width / Height    public int getWidth() {        return width;    }    public int getHeigh() {        return height;    }    /**    * Gets display duration for specified frame.    *     * @param n    *            int index of frame    * @return delay in milliseconds    */    public int getDelay(int n) {        delay = -1;        if ((n >= 0) && (n < frameCount)) {            delay = ((GifFrame) frames.elementAt(n)).delay;        }        return delay;    }    public int getFrameCount() {        return frameCount;    }    public Bitmap getImage() {        return getFrame(0);    }    public int getLoopCount() {        return loopCount;    }    protected void setPixels() {        int[] dest = new int[width * height];        // fill in starting image contents based on last image's dispose code        if (lastDispose > 0) {            if (lastDispose == 3) {                // use image before last                int n = frameCount - 2;                if (n > 0) {                    lastImage = getFrame(n - 1);                } else {                    lastImage = null;                }            }            if (lastImage != null) {                lastImage.getPixels(dest, 0, width, 0, 0, width, height);                // copy pixels                if (lastDispose == 2) {                    // fill last image rect area with background color                    int c = 0;                    if (!transparency) {                        c = lastBgColor;                    }                    for (int i = 0; i < lrh; i++) {                        int n1 = (lry + i) * width + lrx;                        int n2 = n1 + lrw;                        for (int k = n1; k < n2; k++) {                            dest[k] = c;                        }                    }                }            }        }        // copy each source line to the appropriate place in the destination        int pass = 1;        int inc = 8;        int iline = 0;        for (int i = 0; i < ih; i++) {            int line = i;            if (interlace) {                if (iline >= ih) {                    pass++;                    switch (pass) {                    case 2:                        iline = 4;                        break;                    case 3:                        iline = 2;                        inc = 4;                        break;                    case 4:                        iline = 1;                        inc = 2;                    }                }                line = iline;                iline += inc;            }            line += iy;            if (line < height) {                int k = line * width;                int dx = k + ix; // start of line in dest                int dlim = dx + iw; // end of dest line                if ((k + width) < dlim) {                    dlim = k + width; // past dest edge                }                int sx = i * iw; // start of line in source                while (dx < dlim) {                    // map color and insert in destination                    int index = ((int) pixels[sx++]) & 0xff;                    int c = act[index];                    if (c != 0) {                        dest[dx] = c;                    }                    dx++;                }            }        }        image = Bitmap.createBitmap(dest, width, height, Config.RGB_565);    }    public Bitmap getFrame(int n) {        Bitmap im = null;        if ((n >= 0) && (n < frameCount)) {            im = ((GifFrame) frames.elementAt(n)).image;        }        return im;    }        public GifFrame[] getFrames() {        if(null != frames) return frames.toArray(new GifFrame[0]);        return null;    }    public Bitmap nextBitmap() {        frameindex++;        if (frameindex > frames.size() - 1) {            frameindex = 0;        }        return ((GifFrame) frames.elementAt(frameindex)).image;    }    public int nextDelay() {        return ((GifFrame) frames.elementAt(frameindex)).delay;    }    // to read & parse all *.gif stream    public int read(InputStream is) {        init();        if (is != null) {            in = is;            readHeader();            if (!err()) {                readContents();                if (frameCount < 0) {                    status = STATUS_FORMAT_ERROR;                }            }        } else {            status = STATUS_OPEN_ERROR;        }        try {            is.close();        } catch (Exception e) {            e.printStackTrace();        }        return status;    }        public boolean isGif(InputStream is) {        init();        if (is != null) {            in = is;            String id = "";            for (int i = 0; i < 6; i++) {                id += (char) read();            }            if (!id.toUpperCase().startsWith("GIF")) {                return false;            }        }        try {            is.close();        } catch (Exception e) {            e.printStackTrace();        }        return true;    }    protected void decodeImageData() {        int NullCode = -1;        int npix = iw * ih;        int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi;        if ((pixels == null) || (pixels.length < npix)) {            pixels = new byte[npix]; // allocate new pixel array        }        if (prefix == null) {            prefix = new short[MaxStackSize];        }        if (suffix == null) {            suffix = new byte[MaxStackSize];        }        if (pixelStack == null) {            pixelStack = new byte[MaxStackSize + 1];        }        // Initialize GIF data stream decoder.        data_size = read();        clear = 1 << data_size;        end_of_information = clear + 1;        available = clear + 2;        old_code = NullCode;        code_size = data_size + 1;        code_mask = (1 << code_size) - 1;        for (code = 0; code < clear; code++) {            prefix[code] = 0;            suffix[code] = (byte) code;        }        // Decode GIF pixel stream.        datum = bits = count = first = top = pi = bi = 0;        for (i = 0; i < npix;) {            if (top == 0) {                if (bits < code_size) {                    // Load bytes until there are enough bits for a code.                    if (count == 0) {                        // Read a new data block.                        count = readBlock();                        if (count <= 0) {                            break;                        }                        bi = 0;                    }                    datum += (((int) block[bi]) & 0xff) << bits;                    bits += 8;                    bi++;                    count--;                    continue;                }                // Get the next code.                code = datum & code_mask;                datum >>= code_size;                bits -= code_size;                // Interpret the code                if ((code > available) || (code == end_of_information)) {                    break;                }                if (code == clear) {                    // Reset decoder.                    code_size = data_size + 1;                    code_mask = (1 << code_size) - 1;                    available = clear + 2;                    old_code = NullCode;                    continue;                }                if (old_code == NullCode) {                    pixelStack[top++] = suffix[code];                    old_code = code;                    first = code;                    continue;                }                in_code = code;                if (code == available) {                    pixelStack[top++] = (byte) first;                    code = old_code;                }                while (code > clear) {                    pixelStack[top++] = suffix[code];                    code = prefix[code];                }                first = ((int) suffix[code]) & 0xff;                // Add a new string to the string table,                if (available >= MaxStackSize) {                    break;                }                pixelStack[top++] = (byte) first;                prefix[available] = (short) old_code;                suffix[available] = (byte) first;                available++;                if (((available & code_mask) == 0)                        && (available < MaxStackSize)) {                    code_size++;                    code_mask += available;                }                old_code = in_code;            }            // Pop a pixel off the pixel stack.            top--;            pixels[pi++] = pixelStack[top];            i++;        }        for (i = pi; i < npix; i++) {            pixels[i] = 0; // clear missing pixels        }    }    protected boolean err() {        return status != STATUS_OK;    }    // to initia variable    protected void init() {        status = STATUS_OK;        frameCount = 0;        frames = new Vector<GifFrame>();        gct = null;        lct = null;    }    protected int read() {        int curByte = 0;        try {            curByte = in.read();        } catch (Exception e) {            status = STATUS_FORMAT_ERROR;        }        return curByte;    }    protected int readBlock() {        blockSize = read();        int n = 0;        if (blockSize > 0) {            try {                int count = 0;                while (n < blockSize) {                    count = in.read(block, n, blockSize - n);                    if (count == -1) {                        break;                    }                    n += count;                }            } catch (Exception e) {                e.printStackTrace();            }            if (n < blockSize) {                status = STATUS_FORMAT_ERROR;            }        }        return n;    }    // Global Color Table    protected int[] readColorTable(int ncolors) {        int nbytes = 3 * ncolors;        int[] tab = null;        byte[] c = new byte[nbytes];        int n = 0;        try {            n = in.read(c);        } catch (Exception e) {            e.printStackTrace();        }        if (n < nbytes) {            status = STATUS_FORMAT_ERROR;        } else {            tab = new int[256]; // max size to avoid bounds checks            int i = 0;            int j = 0;            while (i < ncolors) {                int r = ((int) c[j++]) & 0xff;                int g = ((int) c[j++]) & 0xff;                int b = ((int) c[j++]) & 0xff;                tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;            }        }        return tab;    }    // Image Descriptor    protected void readContents() {        // read GIF file content blocks        boolean done = false;        while (!(done || err())) {            int code = read();            switch (code) {            case 0x2C: // image separator                readImage();                break;            case 0x21: // extension                code = read();                switch (code) {                case 0xf9: // graphics control extension                    readGraphicControlExt();                    break;                case 0xff: // application extension                    readBlock();                    String app = "";                    for (int i = 0; i < 11; i++) {                        app += (char) block[i];                    }                    if (app.equals("NETSCAPE2.0")) {                        readNetscapeExt();                    } else {                        skip(); // don't care                    }                    break;                default: // uninteresting extension                    skip();                }                break;            case 0x3b: // terminator                done = true;                break;            case 0x00: // bad byte, but keep going and see what happens                break;            default:                status = STATUS_FORMAT_ERROR;            }        }    }    protected void readGraphicControlExt() {        read(); // block size        int packed = read(); // packed fields        dispose = (packed & 0x1c) >> 2; // disposal method        if (dispose == 0) {            dispose = 1; // elect to keep old image if discretionary        }        transparency = (packed & 1) != 0;        delay = readShort() * 10; // delay in milliseconds        transIndex = read(); // transparent color index        read(); // block terminator    }    // to get Stream - Head    protected void readHeader() {        String id = "";        for (int i = 0; i < 6; i++) {            id += (char) read();        }        if (!id.toUpperCase().startsWith("GIF")) {            status = STATUS_FORMAT_ERROR;            return;        }        readLSD();        if (gctFlag && !err()) {            gct = readColorTable(gctSize);            bgColor = gct[bgIndex];        }    }    protected void readImage() {        // offset of X        ix = readShort(); // (sub)image position & size        // offset of Y        iy = readShort();        // width of bitmap        iw = readShort();        // height of bitmap        ih = readShort();        // Local Color Table Flag        int packed = read();        lctFlag = (packed & 0x80) != 0; // 1 - local color table flag        // Interlace Flag, to array with interwoven if ENABLE, with order        // otherwise        interlace = (packed & 0x40) != 0; // 2 - interlace flag        // 3 - sort flag        // 4-5 - reserved        lctSize = 2 << (packed & 7); // 6-8 - local color table size        if (lctFlag) {            lct = readColorTable(lctSize); // read table            act = lct; // make local table active        } else {            act = gct; // make global table active            if (bgIndex == transIndex) {                bgColor = 0;            }        }        int save = 0;        if (transparency) {            save = act[transIndex];            act[transIndex] = 0; // set transparent color if specified        }        if (act == null) {            status = STATUS_FORMAT_ERROR; // no color table defined        }        if (err()) {            return;        }        decodeImageData(); // decode pixel data        skip();        if (err()) {            return;        }        frameCount++;        // create new image to receive frame data        image = Bitmap.createBitmap(width, height, Config.RGB_565);        // createImage(width, height);        setPixels(); // transfer pixel data to image        frames.addElement(new GifFrame(image, delay)); // add image to frame        // list        if (transparency) {            act[transIndex] = save;        }        resetFrame();    }    // Logical Screen Descriptor    protected void readLSD() {        // logical screen size        width = readShort();        height = readShort();        // packed fields        int packed = read();        gctFlag = (packed & 0x80) != 0; // 1 : global color table flag        // 2-4 : color resolution        // 5 : gct sort flag        gctSize = 2 << (packed & 7); // 6-8 : gct size        bgIndex = read(); // background color index        pixelAspect = read(); // pixel aspect ratio    }    protected void readNetscapeExt() {        do {            readBlock();            if (block[0] == 1) {                // loop count sub-block                int b1 = ((int) block[1]) & 0xff;                int b2 = ((int) block[2]) & 0xff;                loopCount = (b2 << 8) | b1;            }        } while ((blockSize > 0) && !err());    }    // read 8 bit data    protected int readShort() {        // read 16-bit value, LSB first        return read() | (read() << 8);    }    protected void resetFrame() {        lastDispose = dispose;        lrx = ix;        lry = iy;        lrw = iw;        lrh = ih;        lastImage = image;        lastBgColor = bgColor;        dispose = 0;        transparency = false;        delay = 0;        lct = null;    }    /**    * Skips variable length blocks up to and including next zero length block.    */    protected void skip() {        do {            readBlock();        } while ((blockSize > 0) && !err());    }  }  
复制代码

<3>Activity显示:MainActivity.java

复制代码
package com.yanis.gifphoto;import java.io.FileInputStream;import java.io.InputStream;import android.app.Activity;import android.graphics.Bitmap;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.Log;import android.view.ViewGroup.LayoutParams;import android.widget.ImageView;import android.widget.ImageView.ScaleType;import com.yanis.tools.CommonUtil;import com.yanis.tools.GifHelper.GifFrame;public class MainActivity extends Activity {    private PlayGifTask mGifTask;      ImageView iv;      GifFrame[] frames;      FileInputStream fis=null;            @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);                  iv = new ImageView(this);          iv.setScaleType(ScaleType.CENTER);          setContentView(iv, new LayoutParams(LayoutParams.MATCH_PARENT,                  LayoutParams.MATCH_PARENT));          //对Gif图片进行解码          final InputStream fis = getResources().openRawResource(R.drawable.gidpic);                   /*try {             fis = new FileInputStream(new File(Environment.getExternalStorageDirectory()+File.separator+"/tmp/111.gif"));         } catch (FileNotFoundException e) {             e.printStackTrace();         }*/                frames = CommonUtil.getGif(fis);           mGifTask = new PlayGifTask(iv, frames);           mGifTask.startTask();          Thread th=new Thread(mGifTask);          th.start();                }            @Override      protected void onDestroy() {          super.onDestroy();          if(null != mGifTask) mGifTask.stopTask();                }                 //用来循环播放Gif每帧图片      private class PlayGifTask implements Runnable {          int i = 0;          ImageView iv;          GifFrame[] frames;          int framelen,oncePlayTime=0;            public PlayGifTask(ImageView iv, GifFrame[] frames) {              this.iv = iv;              this.frames = frames;                            int n=0;              framelen=frames.length;              while(n<framelen){                  oncePlayTime+=frames[n].delay;                  n++;              }              Log.d("msg", "playTime= "+oncePlayTime);  //Gif图片单次播放时长                     }            Handler h2=new Handler(){              public void handleMessage(Message msg) {                  switch(msg.what){                   case 1:                      iv.setImageBitmap((Bitmap)msg.obj);                      break;                  }              };          };          @Override          public void run() {              if (!frames[i].image.isRecycled()) {            //      iv.setImageBitmap(frames[i].image);                  Message m=Message.obtain(h2, 1, frames[i].image);                  m.sendToTarget();              }              iv.postDelayed(this, frames[i++].delay);              i %= framelen;            }                    public void startTask() {              iv.post(this);          }                    public void stopTask() {              if(null != iv) iv.removeCallbacks(this);              iv = null;              if(null != frames) {                  for(GifFrame frame : frames) {                      if(frame.image != null && !frame.image.isRecycled()) {                          frame.image.recycle();                          frame.image = null;                      }                  }                  frames = null;            //      mGifTask=null;              }          }      }  }
复制代码

 

 

源代码地址:https://github.com/YeXiaoChao/Yc_demo_gifphoto

来源:http://blog.csdn.net/yudajun/article/details/7865653

原创粉丝点击