1014a111f10a7523415ca210bc6fe1e4f00183d31John Reck/*
2014a111f10a7523415ca210bc6fe1e4f00183d31John Reck * Copyright (C) 2012 The Android Open Source Project
3014a111f10a7523415ca210bc6fe1e4f00183d31John Reck *
4014a111f10a7523415ca210bc6fe1e4f00183d31John Reck * Licensed under the Apache License, Version 2.0 (the "License");
5014a111f10a7523415ca210bc6fe1e4f00183d31John Reck * you may not use this file except in compliance with the License.
6014a111f10a7523415ca210bc6fe1e4f00183d31John Reck * You may obtain a copy of the License at
7014a111f10a7523415ca210bc6fe1e4f00183d31John Reck *
8014a111f10a7523415ca210bc6fe1e4f00183d31John Reck *      http://www.apache.org/licenses/LICENSE-2.0
9014a111f10a7523415ca210bc6fe1e4f00183d31John Reck *
10014a111f10a7523415ca210bc6fe1e4f00183d31John Reck * Unless required by applicable law or agreed to in writing, software
11014a111f10a7523415ca210bc6fe1e4f00183d31John Reck * distributed under the License is distributed on an "AS IS" BASIS,
12014a111f10a7523415ca210bc6fe1e4f00183d31John Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13014a111f10a7523415ca210bc6fe1e4f00183d31John Reck * See the License for the specific language governing permissions and
14014a111f10a7523415ca210bc6fe1e4f00183d31John Reck * limitations under the License.
15014a111f10a7523415ca210bc6fe1e4f00183d31John Reck */
160d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
170d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardpackage com.android.gallery3d.filtershow.cache;
180d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
19accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Linimport android.content.ContentResolver;
200d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.content.Context;
210d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.content.res.Resources;
220d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.database.Cursor;
2302506a90577ba3f767d192b9547d4478bcc149a8Ruben Brunkimport android.database.sqlite.SQLiteException;
240d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.graphics.Bitmap;
250d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.graphics.BitmapFactory;
265448bf8095483574649afcc2add7f153670c7450nicolasroardimport android.graphics.BitmapRegionDecoder;
270d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.graphics.Matrix;
285448bf8095483574649afcc2add7f153670c7450nicolasroardimport android.graphics.Rect;
290d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.media.ExifInterface;
300d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.net.Uri;
310d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.provider.MediaStore;
320d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.util.Log;
330d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
345fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hofordimport com.adobe.xmp.XMPException;
355fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hofordimport com.adobe.xmp.XMPMeta;
363d4f2c7443f6f6015efab769bfaad19263137c67John Hoford
37accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Linimport com.android.gallery3d.R;
38accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Linimport com.android.gallery3d.common.Utils;
39accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Linimport com.android.gallery3d.filtershow.FilterShowActivity;
40accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Linimport com.android.gallery3d.filtershow.HistoryAdapter;
4113b2fd3ab7ff65ac5c18b4c9de69062f3a549669Ruben Brunkimport com.android.gallery3d.filtershow.imageshow.ImageCrop;
42accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Linimport com.android.gallery3d.filtershow.imageshow.ImageShow;
43accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Linimport com.android.gallery3d.filtershow.presets.ImagePreset;
44accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Linimport com.android.gallery3d.filtershow.tools.SaveCopyTask;
45e9c55b28a4a155c2e1c1f5aec615a0c56e38ade4John Hofordimport com.android.gallery3d.util.XmpUtilHelper;
46accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Lin
47accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Linimport java.io.Closeable;
48accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Linimport java.io.File;
49accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Linimport java.io.FileNotFoundException;
50accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Linimport java.io.IOException;
51accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Linimport java.io.InputStream;
52accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Linimport java.util.Vector;
53accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Lin
540d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardpublic class ImageLoader {
550d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
560d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    private static final String LOGTAG = "ImageLoader";
5781eb9976f967d9b3faa1749a8ab29d1743cf347dnicolasroard    private final Vector<ImageShow> mListeners = new Vector<ImageShow>();
580d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    private Bitmap mOriginalBitmapSmall = null;
590d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    private Bitmap mOriginalBitmapLarge = null;
600d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    private Bitmap mBackgroundBitmap = null;
610d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
6281eb9976f967d9b3faa1749a8ab29d1743cf347dnicolasroard    private Cache mCache = null;
6381eb9976f967d9b3faa1749a8ab29d1743cf347dnicolasroard    private Cache mHiresCache = null;
6481eb9976f967d9b3faa1749a8ab29d1743cf347dnicolasroard    private final ZoomCache mZoomCache = new ZoomCache();
650d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
660d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    private int mOrientation = 0;
670d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    private HistoryAdapter mAdapter = null;
68b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford
69e34a5a5eaedb870798a5cc7415079d04a6ca42e0nicolasroard    private FilterShowActivity mActivity = null;
70e34a5a5eaedb870798a5cc7415079d04a6ca42e0nicolasroard
712f8301760867dc269c90bbeb338495f80e841c08nicolasroard    public static final int ORI_NORMAL     = ExifInterface.ORIENTATION_NORMAL;
722f8301760867dc269c90bbeb338495f80e841c08nicolasroard    public static final int ORI_ROTATE_90  = ExifInterface.ORIENTATION_ROTATE_90;
732f8301760867dc269c90bbeb338495f80e841c08nicolasroard    public static final int ORI_ROTATE_180 = ExifInterface.ORIENTATION_ROTATE_180;
742f8301760867dc269c90bbeb338495f80e841c08nicolasroard    public static final int ORI_ROTATE_270 = ExifInterface.ORIENTATION_ROTATE_270;
752f8301760867dc269c90bbeb338495f80e841c08nicolasroard    public static final int ORI_FLIP_HOR   = ExifInterface.ORIENTATION_FLIP_HORIZONTAL;
762f8301760867dc269c90bbeb338495f80e841c08nicolasroard    public static final int ORI_FLIP_VERT  = ExifInterface.ORIENTATION_FLIP_VERTICAL;
772f8301760867dc269c90bbeb338495f80e841c08nicolasroard    public static final int ORI_TRANSPOSE  = ExifInterface.ORIENTATION_TRANSPOSE;
782f8301760867dc269c90bbeb338495f80e841c08nicolasroard    public static final int ORI_TRANSVERSE = ExifInterface.ORIENTATION_TRANSVERSE;
790d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
800d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    private Context mContext = null;
810d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    private Uri mUri = null;
820d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
835448bf8095483574649afcc2add7f153670c7450nicolasroard    private Rect mOriginalBounds = null;
842f8301760867dc269c90bbeb338495f80e841c08nicolasroard    private static int mZoomOrientation = ORI_NORMAL;
855448bf8095483574649afcc2add7f153670c7450nicolasroard
86e34a5a5eaedb870798a5cc7415079d04a6ca42e0nicolasroard    public ImageLoader(FilterShowActivity activity, Context context) {
87e34a5a5eaedb870798a5cc7415079d04a6ca42e0nicolasroard        mActivity = activity;
880d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        mContext = context;
8981eb9976f967d9b3faa1749a8ab29d1743cf347dnicolasroard        mCache = new DelayedPresetCache(this, 30);
9031529940021b9a18611b1a3fb4a0317ab8c89618nicolasroard        mHiresCache = new DelayedPresetCache(this, 3);
910d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
920d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
932f8301760867dc269c90bbeb338495f80e841c08nicolasroard    public static int getZoomOrientation() {
942f8301760867dc269c90bbeb338495f80e841c08nicolasroard        return mZoomOrientation;
952f8301760867dc269c90bbeb338495f80e841c08nicolasroard    }
962f8301760867dc269c90bbeb338495f80e841c08nicolasroard
978bc296e233298dbc76da22f01aaffec11e539d19nicolasroard    public FilterShowActivity getActivity() {
988bc296e233298dbc76da22f01aaffec11e539d19nicolasroard        return mActivity;
998bc296e233298dbc76da22f01aaffec11e539d19nicolasroard    }
1008bc296e233298dbc76da22f01aaffec11e539d19nicolasroard
101fafb2edbb9928039b887f59685d82593bd79e06aJohn Hoford    public void loadBitmap(Uri uri,int size) {
1020d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        mUri = uri;
103014a111f10a7523415ca210bc6fe1e4f00183d31John Reck        mOrientation = getOrientation(mContext, uri);
1040d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        mOriginalBitmapSmall = loadScaledBitmap(uri, 160);
105e34a5a5eaedb870798a5cc7415079d04a6ca42e0nicolasroard        if (mOriginalBitmapSmall == null) {
106e34a5a5eaedb870798a5cc7415079d04a6ca42e0nicolasroard            // Couldn't read the bitmap, let's exit
107e34a5a5eaedb870798a5cc7415079d04a6ca42e0nicolasroard            mActivity.cannotLoadImage();
108e34a5a5eaedb870798a5cc7415079d04a6ca42e0nicolasroard        }
109fafb2edbb9928039b887f59685d82593bd79e06aJohn Hoford        mOriginalBitmapLarge = loadScaledBitmap(uri, size);
1100d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        updateBitmaps();
1110d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
1120d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
1130ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard    public Uri getUri() {
1140ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard        return mUri;
1150ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard    }
1160ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard
1175448bf8095483574649afcc2add7f153670c7450nicolasroard    public Rect getOriginalBounds() {
1185448bf8095483574649afcc2add7f153670c7450nicolasroard        return mOriginalBounds;
1195448bf8095483574649afcc2add7f153670c7450nicolasroard    }
1205448bf8095483574649afcc2add7f153670c7450nicolasroard
121014a111f10a7523415ca210bc6fe1e4f00183d31John Reck    public static int getOrientation(Context context, Uri uri) {
122accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Lin        if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
123accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Lin            return getOrientationFromPath(uri.getPath());
124accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Lin        }
125accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Lin
12602506a90577ba3f767d192b9547d4478bcc149a8Ruben Brunk        Cursor cursor = null;
12702506a90577ba3f767d192b9547d4478bcc149a8Ruben Brunk        try {
128014a111f10a7523415ca210bc6fe1e4f00183d31John Reck            cursor = context.getContentResolver().query(uri,
12902506a90577ba3f767d192b9547d4478bcc149a8Ruben Brunk                    new String[] {
13002506a90577ba3f767d192b9547d4478bcc149a8Ruben Brunk                        MediaStore.Images.ImageColumns.ORIENTATION
13102506a90577ba3f767d192b9547d4478bcc149a8Ruben Brunk                    },
13202506a90577ba3f767d192b9547d4478bcc149a8Ruben Brunk                    null, null, null);
133b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford            if (cursor.moveToNext()){
134b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford              int ori =   cursor.getInt(0);
135b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford
136b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford              switch (ori){
137b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                  case 0:   return ORI_NORMAL;
138b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                  case 90:  return ORI_ROTATE_90;
139b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                  case 270: return ORI_ROTATE_270;
140b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                  case 180: return ORI_ROTATE_180;
141b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                  default:
142b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                      return -1;
143b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford              }
144b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford            } else{
145b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                return -1;
146b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford            }
14702506a90577ba3f767d192b9547d4478bcc149a8Ruben Brunk        } catch (SQLiteException e){
14802506a90577ba3f767d192b9547d4478bcc149a8Ruben Brunk            return ExifInterface.ORIENTATION_UNDEFINED;
149accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Lin        } finally {
150accef756f100d5c27a4d13d6a6bfa5c75714e5bcOwen Lin            Utils.closeSilently(cursor);
15102506a90577ba3f767d192b9547d4478bcc149a8Ruben Brunk        }
1520d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
1530d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
154014a111f10a7523415ca210bc6fe1e4f00183d31John Reck    static int getOrientationFromPath(String path) {
1550d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        int orientation = -1;
1560d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        try {
1570d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            ExifInterface EXIF = new ExifInterface(path);
1580d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            orientation = EXIF.getAttributeInt(ExifInterface.TAG_ORIENTATION,
1590d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard                    1);
1600d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        } catch (IOException e) {
1610d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            e.printStackTrace();
1620d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        }
1630d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        return orientation;
1640d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
1650d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
1660d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    private void updateBitmaps() {
167b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford        if (mOrientation > 1) {
168014a111f10a7523415ca210bc6fe1e4f00183d31John Reck            mOriginalBitmapSmall = rotateToPortrait(mOriginalBitmapSmall, mOrientation);
169014a111f10a7523415ca210bc6fe1e4f00183d31John Reck            mOriginalBitmapLarge = rotateToPortrait(mOriginalBitmapLarge, mOrientation);
170b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford        }
171dc03ae144d838714446b239f2b0c519d956af6ffnicolasroard        mZoomOrientation = mOrientation;
1720d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        mCache.setOriginalBitmap(mOriginalBitmapSmall);
1730d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        mHiresCache.setOriginalBitmap(mOriginalBitmapLarge);
1740d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        warnListeners();
1750d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
1760d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
177014a111f10a7523415ca210bc6fe1e4f00183d31John Reck    public static Bitmap rotateToPortrait(Bitmap bitmap,int ori) {
178b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford           Matrix matrix = new Matrix();
179b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford           int w = bitmap.getWidth();
180b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford           int h = bitmap.getHeight();
181b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford           if (ori == ORI_ROTATE_90 ||
182b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   ori == ORI_ROTATE_270 ||
183b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   ori == ORI_TRANSPOSE||
184b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   ori == ORI_TRANSVERSE) {
185b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford               int tmp = w;
186b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford               w = h;
187b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford               h = tmp;
188b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford           }
189b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford           switch(ori){
190b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford               case ORI_ROTATE_90:
191b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   matrix.setRotate(90,w/2f,h/2f);
192b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   break;
193b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford               case ORI_ROTATE_180:
194b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   matrix.setRotate(180,w/2f,h/2f);
195b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   break;
196b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford               case ORI_ROTATE_270:
197b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   matrix.setRotate(270,w/2f,h/2f);
198b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   break;
199b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford               case ORI_FLIP_HOR:
200b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   matrix.preScale(-1, 1);
201b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   break;
202b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford              case ORI_FLIP_VERT:
203b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   matrix.preScale(1, -1);
204b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   break;
205b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford               case ORI_TRANSPOSE:
206b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   matrix.setRotate(90,w/2f,h/2f);
207b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   matrix.preScale(1, -1);
208b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   break;
209b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford               case ORI_TRANSVERSE:
210b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   matrix.setRotate(270,w/2f,h/2f);
211b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   matrix.preScale(1, -1);
212b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford                   break;
213e5da585e6cb73cff8775b21a69a01f8bf513d2abJohn Hoford               case ORI_NORMAL:
214b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford               default:
215e5da585e6cb73cff8775b21a69a01f8bf513d2abJohn Hoford                   return bitmap;
216b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford            }
217b894202fbb21b237c48e24b2f65b1ca297c61332John Hoford
2180d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
2190d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard                bitmap.getHeight(), matrix, true);
2200d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
2210d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
2220d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    private void closeStream(Closeable stream) {
2230d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        if (stream != null) {
2240d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            try {
2250d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard                stream.close();
2260d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            } catch (IOException e) {
2270d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard                e.printStackTrace();
2280d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            }
2290d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        }
2300d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
2310d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
2325448bf8095483574649afcc2add7f153670c7450nicolasroard    private Bitmap loadRegionBitmap(Uri uri, Rect bounds) {
2335448bf8095483574649afcc2add7f153670c7450nicolasroard        InputStream is = null;
2345448bf8095483574649afcc2add7f153670c7450nicolasroard        try {
2355448bf8095483574649afcc2add7f153670c7450nicolasroard            is = mContext.getContentResolver().openInputStream(uri);
2365448bf8095483574649afcc2add7f153670c7450nicolasroard            BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is, false);
2375448bf8095483574649afcc2add7f153670c7450nicolasroard            return decoder.decodeRegion(bounds, null);
2385448bf8095483574649afcc2add7f153670c7450nicolasroard        } catch (FileNotFoundException e) {
2395448bf8095483574649afcc2add7f153670c7450nicolasroard            Log.e(LOGTAG, "FileNotFoundException: " + uri);
2405448bf8095483574649afcc2add7f153670c7450nicolasroard        } catch (Exception e) {
2415448bf8095483574649afcc2add7f153670c7450nicolasroard            e.printStackTrace();
2425448bf8095483574649afcc2add7f153670c7450nicolasroard        } finally {
2435448bf8095483574649afcc2add7f153670c7450nicolasroard            closeStream(is);
2445448bf8095483574649afcc2add7f153670c7450nicolasroard        }
2455448bf8095483574649afcc2add7f153670c7450nicolasroard        return null;
2465448bf8095483574649afcc2add7f153670c7450nicolasroard    }
2475448bf8095483574649afcc2add7f153670c7450nicolasroard
24820ae55ef793f8a307fd0fc03a6010c36e7cbc56bJohn Hoford    static final int MAX_BITMAP_DIM = 2048;
2490d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    private Bitmap loadScaledBitmap(Uri uri, int size) {
2500d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        InputStream is = null;
2510d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        try {
2520d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            is = mContext.getContentResolver().openInputStream(uri);
2530d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            Log.v(LOGTAG, "loading uri " + uri.getPath() + " input stream: "
2540d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard                    + is);
2550d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            BitmapFactory.Options o = new BitmapFactory.Options();
2560d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            o.inJustDecodeBounds = true;
2570d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            BitmapFactory.decodeStream(is, null, o);
2580d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
2590d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            int width_tmp = o.outWidth;
2600d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            int height_tmp = o.outHeight;
2615448bf8095483574649afcc2add7f153670c7450nicolasroard
2625448bf8095483574649afcc2add7f153670c7450nicolasroard            mOriginalBounds = new Rect(0, 0, width_tmp, height_tmp);
2635448bf8095483574649afcc2add7f153670c7450nicolasroard
2640d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            int scale = 1;
2650d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            while (true) {
26620ae55ef793f8a307fd0fc03a6010c36e7cbc56bJohn Hoford                if (width_tmp <= MAX_BITMAP_DIM && height_tmp <= MAX_BITMAP_DIM) {
26720ae55ef793f8a307fd0fc03a6010c36e7cbc56bJohn Hoford                    if (width_tmp / 2 < size || height_tmp / 2 < size) {
26820ae55ef793f8a307fd0fc03a6010c36e7cbc56bJohn Hoford                        break;
26920ae55ef793f8a307fd0fc03a6010c36e7cbc56bJohn Hoford                    }
27020ae55ef793f8a307fd0fc03a6010c36e7cbc56bJohn Hoford                }
2710d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard                width_tmp /= 2;
2720d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard                height_tmp /= 2;
2730d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard                scale *= 2;
2740d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            }
2750d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
2760d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            // decode with inSampleSize
2770d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            BitmapFactory.Options o2 = new BitmapFactory.Options();
2780d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            o2.inSampleSize = scale;
279fafb2edbb9928039b887f59685d82593bd79e06aJohn Hoford
2800d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            closeStream(is);
2810d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            is = mContext.getContentResolver().openInputStream(uri);
2820d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            return BitmapFactory.decodeStream(is, null, o2);
2830d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        } catch (FileNotFoundException e) {
2840d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            Log.e(LOGTAG, "FileNotFoundException: " + uri);
2850d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        } catch (Exception e) {
2860d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            e.printStackTrace();
2870d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        } finally {
2880d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            closeStream(is);
2890d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        }
2900d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        return null;
2910d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
2920d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
2930d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    public Bitmap getBackgroundBitmap(Resources resources) {
2940d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        if (mBackgroundBitmap == null) {
2950d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            mBackgroundBitmap = BitmapFactory.decodeResource(resources,
2960d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard                    R.drawable.filtershow_background);
2970d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        }
2980d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        return mBackgroundBitmap;
2990d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
3000d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
3010d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
3020d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    public Bitmap getOriginalBitmapSmall() {
3030d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        return mOriginalBitmapSmall;
3040d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
3050d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
3060d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    public Bitmap getOriginalBitmapLarge() {
3070d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        return mOriginalBitmapLarge;
3080d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
3090d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
3100d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    public void addListener(ImageShow imageShow) {
3110d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        if (!mListeners.contains(imageShow)) {
3120d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            mListeners.add(imageShow);
3130d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        }
314e7a71372747af0ef03f9d953c28ed62de58315d3nicolasroard        mHiresCache.addObserver(imageShow);
3150d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
3160d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
317d49d53206a197b08ec4754d8751b6860e33d9f48John Reck    private void warnListeners() {
318d49d53206a197b08ec4754d8751b6860e33d9f48John Reck        mActivity.runOnUiThread(mWarnListenersRunnable);
3190d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
3200d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
321d49d53206a197b08ec4754d8751b6860e33d9f48John Reck    private Runnable mWarnListenersRunnable = new Runnable() {
322d49d53206a197b08ec4754d8751b6860e33d9f48John Reck
323d49d53206a197b08ec4754d8751b6860e33d9f48John Reck        @Override
324d49d53206a197b08ec4754d8751b6860e33d9f48John Reck        public void run() {
325d49d53206a197b08ec4754d8751b6860e33d9f48John Reck            for (int i = 0; i < mListeners.size(); i++) {
326d49d53206a197b08ec4754d8751b6860e33d9f48John Reck                ImageShow imageShow = mListeners.elementAt(i);
32713b2fd3ab7ff65ac5c18b4c9de69062f3a549669Ruben Brunk                imageShow.imageLoaded();
328d49d53206a197b08ec4754d8751b6860e33d9f48John Reck            }
329d49d53206a197b08ec4754d8751b6860e33d9f48John Reck        }
330d49d53206a197b08ec4754d8751b6860e33d9f48John Reck    };
331d49d53206a197b08ec4754d8751b6860e33d9f48John Reck
3325448bf8095483574649afcc2add7f153670c7450nicolasroard    // TODO: this currently does the loading + filtering on the UI thread -- need to
3335448bf8095483574649afcc2add7f153670c7450nicolasroard    // move this to a background thread.
3345448bf8095483574649afcc2add7f153670c7450nicolasroard    public Bitmap getScaleOneImageForPreset(ImageShow caller, ImagePreset imagePreset, Rect bounds,
3355448bf8095483574649afcc2add7f153670c7450nicolasroard            boolean force) {
3365448bf8095483574649afcc2add7f153670c7450nicolasroard        Bitmap bmp = mZoomCache.getImage(imagePreset, bounds);
3375448bf8095483574649afcc2add7f153670c7450nicolasroard        if (force || bmp == null) {
3385448bf8095483574649afcc2add7f153670c7450nicolasroard            bmp = loadRegionBitmap(mUri, bounds);
3395448bf8095483574649afcc2add7f153670c7450nicolasroard            if (bmp != null) {
3405448bf8095483574649afcc2add7f153670c7450nicolasroard                // TODO: this workaround for RS might not be needed ultimately
3415448bf8095483574649afcc2add7f153670c7450nicolasroard                Bitmap bmp2 = bmp.copy(Bitmap.Config.ARGB_8888, true);
342de154778c8f94121cb2117fcf6224c40c01b6132nicolasroard                float scaleFactor = imagePreset.getScaleFactor();
343de154778c8f94121cb2117fcf6224c40c01b6132nicolasroard                imagePreset.setScaleFactor(1.0f);
34481eb9976f967d9b3faa1749a8ab29d1743cf347dnicolasroard                bmp2 = imagePreset.apply(bmp2);
345de154778c8f94121cb2117fcf6224c40c01b6132nicolasroard                imagePreset.setScaleFactor(scaleFactor);
3465448bf8095483574649afcc2add7f153670c7450nicolasroard                mZoomCache.setImage(imagePreset, bounds, bmp2);
3475448bf8095483574649afcc2add7f153670c7450nicolasroard                return bmp2;
3485448bf8095483574649afcc2add7f153670c7450nicolasroard            }
3495448bf8095483574649afcc2add7f153670c7450nicolasroard        }
3505448bf8095483574649afcc2add7f153670c7450nicolasroard        return bmp;
3515448bf8095483574649afcc2add7f153670c7450nicolasroard    }
3525448bf8095483574649afcc2add7f153670c7450nicolasroard
3530d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    // Caching method
3540d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    public Bitmap getImageForPreset(ImageShow caller, ImagePreset imagePreset,
3550d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            boolean hiRes) {
3560d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        if (mOriginalBitmapSmall == null) {
3570d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            return null;
3580d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        }
3590d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        if (mOriginalBitmapLarge == null) {
3600d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            return null;
3610d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        }
3620d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
3630d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        Bitmap filteredImage = null;
3640d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
3650d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        if (hiRes) {
3660d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            filteredImage = mHiresCache.get(imagePreset);
3670d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        } else {
3680d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            filteredImage = mCache.get(imagePreset);
3690d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        }
3700d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
3710d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        if (filteredImage == null) {
3720d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            if (hiRes) {
37331529940021b9a18611b1a3fb4a0317ab8c89618nicolasroard                mHiresCache.prepare(imagePreset);
37431529940021b9a18611b1a3fb4a0317ab8c89618nicolasroard                mHiresCache.addObserver(caller);
3750d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            } else {
37631529940021b9a18611b1a3fb4a0317ab8c89618nicolasroard                mCache.prepare(imagePreset);
37731529940021b9a18611b1a3fb4a0317ab8c89618nicolasroard                mCache.addObserver(caller);
3780d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            }
3790d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        }
3800d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        return filteredImage;
3810d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
3820d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
3830d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    public void resetImageForPreset(ImagePreset imagePreset, ImageShow caller) {
3840d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        mHiresCache.reset(imagePreset);
3850d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        mCache.reset(imagePreset);
3865448bf8095483574649afcc2add7f153670c7450nicolasroard        mZoomCache.reset(imagePreset);
3870d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
3880d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
389014a111f10a7523415ca210bc6fe1e4f00183d31John Reck    public void saveImage(ImagePreset preset, final FilterShowActivity filterShowActivity,
3900ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard            File destination) {
391014a111f10a7523415ca210bc6fe1e4f00183d31John Reck        preset.setIsHighQuality(true);
392014a111f10a7523415ca210bc6fe1e4f00183d31John Reck        preset.setScaleFactor(1.0f);
393014a111f10a7523415ca210bc6fe1e4f00183d31John Reck        new SaveCopyTask(mContext, mUri, destination, new SaveCopyTask.Callback() {
3940d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
395014a111f10a7523415ca210bc6fe1e4f00183d31John Reck            @Override
396014a111f10a7523415ca210bc6fe1e4f00183d31John Reck            public void onComplete(Uri result) {
397014a111f10a7523415ca210bc6fe1e4f00183d31John Reck                filterShowActivity.completeSaveImage(result);
398014a111f10a7523415ca210bc6fe1e4f00183d31John Reck            }
3990d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
400014a111f10a7523415ca210bc6fe1e4f00183d31John Reck        }).execute(preset);
4010d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
4020d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
4030d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    public void setAdapter(HistoryAdapter adapter) {
4040d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        mAdapter = adapter;
4050d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
4060d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
4070d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    public HistoryAdapter getHistory() {
4080d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        return mAdapter;
4090d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
4100d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
411c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling    public XMPMeta getXmpObject() {
412e9c55b28a4a155c2e1c1f5aec615a0c56e38ade4John Hoford        try {
413e9c55b28a4a155c2e1c1f5aec615a0c56e38ade4John Hoford            InputStream is = mContext.getContentResolver().openInputStream(getUri());
414e9c55b28a4a155c2e1c1f5aec615a0c56e38ade4John Hoford            return XmpUtilHelper.extractXMPMeta(is);
415e9c55b28a4a155c2e1c1f5aec615a0c56e38ade4John Hoford        } catch (FileNotFoundException e) {
416e9c55b28a4a155c2e1c1f5aec615a0c56e38ade4John Hoford            return null;
417e9c55b28a4a155c2e1c1f5aec615a0c56e38ade4John Hoford        }
418e9c55b28a4a155c2e1c1f5aec615a0c56e38ade4John Hoford    }
4195fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford
4205fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford    /**
4215fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford     * Determine if this is a light cycle 360 image
4225fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford     *
4235fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford     * @return true if it is a light Cycle image that is full 360
4245fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford     */
4253d4f2c7443f6f6015efab769bfaad19263137c67John Hoford    public boolean queryLightCycle360() {
4265fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford        try {
4275fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford            InputStream is = mContext.getContentResolver().openInputStream(getUri());
4285fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford            XMPMeta meta = XmpUtilHelper.extractXMPMeta(is);
4295fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford            if (meta == null) {
4305fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                return false;
4315fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford            }
4325fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford            String name = meta.getPacketHeader();
4335fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford            try {
4345fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                String namespace = "http://ns.google.com/photos/1.0/panorama/";
4355fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                String cropWidthName = "GPano:CroppedAreaImageWidthPixels";
4365fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                String fullWidthName = "GPano:FullPanoWidthPixels";
4375fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford
4385fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                if (!meta.doesPropertyExist(namespace, cropWidthName)) {
4395fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                    return false;
4405fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                }
4415fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                if (!meta.doesPropertyExist(namespace, fullWidthName)) {
4425fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                    return false;
4435fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                }
4445fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford
4455fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                Integer cropValue = meta.getPropertyInteger(namespace, cropWidthName);
4465fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                Integer fullValue = meta.getPropertyInteger(namespace, fullWidthName);
4475fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford
4485fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                // Definition of a 360:
4495fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                // GFullPanoWidthPixels == CroppedAreaImageWidthPixels
4505fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                if (cropValue != null && fullValue != null) {
4515fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                    return cropValue.equals(fullValue);
4525fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                }
4535fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford
4545fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                return false;
4555fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford            } catch (XMPException e) {
4565fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford                return false;
4575fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford            }
4585fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford        } catch (FileNotFoundException e) {
4595fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford            return false;
4605fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford        }
4615fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford    }
4625fbfe6f1d1f407e68b7334c6a5988f20bcf16d79John Hoford
4630d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard}
464