diff options
author | Likai Ding <likaid@codeaurora.org> | 2013-08-13 14:43:40 +0800 |
---|---|---|
committer | Xiaojing Zhang <zhangx@codeaurora.org> | 2014-11-04 20:37:42 -0800 |
commit | 65b4d0c1ded85105802bf69ddb5646eb72839e17 (patch) | |
tree | a800c2a1d8c605af06560123486ebb8b94c20147 | |
parent | dcba1c2fbf5eb71b688810434a20298ef8202339 (diff) | |
download | android_packages_apps_Gallery2-65b4d0c1ded85105802bf69ddb5646eb72839e17.tar.gz android_packages_apps_Gallery2-65b4d0c1ded85105802bf69ddb5646eb72839e17.tar.bz2 android_packages_apps_Gallery2-65b4d0c1ded85105802bf69ddb5646eb72839e17.zip |
Gallery2: support GIF animation
This change implements a Java GIF decoder.
Change-Id: I72b6e8eb25572bba77a2a46e1754d8db8c47a0cc
Signed-off-by: Xiaojing Zhang <zhangx@codeaurora.org>
-rw-r--r-- | AndroidManifest.xml | 10 | ||||
-rw-r--r--[-rwxr-xr-x] | res/layout/view_gif_image.xml | 55 | ||||
-rwxr-xr-x[-rw-r--r--] | src/com/android/gallery3d/app/PhotoDataAdapter.java | 7 | ||||
-rwxr-xr-x[-rw-r--r--] | src/com/android/gallery3d/app/PhotoPage.java | 9 | ||||
-rwxr-xr-x[-rw-r--r--] | src/com/android/gallery3d/app/SinglePhotoDataAdapter.java | 5 | ||||
-rw-r--r-- | src/com/android/gallery3d/data/MediaItem.java | 1 | ||||
-rwxr-xr-x[-rw-r--r--] | src/com/android/gallery3d/ui/PhotoView.java | 21 | ||||
-rwxr-xr-x | src/com/android/gallery3d/util/GIFView.java | 377 | ||||
-rw-r--r--[-rwxr-xr-x] | src/com/android/gallery3d/util/GifAction.java | 2 | ||||
-rwxr-xr-x | src/com/android/gallery3d/util/GifDecoder.java | 1396 | ||||
-rwxr-xr-x | src/com/android/gallery3d/util/GifFrame.java | 17 | ||||
-rwxr-xr-x | src/com/android/gallery3d/util/ViewGifImage.java | 110 |
12 files changed, 957 insertions, 1053 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 95beee19c..52048895b 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -297,6 +297,16 @@ android:theme="@style/Theme.Gallery" android:configChanges="orientation|keyboardHidden|screenSize" /> + <activity android:name="com.android.gallery3d.util.ViewGifImage" + android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" + android:configChanges="orientation|keyboardHidden|screenSize|keyboard|navigation"> + <intent-filter> + <action android:name="com.android.gallery3d.VIEW_GIF" /> + <data android:mimeType="image/gif" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + <provider android:name="com.android.gallery3d.provider.GalleryProvider" android:syncable="false" android:grantUriPermissions="true" diff --git a/res/layout/view_gif_image.xml b/res/layout/view_gif_image.xml index bceb16f44..976549a6b 100755..100644 --- a/res/layout/view_gif_image.xml +++ b/res/layout/view_gif_image.xml @@ -1,46 +1,17 @@ <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <LinearLayout - android:id="@+id/image_absoluteLayout" - android:layout_height="match_parent" - android:layout_width="match_parent"> - <ImageView android:id="@+id/image_dispaly_area" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:clickable="true"> - </ImageView> - </LinearLayout> + android:layout_width="match_parent" + android:layout_height="match_parent"> -<!-- - <ImageView android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:id="@+id/arrow_left" - android:layout_centerVertical="true" - android:clickable="true" - android:src="@drawable/arrow_left"> - </ImageView> - - <ImageView android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:id="@+id/arrow_right" - android:layout_alignParentRight="true" - android:layout_centerVertical="true" - android:clickable="true" - android:src="@drawable/arrow_right"> - </ImageView> - - <TextView android:id="@+id/tv_count" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_centerHorizontal="true" - android:textSize="18sp" - android:textColor="#ffffffff" - android:layout_marginTop="5dip" - android:background="@drawable/text_frame"> - </TextView> ---> -</RelativeLayout> + <LinearLayout + android:id="@+id/image_absoluteLayout" + android:layout_height="match_parent" + android:layout_width="match_parent"> + <ImageView android:id="@+id/image_display_area" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:clickable="true"> + </ImageView> + </LinearLayout> +</RelativeLayout> diff --git a/src/com/android/gallery3d/app/PhotoDataAdapter.java b/src/com/android/gallery3d/app/PhotoDataAdapter.java index fd3a7cf73..40967a118 100644..100755 --- a/src/com/android/gallery3d/app/PhotoDataAdapter.java +++ b/src/com/android/gallery3d/app/PhotoDataAdapter.java @@ -512,6 +512,13 @@ public class PhotoDataAdapter implements PhotoPage.Model { } @Override + public boolean isGif(int offset) { + MediaItem item = getItem(mCurrentIndex + offset); + return (item != null) && + MediaItem.MIME_TYPE_GIF.equalsIgnoreCase(item.getMimeType()); + } + + @Override public boolean isDeletable(int offset) { MediaItem item = getItem(mCurrentIndex + offset); return (item == null) diff --git a/src/com/android/gallery3d/app/PhotoPage.java b/src/com/android/gallery3d/app/PhotoPage.java index 915fdab5a..667ab3805 100644..100755 --- a/src/com/android/gallery3d/app/PhotoPage.java +++ b/src/com/android/gallery3d/app/PhotoPage.java @@ -72,6 +72,7 @@ import com.android.gallery3d.ui.SelectionManager; import com.android.gallery3d.ui.SynchronizedHandler; import com.android.gallery3d.util.GalleryUtils; import com.android.gallery3d.util.UsageStatistics; +import com.android.gallery3d.util.ViewGifImage; public abstract class PhotoPage extends ActivityState implements PhotoView.Listener, AppBridge.Server, ShareActionProvider.OnShareTargetSelectedListener, @@ -1136,6 +1137,10 @@ public abstract class PhotoPage extends ActivityState implements // item is not ready or it is camera preview, ignore return; } + if (item.getMimeType().equals(MediaItem.MIME_TYPE_GIF)) { + viewAnimateGif((Activity) mActivity, item.getContentUri()); + return; + } int supported = item.getSupportedOperations(); boolean playVideo = ((supported & MediaItem.SUPPORT_PLAY) != 0); @@ -1530,4 +1535,8 @@ public abstract class PhotoPage extends ActivityState implements } } + private static void viewAnimateGif(Activity activity, Uri uri) { + Intent intent = new Intent(ViewGifImage.VIEW_GIF_ACTION, uri); + activity.startActivity(intent); + } } diff --git a/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java b/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java index 00f2fe78f..fe39e4e3d 100644..100755 --- a/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java +++ b/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java @@ -227,6 +227,11 @@ public class SinglePhotoDataAdapter extends TileImageViewAdapter } @Override + public boolean isGif(int offset) { + return MediaItem.MIME_TYPE_GIF.equalsIgnoreCase(mItem.getMimeType()); + } + + @Override public boolean isDeletable(int offset) { return (mItem.getSupportedOperations() & MediaItem.SUPPORT_DELETE) != 0; } diff --git a/src/com/android/gallery3d/data/MediaItem.java b/src/com/android/gallery3d/data/MediaItem.java index 59ea86551..92ac88dc6 100644 --- a/src/com/android/gallery3d/data/MediaItem.java +++ b/src/com/android/gallery3d/data/MediaItem.java @@ -37,6 +37,7 @@ public abstract class MediaItem extends MediaObject { public static final int IMAGE_ERROR = -1; public static final String MIME_TYPE_JPEG = "image/jpeg"; + public static final String MIME_TYPE_GIF = "image/gif"; private static final int BYTESBUFFE_POOL_SIZE = 4; private static final int BYTESBUFFER_SIZE = 200 * 1024; diff --git a/src/com/android/gallery3d/ui/PhotoView.java b/src/com/android/gallery3d/ui/PhotoView.java index 7afa20348..5647e36af 100644..100755 --- a/src/com/android/gallery3d/ui/PhotoView.java +++ b/src/com/android/gallery3d/ui/PhotoView.java @@ -93,6 +93,9 @@ public class PhotoView extends GLView { // Returns true if the item is a Video. public boolean isVideo(int offset); + // Returns true if the item is a Gif. + public boolean isGif(int offset); + // Returns true if the item can be deleted. public boolean isDeletable(int offset); @@ -594,7 +597,6 @@ public class PhotoView extends GLView { private boolean mIsCamera; private boolean mIsPanorama; private boolean mIsStaticCamera; - private boolean mIsVideo; private boolean mIsDeletable; private int mLoadingState = Model.LOADING_INIT; private Size mSize = new Size(); @@ -607,7 +609,6 @@ public class PhotoView extends GLView { mIsCamera = mModel.isCamera(0); mIsPanorama = mModel.isPanorama(0); mIsStaticCamera = mModel.isStaticCamera(0); - mIsVideo = mModel.isVideo(0); mIsDeletable = mModel.isDeletable(0); mLoadingState = mModel.getLoadingState(0); setScreenNail(mModel.getScreenNail(0)); @@ -732,8 +733,11 @@ public class PhotoView extends GLView { // Draw the play video icon and the message. canvas.translate((int) (cx + 0.5f), (int) (cy + 0.5f)); int s = (int) (scale * Math.min(r.width(), r.height()) + 0.5f); - if (mIsVideo) drawVideoPlayIcon(canvas, s); - if (mLoadingState == Model.LOADING_FAIL) { + //Full pic locates at index 0 of the array in PhotoDataAdapter + if (mModel.isVideo(0) || mModel.isGif(0)) { + drawVideoPlayIcon(canvas, s); + } + if (mLoadingState == Model.LOADING_FAIL ) { drawLoadingFailMessage(canvas); } @@ -775,7 +779,6 @@ public class PhotoView extends GLView { private boolean mIsCamera; private boolean mIsPanorama; private boolean mIsStaticCamera; - private boolean mIsVideo; private boolean mIsDeletable; private int mLoadingState = Model.LOADING_INIT; private Size mSize = new Size(); @@ -789,7 +792,6 @@ public class PhotoView extends GLView { mIsCamera = mModel.isCamera(mIndex); mIsPanorama = mModel.isPanorama(mIndex); mIsStaticCamera = mModel.isStaticCamera(mIndex); - mIsVideo = mModel.isVideo(mIndex); mIsDeletable = mModel.isDeletable(mIndex); mLoadingState = mModel.getLoadingState(mIndex); setScreenNail(mModel.getScreenNail(mIndex)); @@ -853,8 +855,10 @@ public class PhotoView extends GLView { invalidate(); } int s = Math.min(drawW, drawH); - if (mIsVideo) drawVideoPlayIcon(canvas, s); - if (mLoadingState == Model.LOADING_FAIL) { + if (mModel.isVideo(mIndex) || mModel.isGif(mIndex)) { + drawVideoPlayIcon(canvas, s); + } + if (mLoadingState == Model.LOADING_FAIL ) { drawLoadingFailMessage(canvas); } canvas.restore(); @@ -1855,4 +1859,5 @@ public class PhotoView extends GLView { } return effect; } + } diff --git a/src/com/android/gallery3d/util/GIFView.java b/src/com/android/gallery3d/util/GIFView.java index 0e71aa314..fd4a5b269 100755 --- a/src/com/android/gallery3d/util/GIFView.java +++ b/src/com/android/gallery3d/util/GIFView.java @@ -1,300 +1,211 @@ package com.android.gallery3d.util; -import java.io.InputStream; +import com.android.gallery3d.R; + import android.content.Context; +import android.content.ContentResolver; +import android.content.res.AssetManager; +import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Rect; +import android.net.Uri; 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{ +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.IOException; + +public class GIFView extends ImageView implements GifAction { - private static final String TAG = "GIFView"; - - private GifDecoder gifDecoder = null; + private static final String TAG = "GIFView"; + private static final float SCALE_LIMIT = 4; + private static final long FRAME_DELAY = 200; //milliseconds - private Bitmap currentImage = null; - - private static boolean isRun = false; - - private static boolean pause = true; + private GifDecoder mGifDecoder = null; + private Bitmap mCurrentImage = null; + private DrawThread mDrawThread = null; - private int W; - - private int H; - - private DrawThread drawThread = null; + private Uri mUri; + private Context mContext; - Uri mUri; - private Context mContext; - public GIFView(Context context) { super(context); - mContext=context; - + mContext = context; } - public boolean setDrawable(Uri uri){ - if (null == uri){ + 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; + + InputStream is = getInputStream(uri); + if (is == null || (getFileSize (is) == 0)) { + return false; + } + startDecode(is); + return true; + } + + private int getFileSize (InputStream is) { + if(is == null) return 0; + + int size = 0; try { - input = cr.openInputStream(uri); - - if (input instanceof FileInputStream) { - FileInputStream f = (FileInputStream) input; - mSize = (int) f.getChannel().size(); + if (is instanceof FileInputStream) { + FileInputStream f = (FileInputStream) is; + size = (int) f.getChannel().size(); } else { - while (-1 != input.read()) { - mSize++; + while (-1 != is.read()) { + size++; } } } catch (IOException e) { - - } finally { - - } - //wss , return if file is invalid - if(mSize == 0){ - return false; + Log.e(TAG, "catch exception:" + e); } - 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; + return size; + + } + + private InputStream getInputStream (Uri uri) { + ContentResolver cr = mContext.getContentResolver(); + InputStream input = null; + try { + input = cr.openInputStream(uri); + } catch (IOException e) { + Log.e(TAG, "catch exception:" + e); } - - 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; + return input; } - - private void setGifDecoderImage(InputStream is){ - if(gifDecoder != null){ - gifDecoder.free(); - gifDecoder= null; - } - gifDecoder = new GifDecoder(is,this); - gifDecoder.start(); + + private void startDecode(InputStream is) { + freeGifDecoder(); + mGifDecoder = new GifDecoder(is, this); + mGifDecoder.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){ + if (mGifDecoder == null) { return; } - - if(currentImage == null){ - currentImage = gifDecoder.getImage(); + + if (mCurrentImage == null) { + mCurrentImage = mGifDecoder.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 + if (mCurrentImage == null) { + // if this gif can not be displayed, just try to show it as jpg by parsing mUri + setImageURI(mUri); 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 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); + + int imageHeight = mCurrentImage.getHeight(); + int imageWidth = mCurrentImage.getWidth(); + + int displayHeight = ViewGifImage.mDM.heightPixels; + int displayWidth = ViewGifImage.mDM.widthPixels; + + int width, height; + if (imageWidth >= displayWidth || imageHeight >= displayHeight) { + // scale-down the image + if (imageWidth * displayHeight > displayWidth * imageHeight) { + width = displayWidth; + height = (imageHeight * width) / imageWidth; + } else { + height = displayHeight; + width = (imageWidth * height) / imageHeight; } - 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 { + // scale-up the image + float scale = Math.min(SCALE_LIMIT, Math.min(displayWidth / (float) imageWidth, + displayHeight / (float) imageHeight)); + width = (int) (imageWidth * scale); + height = (int) (imageHeight * scale); } - else - { - //h small, w small; - canvas.drawBitmap(currentImage, (W - imageWidth) / 2, (H - imageHeight) / 2, null); - } - + dRect = new Rect((displayWidth - width) / 2, (displayHeight - height) / 2, + (displayWidth + width) / 2, (displayHeight + height) / 2); + canvas.drawBitmap(mCurrentImage, sRect, dRect, 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(); - } + + public void parseOk(boolean parseStatus, int frameIndex) { + if (parseStatus) { + //indicates the start of a new GIF + if (mGifDecoder != null && frameIndex == -1 + && mGifDecoder.getFrameCount() > 1) { + if (mDrawThread != null) { + mDrawThread = null; } + mDrawThread = new DrawThread(); + mDrawThread.start(); } - }else{ - Log.e("gif","parse error"); + } else { + Log.e(TAG, "parse error"); } } - private Handler redrawHandler = new Handler(){ - public void handleMessage(Message msg) { - invalidate(); - } + private Handler mRedrawHandler = new Handler() { + public void handleMessage(Message msg) { + invalidate(); + } }; - - private class DrawThread extends Thread{ - public void run(){ - if(gifDecoder == null){ + + private class DrawThread extends Thread { + public void run() { + if (mGifDecoder == 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{ + + while (true) { + if (!isShown() || mRedrawHandler == null) { break; } + GifFrame frame = mGifDecoder.next(); + mCurrentImage = frame.mImage; + + Message msg = mRedrawHandler.obtainMessage(); + mRedrawHandler.sendMessage(msg); + try { + Thread.sleep(getDelay(frame)); + } catch (InterruptedException e) { + Log.e(TAG, "catch exception:" + e); + } } - 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; - } + + private long getDelay (GifFrame frame) { + //in milliseconds + return frame.mDelayInMs == 0 ? FRAME_DELAY : frame.mDelayInMs; } -} + private void freeGifDecoder () { + if (mGifDecoder != null) { + mGifDecoder.free(); + mGifDecoder = null; + } + } + public void freeMemory() { + if (mDrawThread != null) { + mDrawThread = null; + } + freeGifDecoder(); + } +} diff --git a/src/com/android/gallery3d/util/GifAction.java b/src/com/android/gallery3d/util/GifAction.java index b273a1768..88e3cdee0 100755..100644 --- a/src/com/android/gallery3d/util/GifAction.java +++ b/src/com/android/gallery3d/util/GifAction.java @@ -1,5 +1,5 @@ package com.android.gallery3d.util; public interface GifAction { - public void parseOk(boolean parseStatus,int frameIndex); + 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 index 60bc1980b..4235fc5a5 100755 --- a/src/com/android/gallery3d/util/GifDecoder.java +++ b/src/com/android/gallery3d/util/GifDecoder.java @@ -1,697 +1,723 @@ 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(); +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +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 mIS; + private int mStatus; + + public int mWidth; // full image width + public int mHeight; // full image height + private boolean mGctFlag; // global color table used + private int mGctSize; // size of global color table + private int mLoopCount = 1; // iterations; 0 = repeat forever + + private int[] mGct; // global color table + private int[] mLct; // local color table + private int[] mAct; // active color table + + private int mBgIndex; // background color index + private int mBgColor; // background color + private int mLastBgColor; // previous bg color + private int mPixelAspect; // pixel aspect ratio + + private boolean mLctFlag; // local color table flag + private boolean mInterlace; // interlace flag + private int mLctSize; // local color table size + + private int mIx, mIy, mIw, mIh; // current image rectangle + private int mLrx, mLry, mLrw, mLrh; + private Bitmap mImage; // current frame + private Bitmap mLastImage; // previous frame + private GifFrame mCurrentFrame = null; + + private boolean mIsShow = false; + + private byte[] mBlock = new byte[256]; // current data block + private int mBlockSize = 0; // block size + private int mDispose = 0; + private int mLastDispose = 0; + private boolean mTransparency = false; // use transparent color + private int mDelay = 0; // delay in milliseconds + private int mTransIndex; // transparent color index + + // max decoder pixel stack size + private static final int MaxStackSize = 4096; + + // LZW decoder working arrays + private short[] mPrefix; + private byte[] mSuffix; + private byte[] mPixelStack; + private byte[] mPixels; + + private GifFrame mGifFrame; // frames read from current file + private int mFrameCount; + + private GifAction mGifAction = null; + + private byte[] mGifData = null; + + public GifDecoder(byte[] data, GifAction act) { + mGifData = data; + mGifAction = act; + } + + public GifDecoder(InputStream is, GifAction act) { + mIS = is; + mGifAction = act; + } + + public void run() { + if (mIS != null) { + readStream(); + } else if (mGifData != null) { + readByte(); + } + } + + public void free() { + freeFrame(); + freeIS(); + freeImage(); + } + + public int getStatus() { + return mStatus; + } + + public boolean parseOk() { + return mStatus == STATUS_FINISH; + } + + public int getDelay(int n) { + mDelay = -1; + if ((n >= 0) && (n < mFrameCount)) { + GifFrame f = getFrame(n); + if (f != null) { + mDelay = f.mDelayInMs; + } + } + return mDelay; + } + + public int[] getDelays() { + GifFrame f = mGifFrame; + int[] d = new int[mFrameCount]; + int i = 0; + while (f != null && i < mFrameCount) { + d[i] = f.mDelayInMs; + f = f.mNextFrame; + i++; + } + return d; + } + + public int getFrameCount() { + return mFrameCount; + } + + public Bitmap getImage() { + return getFrameImage(0); + } + + public int getLoopCount() { + return mLoopCount; + } + + private void setPixels() { + int[] dest = new int[mWidth * mHeight]; + // fill in starting image contents based on last image's dispose code + if (mLastDispose > 0) { + if (mLastDispose == 3) { + // use image before last + int n = mFrameCount - 2; + if (n > 0) { + mLastImage = getPreUndisposedImage(n - 1); + } else { + mLastImage = null; + } + } + if (mLastImage != null) { + mLastImage.getPixels(dest, 0, mWidth, 0, 0, mWidth, mHeight); + // copy pixels + if (mLastDispose == 2) { + // fill last image rect area with background color + int c = 0; + if (!mTransparency) { + c = mLastBgColor; + } + for (int i = 0; i < mLrh; i++) { + int n1 = (mLry + i) * mWidth + mLrx; + int n2 = n1 + mLrw; + 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 < mIh; i++) { + int line = i; + if (mInterlace) { + if (iline >= mIh) { + 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 += mIy; + if (line < mHeight) { + int k = line * mWidth; + int dx = k + mIx; // start of line in dest + int dlim = dx + mIw; // end of dest line + if ((k + mWidth) < dlim) { + dlim = k + mWidth; // past dest edge + } + int sx = i * mIw; // start of line in source + while (dx < dlim) { + // map color and insert in destination + int index = ((int) mPixels[sx++]) & 0xff; + int c = mAct[index]; + if (c != 0) { + dest[dx] = c; + } + dx++; + } + } + } + mImage = Bitmap.createBitmap(dest, mWidth, mHeight, Config.ARGB_4444); + } + + public Bitmap getFrameImage(int n) { + GifFrame frame = getFrame(n); + if (frame == null) { + return null; + } else { + return frame.mImage; + } + } + + public GifFrame getCurrentFrame() { + return mCurrentFrame; + } + + public GifFrame getFrame(int n) { + GifFrame frame = mGifFrame; + int i = 0; + while (frame != null) { + if (i == n) { + return frame; + } else { + frame = frame.mNextFrame; + } + i++; + } + return null; + } + + private Bitmap getPreUndisposedImage(int n) { + Bitmap preUndisposedImage = null; + GifFrame frame = mGifFrame; + int i = 0; + while (frame != null && i <= n) { + if (frame.mDispose == 1) { + preUndisposedImage = frame.mImage; + } else { + frame = frame.mNextFrame; + } + i++; + } + return preUndisposedImage; + } + + public void reset() { + mCurrentFrame = mGifFrame; + } + + public GifFrame next() { + if (mIsShow == false) { + mIsShow = true; + return mGifFrame; + } else { + if (mStatus == STATUS_PARSING) { + if (mCurrentFrame.mNextFrame != null) { + mCurrentFrame = mCurrentFrame.mNextFrame; + } + } else { + mCurrentFrame = mCurrentFrame.mNextFrame; + if (mCurrentFrame == null) { + mCurrentFrame = mGifFrame; + } + } + return mCurrentFrame; + } + } + + private int readByte() { + mIS = new ByteArrayInputStream(mGifData); + mGifData = null; + return readStream(); + } + + private int readStream() { + init(); + if (mIS != null) { + readHeader(); + if (!err()) { + readContents(); + if (mFrameCount < 0) { + mStatus = STATUS_FORMAT_ERROR; + mGifAction.parseOk(false, -1); + } else { + mStatus = STATUS_FINISH; + mGifAction.parseOk(true, -1); + } + } + try { + mIS.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + mStatus = STATUS_OPEN_ERROR; + mGifAction.parseOk(false, -1); + } + return mStatus; + } + + private void decodeImageData() { + int NullCode = -1; + int npix = mIw * mIh; + 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 ((mPixels == null) || (mPixels.length < npix)) { + mPixels = new byte[npix]; // allocate new pixel array + } + if (mPrefix == null) { + mPrefix = new short[MaxStackSize]; + } + if (mSuffix == null) { + mSuffix = new byte[MaxStackSize]; + } + if (mPixelStack == null) { + mPixelStack = 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++) { + mPrefix[code] = 0; + mSuffix[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) mBlock[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) { + mPixelStack[top++] = mSuffix[code]; + old_code = code; + first = code; + continue; + } + in_code = code; + if (code == available) { + mPixelStack[top++] = (byte) first; + code = old_code; + } + while (code > clear) { + mPixelStack[top++] = mSuffix[code]; + code = mPrefix[code]; + } + first = ((int) mSuffix[code]) & 0xff; + // Add a new string to the string table, + if (available >= MaxStackSize) { + break; + } + mPixelStack[top++] = (byte) first; + mPrefix[available] = (short) old_code; + mSuffix[available] = (byte) first; + available++; + if (((available & code_mask) == 0) + && (available < MaxStackSize)) { + code_size++; + code_mask += available; + } + old_code = in_code; } - 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; - } + + // Pop a pixel off the pixel stack. + top--; + mPixels[pi++] = mPixelStack[top]; + i++; + } + for (i = pi; i < npix; i++) { + mPixels[i] = 0; // clear missing pixels + } + } + + private boolean err() { + return mStatus != STATUS_PARSING; + } + + private void init() { + mStatus = STATUS_PARSING; + mFrameCount = 0; + mGifFrame = null; + mGct = null; + mLct = null; + } + + private int read() { + int curByte = 0; 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) { + curByte = mIS.read(); + } catch (Exception e) { + mStatus = STATUS_FORMAT_ERROR; + } + return curByte; + } + + private int readBlock() { + mBlockSize = read(); + int n = 0; + if (mBlockSize > 0) { + try { + int count = 0; + while (n < mBlockSize) { + count = mIS.read(mBlock, n, mBlockSize - n); + if (count == -1) { + break; + } + n += count; + } + } catch (Exception e) { + e.printStackTrace(); + } + if (n < mBlockSize) { + mStatus = 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 = mIS.read(c); + } catch (Exception e) { + e.printStackTrace(); + } + if (n < nbytes) { + mStatus = 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) mBlock[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: + mStatus = STATUS_FORMAT_ERROR; + } + } + } + + private void readGraphicControlExt() { + read(); // block size + int packed = read(); // packed fields + mDispose = (packed & 0x1c) >> 2; // disposal method + if (mDispose == 0) { + mDispose = 1; // elect to keep old image if discretionary + } + mTransparency = (packed & 1) != 0; + mDelay = readShort() * 10; // delay in milliseconds + mTransIndex = 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")) { + mStatus = STATUS_FORMAT_ERROR; + return; + } + readLSD(); + if (mGctFlag && !err()) { + mGct = readColorTable(mGctSize); + mBgColor = mGct[mBgIndex]; + } + } + + private void readImage() { + mIx = readShort(); // (sub)image position & size + mIy = readShort(); + mIw = readShort(); + mIh = readShort(); + int packed = read(); + mLctFlag = (packed & 0x80) != 0; // 1 - local color table flag + mInterlace = (packed & 0x40) != 0; // 2 - interlace flag + // 3 - sort flag + // 4-5 - reserved + mLctSize = 2 << (packed & 7); // 6-8 - local color table size + if (mLctFlag) { + mLct = readColorTable(mLctSize); // read table + mAct = mLct; // make local table active + } else { + mAct = mGct; // make global table active + if (mBgIndex == mTransIndex) { + mBgColor = 0; + } + } + int save = 0; + if (mTransparency) { + save = mAct[mTransIndex]; + mAct[mTransIndex] = 0; // set transparent color if specified + } + if (mAct == null) { + mStatus = STATUS_FORMAT_ERROR; // no color table defined + } + if (err()) { + return; + } + try { + decodeImageData(); // decode pixel data + skip(); + if (err()) { + return; + } + mFrameCount++; + // create new image to receive frame data + mImage = Bitmap.createBitmap(mWidth, mHeight, Config.ARGB_4444); + // createImage(mWidth, mHeight); + setPixels(); // transfer pixel data to image + if (mGifFrame == null) { + mGifFrame = new GifFrame(mImage, mDelay, mDispose); + mCurrentFrame = mGifFrame; + } else { + GifFrame f = mGifFrame; + while (f.mNextFrame != null) { + f = f.mNextFrame; + } + f.mNextFrame = new GifFrame(mImage, mDelay, mDispose); + } + // frames.addElement(new GifFrame(image, delay)); // add image to + // frame + // list + if (mTransparency) { + mAct[mTransIndex] = save; + } + resetFrame(); + mGifAction.parseOk(true, mFrameCount); + } 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()); - } + } + + private void readLSD() { + // logical screen size + mWidth = readShort(); + mHeight = readShort(); + // packed fields + int packed = read(); + mGctFlag = (packed & 0x80) != 0; // 1 : global color table flag + // 2-4 : color resolution + // 5 : gct sort flag + mGctSize = 2 << (packed & 7); // 6-8 : gct size + mBgIndex = read(); // background color index + mPixelAspect = read(); // pixel aspect ratio + } + + private void readNetscapeExt() { + do { + readBlock(); + if (mBlock[0] == 1) { + // loop count sub-block + int b1 = ((int) mBlock[1]) & 0xff; + int b2 = ((int) mBlock[2]) & 0xff; + mLoopCount = (b2 << 8) | b1; + } + } while ((mBlockSize > 0) && !err()); + } + + private int readShort() { + // read 16-bit value, LSB first + return read() | (read() << 8); + } + + private void resetFrame() { + mLastDispose = mDispose; + mLrx = mIx; + mLry = mIy; + mLrw = mIw; + mLrh = mIh; + mLastImage = mImage; + mLastBgColor = mBgColor; + mDispose = 0; + mTransparency = false; + mDelay = 0; + mLct = null; + } + + /** + * Skips variable length blocks up to and including next zero length block. + */ + private void skip() { + do { + readBlock(); + } while ((mBlockSize > 0) && !err()); + } + + private void freeFrame() { + GifFrame fg = mGifFrame; + while (fg != null) { + if (fg.mImage != null) { + fg.mImage.recycle(); + } + fg.mImage = null; + fg = null; + mGifFrame = mGifFrame.mNextFrame; + fg = mGifFrame; + } + } + + private void freeIS() { + if (mIS != null) { + try { + mIS.close(); + } catch (Exception ex) { + ex.printStackTrace(); + } + mIS = null; + } + mGifData = null; + } + + private void freeImage() { + if (mImage != null) { + mImage.recycle(); + mImage = null; + } + if (mLastImage != null) { + mLastImage.recycle(); + mLastImage = null; + } + } } diff --git a/src/com/android/gallery3d/util/GifFrame.java b/src/com/android/gallery3d/util/GifFrame.java index 926ed57b4..87d58a40d 100755 --- a/src/com/android/gallery3d/util/GifFrame.java +++ b/src/com/android/gallery3d/util/GifFrame.java @@ -3,12 +3,15 @@ package com.android.gallery3d.util; import android.graphics.Bitmap; public class GifFrame { - public GifFrame(Bitmap im, int del) { - image = im; - delay = del; + + public Bitmap mImage; + public int mDelayInMs; //in milliseconds + public int mDispose; + public GifFrame mNextFrame = null; + + public GifFrame(Bitmap bitmap, int delay, int dispose) { + mImage = bitmap; + mDelayInMs = delay; + mDispose = dispose; } - - 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 index b157e2f3b..cdd509280 100755 --- a/src/com/android/gallery3d/util/ViewGifImage.java +++ b/src/com/android/gallery3d/util/ViewGifImage.java @@ -1,111 +1,67 @@ -/** - * File property dialog - * - * @Author wangxuguang - * - * caozhe add this file, for displya gif image, 2011.3.28 - */ - package com.android.gallery3d.util; +import com.android.gallery3d.R; import android.app.Activity; +import android.content.res.Configuration; +import android.net.Uri; 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.util.DisplayMetrics; import android.view.ViewGroup.LayoutParams; +import android.widget.ImageView; 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; +public class ViewGifImage extends Activity { + private static final String TAG = "ViewGifImage"; + public static final String VIEW_GIF_ACTION = "com.android.gallery3d.VIEW_GIF"; - static final int WIDTH = 320; - static final int HEIGHT = 480; + public static DisplayMetrics mDM; - - private Handler mHandler = new Handler() { - public void handleMessage(Message msg) - { - super.handleMessage(msg); - } - }; + private ImageView mGifView; @Override - public void onCreate(Bundle savedInstanceState) - { - //android.util.Log.d(TAG, "=== onCreate() ==="); + public void onCreate(Bundle savedInstanceState) { 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 + mDM = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(mDM); + if (getIntent().getAction() != null + && getIntent().getAction().equals(VIEW_GIF_ACTION)) { 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() - { + protected void onStop() { super.onStop(); finish(); } - + @Override - protected void onDestroy() { - if (gifView != null){ - if (gifView instanceof GIFView) - { - ((GIFView)gifView).freeMemory(); - gifView = null; - } - } - super.onDestroy(); - } + protected void onDestroy() { + if (mGifView != null && mGifView instanceof GIFView) { + ((GIFView) mGifView).freeMemory(); + mGifView = null; + } + super.onDestroy(); + } + + private void showGifPicture(Uri uri) { + mGifView = new GIFView(this); + ((LinearLayout) findViewById(R.id.image_absoluteLayout)).addView(mGifView, + new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + if (((GIFView) mGifView).setDrawable(uri)) return; + + finish(); - 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); + getWindowManager().getDefaultDisplay().getMetrics(mDM); super.onConfigurationChanged(newConfig); } - - } |