blob: 0d20b0757cab67c46015a344e1a88708f5a56359 [file] [log] [blame]
Owen Linf9a0a432011-08-17 22:07:43 +08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.gallery3d.ui;
18
Owen Lined97d582012-07-26 17:16:47 +080019import android.annotation.TargetApi;
Owen Linf9a0a432011-08-17 22:07:43 +080020import android.graphics.Bitmap;
21import android.graphics.Bitmap.Config;
22import android.graphics.BitmapFactory;
23import android.graphics.BitmapRegionDecoder;
Owen Lin30aa9202012-06-27 19:01:21 +080024import android.graphics.Canvas;
Owen Linf9a0a432011-08-17 22:07:43 +080025import android.graphics.Rect;
26
Owen Lin30aa9202012-06-27 19:01:21 +080027import com.android.gallery3d.common.ApiHelper;
Owen Lin1b2cfc12011-10-18 16:57:15 +080028import com.android.gallery3d.common.Utils;
Owen Linc2c0b012012-05-17 15:59:25 -070029import com.android.gallery3d.data.BitmapPool;
Owen Lin1b2cfc12011-10-18 16:57:15 +080030
Your Name6dc38662012-12-04 10:01:41 -080031public class TileImageViewAdapter implements TileImageView.TileSource {
Owen Lin1b2cfc12011-10-18 16:57:15 +080032 private static final String TAG = "TileImageViewAdapter";
Chih-Chung Chang15b351a2012-03-15 16:38:45 +080033 protected ScreenNail mScreenNail;
Chih-Chung Changb8be1e02012-04-17 20:35:14 +080034 protected boolean mOwnScreenNail;
Owen Linf9a0a432011-08-17 22:07:43 +080035 protected BitmapRegionDecoder mRegionDecoder;
36 protected int mImageWidth;
37 protected int mImageHeight;
Owen Linf9a0a432011-08-17 22:07:43 +080038 protected int mLevelCount;
Owen Linf9a0a432011-08-17 22:07:43 +080039
Owen Linf9a0a432011-08-17 22:07:43 +080040 public TileImageViewAdapter() {
41 }
42
Owen Linf9a0a432011-08-17 22:07:43 +080043 public synchronized void clear() {
Owen Lin030f8da2012-10-11 15:50:38 +080044 mScreenNail = null;
Owen Linf9a0a432011-08-17 22:07:43 +080045 mImageWidth = 0;
46 mImageHeight = 0;
47 mLevelCount = 0;
48 mRegionDecoder = null;
Owen Linf9a0a432011-08-17 22:07:43 +080049 }
50
Owen Lin030f8da2012-10-11 15:50:38 +080051 // Caller is responsible to recycle the ScreenNail
Chih-Chung Chang15b351a2012-03-15 16:38:45 +080052 public synchronized void setScreenNail(
53 ScreenNail screenNail, int width, int height) {
Chih-Chung Changb8be1e02012-04-17 20:35:14 +080054 Utils.checkNotNull(screenNail);
Owen Lin030f8da2012-10-11 15:50:38 +080055 mScreenNail = screenNail;
Owen Linf9a0a432011-08-17 22:07:43 +080056 mImageWidth = width;
57 mImageHeight = height;
58 mRegionDecoder = null;
59 mLevelCount = 0;
Owen Linf9a0a432011-08-17 22:07:43 +080060 }
61
62 public synchronized void setRegionDecoder(BitmapRegionDecoder decoder) {
63 mRegionDecoder = Utils.checkNotNull(decoder);
64 mImageWidth = decoder.getWidth();
65 mImageHeight = decoder.getHeight();
66 mLevelCount = calculateLevelCount();
Owen Linf9a0a432011-08-17 22:07:43 +080067 }
68
69 private int calculateLevelCount() {
70 return Math.max(0, Utils.ceilLog2(
Chih-Chung Chang15b351a2012-03-15 16:38:45 +080071 (float) mImageWidth / mScreenNail.getWidth()));
Owen Linf9a0a432011-08-17 22:07:43 +080072 }
73
Owen Linc2c0b012012-05-17 15:59:25 -070074 // Gets a sub image on a rectangle of the current photo. For example,
75 // getTile(1, 50, 50, 100, 3, pool) means to get the region located
76 // at (50, 50) with sample level 1 (ie, down sampled by 2^1) and the
77 // target tile size (after sampling) 100 with border 3.
78 //
79 // From this spec, we can infer the actual tile size to be
80 // 100 + 3x2 = 106, and the size of the region to be extracted from the
81 // photo to be 200 with border 6.
82 //
83 // As a result, we should decode region (50-6, 50-6, 250+6, 250+6) or
84 // (44, 44, 256, 256) from the original photo and down sample it to 106.
Owen Lined97d582012-07-26 17:16:47 +080085 @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
Owen Linf9a0a432011-08-17 22:07:43 +080086 @Override
Your Name6dc38662012-12-04 10:01:41 -080087 public Bitmap getTile(int level, int x, int y, int tileSize, BitmapPool pool) {
Owen Lin30aa9202012-06-27 19:01:21 +080088 if (!ApiHelper.HAS_REUSING_BITMAP_IN_BITMAP_REGION_DECODER) {
Your Name6dc38662012-12-04 10:01:41 -080089 return getTileWithoutReusingBitmap(level, x, y, tileSize);
Owen Lin30aa9202012-06-27 19:01:21 +080090 }
91
Owen Linc2c0b012012-05-17 15:59:25 -070092 int t = tileSize << level;
Chih-Chung Changcb4fb7c2012-03-21 16:19:21 +080093
Your Name6dc38662012-12-04 10:01:41 -080094 Rect wantRegion = new Rect(x, y, x + t, y + t);
Owen Linc2c0b012012-05-17 15:59:25 -070095
96 boolean needClear;
Ray Chen6fc8d722012-05-02 15:31:38 +080097 BitmapRegionDecoder regionDecoder = null;
Owen Linc2c0b012012-05-17 15:59:25 -070098
Ray Chen6fc8d722012-05-02 15:31:38 +080099 synchronized (this) {
100 regionDecoder = mRegionDecoder;
101 if (regionDecoder == null) return null;
Owen Linc2c0b012012-05-17 15:59:25 -0700102
103 // We need to clear a reused bitmap, if wantRegion is not fully
104 // within the image.
105 needClear = !new Rect(0, 0, mImageWidth, mImageHeight)
106 .contains(wantRegion);
Ray Chen6fc8d722012-05-02 15:31:38 +0800107 }
108
Owen Linc2c0b012012-05-17 15:59:25 -0700109 Bitmap bitmap = pool == null ? null : pool.getBitmap();
110 if (bitmap != null) {
111 if (needClear) bitmap.eraseColor(0);
112 } else {
Your Name6dc38662012-12-04 10:01:41 -0800113 bitmap = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888);
Owen Linc2c0b012012-05-17 15:59:25 -0700114 }
Owen Linf9a0a432011-08-17 22:07:43 +0800115
116 BitmapFactory.Options options = new BitmapFactory.Options();
117 options.inPreferredConfig = Config.ARGB_8888;
118 options.inPreferQualityOverSpeed = true;
119 options.inSampleSize = (1 << level);
Owen Linc2c0b012012-05-17 15:59:25 -0700120 options.inBitmap = bitmap;
Owen Linf9a0a432011-08-17 22:07:43 +0800121
Owen Linc2c0b012012-05-17 15:59:25 -0700122 try {
123 // In CropImage, we may call the decodeRegion() concurrently.
124 synchronized (regionDecoder) {
125 bitmap = regionDecoder.decodeRegion(wantRegion, options);
126 }
127 } finally {
128 if (options.inBitmap != bitmap && options.inBitmap != null) {
129 if (pool != null) pool.recycle(options.inBitmap);
130 options.inBitmap = null;
131 }
Owen Linf9a0a432011-08-17 22:07:43 +0800132 }
133
Owen Lin1b2cfc12011-10-18 16:57:15 +0800134 if (bitmap == null) {
135 Log.w(TAG, "fail in decoding region");
Owen Lin1b2cfc12011-10-18 16:57:15 +0800136 }
Owen Linc2c0b012012-05-17 15:59:25 -0700137 return bitmap;
Owen Linf9a0a432011-08-17 22:07:43 +0800138 }
139
Owen Lin30aa9202012-06-27 19:01:21 +0800140 private Bitmap getTileWithoutReusingBitmap(
Your Name6dc38662012-12-04 10:01:41 -0800141 int level, int x, int y, int tileSize) {
Owen Lin30aa9202012-06-27 19:01:21 +0800142 int t = tileSize << level;
Your Name6dc38662012-12-04 10:01:41 -0800143 Rect wantRegion = new Rect(x, y, x + t, y + t);
Owen Lin30aa9202012-06-27 19:01:21 +0800144
145 BitmapRegionDecoder regionDecoder;
146 Rect overlapRegion;
147
148 synchronized (this) {
149 regionDecoder = mRegionDecoder;
150 if (regionDecoder == null) return null;
151 overlapRegion = new Rect(0, 0, mImageWidth, mImageHeight);
152 Utils.assertTrue(overlapRegion.intersect(wantRegion));
153 }
154
155 BitmapFactory.Options options = new BitmapFactory.Options();
156 options.inPreferredConfig = Config.ARGB_8888;
157 options.inPreferQualityOverSpeed = true;
158 options.inSampleSize = (1 << level);
159 Bitmap bitmap = null;
160
161 // In CropImage, we may call the decodeRegion() concurrently.
162 synchronized (regionDecoder) {
163 bitmap = regionDecoder.decodeRegion(overlapRegion, options);
164 }
165
166 if (bitmap == null) {
167 Log.w(TAG, "fail in decoding region");
168 }
169
170 if (wantRegion.equals(overlapRegion)) return bitmap;
171
Your Name6dc38662012-12-04 10:01:41 -0800172 Bitmap result = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888);
Owen Lin30aa9202012-06-27 19:01:21 +0800173 Canvas canvas = new Canvas(result);
174 canvas.drawBitmap(bitmap,
175 (overlapRegion.left - wantRegion.left) >> level,
176 (overlapRegion.top - wantRegion.top) >> level, null);
177 return result;
178 }
179
180
Owen Linf9a0a432011-08-17 22:07:43 +0800181 @Override
Chih-Chung Chang15b351a2012-03-15 16:38:45 +0800182 public ScreenNail getScreenNail() {
183 return mScreenNail;
Owen Linf9a0a432011-08-17 22:07:43 +0800184 }
185
186 @Override
187 public int getImageHeight() {
188 return mImageHeight;
189 }
190
191 @Override
192 public int getImageWidth() {
193 return mImageWidth;
194 }
195
196 @Override
197 public int getLevelCount() {
198 return mLevelCount;
199 }
Owen Linf9a0a432011-08-17 22:07:43 +0800200}