android 开发 解码gif图片,获取每帧bitmap

环境:android 4.3  (注意对于android4.4版本解码出来不正确,除了第一帧正确外,其余的都是显示不同的地方)  通用版本见: android 开发对gif解码(适配android 4.2、4.3、4.4版本)

使用方法:

void showGif2()

    {

        gifDecoder = new GifImageDecoder();

        try {

            gifDecoder.read(this.getResources().openRawResource(R.drawable.b17));  //这是Gif图片资源

            int size =gifDecoder.getFrameCount();

            for(int i=0;i<size;i++)

            {

                

                ImageView iv_image = new ImageView(CustomActivity.this);

                iv_image.setPadding(5, 5, 5, 5);

                LayoutParams lparams = new LayoutParams(100,100);

                iv_image.setLayoutParams(lparams);

                iv_image.setImageBitmap(gifDecoder.getFrame(i));

                ll_decodeimages.addView(iv_image);

//                gifFrame.nextFrame();

            }

        } catch (NotFoundException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        } catch (IOException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

    }


见效果:

android 开发 解码gif图片,获取每帧bitmap

 

全部代码:

package com.xlm.testgif;



import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.InputStream;



import android.net.Uri;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.app.Activity;

import android.content.Context;

import android.content.res.Resources.NotFoundException;

import android.graphics.Bitmap;

import android.view.Menu;

import android.widget.ImageView;

import android.widget.LinearLayout;

import android.widget.LinearLayout.LayoutParams;



public class CustomActivity extends Activity {



    LinearLayout ll_decodeimages;

//    GifFrame gifFrame = null;

    GifImageDecoder gifDecoder;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_custom);

        ll_decodeimages = (LinearLayout) findViewById(R.id.ll_decodeimages);

        showGif2();

    }

//    void showGif()

//    {

//        // 解析gif动画

//        gifFrame = GifFrame.createGifImage(fileConnect(this.getResources().openRawResource(R.drawable.b10)));

//        int size = gifFrame.size();

//        for(int i=0;i<size;i++)

//        {

//            

//            ImageView iv_image = new ImageView(CustomActivity.this);

//            iv_image.setPadding(5, 5, 5, 5);

//            LayoutParams lparams = new LayoutParams(100,100);

//            iv_image.setLayoutParams(lparams);

//            iv_image.setImageBitmap(gifFrame.getImage());

//            ll_decodeimages.addView(iv_image);

//            gifFrame.nextFrame();

//        }

//    }

    void showGif2()

    {

        gifDecoder = new GifImageDecoder();

        try {

            gifDecoder.read(this.getResources().openRawResource(R.drawable.b17));

            int size =gifDecoder.getFrameCount();

            for(int i=0;i<size;i++)

            {

                

                ImageView iv_image = new ImageView(CustomActivity.this);

                iv_image.setPadding(5, 5, 5, 5);

                LayoutParams lparams = new LayoutParams(100,100);

                iv_image.setLayoutParams(lparams);

                iv_image.setImageBitmap(gifDecoder.getFrame(i));

                ll_decodeimages.addView(iv_image);

//                gifFrame.nextFrame();

            }

        } catch (NotFoundException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        } catch (IOException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

    }

//    Handler handler = new Handler()

//    {

//

//        @Override

//        public void handleMessage(Message msg) {

//            switch(msg.what)

//            {

//            case 1:

//                Bitmap bmp = (Bitmap) msg.obj;

//                if(bmp!=null)

//                {

//                    ImageView iv_image = new ImageView(CustomActivity.this);

//                    iv_image.setImageBitmap(bmp);

//                    ll_decodeimages.addView(iv_image);

//                }

//                break;

//            }

//        }

//        

//    };

    /**

     * 独立线程解码gif图片

     * @author huqiang

     *

     */

//    class DecodeGif implements Runnable 

//    {

//        Context mContext ;

//        Handler mHandler;

//        public DecodeGif(Context context,Handler handler)

//        {

//            this.mContext = context;

//            this.mHandler = handler;

//        }

//        @Override

//        public void run() {

//            //开始解析gif

//            // 解析gif动画

////            gifFrame = GifFrame.createGifImage(fileConnect(this.getResources().openRawResource(R.drawable.test)));

//        }

//        public void start()

//        {

//            new Thread(this).start();

//        }

//    }

    // 读取文件

        public byte[] fileConnect(InputStream is)

        {

            try

            {

                ByteArrayOutputStream baos = new ByteArrayOutputStream();

                int ch = 0;

                while ((ch = is.read()) != -1)

                {

                    baos.write(ch);

                }

                byte[] b = baos.toByteArray();

                baos.close();

                baos = null;

                is.close();

                is = null;

                return b;

            } catch (Exception e)

            {

                return null;

            }

        }



}

 

