TileImageViewAdapter.java revision 6dc3866ac10cc6bf38e73f098fe1988d1a6eecd4
1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/* 2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project 3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License. 6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at 7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software 11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and 14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License. 15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.ui; 18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 19ed97d58f2028938aeb3e49c10ac598cc3e7a28c6Owen Linimport android.annotation.TargetApi; 20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Bitmap; 21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Bitmap.Config; 22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.BitmapFactory; 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.BitmapRegionDecoder; 2430aa92093126f00b46543ae3b5d1035a3270f240Owen Linimport android.graphics.Canvas; 25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Rect; 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 2730aa92093126f00b46543ae3b5d1035a3270f240Owen Linimport com.android.gallery3d.common.ApiHelper; 281b2cfc142830875991dd190f163ad14af66d9e11Owen Linimport com.android.gallery3d.common.Utils; 29c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Linimport com.android.gallery3d.data.BitmapPool; 301b2cfc142830875991dd190f163ad14af66d9e11Owen Lin 316dc3866ac10cc6bf38e73f098fe1988d1a6eecd4Your Namepublic class TileImageViewAdapter implements TileImageView.TileSource { 321b2cfc142830875991dd190f163ad14af66d9e11Owen Lin private static final String TAG = "TileImageViewAdapter"; 3315b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang protected ScreenNail mScreenNail; 34b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang protected boolean mOwnScreenNail; 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected BitmapRegionDecoder mRegionDecoder; 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected int mImageWidth; 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected int mImageHeight; 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected int mLevelCount; 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public TileImageViewAdapter() { 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public synchronized void clear() { 44030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin mScreenNail = null; 45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mImageWidth = 0; 46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mImageHeight = 0; 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLevelCount = 0; 48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRegionDecoder = null; 49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 51030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin // Caller is responsible to recycle the ScreenNail 5215b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang public synchronized void setScreenNail( 5315b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang ScreenNail screenNail, int width, int height) { 54b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang Utils.checkNotNull(screenNail); 55030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin mScreenNail = screenNail; 56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mImageWidth = width; 57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mImageHeight = height; 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRegionDecoder = null; 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLevelCount = 0; 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public synchronized void setRegionDecoder(BitmapRegionDecoder decoder) { 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRegionDecoder = Utils.checkNotNull(decoder); 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mImageWidth = decoder.getWidth(); 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mImageHeight = decoder.getHeight(); 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLevelCount = calculateLevelCount(); 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int calculateLevelCount() { 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return Math.max(0, Utils.ceilLog2( 7115b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang (float) mImageWidth / mScreenNail.getWidth())); 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 74c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin // Gets a sub image on a rectangle of the current photo. For example, 75c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin // getTile(1, 50, 50, 100, 3, pool) means to get the region located 76c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin // at (50, 50) with sample level 1 (ie, down sampled by 2^1) and the 77c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin // target tile size (after sampling) 100 with border 3. 78c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin // 79c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin // From this spec, we can infer the actual tile size to be 80c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin // 100 + 3x2 = 106, and the size of the region to be extracted from the 81c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin // photo to be 200 with border 6. 82c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin // 83c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin // As a result, we should decode region (50-6, 50-6, 250+6, 250+6) or 84c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin // (44, 44, 256, 256) from the original photo and down sample it to 106. 85ed97d58f2028938aeb3e49c10ac598cc3e7a28c6Owen Lin @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) 86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 876dc3866ac10cc6bf38e73f098fe1988d1a6eecd4Your Name public Bitmap getTile(int level, int x, int y, int tileSize, BitmapPool pool) { 8830aa92093126f00b46543ae3b5d1035a3270f240Owen Lin if (!ApiHelper.HAS_REUSING_BITMAP_IN_BITMAP_REGION_DECODER) { 896dc3866ac10cc6bf38e73f098fe1988d1a6eecd4Your Name return getTileWithoutReusingBitmap(level, x, y, tileSize); 9030aa92093126f00b46543ae3b5d1035a3270f240Owen Lin } 9130aa92093126f00b46543ae3b5d1035a3270f240Owen Lin 92c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin int t = tileSize << level; 93c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin 946dc3866ac10cc6bf38e73f098fe1988d1a6eecd4Your Name Rect wantRegion = new Rect(x, y, x + t, y + t); 95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 96c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin boolean needClear; 976fc8d72ce0814a70c74be71fb9d0775b8d7ca768Ray Chen BitmapRegionDecoder regionDecoder = null; 98c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin 996fc8d72ce0814a70c74be71fb9d0775b8d7ca768Ray Chen synchronized (this) { 1006fc8d72ce0814a70c74be71fb9d0775b8d7ca768Ray Chen regionDecoder = mRegionDecoder; 1016fc8d72ce0814a70c74be71fb9d0775b8d7ca768Ray Chen if (regionDecoder == null) return null; 102c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin 103c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin // We need to clear a reused bitmap, if wantRegion is not fully 104c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin // within the image. 105c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin needClear = !new Rect(0, 0, mImageWidth, mImageHeight) 106c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin .contains(wantRegion); 1076fc8d72ce0814a70c74be71fb9d0775b8d7ca768Ray Chen } 1086fc8d72ce0814a70c74be71fb9d0775b8d7ca768Ray Chen 109c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin Bitmap bitmap = pool == null ? null : pool.getBitmap(); 110c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin if (bitmap != null) { 111c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin if (needClear) bitmap.eraseColor(0); 112c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin } else { 1136dc3866ac10cc6bf38e73f098fe1988d1a6eecd4Your Name bitmap = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888); 114c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin } 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin BitmapFactory.Options options = new BitmapFactory.Options(); 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin options.inPreferredConfig = Config.ARGB_8888; 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin options.inPreferQualityOverSpeed = true; 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin options.inSampleSize = (1 << level); 120c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin options.inBitmap = bitmap; 121c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin 122c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin try { 123c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin // In CropImage, we may call the decodeRegion() concurrently. 124c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin synchronized (regionDecoder) { 125c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin bitmap = regionDecoder.decodeRegion(wantRegion, options); 126c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin } 127c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin } finally { 128c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin if (options.inBitmap != bitmap && options.inBitmap != null) { 129c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin if (pool != null) pool.recycle(options.inBitmap); 130c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin options.inBitmap = null; 131c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin } 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1341b2cfc142830875991dd190f163ad14af66d9e11Owen Lin if (bitmap == null) { 1351b2cfc142830875991dd190f163ad14af66d9e11Owen Lin Log.w(TAG, "fail in decoding region"); 136cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 137c2c0b01fbbf243eee1a11c33ba6dd1ce918a9ce5Owen Lin return bitmap; 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 14030aa92093126f00b46543ae3b5d1035a3270f240Owen Lin private Bitmap getTileWithoutReusingBitmap( 1416dc3866ac10cc6bf38e73f098fe1988d1a6eecd4Your Name int level, int x, int y, int tileSize) { 14230aa92093126f00b46543ae3b5d1035a3270f240Owen Lin int t = tileSize << level; 1436dc3866ac10cc6bf38e73f098fe1988d1a6eecd4Your Name Rect wantRegion = new Rect(x, y, x + t, y + t); 14430aa92093126f00b46543ae3b5d1035a3270f240Owen Lin 14530aa92093126f00b46543ae3b5d1035a3270f240Owen Lin BitmapRegionDecoder regionDecoder; 14630aa92093126f00b46543ae3b5d1035a3270f240Owen Lin Rect overlapRegion; 14730aa92093126f00b46543ae3b5d1035a3270f240Owen Lin 14830aa92093126f00b46543ae3b5d1035a3270f240Owen Lin synchronized (this) { 14930aa92093126f00b46543ae3b5d1035a3270f240Owen Lin regionDecoder = mRegionDecoder; 15030aa92093126f00b46543ae3b5d1035a3270f240Owen Lin if (regionDecoder == null) return null; 15130aa92093126f00b46543ae3b5d1035a3270f240Owen Lin overlapRegion = new Rect(0, 0, mImageWidth, mImageHeight); 15230aa92093126f00b46543ae3b5d1035a3270f240Owen Lin Utils.assertTrue(overlapRegion.intersect(wantRegion)); 15330aa92093126f00b46543ae3b5d1035a3270f240Owen Lin } 15430aa92093126f00b46543ae3b5d1035a3270f240Owen Lin 15530aa92093126f00b46543ae3b5d1035a3270f240Owen Lin BitmapFactory.Options options = new BitmapFactory.Options(); 15630aa92093126f00b46543ae3b5d1035a3270f240Owen Lin options.inPreferredConfig = Config.ARGB_8888; 15730aa92093126f00b46543ae3b5d1035a3270f240Owen Lin options.inPreferQualityOverSpeed = true; 15830aa92093126f00b46543ae3b5d1035a3270f240Owen Lin options.inSampleSize = (1 << level); 15930aa92093126f00b46543ae3b5d1035a3270f240Owen Lin Bitmap bitmap = null; 16030aa92093126f00b46543ae3b5d1035a3270f240Owen Lin 16130aa92093126f00b46543ae3b5d1035a3270f240Owen Lin // In CropImage, we may call the decodeRegion() concurrently. 16230aa92093126f00b46543ae3b5d1035a3270f240Owen Lin synchronized (regionDecoder) { 16330aa92093126f00b46543ae3b5d1035a3270f240Owen Lin bitmap = regionDecoder.decodeRegion(overlapRegion, options); 16430aa92093126f00b46543ae3b5d1035a3270f240Owen Lin } 16530aa92093126f00b46543ae3b5d1035a3270f240Owen Lin 16630aa92093126f00b46543ae3b5d1035a3270f240Owen Lin if (bitmap == null) { 16730aa92093126f00b46543ae3b5d1035a3270f240Owen Lin Log.w(TAG, "fail in decoding region"); 16830aa92093126f00b46543ae3b5d1035a3270f240Owen Lin } 16930aa92093126f00b46543ae3b5d1035a3270f240Owen Lin 17030aa92093126f00b46543ae3b5d1035a3270f240Owen Lin if (wantRegion.equals(overlapRegion)) return bitmap; 17130aa92093126f00b46543ae3b5d1035a3270f240Owen Lin 1726dc3866ac10cc6bf38e73f098fe1988d1a6eecd4Your Name Bitmap result = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888); 17330aa92093126f00b46543ae3b5d1035a3270f240Owen Lin Canvas canvas = new Canvas(result); 17430aa92093126f00b46543ae3b5d1035a3270f240Owen Lin canvas.drawBitmap(bitmap, 17530aa92093126f00b46543ae3b5d1035a3270f240Owen Lin (overlapRegion.left - wantRegion.left) >> level, 17630aa92093126f00b46543ae3b5d1035a3270f240Owen Lin (overlapRegion.top - wantRegion.top) >> level, null); 17730aa92093126f00b46543ae3b5d1035a3270f240Owen Lin return result; 17830aa92093126f00b46543ae3b5d1035a3270f240Owen Lin } 17930aa92093126f00b46543ae3b5d1035a3270f240Owen Lin 18030aa92093126f00b46543ae3b5d1035a3270f240Owen Lin 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 18215b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang public ScreenNail getScreenNail() { 18315b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang return mScreenNail; 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getImageHeight() { 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mImageHeight; 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getImageWidth() { 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mImageWidth; 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getLevelCount() { 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mLevelCount; 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 201