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