1f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka/* 2f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * Copyright (C) 2013 The Android Open Source Project 3f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * 4f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License"); 5f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * you may not use this file except in compliance with the License. 6f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * You may obtain a copy of the License at 7f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * 8f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * http://www.apache.org/licenses/LICENSE-2.0 9f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * 10f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * Unless required by applicable law or agreed to in writing, software 11f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * distributed under the License is distributed on an "AS IS" BASIS, 12f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * See the License for the specific language governing permissions and 14f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * limitations under the License. 15f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka */ 16f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 17f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkapackage com.android.photos; 18f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 19f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.annotation.TargetApi; 20f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.content.Context; 21f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.content.res.Resources; 22f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.Bitmap; 23f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.BitmapFactory; 24f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.BitmapRegionDecoder; 25f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.Canvas; 26f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.Paint; 27f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.Rect; 28f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.net.Uri; 2978776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyalimport android.opengl.GLUtils; 30f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.os.Build; 31f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.util.Log; 32f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 335bfa1defa156cde58a9c95ba3f5b7ae4e8ec7a96Sunny Goyalimport com.android.gallery3d.common.ExifOrientation; 34f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport com.android.gallery3d.common.Utils; 35f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport com.android.gallery3d.glrenderer.BasicTexture; 36f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport com.android.gallery3d.glrenderer.BitmapTexture; 37f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport com.android.photos.views.TiledImageRenderer; 38841a502864d307341945eae62569b92cada93e75Sunny Goyalimport com.android.wallpaperpicker.common.InputStreamProvider; 39f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 40841a502864d307341945eae62569b92cada93e75Sunny Goyalimport java.io.File; 41f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport java.io.IOException; 42f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport java.io.InputStream; 43f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 44f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkainterface SimpleBitmapRegionDecoder { 45f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int getWidth(); 46f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int getHeight(); 47f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options); 48f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka} 49f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 50f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaclass SimpleBitmapRegionDecoderWrapper implements SimpleBitmapRegionDecoder { 51f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka BitmapRegionDecoder mDecoder; 52f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private SimpleBitmapRegionDecoderWrapper(BitmapRegionDecoder decoder) { 53f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mDecoder = decoder; 54f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 55841a502864d307341945eae62569b92cada93e75Sunny Goyal 56f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public static SimpleBitmapRegionDecoderWrapper newInstance( 57f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka InputStream is, boolean isShareable) { 58f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka try { 59f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka BitmapRegionDecoder d = BitmapRegionDecoder.newInstance(is, isShareable); 60f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (d != null) { 61f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return new SimpleBitmapRegionDecoderWrapper(d); 62f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 63f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } catch (IOException e) { 64f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Log.w("BitmapRegionTileSource", "getting decoder failed", e); 65f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return null; 66f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 67f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return null; 68f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 69f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public int getWidth() { 70f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mDecoder.getWidth(); 71f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 72f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public int getHeight() { 73f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mDecoder.getHeight(); 74f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 75f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options) { 76f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mDecoder.decodeRegion(wantRegion, options); 77f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 78f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka} 79f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 80f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaclass DumbBitmapRegionDecoder implements SimpleBitmapRegionDecoder { 81f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Bitmap mBuffer; 82f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Canvas mTempCanvas; 83f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Paint mTempPaint; 84f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private DumbBitmapRegionDecoder(Bitmap b) { 85f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mBuffer = b; 86f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 87f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public static DumbBitmapRegionDecoder newInstance(InputStream is) { 88f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Bitmap b = BitmapFactory.decodeStream(is); 89f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (b != null) { 90f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return new DumbBitmapRegionDecoder(b); 91f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 92f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return null; 93f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 94f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public int getWidth() { 95f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mBuffer.getWidth(); 96f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 97f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public int getHeight() { 98f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mBuffer.getHeight(); 99f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 100f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options) { 101f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mTempCanvas == null) { 102f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mTempCanvas = new Canvas(); 103f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mTempPaint = new Paint(); 104f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mTempPaint.setFilterBitmap(true); 105f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 106f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int sampleSize = Math.max(options.inSampleSize, 1); 107f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Bitmap newBitmap = Bitmap.createBitmap( 108f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka wantRegion.width() / sampleSize, 109f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka wantRegion.height() / sampleSize, 110f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Bitmap.Config.ARGB_8888); 111f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mTempCanvas.setBitmap(newBitmap); 112f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mTempCanvas.save(); 113f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mTempCanvas.scale(1f / sampleSize, 1f / sampleSize); 114f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mTempCanvas.drawBitmap(mBuffer, -wantRegion.left, -wantRegion.top, mTempPaint); 115f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mTempCanvas.restore(); 116f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mTempCanvas.setBitmap(null); 117f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return newBitmap; 118f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 119f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka} 120f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 121f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka/** 122f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * A {@link com.android.photos.views.TiledImageRenderer.TileSource} using 123f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * {@link BitmapRegionDecoder} to wrap a local file 124f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka */ 125f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) 126f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkapublic class BitmapRegionTileSource implements TiledImageRenderer.TileSource { 127f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 128f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private static final String TAG = "BitmapRegionTileSource"; 129f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 130f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private static final int GL_SIZE_LIMIT = 2048; 131f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // This must be no larger than half the size of the GL_SIZE_LIMIT 132f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // due to decodePreview being allowed to be up to 2x the size of the target 13378776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal private static final int MAX_PREVIEW_SIZE = GL_SIZE_LIMIT / 2; 134f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 135f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public static abstract class BitmapSource { 136f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private SimpleBitmapRegionDecoder mDecoder; 137f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private Bitmap mPreview; 138f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private int mRotation; 139f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public enum State { NOT_LOADED, LOADED, ERROR_LOADING }; 140f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private State mState = State.NOT_LOADED; 14178776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal 142371bf2f71613dbe646555190789f5d30037fa084Tony Wickham /** Returns whether loading was successful. */ 1432a218b718e5f498a284341532178c84fe3850e63Sunny Goyal public boolean loadInBackground(InBitmapProvider bitmapProvider) { 1445bfa1defa156cde58a9c95ba3f5b7ae4e8ec7a96Sunny Goyal mRotation = getExifRotation(); 145f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mDecoder = loadBitmapRegionDecoder(); 146f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mDecoder == null) { 147f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mState = State.ERROR_LOADING; 148f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return false; 149f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else { 150f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int width = mDecoder.getWidth(); 151f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int height = mDecoder.getHeight(); 152f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 15378776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal BitmapFactory.Options opts = new BitmapFactory.Options(); 15478776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal opts.inPreferredConfig = Bitmap.Config.ARGB_8888; 15578776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal opts.inPreferQualityOverSpeed = true; 1562a218b718e5f498a284341532178c84fe3850e63Sunny Goyal 15778776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal float scale = (float) MAX_PREVIEW_SIZE / Math.max(width, height); 158841a502864d307341945eae62569b92cada93e75Sunny Goyal opts.inSampleSize = Utils.computeSampleSizeLarger(scale); 15978776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal opts.inJustDecodeBounds = false; 16078776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal opts.inMutable = true; 16178776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal 16278776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal if (bitmapProvider != null) { 16378776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal int expectedPixles = (width / opts.inSampleSize) * (height / opts.inSampleSize); 16478776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal Bitmap reusableBitmap = bitmapProvider.forPixelCount(expectedPixles); 16578776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal if (reusableBitmap != null) { 16678776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal // Try loading with reusable bitmap 16778776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal opts.inBitmap = reusableBitmap; 16878776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal try { 16978776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal mPreview = loadPreviewBitmap(opts); 17078776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal } catch (IllegalArgumentException e) { 171371bf2f71613dbe646555190789f5d30037fa084Tony Wickham Log.d(TAG, "Unable to reuse bitmap", e); 17278776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal opts.inBitmap = null; 17378776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal mPreview = null; 1742a218b718e5f498a284341532178c84fe3850e63Sunny Goyal } 1752a218b718e5f498a284341532178c84fe3850e63Sunny Goyal } 176f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 17778776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal if (mPreview == null) { 17878776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal mPreview = loadPreviewBitmap(opts); 17978776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal } 180371bf2f71613dbe646555190789f5d30037fa084Tony Wickham if (mPreview == null) { 181371bf2f71613dbe646555190789f5d30037fa084Tony Wickham mState = State.ERROR_LOADING; 182371bf2f71613dbe646555190789f5d30037fa084Tony Wickham return false; 183371bf2f71613dbe646555190789f5d30037fa084Tony Wickham } 18478776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal 18578776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal // Verify that the bitmap can be used on GL surface 18678776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal try { 18778776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal GLUtils.getInternalFormat(mPreview); 18878776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal GLUtils.getType(mPreview); 18978776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal mState = State.LOADED; 19078776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal } catch (IllegalArgumentException e) { 19178776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal Log.d(TAG, "Image cannot be rendered on a GL surface", e); 19278776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal mState = State.ERROR_LOADING; 19378776d77ca661361dcdc6f84d740a95b51e28cffSunny Goyal } 194371bf2f71613dbe646555190789f5d30037fa084Tony Wickham return mState == State.LOADED; 195f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 196f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 197f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 198f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public State getLoadingState() { 199f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mState; 200f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 201f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 202f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public SimpleBitmapRegionDecoder getBitmapRegionDecoder() { 203f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mDecoder; 204f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 205f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 206f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public Bitmap getPreviewBitmap() { 207f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mPreview; 208f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 209f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 210f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public int getRotation() { 211f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mRotation; 212f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 213f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 2145bfa1defa156cde58a9c95ba3f5b7ae4e8ec7a96Sunny Goyal public abstract int getExifRotation(); 215f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public abstract SimpleBitmapRegionDecoder loadBitmapRegionDecoder(); 216f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public abstract Bitmap loadPreviewBitmap(BitmapFactory.Options options); 2172a218b718e5f498a284341532178c84fe3850e63Sunny Goyal 2182a218b718e5f498a284341532178c84fe3850e63Sunny Goyal public interface InBitmapProvider { 2192a218b718e5f498a284341532178c84fe3850e63Sunny Goyal Bitmap forPixelCount(int count); 2202a218b718e5f498a284341532178c84fe3850e63Sunny Goyal } 221f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 222f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 223841a502864d307341945eae62569b92cada93e75Sunny Goyal public static class InputStreamSource extends BitmapSource { 224841a502864d307341945eae62569b92cada93e75Sunny Goyal private final InputStreamProvider mStreamProvider; 225841a502864d307341945eae62569b92cada93e75Sunny Goyal private final Context mContext; 226841a502864d307341945eae62569b92cada93e75Sunny Goyal 227841a502864d307341945eae62569b92cada93e75Sunny Goyal public InputStreamSource(Context context, Uri uri) { 228841a502864d307341945eae62569b92cada93e75Sunny Goyal this(InputStreamProvider.fromUri(context, uri), context); 229f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 2305bfa1defa156cde58a9c95ba3f5b7ae4e8ec7a96Sunny Goyal 231841a502864d307341945eae62569b92cada93e75Sunny Goyal public InputStreamSource(Resources res, int resId, Context context) { 232841a502864d307341945eae62569b92cada93e75Sunny Goyal this(InputStreamProvider.fromResource(res, resId), context); 233f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 234f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 235841a502864d307341945eae62569b92cada93e75Sunny Goyal public InputStreamSource(InputStreamProvider streamProvider, Context context) { 236841a502864d307341945eae62569b92cada93e75Sunny Goyal mStreamProvider = streamProvider; 237f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mContext = context; 238f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 239841a502864d307341945eae62569b92cada93e75Sunny Goyal 240f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 241f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() { 242f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka try { 243841a502864d307341945eae62569b92cada93e75Sunny Goyal InputStream is = mStreamProvider.newStreamNotNull(); 244f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka SimpleBitmapRegionDecoder regionDecoder = 245f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka SimpleBitmapRegionDecoderWrapper.newInstance(is, false); 246f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Utils.closeSilently(is); 247f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (regionDecoder == null) { 248841a502864d307341945eae62569b92cada93e75Sunny Goyal is = mStreamProvider.newStreamNotNull(); 249f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka regionDecoder = DumbBitmapRegionDecoder.newInstance(is); 250f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Utils.closeSilently(is); 251f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 252f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return regionDecoder; 253841a502864d307341945eae62569b92cada93e75Sunny Goyal } catch (IOException e) { 254841a502864d307341945eae62569b92cada93e75Sunny Goyal Log.e("InputStreamSource", "Failed to load stream", e); 255f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return null; 256f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 257f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 258841a502864d307341945eae62569b92cada93e75Sunny Goyal 259841a502864d307341945eae62569b92cada93e75Sunny Goyal @Override 260841a502864d307341945eae62569b92cada93e75Sunny Goyal public int getExifRotation() { 261841a502864d307341945eae62569b92cada93e75Sunny Goyal return mStreamProvider.getRotationFromExif(mContext); 262841a502864d307341945eae62569b92cada93e75Sunny Goyal } 263841a502864d307341945eae62569b92cada93e75Sunny Goyal 264f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 265f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { 266f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka try { 267841a502864d307341945eae62569b92cada93e75Sunny Goyal InputStream is = mStreamProvider.newStreamNotNull(); 268f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Bitmap b = BitmapFactory.decodeStream(is, null, options); 269f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Utils.closeSilently(is); 270f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return b; 271841a502864d307341945eae62569b92cada93e75Sunny Goyal } catch (IOException | OutOfMemoryError e) { 272841a502864d307341945eae62569b92cada93e75Sunny Goyal Log.e("InputStreamSource", "Failed to load stream", e); 273f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return null; 274f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 275f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 276f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 277f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 278841a502864d307341945eae62569b92cada93e75Sunny Goyal public static class FilePathBitmapSource extends InputStreamSource { 279841a502864d307341945eae62569b92cada93e75Sunny Goyal private String mPath; 280841a502864d307341945eae62569b92cada93e75Sunny Goyal public FilePathBitmapSource(File file, Context context) { 281841a502864d307341945eae62569b92cada93e75Sunny Goyal super(context, Uri.fromFile(file)); 282841a502864d307341945eae62569b92cada93e75Sunny Goyal mPath = file.getAbsolutePath(); 283f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 2845bfa1defa156cde58a9c95ba3f5b7ae4e8ec7a96Sunny Goyal 285f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 2865bfa1defa156cde58a9c95ba3f5b7ae4e8ec7a96Sunny Goyal public int getExifRotation() { 287841a502864d307341945eae62569b92cada93e75Sunny Goyal return ExifOrientation.readRotation(mPath); 288f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 289f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 290f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 291f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka SimpleBitmapRegionDecoder mDecoder; 292f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int mWidth; 293f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int mHeight; 294f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int mTileSize; 295f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private BasicTexture mPreview; 296f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private final int mRotation; 297f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 298f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // For use only by getTile 299f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private Rect mWantRegion = new Rect(); 300f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private BitmapFactory.Options mOptions; 301f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 3022a218b718e5f498a284341532178c84fe3850e63Sunny Goyal public BitmapRegionTileSource(Context context, BitmapSource source, byte[] tempStorage) { 303f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mTileSize = TiledImageRenderer.suggestedTileSize(context); 304f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mRotation = source.getRotation(); 305f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mDecoder = source.getBitmapRegionDecoder(); 306f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mDecoder != null) { 307f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mWidth = mDecoder.getWidth(); 308f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mHeight = mDecoder.getHeight(); 309f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mOptions = new BitmapFactory.Options(); 310f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888; 311f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mOptions.inPreferQualityOverSpeed = true; 3122a218b718e5f498a284341532178c84fe3850e63Sunny Goyal mOptions.inTempStorage = tempStorage; 3132a218b718e5f498a284341532178c84fe3850e63Sunny Goyal 3142a218b718e5f498a284341532178c84fe3850e63Sunny Goyal Bitmap preview = source.getPreviewBitmap(); 3152a218b718e5f498a284341532178c84fe3850e63Sunny Goyal if (preview != null && 3162a218b718e5f498a284341532178c84fe3850e63Sunny Goyal preview.getWidth() <= GL_SIZE_LIMIT && preview.getHeight() <= GL_SIZE_LIMIT) { 317f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mPreview = new BitmapTexture(preview); 3182a218b718e5f498a284341532178c84fe3850e63Sunny Goyal } else { 3192a218b718e5f498a284341532178c84fe3850e63Sunny Goyal Log.w(TAG, String.format( 3202a218b718e5f498a284341532178c84fe3850e63Sunny Goyal "Failed to create preview of apropriate size! " 3212a218b718e5f498a284341532178c84fe3850e63Sunny Goyal + " in: %dx%d, out: %dx%d", 3222a218b718e5f498a284341532178c84fe3850e63Sunny Goyal mWidth, mHeight, 323371bf2f71613dbe646555190789f5d30037fa084Tony Wickham preview == null ? -1 : preview.getWidth(), 324371bf2f71613dbe646555190789f5d30037fa084Tony Wickham preview == null ? -1 : preview.getHeight())); 325f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 326f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 327f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 328f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 3292a218b718e5f498a284341532178c84fe3850e63Sunny Goyal public Bitmap getBitmap() { 3302a218b718e5f498a284341532178c84fe3850e63Sunny Goyal return mPreview instanceof BitmapTexture ? ((BitmapTexture) mPreview).getBitmap() : null; 3312a218b718e5f498a284341532178c84fe3850e63Sunny Goyal } 3322a218b718e5f498a284341532178c84fe3850e63Sunny Goyal 333f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 334f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public int getTileSize() { 335f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mTileSize; 336f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 337f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 338f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 339f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public int getImageWidth() { 340f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mWidth; 341f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 342f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 343f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 344f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public int getImageHeight() { 345f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mHeight; 346f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 347f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 348f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 349f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public BasicTexture getPreview() { 350f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mPreview; 351f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 352f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 353f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 354f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public int getRotation() { 355f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mRotation; 356f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 357f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 358f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 359f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public Bitmap getTile(int level, int x, int y, Bitmap bitmap) { 360f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int tileSize = getTileSize(); 361f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int t = tileSize << level; 362f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mWantRegion.set(x, y, x + t, y + t); 363f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 364f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (bitmap == null) { 365f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka bitmap = Bitmap.createBitmap(tileSize, tileSize, Bitmap.Config.ARGB_8888); 366f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 367f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 368f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mOptions.inSampleSize = (1 << level); 369f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mOptions.inBitmap = bitmap; 370f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 371f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka try { 372f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka bitmap = mDecoder.decodeRegion(mWantRegion, mOptions); 373f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } finally { 374f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mOptions.inBitmap != bitmap && mOptions.inBitmap != null) { 375f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mOptions.inBitmap = null; 376f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 377f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 378f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 379f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (bitmap == null) { 380f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Log.w("BitmapRegionTileSource", "fail in decoding region"); 381f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 382f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return bitmap; 383f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 384f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka} 385