zoukankan      html  css  js  c++  java
  • 【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);  
        }  
    }
    View Code

    <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());  
      }  
    }  
    View Code

    <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;  
                }  
            }  
        }  
    }
    View Code

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

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

  • 相关阅读:
    Selenium
    Selenium和ChromeDriver下载地址
    CQRS Event Sourcing介绍
    JAVA程序员面试30问(附带答案)
    拼多多、饿了么、蚂蚁金服Java面试题大集合
    40K刚面完Java岗,这些技术必须掌握
    接口测试之深入理解HTTPS
    选择了软件测试,你后悔吗?
    如何优雅的使用 Python 实现文件递归遍历
    刚从阿里回来,有些想法想跟测试员说说
  • 原文地址:https://www.cnblogs.com/yc-755909659/p/4307794.html
Copyright © 2011-2022 走看看