package com.xlm.testgif;



import android.annotation.SuppressLint;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Canvas;



import java.io.BufferedInputStream;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.util.ArrayList;



public class GifImageDecoder {

    private static final String TAG = GifImageDecoder.class.getSimpleName();

    private final GifImageDecoder self = this;



    // File read status: No errors.

    public static final int STATUS_OK = 0;

    // File read status: Error decoding file (may be partially decoded)

    public static final int STATUS_FORMAT_ERROR = 1;

    // File read status: Unable to open source.

    public static final int STATUS_OPEN_ERROR = 2;

    // Trailer

    private static final byte TRR_CODE = (byte) 0x3B;

    // Image Block

    private static final byte IMG_CODE = (byte) 0x2C;

    // Extension

    private static final byte EXT_CODE = (byte) 0x21;

    // Graphic Control Extension

    private static final byte GC_EXT = (byte) 0xF9;

    // Application Extension

    private static final byte APP_EXT = (byte) 0xFF;

    // Comment Extension

    private static final byte CMT_EXT = (byte) 0xFE;

    // Plain Text Extension

    private static final byte TXT_EXT = (byte) 0x01;



    private static final int MIN_DELAY = 100;

    private static final int MIN_DELAY_ENFORCE_THRESHOLD = 20;



    protected int mStatus;

    protected int mWidth; // full mCurrentImage mWidth

    protected int mHeight; // full mCurrentImage mHeight

    protected Bitmap mCurrentImage; // current frame

    protected Bitmap mLastImage; // previous frame

    protected int mDispose = 0; // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev

    protected int mLastDispose = 0;

    protected int mDelay = 0; // mDelay in milliseconds

    protected ArrayList<GifFrame> mGifFrames; // mGifFrames read from current file

    protected int mFrameCount;



    private int mOffset = 0;



    private GifHeader mGifHeader;

    private GraphicControlExtension mGcExt;

    private ImageBlock mImageBlock;



    private static class GifFrame {

        public GifFrame(Bitmap im, int del) {

            image = im;

            delay = del;

        }



        public Bitmap image;

        public int delay;

    }



    /**

     * Gets display duration for specified frame.

     *

     * @param n int index of frame

     * @return delay in milliseconds

     */

    public int getDelay(int n) {

        mDelay = -1;

        if ((n >= 0) && (n < mFrameCount)) {

            mDelay = mGifFrames.get(n).delay;

            if (mDelay < MIN_DELAY_ENFORCE_THRESHOLD) {

                mDelay = MIN_DELAY;

            }

        }

        return mDelay;

    }

    /**

     * Gets the number of GifFrames read from file.

     *

     * @return frame count

     */

    public int getFrameCount() {

        return mFrameCount;

    }



    /**

     * Gets the first (or only) image read.

     *

     * @return BufferedBitmap containing first frame, or null if none.

     */

    public Bitmap getBitmap() {

        return getFrame(0);

    }



    /**

     * Gets the image contents of frame n.

     *

     * @return BufferedBitmap representation of frame, or null if n is invalid.

     */

    public Bitmap getFrame(int n) {

        if (mFrameCount <= 0)

            return null;

        n = n % mFrameCount;

        return (mGifFrames.get(n)).image;

    }



    /**

     * Reads GIF image from stream

     *

     * @param is containing GIF file.

     * @return read status code (0 = no errors)

     */



