diff options
Diffstat (limited to 'src/com/android/photos/BitmapRegionTileSource.java')
-rw-r--r-- | src/com/android/photos/BitmapRegionTileSource.java | 524 |
1 files changed, 0 insertions, 524 deletions
diff --git a/src/com/android/photos/BitmapRegionTileSource.java b/src/com/android/photos/BitmapRegionTileSource.java deleted file mode 100644 index 8511de2da..000000000 --- a/src/com/android/photos/BitmapRegionTileSource.java +++ /dev/null @@ -1,524 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.photos; - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.graphics.BitmapFactory; -import android.graphics.BitmapRegionDecoder; -import android.graphics.Canvas; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.Rect; -import android.net.Uri; -import android.os.Build; -import android.os.Build.VERSION_CODES; -import android.util.Log; - -import com.android.gallery3d.common.BitmapUtils; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.exif.ExifInterface; -import com.android.gallery3d.glrenderer.BasicTexture; -import com.android.gallery3d.glrenderer.BitmapTexture; -import com.android.photos.views.TiledImageRenderer; - -import java.io.BufferedInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; - -interface SimpleBitmapRegionDecoder { - int getWidth(); - int getHeight(); - Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options); -} - -class SimpleBitmapRegionDecoderWrapper implements SimpleBitmapRegionDecoder { - BitmapRegionDecoder mDecoder; - private SimpleBitmapRegionDecoderWrapper(BitmapRegionDecoder decoder) { - mDecoder = decoder; - } - public static SimpleBitmapRegionDecoderWrapper newInstance( - String pathName, boolean isShareable) { - try { - BitmapRegionDecoder d = BitmapRegionDecoder.newInstance(pathName, isShareable); - if (d != null) { - return new SimpleBitmapRegionDecoderWrapper(d); - } - } catch (IOException e) { - Log.w("BitmapRegionTileSource", "getting decoder failed for path " + pathName, e); - return null; - } - return null; - } - public static SimpleBitmapRegionDecoderWrapper newInstance( - InputStream is, boolean isShareable) { - try { - BitmapRegionDecoder d = BitmapRegionDecoder.newInstance(is, isShareable); - if (d != null) { - return new SimpleBitmapRegionDecoderWrapper(d); - } - } catch (IOException e) { - Log.w("BitmapRegionTileSource", "getting decoder failed", e); - return null; - } - return null; - } - public int getWidth() { - return mDecoder.getWidth(); - } - public int getHeight() { - return mDecoder.getHeight(); - } - public Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options) { - return mDecoder.decodeRegion(wantRegion, options); - } -} - -class DumbBitmapRegionDecoder implements SimpleBitmapRegionDecoder { - Bitmap mBuffer; - Canvas mTempCanvas; - Paint mTempPaint; - private DumbBitmapRegionDecoder(Bitmap b) { - mBuffer = b; - } - public static DumbBitmapRegionDecoder newInstance(String pathName) { - Bitmap b = BitmapFactory.decodeFile(pathName); - if (b != null) { - return new DumbBitmapRegionDecoder(b); - } - return null; - } - public static DumbBitmapRegionDecoder newInstance(InputStream is) { - Bitmap b = BitmapFactory.decodeStream(is); - if (b != null) { - return new DumbBitmapRegionDecoder(b); - } - return null; - } - public int getWidth() { - return mBuffer.getWidth(); - } - public int getHeight() { - return mBuffer.getHeight(); - } - public Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options) { - if (mTempCanvas == null) { - mTempCanvas = new Canvas(); - mTempPaint = new Paint(); - mTempPaint.setFilterBitmap(true); - } - int sampleSize = Math.max(options.inSampleSize, 1); - Bitmap newBitmap = Bitmap.createBitmap( - wantRegion.width() / sampleSize, - wantRegion.height() / sampleSize, - Bitmap.Config.ARGB_8888); - mTempCanvas.setBitmap(newBitmap); - mTempCanvas.save(); - mTempCanvas.scale(1f / sampleSize, 1f / sampleSize); - mTempCanvas.drawBitmap(mBuffer, -wantRegion.left, -wantRegion.top, mTempPaint); - mTempCanvas.restore(); - mTempCanvas.setBitmap(null); - return newBitmap; - } -} - -/** - * A {@link com.android.photos.views.TiledImageRenderer.TileSource} using - * {@link BitmapRegionDecoder} to wrap a local file - */ -@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) -public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { - - private static final String TAG = "BitmapRegionTileSource"; - - private static final boolean REUSE_BITMAP = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - private static final int GL_SIZE_LIMIT = 2048; - // This must be no larger than half the size of the GL_SIZE_LIMIT - // due to decodePreview being allowed to be up to 2x the size of the target - public static final int MAX_PREVIEW_SIZE = GL_SIZE_LIMIT / 2; - - public static abstract class BitmapSource { - private SimpleBitmapRegionDecoder mDecoder; - private Bitmap mPreview; - private int mPreviewSize; - private int mRotation; - public enum State { NOT_LOADED, LOADED, ERROR_LOADING }; - private State mState = State.NOT_LOADED; - public BitmapSource(int previewSize) { - mPreviewSize = previewSize; - } - public boolean loadInBackground() { - ExifInterface ei = new ExifInterface(); - if (readExif(ei)) { - Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION); - if (ori != null) { - mRotation = ExifInterface.getRotationForOrientationValue(ori.shortValue()); - } - } - mDecoder = loadBitmapRegionDecoder(); - if (mDecoder == null) { - mState = State.ERROR_LOADING; - return false; - } else { - int width = mDecoder.getWidth(); - int height = mDecoder.getHeight(); - if (mPreviewSize != 0) { - int previewSize = Math.min(mPreviewSize, MAX_PREVIEW_SIZE); - BitmapFactory.Options opts = new BitmapFactory.Options(); - opts.inPreferredConfig = Bitmap.Config.ARGB_8888; - opts.inPreferQualityOverSpeed = true; - - float scale = (float) previewSize / Math.max(width, height); - opts.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale); - opts.inJustDecodeBounds = false; - mPreview = loadPreviewBitmap(opts); - } - mState = State.LOADED; - return true; - } - } - - public State getLoadingState() { - return mState; - } - - public SimpleBitmapRegionDecoder getBitmapRegionDecoder() { - return mDecoder; - } - - public Bitmap getPreviewBitmap() { - return mPreview; - } - - public int getPreviewSize() { - return mPreviewSize; - } - - public int getRotation() { - return mRotation; - } - - public abstract boolean readExif(ExifInterface ei); - public abstract SimpleBitmapRegionDecoder loadBitmapRegionDecoder(); - public abstract Bitmap loadPreviewBitmap(BitmapFactory.Options options); - } - - public static class FilePathBitmapSource extends BitmapSource { - private String mPath; - public FilePathBitmapSource(String path, int previewSize) { - super(previewSize); - mPath = path; - } - @Override - public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() { - SimpleBitmapRegionDecoder d; - d = SimpleBitmapRegionDecoderWrapper.newInstance(mPath, true); - if (d == null) { - d = DumbBitmapRegionDecoder.newInstance(mPath); - } - return d; - } - @Override - public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { - return BitmapFactory.decodeFile(mPath, options); - } - @Override - public boolean readExif(ExifInterface ei) { - try { - ei.readExif(mPath); - return true; - } catch (IOException e) { - Log.w("BitmapRegionTileSource", "getting decoder failed", e); - return false; - } - } - } - - public static class UriBitmapSource extends BitmapSource { - private Context mContext; - private Uri mUri; - public UriBitmapSource(Context context, Uri uri, int previewSize) { - super(previewSize); - mContext = context; - mUri = uri; - } - private InputStream regenerateInputStream() throws FileNotFoundException { - InputStream is = mContext.getContentResolver().openInputStream(mUri); - return new BufferedInputStream(is); - } - @Override - public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() { - try { - InputStream is = regenerateInputStream(); - SimpleBitmapRegionDecoder regionDecoder = - SimpleBitmapRegionDecoderWrapper.newInstance(is, false); - Utils.closeSilently(is); - if (regionDecoder == null) { - is = regenerateInputStream(); - regionDecoder = DumbBitmapRegionDecoder.newInstance(is); - Utils.closeSilently(is); - } - return regionDecoder; - } catch (FileNotFoundException e) { - Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); - return null; - } catch (IOException e) { - Log.e("BitmapRegionTileSource", "Failure while reading URI " + mUri, e); - return null; - } - } - @Override - public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { - try { - InputStream is = regenerateInputStream(); - Bitmap b = BitmapFactory.decodeStream(is, null, options); - Utils.closeSilently(is); - return b; - } catch (FileNotFoundException e) { - Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); - return null; - } - } - @Override - public boolean readExif(ExifInterface ei) { - InputStream is = null; - try { - is = regenerateInputStream(); - ei.readExif(is); - Utils.closeSilently(is); - return true; - } catch (FileNotFoundException e) { - Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); - return false; - } catch (IOException e) { - Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); - return false; - } finally { - Utils.closeSilently(is); - } - } - } - - public static class ResourceBitmapSource extends BitmapSource { - private Resources mRes; - private int mResId; - public ResourceBitmapSource(Resources res, int resId, int previewSize) { - super(previewSize); - mRes = res; - mResId = resId; - } - private InputStream regenerateInputStream() { - InputStream is = mRes.openRawResource(mResId); - return new BufferedInputStream(is); - } - @Override - public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() { - InputStream is = regenerateInputStream(); - SimpleBitmapRegionDecoder regionDecoder = - SimpleBitmapRegionDecoderWrapper.newInstance(is, false); - Utils.closeSilently(is); - if (regionDecoder == null) { - is = regenerateInputStream(); - regionDecoder = DumbBitmapRegionDecoder.newInstance(is); - Utils.closeSilently(is); - } - return regionDecoder; - } - @Override - public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { - return BitmapFactory.decodeResource(mRes, mResId, options); - } - @Override - public boolean readExif(ExifInterface ei) { - try { - InputStream is = regenerateInputStream(); - ei.readExif(is); - Utils.closeSilently(is); - return true; - } catch (IOException e) { - Log.e("BitmapRegionTileSource", "Error reading resource", e); - return false; - } - } - } - - SimpleBitmapRegionDecoder mDecoder; - int mWidth; - int mHeight; - int mTileSize; - private BasicTexture mPreview; - private final int mRotation; - - // For use only by getTile - private Rect mWantRegion = new Rect(); - private Rect mOverlapRegion = new Rect(); - private BitmapFactory.Options mOptions; - private Canvas mCanvas; - - public BitmapRegionTileSource(Context context, BitmapSource source) { - mTileSize = TiledImageRenderer.suggestedTileSize(context); - mRotation = source.getRotation(); - mDecoder = source.getBitmapRegionDecoder(); - if (mDecoder != null) { - mWidth = mDecoder.getWidth(); - mHeight = mDecoder.getHeight(); - mOptions = new BitmapFactory.Options(); - mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888; - mOptions.inPreferQualityOverSpeed = true; - mOptions.inTempStorage = new byte[16 * 1024]; - int previewSize = source.getPreviewSize(); - if (previewSize != 0) { - previewSize = Math.min(previewSize, MAX_PREVIEW_SIZE); - // Although this is the same size as the Bitmap that is likely already - // loaded, the lifecycle is different and interactions are on a different - // thread. Thus to simplify, this source will decode its own bitmap. - Bitmap preview = decodePreview(source, previewSize); - if (preview.getWidth() <= GL_SIZE_LIMIT && preview.getHeight() <= GL_SIZE_LIMIT) { - mPreview = new BitmapTexture(preview); - } else { - Log.w(TAG, String.format( - "Failed to create preview of apropriate size! " - + " in: %dx%d, out: %dx%d", - mWidth, mHeight, - preview.getWidth(), preview.getHeight())); - } - } - } - } - - @Override - public int getTileSize() { - return mTileSize; - } - - @Override - public int getImageWidth() { - return mWidth; - } - - @Override - public int getImageHeight() { - return mHeight; - } - - @Override - public BasicTexture getPreview() { - return mPreview; - } - - @Override - public int getRotation() { - return mRotation; - } - - @Override - public Bitmap getTile(int level, int x, int y, Bitmap bitmap) { - int tileSize = getTileSize(); - if (!REUSE_BITMAP) { - return getTileWithoutReusingBitmap(level, x, y, tileSize); - } - - int t = tileSize << level; - mWantRegion.set(x, y, x + t, y + t); - - if (bitmap == null) { - bitmap = Bitmap.createBitmap(tileSize, tileSize, Bitmap.Config.ARGB_8888); - } - - mOptions.inSampleSize = (1 << level); - mOptions.inBitmap = bitmap; - - try { - bitmap = mDecoder.decodeRegion(mWantRegion, mOptions); - } finally { - if (mOptions.inBitmap != bitmap && mOptions.inBitmap != null) { - mOptions.inBitmap = null; - } - } - - if (bitmap == null) { - Log.w("BitmapRegionTileSource", "fail in decoding region"); - } - return bitmap; - } - - private Bitmap getTileWithoutReusingBitmap( - int level, int x, int y, int tileSize) { - - int t = tileSize << level; - mWantRegion.set(x, y, x + t, y + t); - - mOverlapRegion.set(0, 0, mWidth, mHeight); - - mOptions.inSampleSize = (1 << level); - Bitmap bitmap = mDecoder.decodeRegion(mOverlapRegion, mOptions); - - if (bitmap == null) { - Log.w(TAG, "fail in decoding region"); - } - - if (mWantRegion.equals(mOverlapRegion)) { - return bitmap; - } - - Bitmap result = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888); - if (mCanvas == null) { - mCanvas = new Canvas(); - } - mCanvas.setBitmap(result); - mCanvas.drawBitmap(bitmap, - (mOverlapRegion.left - mWantRegion.left) >> level, - (mOverlapRegion.top - mWantRegion.top) >> level, null); - mCanvas.setBitmap(null); - return result; - } - - /** - * Note that the returned bitmap may have a long edge that's longer - * than the targetSize, but it will always be less than 2x the targetSize - */ - private Bitmap decodePreview(BitmapSource source, int targetSize) { - Bitmap result = source.getPreviewBitmap(); - if (result == null) { - return null; - } - - // We need to resize down if the decoder does not support inSampleSize - // or didn't support the specified inSampleSize (some decoders only do powers of 2) - float scale = (float) targetSize / (float) (Math.max(result.getWidth(), result.getHeight())); - - if (scale <= 0.5) { - result = BitmapUtils.resizeBitmapByScale(result, scale, true); - } - return ensureGLCompatibleBitmap(result); - } - - private static Bitmap ensureGLCompatibleBitmap(Bitmap bitmap) { - if (bitmap == null || bitmap.getConfig() != null) { - return bitmap; - } - Bitmap newBitmap = bitmap.copy(Config.ARGB_8888, false); - bitmap.recycle(); - return newBitmap; - } -} |