summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/gallery3d/filtershow/cache/ImageLoader.java')
-rw-r--r--src/com/android/gallery3d/filtershow/cache/ImageLoader.java279
1 files changed, 215 insertions, 64 deletions
diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
index afef58aad..a1a1ba186 100644
--- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
+++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
@@ -18,6 +18,7 @@ package com.android.gallery3d.filtershow.cache;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
@@ -26,6 +27,7 @@ import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.Bitmap.CompressFormat;
import android.media.ExifInterface;
import android.net.Uri;
import android.provider.MediaStore;
@@ -36,19 +38,27 @@ import com.adobe.xmp.XMPMeta;
import com.android.gallery3d.R;
import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.exif.ExifInvalidFormatException;
+import com.android.gallery3d.exif.ExifParser;
+import com.android.gallery3d.exif.ExifTag;
+import com.android.gallery3d.filtershow.CropExtras;
import com.android.gallery3d.filtershow.FilterShowActivity;
import com.android.gallery3d.filtershow.HistoryAdapter;
import com.android.gallery3d.filtershow.imageshow.ImageCrop;
import com.android.gallery3d.filtershow.imageshow.ImageShow;
import com.android.gallery3d.filtershow.presets.ImagePreset;
+import com.android.gallery3d.filtershow.tools.BitmapTask;
import com.android.gallery3d.filtershow.tools.SaveCopyTask;
+import com.android.gallery3d.util.InterruptableOutputStream;
import com.android.gallery3d.util.XmpUtilHelper;
import java.io.Closeable;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.util.Vector;
import java.util.concurrent.locks.ReentrantLock;
@@ -69,13 +79,16 @@ public class ImageLoader {
private FilterShowActivity mActivity = null;
- public static final int ORI_NORMAL = ExifInterface.ORIENTATION_NORMAL;
- public static final int ORI_ROTATE_90 = ExifInterface.ORIENTATION_ROTATE_90;
+ public static final String DEFAULT_SAVE_DIRECTORY = "EditedOnlinePhotos";
+ public static final int DEFAULT_COMPRESS_QUALITY = 95;
+
+ public static final int ORI_NORMAL = ExifInterface.ORIENTATION_NORMAL;
+ public static final int ORI_ROTATE_90 = ExifInterface.ORIENTATION_ROTATE_90;
public static final int ORI_ROTATE_180 = ExifInterface.ORIENTATION_ROTATE_180;
public static final int ORI_ROTATE_270 = ExifInterface.ORIENTATION_ROTATE_270;
- public static final int ORI_FLIP_HOR = ExifInterface.ORIENTATION_FLIP_HORIZONTAL;
- public static final int ORI_FLIP_VERT = ExifInterface.ORIENTATION_FLIP_VERTICAL;
- public static final int ORI_TRANSPOSE = ExifInterface.ORIENTATION_TRANSPOSE;
+ public static final int ORI_FLIP_HOR = ExifInterface.ORIENTATION_FLIP_HORIZONTAL;
+ public static final int ORI_FLIP_VERT = ExifInterface.ORIENTATION_FLIP_VERTICAL;
+ public static final int ORI_TRANSPOSE = ExifInterface.ORIENTATION_TRANSPOSE;
public static final int ORI_TRANSVERSE = ExifInterface.ORIENTATION_TRANSVERSE;
private Context mContext = null;
@@ -101,18 +114,24 @@ public class ImageLoader {
return mActivity;
}
- public void loadBitmap(Uri uri,int size) {
+ public boolean loadBitmap(Uri uri, int size) {
mLoadingLock.lock();
mUri = uri;
mOrientation = getOrientation(mContext, uri);
mOriginalBitmapSmall = loadScaledBitmap(uri, 160);
if (mOriginalBitmapSmall == null) {
// Couldn't read the bitmap, let's exit
- mActivity.cannotLoadImage();
+ mLoadingLock.unlock();
+ return false;
}
mOriginalBitmapLarge = loadScaledBitmap(uri, size);
+ if (mOriginalBitmapLarge == null) {
+ mLoadingLock.unlock();
+ return false;
+ }
updateBitmaps();
mLoadingLock.unlock();
+ return true;
}
public Uri getUri() {
@@ -135,21 +154,25 @@ public class ImageLoader {
MediaStore.Images.ImageColumns.ORIENTATION
},
null, null, null);
- if (cursor.moveToNext()){
- int ori = cursor.getInt(0);
-
- switch (ori){
- case 0: return ORI_NORMAL;
- case 90: return ORI_ROTATE_90;
- case 270: return ORI_ROTATE_270;
- case 180: return ORI_ROTATE_180;
- default:
- return -1;
- }
- } else{
+ if (cursor.moveToNext()) {
+ int ori = cursor.getInt(0);
+
+ switch (ori) {
+ case 0:
+ return ORI_NORMAL;
+ case 90:
+ return ORI_ROTATE_90;
+ case 270:
+ return ORI_ROTATE_270;
+ case 180:
+ return ORI_ROTATE_180;
+ default:
+ return -1;
+ }
+ } else {
return -1;
}
- } catch (SQLiteException e){
+ } catch (SQLiteException e) {
return ExifInterface.ORIENTATION_UNDEFINED;
} catch (IllegalArgumentException e) {
return ExifInterface.ORIENTATION_UNDEFINED;
@@ -160,12 +183,27 @@ public class ImageLoader {
static int getOrientationFromPath(String path) {
int orientation = -1;
+ InputStream is = null;
try {
- ExifInterface EXIF = new ExifInterface(path);
- orientation = EXIF.getAttributeInt(ExifInterface.TAG_ORIENTATION,
- 1);
+ is = new FileInputStream(path);
+ ExifParser parser = ExifParser.parse(is, ExifParser.OPTION_IFD_0);
+ int event = parser.next();
+ while (event != ExifParser.EVENT_END) {
+ if (event == ExifParser.EVENT_NEW_TAG) {
+ ExifTag tag = parser.getTag();
+ if (tag.getTagId() == ExifTag.TAG_ORIENTATION) {
+ orientation = (int) tag.getValueAt(0);
+ break;
+ }
+ }
+ event = parser.next();
+ }
} catch (IOException e) {
e.printStackTrace();
+ } catch (ExifInvalidFormatException e) {
+ e.printStackTrace();
+ } finally {
+ Utils.closeSilently(is);
}
return orientation;
}
@@ -181,46 +219,46 @@ public class ImageLoader {
warnListeners();
}
- public static Bitmap rotateToPortrait(Bitmap bitmap,int ori) {
- Matrix matrix = new Matrix();
- int w = bitmap.getWidth();
- int h = bitmap.getHeight();
- if (ori == ORI_ROTATE_90 ||
- ori == ORI_ROTATE_270 ||
- ori == ORI_TRANSPOSE||
- ori == ORI_TRANSVERSE) {
- int tmp = w;
- w = h;
- h = tmp;
- }
- switch(ori){
- case ORI_ROTATE_90:
- matrix.setRotate(90,w/2f,h/2f);
- break;
- case ORI_ROTATE_180:
- matrix.setRotate(180,w/2f,h/2f);
- break;
- case ORI_ROTATE_270:
- matrix.setRotate(270,w/2f,h/2f);
- break;
- case ORI_FLIP_HOR:
- matrix.preScale(-1, 1);
- break;
- case ORI_FLIP_VERT:
- matrix.preScale(1, -1);
- break;
- case ORI_TRANSPOSE:
- matrix.setRotate(90,w/2f,h/2f);
- matrix.preScale(1, -1);
- break;
- case ORI_TRANSVERSE:
- matrix.setRotate(270,w/2f,h/2f);
- matrix.preScale(1, -1);
- break;
- case ORI_NORMAL:
- default:
- return bitmap;
- }
+ public static Bitmap rotateToPortrait(Bitmap bitmap, int ori) {
+ Matrix matrix = new Matrix();
+ int w = bitmap.getWidth();
+ int h = bitmap.getHeight();
+ if (ori == ORI_ROTATE_90 ||
+ ori == ORI_ROTATE_270 ||
+ ori == ORI_TRANSPOSE ||
+ ori == ORI_TRANSVERSE) {
+ int tmp = w;
+ w = h;
+ h = tmp;
+ }
+ switch (ori) {
+ case ORI_ROTATE_90:
+ matrix.setRotate(90, w / 2f, h / 2f);
+ break;
+ case ORI_ROTATE_180:
+ matrix.setRotate(180, w / 2f, h / 2f);
+ break;
+ case ORI_ROTATE_270:
+ matrix.setRotate(270, w / 2f, h / 2f);
+ break;
+ case ORI_FLIP_HOR:
+ matrix.preScale(-1, 1);
+ break;
+ case ORI_FLIP_VERT:
+ matrix.preScale(1, -1);
+ break;
+ case ORI_TRANSPOSE:
+ matrix.setRotate(90, w / 2f, h / 2f);
+ matrix.preScale(1, -1);
+ break;
+ case ORI_TRANSVERSE:
+ matrix.setRotate(270, w / 2f, h / 2f);
+ matrix.preScale(1, -1);
+ break;
+ case ORI_NORMAL:
+ default:
+ return bitmap;
+ }
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, true);
@@ -253,6 +291,7 @@ public class ImageLoader {
}
static final int MAX_BITMAP_DIM = 2048;
+
private Bitmap loadScaledBitmap(Uri uri, int size) {
InputStream is = null;
try {
@@ -338,7 +377,8 @@ public class ImageLoader {
}
};
- // TODO: this currently does the loading + filtering on the UI thread -- need to
+ // TODO: this currently does the loading + filtering on the UI thread --
+ // need to
// move this to a background thread.
public Bitmap getScaleOneImageForPreset(ImageShow caller, ImagePreset imagePreset, Rect bounds,
boolean force) {
@@ -354,6 +394,7 @@ public class ImageLoader {
bmp2 = imagePreset.apply(bmp2);
imagePreset.setScaleFactor(scaleFactor);
mZoomCache.setImage(imagePreset, bounds, bmp2);
+ mLoadingLock.unlock();
return bmp2;
}
}
@@ -366,9 +407,11 @@ public class ImageLoader {
boolean hiRes) {
mLoadingLock.lock();
if (mOriginalBitmapSmall == null) {
+ mLoadingLock.unlock();
return null;
}
if (mOriginalBitmapLarge == null) {
+ mLoadingLock.unlock();
return null;
}
@@ -415,6 +458,109 @@ public class ImageLoader {
}).execute(preset);
}
+ public static Bitmap loadMutableBitmap(Context context, Uri sourceUri)
+ throws FileNotFoundException {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ // TODO: on <3.x we need a copy of the bitmap (inMutable doesn't
+ // exist)
+ options.inMutable = true;
+
+ InputStream is = context.getContentResolver().openInputStream(sourceUri);
+ Bitmap bitmap = BitmapFactory.decodeStream(is, null, options);
+ int orientation = ImageLoader.getOrientation(context, sourceUri);
+ bitmap = ImageLoader.rotateToPortrait(bitmap, orientation);
+ return bitmap;
+ }
+
+ public void returnFilteredResult(ImagePreset preset,
+ final FilterShowActivity filterShowActivity) {
+ preset.setIsHighQuality(true);
+ preset.setScaleFactor(1.0f);
+
+ BitmapTask.Callbacks<ImagePreset> cb = new BitmapTask.Callbacks<ImagePreset>() {
+
+ @Override
+ public void onComplete(Bitmap result) {
+ filterShowActivity.onFilteredResult(result);
+ }
+
+ @Override
+ public void onCancel() {
+ }
+
+ @Override
+ public Bitmap onExecute(ImagePreset param) {
+ if (param == null) {
+ return null;
+ }
+ try {
+ Bitmap bitmap = param.apply(loadMutableBitmap(mContext, mUri));
+ return bitmap;
+ } catch (FileNotFoundException ex) {
+ Log.w(LOGTAG, "Failed to save image!", ex);
+ return null;
+ }
+ }
+ };
+
+ (new BitmapTask<ImagePreset>(cb)).execute(preset);
+ }
+
+ private String getFileExtension(String requestFormat) {
+ String outputFormat = (requestFormat == null)
+ ? "jpg"
+ : requestFormat;
+ outputFormat = outputFormat.toLowerCase();
+ return (outputFormat.equals("png") || outputFormat.equals("gif"))
+ ? "png" // We don't support gif compression.
+ : "jpg";
+ }
+
+ private CompressFormat convertExtensionToCompressFormat(String extension) {
+ return extension.equals("png") ? CompressFormat.PNG : CompressFormat.JPEG;
+ }
+
+ public void saveToUri(Bitmap bmap, Uri uri, final String outputFormat,
+ final FilterShowActivity filterShowActivity) {
+
+ OutputStream out = null;
+ try {
+ out = filterShowActivity.getContentResolver().openOutputStream(uri);
+ } catch (FileNotFoundException e) {
+ Log.w(LOGTAG, "cannot write output", e);
+ out = null;
+ } finally {
+ if (bmap == null || out == null) {
+ return;
+ }
+ }
+
+ final InterruptableOutputStream ios = new InterruptableOutputStream(out);
+
+ BitmapTask.Callbacks<Bitmap> cb = new BitmapTask.Callbacks<Bitmap>() {
+
+ @Override
+ public void onComplete(Bitmap result) {
+ filterShowActivity.done();
+ }
+
+ @Override
+ public void onCancel() {
+ ios.interrupt();
+ }
+
+ @Override
+ public Bitmap onExecute(Bitmap param) {
+ CompressFormat cf = convertExtensionToCompressFormat(getFileExtension(outputFormat));
+ param.compress(cf, DEFAULT_COMPRESS_QUALITY, ios);
+ Utils.closeSilently(ios);
+ return null;
+ }
+ };
+
+ (new BitmapTask<Bitmap>(cb)).execute(bmap);
+ }
+
public void setAdapter(HistoryAdapter adapter) {
mAdapter = adapter;
}
@@ -475,4 +621,9 @@ public class ImageLoader {
}
}
+ public void addCacheListener(ImageShow imageShow) {
+ mHiresCache.addObserver(imageShow);
+ mCache.addObserver(imageShow);
+ }
+
}