summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/ui/TileImageViewAdapter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/gallery3d/ui/TileImageViewAdapter.java')
-rw-r--r--src/com/android/gallery3d/ui/TileImageViewAdapter.java200
1 files changed, 200 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/ui/TileImageViewAdapter.java b/src/com/android/gallery3d/ui/TileImageViewAdapter.java
new file mode 100644
index 000000000..0c1f66d0c
--- /dev/null
+++ b/src/com/android/gallery3d/ui/TileImageViewAdapter.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2010 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.gallery3d.ui;
+
+import android.annotation.TargetApi;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapRegionDecoder;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+
+import com.android.gallery3d.common.ApiHelper;
+import com.android.gallery3d.common.Utils;
+import com.android.photos.data.GalleryBitmapPool;
+
+public class TileImageViewAdapter implements TileImageView.TileSource {
+ private static final String TAG = "TileImageViewAdapter";
+ protected ScreenNail mScreenNail;
+ protected boolean mOwnScreenNail;
+ protected BitmapRegionDecoder mRegionDecoder;
+ protected int mImageWidth;
+ protected int mImageHeight;
+ protected int mLevelCount;
+
+ public TileImageViewAdapter() {
+ }
+
+ public synchronized void clear() {
+ mScreenNail = null;
+ mImageWidth = 0;
+ mImageHeight = 0;
+ mLevelCount = 0;
+ mRegionDecoder = null;
+ }
+
+ // Caller is responsible to recycle the ScreenNail
+ public synchronized void setScreenNail(
+ ScreenNail screenNail, int width, int height) {
+ Utils.checkNotNull(screenNail);
+ mScreenNail = screenNail;
+ mImageWidth = width;
+ mImageHeight = height;
+ mRegionDecoder = null;
+ mLevelCount = 0;
+ }
+
+ public synchronized void setRegionDecoder(BitmapRegionDecoder decoder) {
+ mRegionDecoder = Utils.checkNotNull(decoder);
+ mImageWidth = decoder.getWidth();
+ mImageHeight = decoder.getHeight();
+ mLevelCount = calculateLevelCount();
+ }
+
+ private int calculateLevelCount() {
+ return Math.max(0, Utils.ceilLog2(
+ (float) mImageWidth / mScreenNail.getWidth()));
+ }
+
+ // Gets a sub image on a rectangle of the current photo. For example,
+ // getTile(1, 50, 50, 100, 3, pool) means to get the region located
+ // at (50, 50) with sample level 1 (ie, down sampled by 2^1) and the
+ // target tile size (after sampling) 100 with border 3.
+ //
+ // From this spec, we can infer the actual tile size to be
+ // 100 + 3x2 = 106, and the size of the region to be extracted from the
+ // photo to be 200 with border 6.
+ //
+ // As a result, we should decode region (50-6, 50-6, 250+6, 250+6) or
+ // (44, 44, 256, 256) from the original photo and down sample it to 106.
+ @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
+ @Override
+ public Bitmap getTile(int level, int x, int y, int tileSize) {
+ if (!ApiHelper.HAS_REUSING_BITMAP_IN_BITMAP_REGION_DECODER) {
+ return getTileWithoutReusingBitmap(level, x, y, tileSize);
+ }
+
+ int t = tileSize << level;
+
+ Rect wantRegion = new Rect(x, y, x + t, y + t);
+
+ boolean needClear;
+ BitmapRegionDecoder regionDecoder = null;
+
+ synchronized (this) {
+ regionDecoder = mRegionDecoder;
+ if (regionDecoder == null) return null;
+
+ // We need to clear a reused bitmap, if wantRegion is not fully
+ // within the image.
+ needClear = !new Rect(0, 0, mImageWidth, mImageHeight)
+ .contains(wantRegion);
+ }
+
+ Bitmap bitmap = GalleryBitmapPool.getInstance().get(tileSize, tileSize);
+ if (bitmap != null) {
+ if (needClear) bitmap.eraseColor(0);
+ } else {
+ bitmap = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888);
+ }
+
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inPreferredConfig = Config.ARGB_8888;
+ options.inPreferQualityOverSpeed = true;
+ options.inSampleSize = (1 << level);
+ options.inBitmap = bitmap;
+
+ try {
+ // In CropImage, we may call the decodeRegion() concurrently.
+ synchronized (regionDecoder) {
+ bitmap = regionDecoder.decodeRegion(wantRegion, options);
+ }
+ } finally {
+ if (options.inBitmap != bitmap && options.inBitmap != null) {
+ GalleryBitmapPool.getInstance().put(options.inBitmap);
+ options.inBitmap = null;
+ }
+ }
+
+ if (bitmap == null) {
+ Log.w(TAG, "fail in decoding region");
+ }
+ return bitmap;
+ }
+
+ private Bitmap getTileWithoutReusingBitmap(
+ int level, int x, int y, int tileSize) {
+ int t = tileSize << level;
+ Rect wantRegion = new Rect(x, y, x + t, y + t);
+
+ BitmapRegionDecoder regionDecoder;
+ Rect overlapRegion;
+
+ synchronized (this) {
+ regionDecoder = mRegionDecoder;
+ if (regionDecoder == null) return null;
+ overlapRegion = new Rect(0, 0, mImageWidth, mImageHeight);
+ Utils.assertTrue(overlapRegion.intersect(wantRegion));
+ }
+
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inPreferredConfig = Config.ARGB_8888;
+ options.inPreferQualityOverSpeed = true;
+ options.inSampleSize = (1 << level);
+ Bitmap bitmap = null;
+
+ // In CropImage, we may call the decodeRegion() concurrently.
+ synchronized (regionDecoder) {
+ bitmap = regionDecoder.decodeRegion(overlapRegion, options);
+ }
+
+ if (bitmap == null) {
+ Log.w(TAG, "fail in decoding region");
+ }
+
+ if (wantRegion.equals(overlapRegion)) return bitmap;
+
+ Bitmap result = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888);
+ Canvas canvas = new Canvas(result);
+ canvas.drawBitmap(bitmap,
+ (overlapRegion.left - wantRegion.left) >> level,
+ (overlapRegion.top - wantRegion.top) >> level, null);
+ return result;
+ }
+
+
+ @Override
+ public ScreenNail getScreenNail() {
+ return mScreenNail;
+ }
+
+ @Override
+ public int getImageHeight() {
+ return mImageHeight;
+ }
+
+ @Override
+ public int getImageWidth() {
+ return mImageWidth;
+ }
+
+ @Override
+ public int getLevelCount() {
+ return mLevelCount;
+ }
+}