    public int read(InputStream is) throws IOException {

        init();

        if (is != null) {

            byte[] buffer = Utils.streamToBytes(is);

            mGifHeader = new GifHeader(buffer, mOffset);

            mOffset += mGifHeader.size;

            mWidth = mGifHeader.getWidth();

            mHeight = mGifHeader.getHeight();

            if (!mGifHeader.getSignature().equals("GIF")) {

                return STATUS_FORMAT_ERROR;

            }

            while (buffer[mOffset] != TRR_CODE) {

                if (buffer[mOffset] == IMG_CODE) {

                    // ImageBlock

                    mImageBlock = new ImageBlock(buffer, mOffset);

                    mOffset += mImageBlock.size;



                    mFrameCount++;

                    // create new image to receive frame data

                    mCurrentImage = extractImage();

                    if (mLastDispose > 0) {

                        if (mLastDispose == 3) {

                            // use image before last

                            int n = mFrameCount - 2;

                            if (n > 0) {

                                mLastImage = getFrame(n - 1);

                            } else {

                                mLastImage = null;

                            }

                        }

                    }

                    mGifFrames.add(new GifFrame(mCurrentImage, mDelay)); // add image to frame

                    resetFrame();

                } else if (buffer[mOffset] == EXT_CODE) {

                    if (buffer[mOffset + 1] == GC_EXT) {

                        //GraphicControlExtension

                        mGcExt = new GraphicControlExtension(buffer, mOffset);

                        mOffset += mGcExt.size;

                        mDispose = mGcExt.getDisposalMothod(); // disposal method

                        if (mDispose == 0) {

                            mDispose = 1; // elect to keep old image if discretionary

                        }

                        mDelay = mGcExt.getDelayTime() * 10; // delay in milliseconds

                    } else if (buffer[mOffset + 1] == APP_EXT) {

                        //ApplicationExtension

                        ApplicationExtension appExt = new ApplicationExtension(buffer, mOffset);

                        mOffset += appExt.size;

                    } else if (buffer[mOffset + 1] == CMT_EXT) {

                        //CommentExtension

                        CommentExtension cmtExt = new CommentExtension(buffer, mOffset);

                        mOffset += cmtExt.size;

                    } else if (buffer[mOffset + 1] == TXT_EXT) {

                        //PlainTextExtension

                        PlainTextExtension txtExt = new PlainTextExtension(buffer, mOffset);

                        mOffset += txtExt.size;

                    } else {

                        throw new IOException();

                    }

                } else {

                    throw new IOException();

                }

            }

        } else {

            mStatus = STATUS_OPEN_ERROR;

        }

        return mStatus;

    }



    /**

     * Initializes or re-initializes reader

     */

    protected void init() {

        mStatus = STATUS_OK;

        mFrameCount = 0;

        mGifFrames = new ArrayList<GifFrame>();

    }



    /**

     * Resets frame state for reading next image.

     */

    protected void resetFrame() {

        mLastDispose = mDispose;

        mLastImage = mCurrentImage;

        mDispose = 0;

        mDelay = 0;

    }



    /**

     * Extract new image

     *

     * @return image

     */

    @SuppressLint("NewApi") private Bitmap extractImage() {

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        try {

            outputStream.write(mGifHeader.bytes);

            if (mGcExt != null) {

                if ((mWidth != mImageBlock.getImageWidth() || mHeight != mImageBlock.getImageHeight()) &&

                        mGcExt.getTransparentColorFlag() == 0) {

                    mGcExt.setTransparentColorFlagTrue();

                }

                outputStream.write(mGcExt.bytes);

            }

            outputStream.write(mImageBlock.bytes);

            outputStream.write((byte) 0x3B);

            outputStream.flush();



            BitmapFactory.Options options = new BitmapFactory.Options();

            options.inMutable = true;

            options.inPreferredConfig = Bitmap.Config.RGB_565;

            Bitmap newBitmap = BitmapFactory.decodeStream(new BufferedInputStream(new ByteArrayInputStream(outputStream.toByteArray())));

            if (newBitmap != null) {

                if (mLastImage == null) {

                    return newBitmap;

                } else {

                    Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.RGB_565);

                    Canvas canvas = new Canvas(bitmap);

                    canvas.drawBitmap(mLastImage, 0, 0, null);

                    canvas.drawBitmap(newBitmap, 0, 0, null);

                    return bitmap;

                }

            } else {

                if (mLastImage != null) {

                    return mLastImage;

                }

            }

        } catch (IOException e) {

            e.printStackTrace();

        } finally {

            try {

                outputStream.close();

            } catch (IOException e) {

                e.printStackTrace();

            }



        }

