diff options
Diffstat (limited to 'src/com/android/gallery3d/filtershow/cache/ImageLoader.java')
-rw-r--r-- | src/com/android/gallery3d/filtershow/cache/ImageLoader.java | 279 |
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); + } + } |