summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/android/gallery3d/filtershow/cache/ImageLoader.java74
-rw-r--r--src/com/android/gallery3d/filtershow/presets/ImagePreset.java17
-rw-r--r--src/com/android/gallery3d/filtershow/tools/ProcessedBitmap.java18
-rw-r--r--src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java134
-rw-r--r--src_pd/com/android/gallery3d/util/XmpUtilHelper.java31
5 files changed, 195 insertions, 79 deletions
diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
index 6beaed603..d0cab767e 100644
--- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
+++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.gallery3d.filtershow.cache;
@@ -22,7 +37,6 @@ import com.android.gallery3d.filtershow.FilterShowActivity;
import com.android.gallery3d.filtershow.HistoryAdapter;
import com.android.gallery3d.filtershow.imageshow.ImageShow;
import com.android.gallery3d.filtershow.presets.ImagePreset;
-import com.android.gallery3d.filtershow.tools.ProcessedBitmap;
import com.android.gallery3d.filtershow.tools.SaveCopyTask;
import java.io.Closeable;
@@ -39,8 +53,6 @@ public class ImageLoader {
private Bitmap mOriginalBitmapSmall = null;
private Bitmap mOriginalBitmapLarge = null;
private Bitmap mBackgroundBitmap = null;
- private Bitmap mFullOriginalBitmap = null;
- private Bitmap mSaveCopy = null;
private Cache mCache = null;
private Cache mHiresCache = null;
@@ -74,7 +86,7 @@ public class ImageLoader {
public void loadBitmap(Uri uri,int size) {
mUri = uri;
- mOrientation = getOrientation(uri);
+ mOrientation = getOrientation(mContext, uri);
mOriginalBitmapSmall = loadScaledBitmap(uri, 160);
if (mOriginalBitmapSmall == null) {
// Couldn't read the bitmap, let's exit
@@ -92,14 +104,14 @@ public class ImageLoader {
return mOriginalBounds;
}
- private int getOrientation(Uri uri) {
+ public static int getOrientation(Context context, Uri uri) {
if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
return getOrientationFromPath(uri.getPath());
}
Cursor cursor = null;
try {
- cursor = mContext.getContentResolver().query(uri,
+ cursor = context.getContentResolver().query(uri,
new String[] {
MediaStore.Images.ImageColumns.ORIENTATION
},
@@ -125,7 +137,7 @@ public class ImageLoader {
}
}
- private int getOrientationFromPath(String path) {
+ static int getOrientationFromPath(String path) {
int orientation = -1;
try {
ExifInterface EXIF = new ExifInterface(path);
@@ -139,15 +151,15 @@ public class ImageLoader {
private void updateBitmaps() {
if (mOrientation > 1) {
- mOriginalBitmapSmall = rotateToPortrait(mOriginalBitmapSmall,mOrientation);
- mOriginalBitmapLarge = rotateToPortrait(mOriginalBitmapLarge,mOrientation);
+ mOriginalBitmapSmall = rotateToPortrait(mOriginalBitmapSmall, mOrientation);
+ mOriginalBitmapLarge = rotateToPortrait(mOriginalBitmapLarge, mOrientation);
}
mCache.setOriginalBitmap(mOriginalBitmapSmall);
mHiresCache.setOriginalBitmap(mOriginalBitmapLarge);
warnListeners();
}
- private Bitmap rotateToPortrait(Bitmap bitmap,int ori) {
+ public static Bitmap rotateToPortrait(Bitmap bitmap,int ori) {
Matrix matrix = new Matrix();
int w = bitmap.getWidth();
int h = bitmap.getHeight();
@@ -344,42 +356,18 @@ public class ImageLoader {
mZoomCache.reset(imagePreset);
}
- public Uri saveImage(ImagePreset preset, final FilterShowActivity filterShowActivity,
+ public void saveImage(ImagePreset preset, final FilterShowActivity filterShowActivity,
File destination) {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inMutable = true;
+ preset.setIsHighQuality(true);
+ preset.setScaleFactor(1.0f);
+ new SaveCopyTask(mContext, mUri, destination, new SaveCopyTask.Callback() {
- if (mFullOriginalBitmap != null) {
- mFullOriginalBitmap.recycle();
- }
-
- InputStream is = null;
- Uri saveUri = null;
- try {
- is = mContext.getContentResolver().openInputStream(mUri);
- mFullOriginalBitmap = BitmapFactory.decodeStream(is, null, options);
- // TODO: on <3.x we need a copy of the bitmap (inMutable doesn't
- // exist)
- mFullOriginalBitmap = rotateToPortrait(mFullOriginalBitmap,mOrientation);
- mSaveCopy = mFullOriginalBitmap;
- preset.setIsHighQuality(true);
- preset.setScaleFactor(1.0f);
- ProcessedBitmap processedBitmap = new ProcessedBitmap(mSaveCopy, preset);
- new SaveCopyTask(mContext, mUri, destination, new SaveCopyTask.Callback() {
-
- @Override
- public void onComplete(Uri result) {
- filterShowActivity.completeSaveImage(result);
- }
-
- }).execute(processedBitmap);
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } finally {
- closeStream(is);
- }
+ @Override
+ public void onComplete(Uri result) {
+ filterShowActivity.completeSaveImage(result);
+ }
- return saveUri;
+ }).execute(preset);
}
public void setAdapter(HistoryAdapter adapter) {
diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
index f303d4c15..0d8fc317e 100644
--- a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
+++ b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
@@ -76,6 +76,23 @@ public class ImagePreset {
return false;
}
+ public boolean isPanoramaSafe() {
+ if (mImageBorder != null && !mImageBorder.isNil()) {
+ return false;
+ }
+ if (mGeoData.hasModifications()) {
+ return false;
+ }
+ for (ImageFilter filter : mFilters) {
+ if (filter.getFilterType() == ImageFilter.TYPE_VIGNETTE
+ && !filter.isNil()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
public void setGeometry(GeometryMetadata m) {
mGeoData.set(m);
}
diff --git a/src/com/android/gallery3d/filtershow/tools/ProcessedBitmap.java b/src/com/android/gallery3d/filtershow/tools/ProcessedBitmap.java
deleted file mode 100644
index 24e38fbb1..000000000
--- a/src/com/android/gallery3d/filtershow/tools/ProcessedBitmap.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.android.gallery3d.filtershow.tools;
-
-import android.graphics.Bitmap;
-
-import com.android.gallery3d.filtershow.presets.ImagePreset;
-
-public class ProcessedBitmap {
- private Bitmap mBitmap;
- private final ImagePreset mPreset;
- public ProcessedBitmap(Bitmap bitmap, ImagePreset preset) {
- mBitmap = bitmap;
- mPreset = preset;
- }
- public Bitmap apply() {
- mBitmap = mPreset.apply(mBitmap);
- return mBitmap;
- }
-} \ No newline at end of file
diff --git a/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java b/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java
index 8b3eb530b..9c55623d1 100644
--- a/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java
+++ b/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java
@@ -21,26 +21,26 @@ import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.graphics.Bitmap.CompressFormat;
+import android.media.ExifInterface;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Environment;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Images.ImageColumns;
-import android.view.Gravity;
-import android.widget.Toast;
+import android.util.Log;
-import com.android.camera.R;
+import com.android.gallery3d.filtershow.cache.ImageLoader;
import com.android.gallery3d.filtershow.presets.ImagePreset;
-
-//import com.android.gallery3d.R;
-//import com.android.gallery3d.util.BucketNames;
+import com.android.gallery3d.util.XmpUtilHelper;
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Date;
import java.text.SimpleDateFormat;
@@ -48,24 +48,29 @@ import java.text.SimpleDateFormat;
/**
* Asynchronous task for saving edited photo as a new copy.
*/
-public class SaveCopyTask extends AsyncTask<ProcessedBitmap, Void, Uri> {
+public class SaveCopyTask extends AsyncTask<ImagePreset, Void, Uri> {
+
+ private static final String LOGTAG = "SaveCopyTask";
private static final int DEFAULT_COMPRESS_QUALITY = 95;
private static final String DEFAULT_SAVE_DIRECTORY = "EditedOnlinePhotos";
/**
* Saves the bitmap in the final destination
*/
- public static void saveBitmap(Bitmap bitmap, File destination) {
+ public static void saveBitmap(Bitmap bitmap, File destination, Object xmp) {
OutputStream os = null;
try {
os = new FileOutputStream(destination);
bitmap.compress(CompressFormat.JPEG, DEFAULT_COMPRESS_QUALITY, os);
} catch (FileNotFoundException e) {
- e.printStackTrace();
+ Log.v(LOGTAG,"Error in writing "+destination.getAbsolutePath());
} finally {
closeStream(os);
}
+ if (xmp != null) {
+ XmpUtilHelper.writeXMPMeta(destination.getAbsolutePath(), xmp);
+ }
}
private static void closeStream(Closeable stream) {
@@ -132,24 +137,116 @@ public class SaveCopyTask extends AsyncTask<ProcessedBitmap, Void, Uri> {
return new File(saveDirectory, filename + ".JPG");
}
+ private Bitmap loadMutableBitmap() 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;
+ }
+
+ private static final String[] COPY_EXIF_ATTRIBUTES = new String[] {
+ ExifInterface.TAG_APERTURE,
+ ExifInterface.TAG_DATETIME,
+ ExifInterface.TAG_EXPOSURE_TIME,
+ ExifInterface.TAG_FLASH,
+ ExifInterface.TAG_FOCAL_LENGTH,
+ ExifInterface.TAG_GPS_ALTITUDE,
+ ExifInterface.TAG_GPS_ALTITUDE_REF,
+ ExifInterface.TAG_GPS_DATESTAMP,
+ ExifInterface.TAG_GPS_LATITUDE,
+ ExifInterface.TAG_GPS_LATITUDE_REF,
+ ExifInterface.TAG_GPS_LONGITUDE,
+ ExifInterface.TAG_GPS_LONGITUDE_REF,
+ ExifInterface.TAG_GPS_PROCESSING_METHOD,
+ ExifInterface.TAG_GPS_DATESTAMP,
+ ExifInterface.TAG_ISO,
+ ExifInterface.TAG_MAKE,
+ ExifInterface.TAG_MODEL,
+ ExifInterface.TAG_WHITE_BALANCE,
+ };
+
+ private static void copyExif(String sourcePath, String destPath) {
+ try {
+ ExifInterface source = new ExifInterface(sourcePath);
+ ExifInterface dest = new ExifInterface(destPath);
+ boolean needsSave = false;
+ for (String tag : COPY_EXIF_ATTRIBUTES) {
+ String value = source.getAttribute(tag);
+ if (value != null) {
+ needsSave = true;
+ dest.setAttribute(tag, value);
+ }
+ }
+ if (needsSave) {
+ dest.saveAttributes();
+ }
+ } catch (IOException ex) {
+ Log.w(LOGTAG, "Failed to copy exif metadata", ex);
+ }
+ }
+
+ private void copyExif(Uri sourceUri, String destPath) {
+ if (ContentResolver.SCHEME_FILE.equals(sourceUri.getScheme())) {
+ copyExif(sourceUri.getPath(), destPath);
+ return;
+ }
+
+ final String[] PROJECTION = new String[] {
+ ImageColumns.DATA
+ };
+ try {
+ Cursor c = context.getContentResolver().query(sourceUri, PROJECTION,
+ null, null, null);
+ if (c.moveToFirst()) {
+ String path = c.getString(0);
+ if (new File(path).exists()) {
+ copyExif(path, destPath);
+ }
+ }
+ c.close();
+ } catch (Exception e) {
+ Log.w(LOGTAG, "Failed to copy exif", e);
+ }
+ }
+
/**
* The task should be executed with one given bitmap to be saved.
*/
@Override
- protected Uri doInBackground(ProcessedBitmap... params) {
+ protected Uri doInBackground(ImagePreset... params) {
// TODO: Support larger dimensions for photo saving.
if (params[0] == null) {
return null;
}
- ProcessedBitmap processedBitmap = params[0];
+ ImagePreset preset = params[0];
- Bitmap bitmap = processedBitmap.apply();
- saveBitmap(bitmap, this.destinationFile);
+ try {
+ Bitmap bitmap = preset.apply(loadMutableBitmap());
+
+ Object xmp = null;
+ InputStream is = null;
+ if (preset.isPanoramaSafe()) {
+ is = context.getContentResolver().openInputStream(sourceUri);
+ xmp = XmpUtilHelper.extractXMPMeta(is);
+ }
+ saveBitmap(bitmap, this.destinationFile, xmp);
+ copyExif(sourceUri, destinationFile.getAbsolutePath());
+
+ Uri uri = insertContent(context, sourceUri, this.destinationFile, saveFileName);
+ bitmap.recycle();
+ return uri;
- Uri uri = insertContent(context, sourceUri, this.destinationFile, saveFileName);
- bitmap.recycle();
- return uri;
+ } catch (FileNotFoundException ex) {
+ Log.w(LOGTAG, "Failed to save image!", ex);
+ return null;
+ }
}
@Override
@@ -210,11 +307,12 @@ public class SaveCopyTask extends AsyncTask<ProcessedBitmap, Void, Uri> {
values.put(Images.Media.DATA, file.getAbsolutePath());
values.put(Images.Media.SIZE, file.length());
- String[] projection = new String[] {
+ final String[] projection = new String[] {
ImageColumns.DATE_TAKEN,
ImageColumns.LATITUDE, ImageColumns.LONGITUDE,
};
- querySource(context, sourceUri, projection, new ContentResolverQueryCallback() {
+ querySource(context, sourceUri, projection,
+ new ContentResolverQueryCallback() {
@Override
public void onCursorResult(Cursor cursor) {
diff --git a/src_pd/com/android/gallery3d/util/XmpUtilHelper.java b/src_pd/com/android/gallery3d/util/XmpUtilHelper.java
new file mode 100644
index 000000000..7cbd7f170
--- /dev/null
+++ b/src_pd/com/android/gallery3d/util/XmpUtilHelper.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.util;
+
+import java.io.InputStream;
+
+public class XmpUtilHelper {
+
+ public static Object extractXMPMeta(InputStream is) {
+ return null;
+ }
+
+ public static boolean writeXMPMeta(String filename, Object meta) {
+ return false;
+ }
+
+}