        return null;

    }



    private class GifHeader {

        public byte[] bytes;

        public int size;



        public GifHeader(byte[] bytes, int offset) {

            boolean globalColorTableFlag = (bytes[offset + 0x0A] & 0x80) != 0x00;

            int globalColorTableSize = (bytes[offset + 0x0A] & 0x07);



            // get size

            size = 0x0D;

            if (globalColorTableFlag) {

                size += Math.pow(2, (globalColorTableSize + 1)) * 3;

            }



            this.bytes = new byte[size];

            System.arraycopy(bytes, offset, this.bytes, 0, size);

        }



        public String getSignature() {

            return new String(bytes, 0, 3);

        }



        public String getVersion() {

            return new String(bytes, 3, 3);

        }



        public int getWidth() {

            return (bytes[6] & 0xFF) + ((bytes[7] & 0xFF) << 8);

        }



        public int getHeight() {

            return (bytes[8] & 0xFF) + ((bytes[9] & 0xFF) << 8);

        }



        public int getGlobalColorTableFlag() {

            return (bytes[10] & 0x80) >> 7;

        }



        public int getColorResolution() {

            return (bytes[10] & 0x70) >> 4;

        }



        public int getSortFlag() {

            return (bytes[10] & 0x08) >> 3;

        }



        public int getSizeOfGlobalColorTable() {

            return (bytes[10] & 0x07);

        }



        public int getBackgroundColorIndex() {

            return bytes[11] & 0xFF;

        }



        public int getPixelAspectRatio() {

            return bytes[12];

        }



        public int[] getGlobalColorTable() {

            if (getGlobalColorTableFlag() == 0) {

                return new int[0];

            }

            int[] colors = new int[(int) Math.pow(2, getSizeOfGlobalColorTable() + 1)];

            for (int i = 0; i < colors.length; i++) {

                colors[i] = ((bytes[13 + (i * 3)] & 0xFF) << 16) + ((bytes[13 + (i * 3) + 1] & 0xFF) << 8) + (bytes[13 + (i * 3) + 2] & 0xFF);

            }

            return colors;

        }

    }



    private class ImageBlock {

        public byte[] bytes;

        public int size;



        public ImageBlock(byte[] bytes, int offset) {

            int blockSize;

            boolean localColorTableFlag = (bytes[offset + 0x09] & 0x80) != 0x00;

            int localColorTableSize = (bytes[offset + 0x09] & 0x07);



            //get size

            size = 0x0A;

            if (localColorTableFlag) {

                size += Math.pow(2, (localColorTableSize + 1)) * 3;

            }

            size += 1; //LZW Minimum Code Size



            //ImageData

            blockSize = bytes[offset + size] & 0xFF;

            size += 1;

            while (blockSize != 0x00) {

                size += blockSize;

                blockSize = bytes[offset + size] & 0xFF;

                size += 1;

            }



            this.bytes = new byte[size];

            System.arraycopy(bytes, offset, this.bytes, 0, size);

        }



        public int getImageSeparator() {

            return bytes[0] & 0xFF;

        }



        public int ImageLeftPosition() {

            return (bytes[1] & 0xFF) + ((bytes[2] & 0xFF) << 8);

        }



        public int getImageTopPosition() {

            return (bytes[3] & 0xFF) + ((bytes[4] & 0xFF) << 8);

        }



        public int getImageWidth() {

            return (bytes[5] & 0xFF) + ((bytes[6] & 0xFF) << 8);

        }



        public int getImageHeight() {

            return (bytes[7] & 0xFF) + ((bytes[8] & 0xFF) << 8);

        }



        public int getLocalColorTableFlag() {

            return (bytes[9] & 0x80) >> 7;

        }



        public int getInterlaceFlag() {

            return (bytes[9] & 0x40) >> 6;

        }



        public int getSortFlag() {

            return (bytes[9] & 0x20) >> 5;

        }



        public int getReserved() {

            return (bytes[9] & 0x18) >> 2;

        }



        public int getSizeOfLocalColorTable() {

            return bytes[9] & 0x03;

        }



        public int[] getLocalColorTable() {

            if (getLocalColorTableFlag() == 0) {

                return new int[0];

            }

            int[] colors = new int[(int) Math.pow(2, getSizeOfLocalColorTable() + 1)];

            for (int i = 0; i < colors.length; i++) {

                colors[i] = ((bytes[10 + (i * 3)] & 0xFF) << 16) + ((bytes[10 + (i * 3) + 1] & 0xFF) << 8) + (bytes[10 + (i * 3) + 2] & 0xFF);

            }

            return colors;

        }



        public int getLZWMinimumCodeSize() {

            if (getLocalColorTableFlag() == 0) {

                return bytes[10] & 0xFF;

            } else {

                return bytes[10 + (int) Math.pow(2, getSizeOfLocalColorTable() + 1) * 3] & 0xFF;

            }

        }

    }



    private class ApplicationExtension {

        public byte[] bytes;

        public int size;



        public ApplicationExtension(byte[] bytes, int offset) {

            int blockSize;

            // get size

            size = 0x0E;



            blockSize = bytes[offset + size] & 0xFF;

            size += 1;

            while (blockSize != 0x00) {

                size += blockSize;

                blockSize = bytes[offset + size] & 0xFF;

                size += 1;

            }



            this.bytes = new byte[size];

            System.arraycopy(bytes, offset, this.bytes, 0, size);

        }



        public int getExtensionIntroducer() {

            return bytes[0] & 0xFF;

        }



        public int getExtensionLabel() {

            return bytes[1] & 0xFF;

        }



        public int getBlockSize1() {

            return bytes[2] & 0xFF;

        }



        public String getApplicationIdentifier() {

            return new String(bytes, 3, 8);

        }



        public String getApplicationAuthenticationCode() {

            return new String(bytes, 11, 3);

        }

    }



    private class GraphicControlExtension {

        public byte[] bytes;

        public int size;



        public GraphicControlExtension(byte[] bytes, int offset) {

            size = 8;

            this.bytes = new byte[size];

            System.arraycopy(bytes, offset, this.bytes, 0, size);

        }



        public int getExtensionIntroducer() {

            return bytes[0] & 0xFF;

        }



        public int getGraphicControlLabel() {

            return bytes[1] & 0xFF;

        }



        public int getBlockSize() {

            return bytes[2] & 0xFF;

        }



        public int getReserved() {

            return (bytes[3] & 0xE0) >> 5;

        }



        public int getDisposalMothod() {

            return (bytes[3] & 0x1C) >> 2;

        }



        public int getUserInputFlag() {

            return (bytes[3] & 0x02) >> 1;

        }



        public int getTransparentColorFlag() {

            return (bytes[3] & 0x01);

        }



        public int getDelayTime() {

            return (bytes[4] & 0xFF) + ((bytes[5] & 0xFF) << 8);

        }



        public int getTransparentColorIndex() {

            return bytes[6];

        }



        public void setTransparentColorFlagTrue() {

            int value = getReserved() | getDisposalMothod() | getUserInputFlag() | 0x01;

            bytes[3] = (byte) Integer.parseInt(Utils.toHex(value, 2), 16);

        }

    }



    private class CommentExtension {

        public byte[] bytes;

        public int size;



        public CommentExtension(byte[] bytes, int offset) {

            int blockSize;

            // get size

            size = 0x02;



            blockSize = bytes[offset + size] & 0xFF;

            size += 1;

            while (blockSize != 0x00) {

                size += blockSize;

                blockSize = bytes[offset + size] & 0xFF;

                size += 1;

            }



            this.bytes = new byte[size];

            System.arraycopy(bytes, offset, this.bytes, 0, size);

        }

    }



    private class PlainTextExtension {

        public byte[] bytes;

        public int size;



        public PlainTextExtension(byte[] bytes, int offset) {

            int blockSize;

            // get size

            size = 0x0F;



            blockSize = bytes[offset + size] & 0xFF;

            size += 1;

            while (blockSize != 0x00) {

                size += blockSize;

                blockSize = bytes[offset + size] & 0xFF;

                size += 1;

            }



            this.bytes = new byte[size];

            System.arraycopy(bytes, offset, this.bytes, 0, size);

        }

    }

}

 

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.InputStream;



public class Utils {

    public static String toHex(int value, int length) {

        String hex = Integer.toHexString(value);

        hex = hex.toUpperCase();



        if (hex.length() < length) {

            while (hex.length() < length)

                hex = "0" + hex;

        } else if (hex.length() > length) {

            hex = hex.substring(hex.length() - length);

        }

        return hex;

    }



    public static byte[] streamToBytes(InputStream stream) throws IOException,

            OutOfMemoryError {

        byte[] buff = new byte[1024];

        int read;

        ByteArrayOutputStream bao = new ByteArrayOutputStream();

        while ((read = stream.read(buff)) != -1) {

            bao.write(buff, 0, read);

        }

        try {

            stream.close();

        } catch (IOException e) {

            e.printStackTrace();

        }

        return bao.toByteArray();

    }

}

 

你可能感兴趣的:(Android 开发)