1e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka/* 2e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Copyright (C) 2013 The Android Open Source Project 3e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * 4e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License"); 5e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * you may not use this file except in compliance with the License. 6e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * You may obtain a copy of the License at 7e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * 8e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * http://www.apache.org/licenses/LICENSE-2.0 9e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * 10e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Unless required by applicable law or agreed to in writing, software 11e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * distributed under the License is distributed on an "AS IS" BASIS, 12e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * See the License for the specific language governing permissions and 14e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * limitations under the License. 15e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka */ 16e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 17e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkapackage com.android.photos; 18e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 19e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.annotation.TargetApi; 20e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.content.Context; 21e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.content.res.Resources; 22e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Bitmap; 23e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Bitmap.Config; 24e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.BitmapFactory; 25e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.BitmapRegionDecoder; 26e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Canvas; 27b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurkaimport android.graphics.Paint; 28e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Rect; 29e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.net.Uri; 30e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.os.Build; 31e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.os.Build.VERSION_CODES; 32e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.util.Log; 33e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 34e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport com.android.gallery3d.common.BitmapUtils; 357b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurkaimport com.android.gallery3d.common.Utils; 365271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurkaimport com.android.gallery3d.exif.ExifInterface; 37e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport com.android.gallery3d.glrenderer.BasicTexture; 38e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport com.android.gallery3d.glrenderer.BitmapTexture; 39e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport com.android.photos.views.TiledImageRenderer; 40e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 41e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.BufferedInputStream; 425271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurkaimport java.io.FileNotFoundException; 43e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.IOException; 44e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.InputStream; 45e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 467b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurkainterface SimpleBitmapRegionDecoder { 477b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka int getWidth(); 487b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka int getHeight(); 497b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options); 507b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka} 517b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka 527b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurkaclass SimpleBitmapRegionDecoderWrapper implements SimpleBitmapRegionDecoder { 537b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka BitmapRegionDecoder mDecoder; 547b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka private SimpleBitmapRegionDecoderWrapper(BitmapRegionDecoder decoder) { 557b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka mDecoder = decoder; 567b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 57b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka public static SimpleBitmapRegionDecoderWrapper newInstance( 58b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka String pathName, boolean isShareable) { 597b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka try { 607b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka BitmapRegionDecoder d = BitmapRegionDecoder.newInstance(pathName, isShareable); 617b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka if (d != null) { 627b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return new SimpleBitmapRegionDecoderWrapper(d); 637b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 647b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } catch (IOException e) { 657b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka Log.w("BitmapRegionTileSource", "getting decoder failed for path " + pathName, e); 667b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return null; 677b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 687b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return null; 697b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 70b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka public static SimpleBitmapRegionDecoderWrapper newInstance( 71b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka InputStream is, boolean isShareable) { 727b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka try { 737b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka BitmapRegionDecoder d = BitmapRegionDecoder.newInstance(is, isShareable); 747b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka if (d != null) { 757b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return new SimpleBitmapRegionDecoderWrapper(d); 767b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 777b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } catch (IOException e) { 787b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka Log.w("BitmapRegionTileSource", "getting decoder failed", e); 797b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return null; 807b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 817b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return null; 827b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 837b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka public int getWidth() { 847b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return mDecoder.getWidth(); 857b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 867b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka public int getHeight() { 877b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return mDecoder.getHeight(); 887b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 897b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka public Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options) { 907b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return mDecoder.decodeRegion(wantRegion, options); 917b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 927b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka} 937b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka 947b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurkaclass DumbBitmapRegionDecoder implements SimpleBitmapRegionDecoder { 957b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka Bitmap mBuffer; 96b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka Canvas mTempCanvas; 97b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka Paint mTempPaint; 987b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka private DumbBitmapRegionDecoder(Bitmap b) { 997b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka mBuffer = b; 1007b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 1017b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka public static DumbBitmapRegionDecoder newInstance(String pathName) { 1027b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka Bitmap b = BitmapFactory.decodeFile(pathName); 1037b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka if (b != null) { 1047b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return new DumbBitmapRegionDecoder(b); 1057b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 1067b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return null; 1077b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 1087b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka public static DumbBitmapRegionDecoder newInstance(InputStream is) { 1097b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka Bitmap b = BitmapFactory.decodeStream(is); 1107b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka if (b != null) { 1117b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return new DumbBitmapRegionDecoder(b); 1127b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 1137b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return null; 1147b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 1157b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka public int getWidth() { 1167b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return mBuffer.getWidth(); 1177b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 1187b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka public int getHeight() { 1197b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return mBuffer.getHeight(); 1207b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 1217b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka public Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options) { 122b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka if (mTempCanvas == null) { 123b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka mTempCanvas = new Canvas(); 124b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka mTempPaint = new Paint(); 125b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka mTempPaint.setFilterBitmap(true); 126b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka } 127b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka int sampleSize = Math.max(options.inSampleSize, 1); 128b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka Bitmap newBitmap = Bitmap.createBitmap( 129b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka wantRegion.width() / sampleSize, 130b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka wantRegion.height() / sampleSize, 131b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka Bitmap.Config.ARGB_8888); 132b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka mTempCanvas.setBitmap(newBitmap); 133b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka mTempCanvas.save(); 134b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka mTempCanvas.scale(1f / sampleSize, 1f / sampleSize); 135b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka mTempCanvas.drawBitmap(mBuffer, -wantRegion.left, -wantRegion.top, mTempPaint); 136b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka mTempCanvas.restore(); 137b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka mTempCanvas.setBitmap(null); 138b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka return newBitmap; 1397b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 1407b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka} 1417b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka 142e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka/** 143e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * A {@link com.android.photos.views.TiledImageRenderer.TileSource} using 144e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * {@link BitmapRegionDecoder} to wrap a local file 145e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka */ 146e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) 147e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkapublic class BitmapRegionTileSource implements TiledImageRenderer.TileSource { 148e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 149e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private static final String TAG = "BitmapRegionTileSource"; 150e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 151e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private static final boolean REUSE_BITMAP = 152e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; 153e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private static final int GL_SIZE_LIMIT = 2048; 154e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka // This must be no larger than half the size of the GL_SIZE_LIMIT 155e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka // due to decodePreview being allowed to be up to 2x the size of the target 1565271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public static final int MAX_PREVIEW_SIZE = GL_SIZE_LIMIT / 2; 1575271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka 1585271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public static abstract class BitmapSource { 1597b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka private SimpleBitmapRegionDecoder mDecoder; 1605271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka private Bitmap mPreview; 1615271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka private int mPreviewSize; 1625271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka private int mRotation; 1637b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka public enum State { NOT_LOADED, LOADED, ERROR_LOADING }; 1647b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka private State mState = State.NOT_LOADED; 1655271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public BitmapSource(int previewSize) { 1665271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka mPreviewSize = previewSize; 1675271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 1687b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka public boolean loadInBackground() { 1695271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka ExifInterface ei = new ExifInterface(); 1705271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka if (readExif(ei)) { 1715271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION); 1725271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka if (ori != null) { 1735271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka mRotation = ExifInterface.getRotationForOrientationValue(ori.shortValue()); 1745271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 1755271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 1765271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka mDecoder = loadBitmapRegionDecoder(); 1777b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka if (mDecoder == null) { 1787b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka mState = State.ERROR_LOADING; 1797b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return false; 1807b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } else { 1817b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka int width = mDecoder.getWidth(); 1827b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka int height = mDecoder.getHeight(); 1837b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka if (mPreviewSize != 0) { 1847b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka int previewSize = Math.min(mPreviewSize, MAX_PREVIEW_SIZE); 1857b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka BitmapFactory.Options opts = new BitmapFactory.Options(); 1867b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka opts.inPreferredConfig = Bitmap.Config.ARGB_8888; 1877b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka opts.inPreferQualityOverSpeed = true; 1885271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka 1897b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka float scale = (float) previewSize / Math.max(width, height); 1907b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka opts.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale); 1917b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka opts.inJustDecodeBounds = false; 1927b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka mPreview = loadPreviewBitmap(opts); 1937b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 1947b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka mState = State.LOADED; 1957b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return true; 1965271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 1975271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 1985271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka 1997b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka public State getLoadingState() { 2007b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return mState; 2017b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 2027b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka 2037b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka public SimpleBitmapRegionDecoder getBitmapRegionDecoder() { 2045271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return mDecoder; 2055271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2065271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka 2075271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public Bitmap getPreviewBitmap() { 2085271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return mPreview; 2095271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2105271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka 2115271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public int getPreviewSize() { 2125271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return mPreviewSize; 2135271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2145271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka 2155271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public int getRotation() { 2165271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return mRotation; 2175271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2185271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka 2195271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public abstract boolean readExif(ExifInterface ei); 2207b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka public abstract SimpleBitmapRegionDecoder loadBitmapRegionDecoder(); 2215271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public abstract Bitmap loadPreviewBitmap(BitmapFactory.Options options); 2225271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2235271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka 2245271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public static class FilePathBitmapSource extends BitmapSource { 2255271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka private String mPath; 2265271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public FilePathBitmapSource(String path, int previewSize) { 2275271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka super(previewSize); 2285271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka mPath = path; 2295271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2305271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka @Override 2317b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() { 2327b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka SimpleBitmapRegionDecoder d; 2337b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka d = SimpleBitmapRegionDecoderWrapper.newInstance(mPath, true); 2347b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka if (d == null) { 2357b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka d = DumbBitmapRegionDecoder.newInstance(mPath); 2365271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2377b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return d; 2385271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2395271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka @Override 2405271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { 2415271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return BitmapFactory.decodeFile(mPath, options); 2425271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2435271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka @Override 2445271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public boolean readExif(ExifInterface ei) { 2455271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka try { 2465271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka ei.readExif(mPath); 2475271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return true; 2485ab7d37d903f336c5a96f8caca9b36439e76bdb4Selim Cinek } catch (NullPointerException e) { 2495ab7d37d903f336c5a96f8caca9b36439e76bdb4Selim Cinek Log.w("BitmapRegionTileSource", "reading exif failed", e); 2505ab7d37d903f336c5a96f8caca9b36439e76bdb4Selim Cinek return false; 2515271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } catch (IOException e) { 2525271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka Log.w("BitmapRegionTileSource", "getting decoder failed", e); 2535271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return false; 2545271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2555271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2565271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2575271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka 2585271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public static class UriBitmapSource extends BitmapSource { 2595271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka private Context mContext; 2605271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka private Uri mUri; 2615271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public UriBitmapSource(Context context, Uri uri, int previewSize) { 2625271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka super(previewSize); 2635271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka mContext = context; 2645271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka mUri = uri; 2655271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2665271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka private InputStream regenerateInputStream() throws FileNotFoundException { 2675271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka InputStream is = mContext.getContentResolver().openInputStream(mUri); 2685271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return new BufferedInputStream(is); 2695271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2705271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka @Override 2717b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() { 2725271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka try { 2737b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka InputStream is = regenerateInputStream(); 2747b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka SimpleBitmapRegionDecoder regionDecoder = 2757b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka SimpleBitmapRegionDecoderWrapper.newInstance(is, false); 2767b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka Utils.closeSilently(is); 2777b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka if (regionDecoder == null) { 2787b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka is = regenerateInputStream(); 2797b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka regionDecoder = DumbBitmapRegionDecoder.newInstance(is); 280b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka Utils.closeSilently(is); 2817b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 2827b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return regionDecoder; 2835271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } catch (FileNotFoundException e) { 2845271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); 2855271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return null; 2865271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2875271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2885271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka @Override 2895271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { 2905271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka try { 2917b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka InputStream is = regenerateInputStream(); 2927b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka Bitmap b = BitmapFactory.decodeStream(is, null, options); 2937b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka Utils.closeSilently(is); 2947b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return b; 2955271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } catch (FileNotFoundException e) { 2965271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); 2975271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return null; 2985271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 2995271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 3005271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka @Override 3015271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public boolean readExif(ExifInterface ei) { 302b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka InputStream is = null; 3035271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka try { 304b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka is = regenerateInputStream(); 3057b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka ei.readExif(is); 3067b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka Utils.closeSilently(is); 3075271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return true; 3085271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } catch (FileNotFoundException e) { 3095271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); 3105271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return false; 3115271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } catch (IOException e) { 3127b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); 3135271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return false; 3145ab7d37d903f336c5a96f8caca9b36439e76bdb4Selim Cinek } catch (NullPointerException e) { 3155ab7d37d903f336c5a96f8caca9b36439e76bdb4Selim Cinek Log.e("BitmapRegionTileSource", "Failed to read EXIF for URI " + mUri, e); 3165ab7d37d903f336c5a96f8caca9b36439e76bdb4Selim Cinek return false; 317b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka } finally { 318b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka Utils.closeSilently(is); 3195271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 3205271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 3215271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 3225271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka 3235271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public static class ResourceBitmapSource extends BitmapSource { 3245271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka private Resources mRes; 3255271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka private int mResId; 3265271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public ResourceBitmapSource(Resources res, int resId, int previewSize) { 3275271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka super(previewSize); 3285271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka mRes = res; 3295271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka mResId = resId; 3305271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 3315271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka private InputStream regenerateInputStream() { 3325271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka InputStream is = mRes.openRawResource(mResId); 3335271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return new BufferedInputStream(is); 3345271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 3355271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka @Override 3367b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() { 3377b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka InputStream is = regenerateInputStream(); 3387b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka SimpleBitmapRegionDecoder regionDecoder = 3397b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka SimpleBitmapRegionDecoderWrapper.newInstance(is, false); 3407b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka Utils.closeSilently(is); 3417b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka if (regionDecoder == null) { 3427b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka is = regenerateInputStream(); 3437b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka regionDecoder = DumbBitmapRegionDecoder.newInstance(is); 344b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka Utils.closeSilently(is); 3455271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 3467b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka return regionDecoder; 3475271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 3485271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka @Override 3495271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { 3505271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return BitmapFactory.decodeResource(mRes, mResId, options); 3515271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 3525271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka @Override 3535271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public boolean readExif(ExifInterface ei) { 3545271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka try { 3557b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka InputStream is = regenerateInputStream(); 3567b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka ei.readExif(is); 3577b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka Utils.closeSilently(is); 3585271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return true; 3595271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } catch (IOException e) { 3605271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka Log.e("BitmapRegionTileSource", "Error reading resource", e); 3615271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka return false; 3625271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 3635271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 3645271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka } 365e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 3667b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka SimpleBitmapRegionDecoder mDecoder; 367e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka int mWidth; 368e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka int mHeight; 369e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka int mTileSize; 370e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private BasicTexture mPreview; 371e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private final int mRotation; 372e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 373e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka // For use only by getTile 374e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private Rect mWantRegion = new Rect(); 375e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private Rect mOverlapRegion = new Rect(); 376e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private BitmapFactory.Options mOptions; 377e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private Canvas mCanvas; 378e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 3795271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka public BitmapRegionTileSource(Context context, BitmapSource source) { 380e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mTileSize = TiledImageRenderer.suggestedTileSize(context); 3815271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka mRotation = source.getRotation(); 3825271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka mDecoder = source.getBitmapRegionDecoder(); 3837b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka if (mDecoder != null) { 3847b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka mWidth = mDecoder.getWidth(); 3857b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka mHeight = mDecoder.getHeight(); 3867b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka mOptions = new BitmapFactory.Options(); 3877b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888; 3887b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka mOptions.inPreferQualityOverSpeed = true; 3897b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka mOptions.inTempStorage = new byte[16 * 1024]; 3907b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka int previewSize = source.getPreviewSize(); 3917b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka if (previewSize != 0) { 3927b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka previewSize = Math.min(previewSize, MAX_PREVIEW_SIZE); 3937b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka // Although this is the same size as the Bitmap that is likely already 3947b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka // loaded, the lifecycle is different and interactions are on a different 3957b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka // thread. Thus to simplify, this source will decode its own bitmap. 3967b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka Bitmap preview = decodePreview(source, previewSize); 3977b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka if (preview.getWidth() <= GL_SIZE_LIMIT && preview.getHeight() <= GL_SIZE_LIMIT) { 3987b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka mPreview = new BitmapTexture(preview); 3997b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } else { 4007b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka Log.w(TAG, String.format( 4017b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka "Failed to create preview of apropriate size! " 4027b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka + " in: %dx%d, out: %dx%d", 4037b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka mWidth, mHeight, 4047b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka preview.getWidth(), preview.getHeight())); 4057b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka } 406e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 407e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 408e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 409e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 410e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 411e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public int getTileSize() { 412e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return mTileSize; 413e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 414e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 415e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 416e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public int getImageWidth() { 417e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return mWidth; 418e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 419e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 420e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 421e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public int getImageHeight() { 422e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return mHeight; 423e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 424e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 425e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 426e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public BasicTexture getPreview() { 427e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return mPreview; 428e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 429e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 430e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 431e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public int getRotation() { 432e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return mRotation; 433e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 434e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 435e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 436e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public Bitmap getTile(int level, int x, int y, Bitmap bitmap) { 437e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka int tileSize = getTileSize(); 438e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (!REUSE_BITMAP) { 439e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return getTileWithoutReusingBitmap(level, x, y, tileSize); 440e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 441e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 442e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka int t = tileSize << level; 443e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mWantRegion.set(x, y, x + t, y + t); 444e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 445e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (bitmap == null) { 446e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka bitmap = Bitmap.createBitmap(tileSize, tileSize, Bitmap.Config.ARGB_8888); 447e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 448e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 449e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mOptions.inSampleSize = (1 << level); 450e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mOptions.inBitmap = bitmap; 451e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 452e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka try { 453e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka bitmap = mDecoder.decodeRegion(mWantRegion, mOptions); 454e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } finally { 455e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (mOptions.inBitmap != bitmap && mOptions.inBitmap != null) { 456e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mOptions.inBitmap = null; 457e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 458e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 459e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 460e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (bitmap == null) { 461e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Log.w("BitmapRegionTileSource", "fail in decoding region"); 462e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 463e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return bitmap; 464e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 465e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 466e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private Bitmap getTileWithoutReusingBitmap( 467e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka int level, int x, int y, int tileSize) { 468e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 469e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka int t = tileSize << level; 470e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mWantRegion.set(x, y, x + t, y + t); 471e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 472e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mOverlapRegion.set(0, 0, mWidth, mHeight); 473e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 474e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mOptions.inSampleSize = (1 << level); 475e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Bitmap bitmap = mDecoder.decodeRegion(mOverlapRegion, mOptions); 476e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 477e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (bitmap == null) { 478e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Log.w(TAG, "fail in decoding region"); 479e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 480e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 481e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (mWantRegion.equals(mOverlapRegion)) { 482e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return bitmap; 483e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 484e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 485e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Bitmap result = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888); 486e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (mCanvas == null) { 487e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mCanvas = new Canvas(); 488e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 489e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mCanvas.setBitmap(result); 490e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mCanvas.drawBitmap(bitmap, 491e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka (mOverlapRegion.left - mWantRegion.left) >> level, 492e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka (mOverlapRegion.top - mWantRegion.top) >> level, null); 493e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mCanvas.setBitmap(null); 494e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return result; 495e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 496e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 497e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka /** 498e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Note that the returned bitmap may have a long edge that's longer 499e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * than the targetSize, but it will always be less than 2x the targetSize 500e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka */ 5015271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka private Bitmap decodePreview(BitmapSource source, int targetSize) { 5025271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka Bitmap result = source.getPreviewBitmap(); 503e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (result == null) { 504e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return null; 505e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 506e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 507e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka // We need to resize down if the decoder does not support inSampleSize 508e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka // or didn't support the specified inSampleSize (some decoders only do powers of 2) 5095271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka float scale = (float) targetSize / (float) (Math.max(result.getWidth(), result.getHeight())); 510e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 511e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (scale <= 0.5) { 512e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka result = BitmapUtils.resizeBitmapByScale(result, scale, true); 513e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 514e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return ensureGLCompatibleBitmap(result); 515e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 516e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 517e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private static Bitmap ensureGLCompatibleBitmap(Bitmap bitmap) { 518e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (bitmap == null || bitmap.getConfig() != null) { 519e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return bitmap; 520e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 521e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Bitmap newBitmap = bitmap.copy(Config.ARGB_8888, false); 522e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka bitmap.recycle(); 523e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return newBitmap; 524e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 525e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka} 526