summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/util
diff options
context:
space:
mode:
authorLikai Ding <likaid@codeaurora.org>2013-08-13 14:07:48 +0800
committerXiaojing Zhang <zhangx@codeaurora.org>2014-11-04 20:37:39 -0800
commitdcba1c2fbf5eb71b688810434a20298ef8202339 (patch)
tree42a708baaeb9e59ad9cc7eb1178d76bd6658868a /src/com/android/gallery3d/util
parentecd9d2b60c89b32e0e7d99e33a89198e6a790ad2 (diff)
downloadandroid_packages_apps_Gallery2-dcba1c2fbf5eb71b688810434a20298ef8202339.tar.gz
android_packages_apps_Gallery2-dcba1c2fbf5eb71b688810434a20298ef8202339.tar.bz2
android_packages_apps_Gallery2-dcba1c2fbf5eb71b688810434a20298ef8202339.zip
Gallery2: support GIF animation
(cherry picked new files from commit 2b133c9747af26701a12d60caef3e7e14cf55536) Change-Id: I227cef76cbacd66b7e87bc59b4f07d518b70a859 Signed-off-by: Xiaojing Zhang <zhangx@codeaurora.org>
Diffstat (limited to 'src/com/android/gallery3d/util')
-rwxr-xr-xsrc/com/android/gallery3d/util/GIFView.java300
-rwxr-xr-xsrc/com/android/gallery3d/util/GifAction.java5
-rwxr-xr-xsrc/com/android/gallery3d/util/GifDecoder.java697
-rwxr-xr-xsrc/com/android/gallery3d/util/GifFrame.java14
-rwxr-xr-xsrc/com/android/gallery3d/util/ViewGifImage.java111
5 files changed, 1127 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/util/GIFView.java b/src/com/android/gallery3d/util/GIFView.java
new file mode 100755
index 000000000..0e71aa314
--- /dev/null
+++ b/src/com/android/gallery3d/util/GIFView.java
@@ -0,0 +1,300 @@
+package com.android.gallery3d.util;
+
+import java.io.InputStream;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.net.Uri;
+import android.content.res.AssetManager;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import android.database.Cursor;
+import android.widget.ImageView;
+import java.io.FileInputStream;
+
+import com.android.gallery3d.R;
+
+import android.content.ContentResolver;
+import android.widget.Toast;
+
+public class GIFView extends ImageView implements GifAction{
+
+ private static final String TAG = "GIFView";
+
+ private GifDecoder gifDecoder = null;
+
+ private Bitmap currentImage = null;
+
+ private static boolean isRun = false;
+
+ private static boolean pause = true;
+
+ private int W;
+
+ private int H;
+
+ private DrawThread drawThread = null;
+
+ Uri mUri;
+ private Context mContext;
+
+ public GIFView(Context context) {
+ super(context);
+ mContext=context;
+
+ }
+
+ public boolean setDrawable(Uri uri){
+ if (null == uri){
+ return false;
+ }
+ isRun = true;
+ pause = false;
+ mUri = uri;
+ int mSize = 0;
+ ContentResolver cr = mContext.getContentResolver();
+ InputStream input = null;
+ try {
+ input = cr.openInputStream(uri);
+
+ if (input instanceof FileInputStream) {
+ FileInputStream f = (FileInputStream) input;
+ mSize = (int) f.getChannel().size();
+ } else {
+ while (-1 != input.read()) {
+ mSize++;
+ }
+ }
+
+ } catch (IOException e) {
+
+ } finally {
+
+ }
+ //wss , return if file is invalid
+ if(mSize == 0){
+ return false;
+ }
+
+ if(mSize > 1024*1024){ //gif must be smaller than 1MB
+ if (null != input) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ }
+ }
+ Toast.makeText(mContext, R.string.gif_image_too_large, Toast.LENGTH_LONG).show();
+ return false;
+ }
+
+ setGifDecoderImage(input);
+
+
+
+ android.content.ContentResolver resolver = mContext.getContentResolver();
+ Cursor c = resolver.query(uri, new String[]{"_data"}, null, null, null);
+
+// if ( c != null && 1 == c.getCount()){
+// c.moveToFirst();
+//
+// AssetManager am = mContext.getAssets();
+// try{
+// System.out.println(">>>>>>>>>1 "+c.getString(0));
+// setGifDecoderImage(am.open(c.getString(0), AssetManager.ACCESS_RANDOM));
+// }catch(FileNotFoundException e){
+// Log.v(TAG, "e:" + e);
+// }catch(IOException e){
+// Log.v(TAG, "e:" + e);
+// }finally{
+// c.close();
+// }
+//
+// return true;
+// }
+// else{
+// AssetManager am1 = mContext.getAssets();
+// try {
+// System.out.println(">>>>>>>>2 "+mUri.getPath());
+// setGifDecoderImage(am1.open(mUri.getPath(), AssetManager.ACCESS_UNKNOWN));
+// } catch (IOException e1) {
+// e1.printStackTrace();
+// }
+// return true;
+// }
+ return true;
+ }
+
+ private void setGifDecoderImage(InputStream is){
+ if(gifDecoder != null){
+ gifDecoder.free();
+ gifDecoder= null;
+ }
+ gifDecoder = new GifDecoder(is,this);
+ gifDecoder.start();
+ }
+
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ //wangmiao add
+ W = ViewGifImage.dm.widthPixels;//480;
+ H = ViewGifImage.dm.heightPixels;//800;
+ //Log.w(TAG,"the width is "+W +"the hight is "+H);
+ if(gifDecoder == null){
+ return;
+ }
+
+ if(currentImage == null){
+ currentImage = gifDecoder.getImage();
+ }
+ if(currentImage == null){
+ setImageURI(mUri); // if can not play this gif, we just try to show it as jpg by parsing mUri, bug: T81-4307
+ return;
+ }
+ setImageURI(null);
+ int saveCount = canvas.getSaveCount();
+ canvas.save();
+ canvas.translate(getPaddingLeft(), getPaddingTop());
+ //canvas.drawBitmap(currentImage, (W - currentImage.getWidth()) / 2, (H - currentImage.getHeight())/2, null);
+ Rect sRect = null;
+ Rect dRect = null;
+
+ int imageHeight = currentImage.getHeight();
+ int imageWidth = currentImage.getWidth();
+
+ //int newHeight = H/2;
+ int newHeight = H;
+ int newWidth = W;
+
+ if (newWidth < imageWidth)
+ {
+ if (newHeight < imageHeight)
+ {
+ //h big, w big;
+ //Log.w(TAG," h big, w big");
+ if (imageHeight*W > imageWidth*H)
+ {
+ //too height
+ //newHeight = H/2;
+ newWidth = (imageWidth * newHeight)/imageHeight;
+ //Log.w(TAG," h too big = "+ newHeight+" w big = "+newWidth);
+ }
+ else
+ {
+ //newWidth = W;
+ newHeight = (imageHeight * newWidth)/imageWidth;
+ //Log.w(TAG," h big = "+ newHeight+" w too big = "+newWidth);
+ }
+
+ //sRect = new Rect(0, 0, currentImage.getWidth(), currentImage.getHeight());
+ dRect = new Rect((W - newWidth) / 2, 0, (W + newWidth) / 2, newHeight);
+ }
+ else
+ {
+ //h small, w big;
+ newHeight = (imageHeight * newWidth)/imageWidth;
+ dRect = new Rect(0, 0, newWidth, newHeight);
+ }
+ canvas.drawBitmap(currentImage, sRect, dRect, null);
+
+ }
+ else if (newHeight < imageHeight)
+ {
+ //h big, w small;
+ newWidth = (imageWidth * newHeight)/imageHeight;
+ dRect = new Rect((W - newWidth) / 2, 0,
+ (W + newWidth) / 2, newHeight);
+ canvas.drawBitmap(currentImage, sRect, dRect, null);
+ }
+ else
+ {
+ //h small, w small;
+ canvas.drawBitmap(currentImage, (W - imageWidth) / 2, (H - imageHeight) / 2, null);
+ }
+
+ canvas.restoreToCount(saveCount);
+ }
+
+ public void parseOk(boolean parseStatus,int frameIndex){
+ if(parseStatus){
+ if(gifDecoder != null){
+ if(frameIndex == -1){
+ if(gifDecoder.getFrameCount() > 1){
+ if(drawThread == null){
+ drawThread = new DrawThread();
+ } else{
+ drawThread = null;
+ drawThread = new DrawThread();
+ }
+ drawThread.start();
+ }
+ }
+ }
+ }else{
+ Log.e("gif","parse error");
+ }
+ }
+
+ private Handler redrawHandler = new Handler(){
+ public void handleMessage(Message msg) {
+ invalidate();
+ }
+ };
+
+ private class DrawThread extends Thread{
+ public void run(){
+ if(gifDecoder == null){
+ return;
+ }
+
+ while(isRun){
+ if(pause == false){
+ if(!isShown()){
+ isRun = false;
+ pause = true;
+ break;
+ }
+ GifFrame frame = gifDecoder.next();
+ currentImage = frame.image;
+ long sp = frame.delay;
+ if(sp == 0) sp = 200; //wangmiao add merge from T92
+ if(redrawHandler != null){
+ Message msg = redrawHandler.obtainMessage();
+ redrawHandler.sendMessage(msg);
+ try{
+ Thread.sleep(sp);
+ } catch(InterruptedException e){}
+ }else{
+ break;
+ }
+ } else{
+ break;
+ }
+ }
+ isRun = true;
+ pause = false;
+ }
+ }
+ public void freeMemory()
+ {
+ isRun = false;
+ pause = true;
+ if (drawThread != null)
+ {
+ //drawThread.isStop = true;
+ drawThread = null;
+ }
+ if (gifDecoder != null)
+ {
+ Log.w(TAG," free");
+ gifDecoder.free();
+ gifDecoder = null;
+ }
+ }
+}
+
+
+
diff --git a/src/com/android/gallery3d/util/GifAction.java b/src/com/android/gallery3d/util/GifAction.java
new file mode 100755
index 000000000..b273a1768
--- /dev/null
+++ b/src/com/android/gallery3d/util/GifAction.java
@@ -0,0 +1,5 @@
+package com.android.gallery3d.util;
+
+public interface GifAction {
+ public void parseOk(boolean parseStatus,int frameIndex);
+}
diff --git a/src/com/android/gallery3d/util/GifDecoder.java b/src/com/android/gallery3d/util/GifDecoder.java
new file mode 100755
index 000000000..60bc1980b
--- /dev/null
+++ b/src/com/android/gallery3d/util/GifDecoder.java
@@ -0,0 +1,697 @@
+package com.android.gallery3d.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.util.Log;
+
+public class GifDecoder extends Thread{
+
+ public static final int STATUS_PARSING = 0;
+ public static final int STATUS_FORMAT_ERROR = 1;
+ public static final int STATUS_OPEN_ERROR = 2;
+ public static final int STATUS_FINISH = -1;
+
+ private InputStream in;
+ private int status;
+
+ public int width; // full image width
+ public int height; // full image height
+ private boolean gctFlag; // global color table used
+ private int gctSize; // size of global color table
+ private int loopCount = 1; // iterations; 0 = repeat forever
+
+ private int[] gct; // global color table
+ private int[] lct; // local color table
+ private int[] act; // active color table
+
+ private int bgIndex; // background color index
+ private int bgColor; // background color
+ private int lastBgColor; // previous bg color
+ private int pixelAspect; // pixel aspect ratio
+
+ private boolean lctFlag; // local color table flag
+ private boolean interlace; // interlace flag
+ private int lctSize; // local color table size
+
+ private int ix, iy, iw, ih; // current image rectangle
+ private int lrx, lry, lrw, lrh;
+ private Bitmap image; // current frame
+ private Bitmap lastImage; // previous frame
+ private GifFrame currentFrame = null;
+
+ private boolean isShow = false;
+
+
+ private byte[] block = new byte[256]; // current data block
+ private int blockSize = 0; // block size
+ private int dispose = 0;
+ private int lastDispose = 0;
+ private boolean transparency = false; // use transparent color
+ private int delay = 0; // delay in milliseconds
+ private int transIndex; // transparent color index
+
+ private static final int MaxStackSize = 4096;
+ // max decoder pixel stack size
+
+ // LZW decoder working arrays
+ private short[] prefix;
+ private byte[] suffix;
+ private byte[] pixelStack;
+ private byte[] pixels;
+
+ private GifFrame gifFrame; // frames read from current file
+ private int frameCount;
+
+ private GifAction action = null;
+
+
+ private byte[] gifData = null;
+
+
+ public GifDecoder(byte[] data,GifAction act){
+ gifData = data;
+ action = act;
+ }
+
+ public GifDecoder(InputStream is,GifAction act){
+ in = is;
+ action = act;
+ }
+
+ public void run(){
+ if(in != null){
+ readStream();
+ }else if(gifData != null){
+ readByte();
+ }
+ }
+
+ public void free(){
+ GifFrame fg = gifFrame;
+ while(fg != null){
+ if (fg.image != null) {
+ fg.image.recycle();
+ }
+ fg.image = null;
+ fg = null;
+ gifFrame = gifFrame.nextFrame;
+ fg = gifFrame;
+ }
+ if(in != null){
+ try{
+ in.close();
+ }catch(Exception ex){}
+ in = null;
+ }
+ gifData = null;
+ if (image != null)
+ {
+ image.recycle();
+ image = null;
+ }
+ if (lastImage != null)
+ {
+ lastImage.recycle();
+ lastImage = null;
+ }
+ }
+
+ public int getStatus(){
+ return status;
+ }
+
+ public boolean parseOk(){
+ return status == STATUS_FINISH;
+ }
+
+ public int getDelay(int n) {
+ delay = -1;
+ if ((n >= 0) && (n < frameCount)) {
+ GifFrame f = getFrame(n);
+ if (f != null)
+ delay = f.delay;
+ }
+ return delay;
+ }
+
+ public int[] getDelays(){
+ GifFrame f = gifFrame;
+ int[] d = new int[frameCount];
+ int i = 0;
+ while(f != null && i < frameCount){
+ d[i] = f.delay;
+ f = f.nextFrame;
+ i++;
+ }
+ return d;
+ }
+
+ public int getFrameCount() {
+ return frameCount;
+ }
+
+ public Bitmap getImage() {
+ return getFrameImage(0);
+ }
+
+ public int getLoopCount() {
+ return loopCount;
+ }
+
+ private 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 = getFrameImage(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.ARGB_4444);
+ }
+
+ public Bitmap getFrameImage(int n) {
+ GifFrame frame = getFrame(n);
+ if (frame == null)
+ return null;
+ else
+ return frame.image;
+ }
+
+ public GifFrame getCurrentFrame(){
+ return currentFrame;
+ }
+
+ public GifFrame getFrame(int n) {
+ GifFrame frame = gifFrame;
+ int i = 0;
+ while (frame != null) {
+ if (i == n) {
+ return frame;
+ } else {
+ frame = frame.nextFrame;
+ }
+ i++;
+ }
+ return null;
+ }
+
+ public void reset(){
+ currentFrame = gifFrame;
+ }
+
+ public GifFrame next() {
+ if(isShow == false){
+ isShow = true;
+ return gifFrame;
+ }else{
+ if(status == STATUS_PARSING){
+ if(currentFrame.nextFrame != null)
+ currentFrame = currentFrame.nextFrame;
+ //currentFrame = gifFrame;
+ }else{
+ currentFrame = currentFrame.nextFrame;
+ if (currentFrame == null) {
+ currentFrame = gifFrame;
+ }
+ }
+ return currentFrame;
+ }
+ }
+
+ private int readByte(){
+ in = new ByteArrayInputStream(gifData);
+ gifData = null;
+ return readStream();
+ }
+
+ private int readStream(){
+ init();
+ if(in != null){
+ readHeader();
+ if(!err()){
+ readContents();
+ if(frameCount < 0){
+ status = STATUS_FORMAT_ERROR;
+ action.parseOk(false,-1);
+ }else{
+ status = STATUS_FINISH;
+ action.parseOk(true,-1);
+ }
+ }
+ try {
+ in.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }else {
+ status = STATUS_OPEN_ERROR;
+ action.parseOk(false,-1);
+ }
+ return status;
+ }
+
+ private 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
+ }
+ }
+
+ private boolean err() {
+ return status != STATUS_PARSING;
+ }
+
+ private void init() {
+ status = STATUS_PARSING;
+ frameCount = 0;
+ gifFrame = null;
+ gct = null;
+ lct = null;
+ }
+
+ private int read() {
+ int curByte = 0;
+ try {
+
+ curByte = in.read();
+ } catch (Exception e) {
+ status = STATUS_FORMAT_ERROR;
+ }
+ return curByte;
+ }
+
+ private 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;
+ }
+
+ private 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;
+ }
+
+ private 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;
+ }
+ }
+ }
+
+ private 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
+ }
+
+ private void readHeader() {
+ String id = "";
+ for (int i = 0; i < 6; i++) {
+ id += (char) read();
+ }
+ if (!id.startsWith("GIF")) {
+ status = STATUS_FORMAT_ERROR;
+ return;
+ }
+ readLSD();
+ if (gctFlag && !err()) {
+ gct = readColorTable(gctSize);
+ bgColor = gct[bgIndex];
+ }
+ }
+
+ private void readImage() {
+ ix = readShort(); // (sub)image position & size
+ iy = readShort();
+ iw = readShort();
+ ih = readShort();
+ int packed = read();
+ lctFlag = (packed & 0x80) != 0; // 1 - local color table flag
+ 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;
+ }
+ try {
+ decodeImageData(); // decode pixel data
+ skip();
+ if (err()) {
+ return;
+ }
+ frameCount++;
+ // create new image to receive frame data
+ image = Bitmap.createBitmap(width, height, Config.ARGB_4444);
+ // createImage(width, height);
+ setPixels(); // transfer pixel data to image
+ if (gifFrame == null) {
+ gifFrame = new GifFrame(image, delay);
+ currentFrame = gifFrame;
+ } else {
+ GifFrame f = gifFrame;
+ while(f.nextFrame != null){
+ f = f.nextFrame;
+ }
+ f.nextFrame = new GifFrame(image, delay);
+ }
+ // frames.addElement(new GifFrame(image, delay)); // add image to frame
+ // list
+ if (transparency) {
+ act[transIndex] = save;
+ }
+ resetFrame();
+ action.parseOk(true, frameCount);
+ }catch (OutOfMemoryError e) {
+ Log.e("GifDecoder", ">>> log : " + e.toString());
+ e.printStackTrace();
+ }
+ }
+
+ private 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
+ }
+
+ private 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());
+ }
+
+ private int readShort() {
+ // read 16-bit value, LSB first
+ return read() | (read() << 8);
+ }
+
+ private 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.
+ */
+ private void skip() {
+ do {
+ readBlock();
+ } while ((blockSize > 0) && !err());
+ }
+}
diff --git a/src/com/android/gallery3d/util/GifFrame.java b/src/com/android/gallery3d/util/GifFrame.java
new file mode 100755
index 000000000..926ed57b4
--- /dev/null
+++ b/src/com/android/gallery3d/util/GifFrame.java
@@ -0,0 +1,14 @@
+package com.android.gallery3d.util;
+
+import android.graphics.Bitmap;
+
+public class GifFrame {
+ public GifFrame(Bitmap im, int del) {
+ image = im;
+ delay = del;
+ }
+
+ public Bitmap image;
+ public int delay;
+ public GifFrame nextFrame = null;
+}
diff --git a/src/com/android/gallery3d/util/ViewGifImage.java b/src/com/android/gallery3d/util/ViewGifImage.java
new file mode 100755
index 000000000..b157e2f3b
--- /dev/null
+++ b/src/com/android/gallery3d/util/ViewGifImage.java
@@ -0,0 +1,111 @@
+/**
+ * File property dialog
+ *
+ * @Author wangxuguang
+ *
+ * caozhe add this file, for displya gif image, 2011.3.28
+ */
+
+package com.android.gallery3d.util;
+
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.widget.ImageView;
+
+import com.android.gallery3d.R;
+import android.net.Uri;
+
+import android.view.ViewGroup.LayoutParams;
+import android.widget.LinearLayout;
+import android.util.DisplayMetrics;
+import android.content.res.Configuration;
+
+public class ViewGifImage extends Activity
+{
+ public static final String TAG = "ViewGifImage";
+ private String mFileDir;
+ public static DisplayMetrics dm;
+ ImageView gifView;
+
+ static final int WIDTH = 320;
+ static final int HEIGHT = 480;
+
+
+ private Handler mHandler = new Handler() {
+ public void handleMessage(Message msg)
+ {
+ super.handleMessage(msg);
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ //android.util.Log.d(TAG, "=== onCreate() ===");
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.view_gif_image);
+ dm = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(dm);
+ //add end
+ if(getIntent().getAction() != null
+ && getIntent().getAction().equals("hisense.view_gif_image")){
+ // i am called by gallery3D or other apps who want to show a gif image
+ Uri gifUri = getIntent().getData();
+ showGifPicture(gifUri);
+
+ return;
+ }
+
+ mFileDir = getIntent().getStringExtra("file_dir");
+ Uri gifUri = getIntent().getData();
+
+
+ showGifPicture(gifUri);
+
+
+ }
+
+ @Override
+ public void onResume()
+ {
+ super.onResume();
+ }
+
+ @Override
+ protected void onStop()
+ {
+ super.onStop();
+ finish();
+ }
+
+ @Override
+ protected void onDestroy() {
+ if (gifView != null){
+ if (gifView instanceof GIFView)
+ {
+ ((GIFView)gifView).freeMemory();
+ gifView = null;
+ }
+ }
+ super.onDestroy();
+ }
+
+ private void showGifPicture(Uri gifUri){
+ gifView = new GIFView(this);
+ ((LinearLayout)findViewById(R.id.image_absoluteLayout)).addView(gifView, new LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+ if(!((GIFView)gifView).setDrawable(gifUri))
+ finish();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ getWindowManager().getDefaultDisplay().getMetrics(dm);
+ super.onConfigurationChanged(newConfig);
+ }
+
+
+}