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