The implementation of the principle is very simple, first GIF animation decoding into multiple bitmap pictures, and then put into the animationdrawable inside to play each one.
Gifhelper Code:
Package Com.android.view;import Java.io.inputstream;import Java.util.vector;import android.graphics.bitmap;import Android.graphics.bitmap.config;//handler for Read & extract Bitmap from *.gifpublic class Gifhelper {//To define some Error typepublic static final int status_ok = 0;public static final int status_format_error = 1;public static final int S Tatus_open_error = 2;protected int status;protected inputstream in;protected int width; Full image widthprotected int height; Full Image heightprotected Boolean gctflag; Global color table usedprotected int gctsize; Size of global color tableprotected int loopcount = 1; iterations; 0 = repeat foreverprotected int[] GCT; Global color tableprotected int[] LCT; Local color tableprotected int[] Act; Active color tableprotected int bgindex; Background color indexprotected int bgColor; Background colorprotected int lastbgcolor; Previous BG colorprotected int pixelaspect; Pixel Aspect ratioprotected Boolean Lctflag; Local Color Table flagprotected Boolean interlace; interlace flagprotected int lctsize; Local color table sizeprotected int IX, IY, IW, IH; Current image rectangleprotected int LRx, lry, LRW, lrh;protected Bitmap image; Current frameprotected Bitmap lastimage; Previous frameprotected 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 blockprotected int blockSize = 0; Block size//last graphic control extension infoprotected int dispose = 0;//0=no action; 1=leave in place; 2=restore to BG; 3=restore to prevprotected int lastdispose = 0;protected Boolean transparency = false; Use transparent colorprotected int delay = 0; Delay in millisecondsprotected int transindex; Transparent color indexprotected static final int maxstacksize = 4096;//Max decoder Pixel stack size//LZW decoder working arraysprotected short[] prefix;protected byte[] suffix;protected byte[] PixelStack ;p rotected byte[] pixels;protected vector<gifframe> frames; Frames read from the fileprotected int framecount;//to get its width/heightpublic 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 Codeif (Lastdispose > 0) {if (Lastdispose = = 3) {//Use image before Lastint n = framecount-2;if (N &Gt 0) {lastimage = GetFrame (n-1);} else {lastimage = null;}} if (lastimage! = null) {lastimage.getpixels (dest, 0, width, 0, 0, width, height);//Copy pixelsif (lastdispose = = 2) {//F Ill last image, rect area with background colorint 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++) {des T[K] = C;}}}} Copy each of the source line to the appropriate place in the Destinationint 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 destint Dlim = dx + IW;//End of Dest Lineif ((k + width) < Dlim) {Dlim = k + width;//past dest Edge}int SX = i * IW; Start of line in Sourcewhile (DX < Dlim) {// Map color and insert in Destinationint index = ((int) pixels[sx++]) & 0xff;int C = act[index];if (c! = 0) {DEST[DX] = C;} dx++;}}} Image = Bitmap.createbitmap (dest, width, height, config.argb_4444);} Public Bitmap getframe (int n) {Bitmap im = Null;if ((n >= 0) && (n < framecount)) {im = ((gifframe) FRAMES.E Lementat (n)). Image; return im;} 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 streampublic int read (InputStream is) {init (), if (is! = null) {in = Is;readheader (); Err ()) {readcontents (); if (Framecount < 0) {status = Status_format_error;}}} else {status = Status_open_error;} try {is.close ();} catch (Exception e) {e.printstacktrace ();} return status;} 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 ((pixel s = = 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;avail Able = 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 is 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 Codeif (CO De > 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--;p ixels[pi++] = pixelstack[top];i++;} for (i = pi; i < Npix; i++) {pixels[i] = 0;//Clear Missing pixels}}protected Boolean err () {return status! = Status_o K;} To Initia variablepublic void init () {status = Status_ok;framecount = 0;frames = new vector<gifframe> (); GCT = nul L;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 tableprotected 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 checksint i = 0;i NT 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 descriptorprotected void ReadContents () {//Read GIF file content Blocksboolean done = False;while (! ( Done | | Err ())) {int code = read (); switch (code) {case 0x2C://Image Separatorreadimage (); Break;case 0x21://Extensioncode = Rea D (); switch (code) {case 0XF9://Graphics control Extensionreadgraphiccontrolext (); Break;case 0xFF://Application Extens Ionreadblock (); 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 Extensionskip ();} Break;case 0x3b://Terminatordone = TRUe;break;case 0x00://Bad Byte, but keep going and see what happensbreak;default:status = Status_format_error;}}} protected void Readgraphiccontrolext () {read ();//block Sizeint packed = read ();//Packed Fieldsdispose = (Packed & 0x1c) >> 2; Disposal Methodif (Dispose = = 0) {dispose = 1;//elect to keep old image if Discretionary}transparency = (Packed & 1)! = 0;delay = Readshort () * 10; Delay in Millisecondstransindex = Read (); Transparent color indexread (); Block terminator}//to get stream-headprotected void Readheader () {StringBuffer id = new StringBuffer (); for (int i = 0; I < 6; i++) {id.append (char) read ());} if (!id.tostring (). StartsWith ("GIF")) {status = Status_format_error;return;} READLSD (); if (Gctflag &&!err ()) {GCT = readcolortable (gctsize); bgColor = Gct[bgindex];}} protected void Readimage () {//offset of Xix = Readshort ();//(sub) image position & size//offset of yiy = Readshort ( );//width of bitmapiw = Readshort ();//Height OF bitmapih = Readshort ();//Local Color Table Flagint packed = read (); Lctflag = (Packed & 0x80)! = 0; 1-local Color Table flag//interlace flag, to array with interwoven if ENABLE, with order//otherwiseinterlace = (PAC Ked & 0x40)! = 0; 2-interlace flag//3-sort flag//4-5-reservedlctsize = 2 << (packed & 7); 6-8-Local color table Sizeif (lctflag) {LCT = readcolortable (lctsize);//Read tableact = LCT;//make local table AC tive} else {act = GCT;//Make Global table activeif (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 dataskip (); if (err ()) {return;} framecount++;//Create new image to receive frame Dataimage = bitmap.createbitmap (width, height, config.argb_4444);//Crea Teimage (width, height); setPixels (); Transfer Pixel data to Imageframes.addelement (new Gifframe (image, delay)); Add image to frame//listif (transparency) {Act[transindex] = save;} Resetframe ();} Logical screen descriptorprotected void Readlsd () {//Logical-screen sizewidth = Readshort (); height = Readshort ();//PA cked Fieldsint packed = read (); Gctflag = (Packed & 0x80)! = 0; 1:global Color Table flag//2-4: Color resolution//5:gct Sort flaggctsize = 2 << (packed & 7); 6-8: GCT sizebgindex = read (); Background color indexpixelaspect = Read (); Pixel aspect ratio}protected void Readnetscapeext () {do {readblock (); if (block[0] = = 1) {//Loop count Sub-blockint B1 = ((int) block[1]) & 0xff;int b2 = ((int) block[2]) & 0xff;loopcount = (b2 << 8) | B1;}} while ((BlockSize > 0) &&!err ());} Read 8 bit dataprotected int Readshort () {//Read 16-bit value, LSB firstreturn 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 ());} public void Recycle () {for (int i = 0; i < frames.size (); i++) {Frames.get (i). Image.recycle ();}} To store *.gif data, Bitmap & Delayprivate class Gifframe {//To access image & delay w/o Interfacepublic BITMA P image;public int delay;public gifframe (Bitmap im, int del) {image = Im;delay = del;}}}
Control code:
Package Com.android.view;import Android.content.context;import Android.content.res.typedarray;import Android.graphics.drawable.animationdrawable;import Android.graphics.drawable.bitmapdrawable;import Android.util.attributeset;import Android.view.view;import Com.gifdemo.r;public class GifView extends View {private Gifhelper ghelper;private animationdrawable animdrawable;public Gifview (context context, AttributeSet Attrs) {super ( context, attrs);//TODO auto-generated constructor stubghelper = new Gifhelper (); TypedArray ta = context.obtainstyledattributes (attrs,r.styleable.gifview); animdrawable = new animationdrawable (); int ResID = Ta.getresourceid (r.styleable.gifview_src,-1); Ghelper.read (Getresources (). Openrawresource (ResID)); for (int i = 0; I < Ghelper.getframecount (); i++) {int delay = Ghelper.getdelay (i), if (i = = 0) animdrawable.addframe (new bitmapdrawable (Ghelper.getframe (i)), delay); Elseanimdrawable.addframe (New Bitmapdrawable (Ghelper.nextbitmap ()), delay);} Animdrawable.setbounds (0, 0, Ghelper.getimage (). GetWidth (), Ghelper.getimage (). GetHeight ()); setbackgrounddrawable (animdrawable); Ta.recycle (); Animdrawable.setoneshot (false); Animdrawable.start ();} public void Recycle () {ghelper.recycle ();}}
Attrs.xml Source:
<?xml version= "1.0" encoding= "Utf-8"?><resources> <declare-styleable name= "Gifview" > <attr name= "src" format= "integer"/> </declare-styleable></resources>
Android for GIF playback (decoding)