在Android中对大图片进行缩放真的很不尽如人意,不知道是不是我的方法不对。下面我列出3种对图片缩放的方法,并给出相应速度。请高人指教。 首先要获得原bitmap,再从原bitmap的基础上生成新图片。这样效率很低。 第三种是用2.2新加的类ThumbnailUtils来做。 下面是我的例子: 1. version='1.0' encoding='utf-8'?> 2. 3. android:orientation='vertical' 4. android:layout_;fill_parent' 5. android:layout_height='fill_parent' 6. > 7. 8. 9. android:id='@+id/imageShow' 10. android:layout_;wrap_content' 11. android:layout_height='wrap_content' 12. /> 13. 14. android:id='@+id/image2' 15. android:layout_;wrap_content' 16. android:layout_height='wrap_content' 17. /> 18. 19. android:id='@+id/text' 20. android:layout_;fill_parent' 21. android:layout_height='wrap_content' 22. android:text='@string/hello' 23. /> 24. 1. package com.linc.ResolvePicture; 2. 3. import java.io.File; 4. import java.io.FileNotFoundException; 5. import java.io.FileOutputStream; 6. import java.io.IOException; 7. 8. import android.app.Activity; 9. import android.graphics.Bitmap; 10. import android.graphics.BitmapFactory; 11. import android.graphics.Matrix; 12. import android.graphics.drawable.BitmapDrawable; 13. import android.graphics.drawable.Drawable; 14. import android.media.ThumbnailUtils; 15. import android.os.Bundle; 16. import android.util.Log; 17. import android.widget.ImageView; 18. import android.widget.TextView; 19. 20. public class ResolvePicture extends Activity { 21. private static String tag='ResolvePicture'; 22. Drawable bmImg; 23. ImageView imView; 24. ImageView imView2; 25. TextView text; 26. String theTime; 27. long start, stop; 28. /** Called when the activity is first created. */ 29. @Override 30. public void onCreate(Bundle savedInstanceState) { 31. super.onCreate(savedInstanceState); 32. setContentView(R.layout.main); 33. 34. text=(TextView)findViewById(R.id.text); 35. 36. imView=(ImageView) findViewById(R.id.imageShow); 37. imView2=(ImageView) findViewById(R.id.image2); 38. 39. Bitmap bitmap = BitmapFactory.decodeResource(getResources(), 40. R.drawable.pic); 41. 42. start=System.currentTimeMillis(); 43. 44. // imView.setImageDrawable(resizeImage(bitmap, 300, 100)); 45. 46. imView2.setImageDrawable(resizeImage2('/sdcard/2.jpeg', 200, 100)); 47. 48. stop=System.currentTimeMillis(); 49. 50. String theTime= String.format('\n1 iterative: (%d msec)', 51. stop - start); 52. 53. start=System.currentTimeMillis(); 54. imView.setImageBitmap(ThumbnailUtils.extractThumbnail(bitmap,200,100));//2.2才加进来的新类,简单易用 55. // imView.setImageDrawable(resizeImage(bitmap, 30, 30)); 56. stop=System.currentTimeMillis(); 57. 58. theTime+= String.format('\n2 iterative: (%d msec)', 59. stop - start); 60. 61. text.setText(theTime); 62. } 63. 64. //使用Bitmap加Matrix来缩放 65. public static Drawable resizeImage(Bitmap bitmap, int w, int h) 66. { 67. Bitmap BitmapOrg = bitmap; 68. int width = BitmapOrg.getWidth(); 69. int height = BitmapOrg.getHeight(); 70. int newWidth = w; 71. int newHeight = h; 72. 73. float scaleWidth = ((float) newWidth) / width; 74. float scaleHeight = ((float) newHeight) / height; 75. 76. Matrix matrix = new Matrix(); 77. matrix.postScale(scaleWidth, scaleHeight); 78. // if you want to rotate the Bitmap 79. // matrix.postRotate(45); 80. Bitmap resizedBitmap = Bitmap.createBitmap(BitmapOrg, 0, 0, width, 81. height, matrix, true); 82. return new BitmapDrawable(resizedBitmap); 83. } 84. 85. //使用BitmapFactory.Options的inSampleSize参数来缩放 86. public static Drawable resizeImage2(String path, 87. int width,int height) 88. { 89. BitmapFactory.Options options = new BitmapFactory.Options(); 90. options.inJustDecodeBounds = true;//不加载bitmap到内存中 91. BitmapFactory.decodeFile(path,options); 92. int outWidth = options.outWidth; 93. int outHeight = options.outHeight; 94. options.inDither = false; 95. options.inPreferredConfig = Bitmap.Config.ARGB_8888; 96. options.inSampleSize = 1; 97. 98. if (outWidth != 0 && outHeight != 0 && width != 0 && height != 0) 99. { 100. int sampleSize=(outWidth/width+outHeight/height)/2; 101. Log.d(tag, 'sampleSize = ' + sampleSize); 102. options.inSampleSize = sampleSize; 103. } 104. 105. options.inJustDecodeBounds = false; 106. return new BitmapDrawable(BitmapFactory.decodeFile(path, options)); 107. } 108. 109. //图片保存 110. private void saveThePicture(Bitmap bitmap) 111. { 112. File file=new File('/sdcard/2.jpeg'); 113. try 114. { 115. FileOutputStream fos=new FileOutputStream(file); 116. if(bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos)) 117. { 118. fos.flush(); 119. fos.close(); 120. } 121. } 122. catch(FileNotFoundException e1) 123. { 124. e1.printStackTrace(); 125. } 126. catch(IOException e2) 127. { 128. e2.printStackTrace(); 129. } 130. } 131. } ThumbnailUtils源码: 1. /* 2. * Copyright (C) 2009 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./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. 17. package android.media; 18. 19. import android.content.ContentResolver; 20. import android.content.ContentUris; 21. import android.content.ContentValues; 22. import android.database.Cursor; 23. import android.graphics.Bitmap; 24. import android.graphics.BitmapFactory; 25. import android.graphics.Canvas; 26. import android.graphics.Matrix; 27. import android.graphics.Rect; 28. import android.media.MediaMetadataRetriever; 29. import android.media.MediaFile.MediaFileType; 30. import android.net.Uri; 31. import android.os.ParcelFileDescriptor; 32. import android.provider.BaseColumns; 33. import android.provider.MediaStore.Images; 34. import android.provider.MediaStore.Images.Thumbnails; 35. import android.util.Log; 36. 37. import java.io.FileInputStream; 38. import java.io.FileDescriptor; 39. import java.io.IOException; 40. import java.io.OutputStream; 41. 42. /** 43. * Thumbnail generation routines for media provider. 44. */ 45. 46. public class ThumbnailUtils { 47. private static final String TAG = 'ThumbnailUtils'; 48. 49. /* Maximum pixels size for created bitmap. */ 50. private static final int MAX_NUM_PIXELS_THUMBNAIL = 512 * 384; 51. private static final int MAX_NUM_PIXELS_MICRO_THUMBNAIL = 128 * 128; 52. private static final int UNCONSTRAINED = -1; 53. 54. /* Options used internally. */ 55. private static final int OPTIONS_NONE = 0x0; 56. private static final int OPTIONS_SCALE_UP = 0x1; 57. 58. /** 59. * Constant used to indicate we should recycle the input in 60. * {@link #extractThumbnail(Bitmap, int, int, int)} unless the output is the input. 61. */ 62. public static final int OPTIONS_RECYCLE_INPUT = 0x2; 63. 64. /** 65. * Constant used to indicate the dimension of mini thumbnail. 66. * @hide Only used by media framework and media provider internally. 67. */ 68. public static final int TARGET_SIZE_MINI_THUMBNAIL = 320; 69. 70. /** 71. * Constant used to indicate the dimension of micro thumbnail. 72. * @hide Only used by media framework and media provider internally. 73. */ 74. public static final int TARGET_SIZE_MICRO_THUMBNAIL = 96; 75. 76. /** 77. * This method first examines if the thumbnail embedded in EXIF is bigger than our target 78. * size. If not, then it'll create a thumbnail from original image. Due to efficiency 79. * consideration, we want to let MediaThumbRequest avoid calling this method twice for 80. * both kinds, so it only requests for MICRO_KIND and set saveImage to true. 81. * 82. * This method always returns a 'square thumbnail' for MICRO_KIND thumbnail. 83. * 84. * @param filePath the path of image file 85. * @param kind could be MINI_KIND or MICRO_KIND 86. * @return Bitmap 87. * 88. * @hide This method is only used by media framework and media provider internally. 89. */ 90. public static Bitmap createImageThumbnail(String filePath, int kind) { 91. boolean wantMini = (kind == Images.Thumbnails.MINI_KIND); 92. int targetSize = wantMini 93. ? TARGET_SIZE_MINI_THUMBNAIL 94. : TARGET_SIZE_MICRO_THUMBNAIL; 95. int maxPixels = wantMini 96. ? MAX_NUM_PIXELS_THUMBNAIL 97. : MAX_NUM_PIXELS_MICRO_THUMBNAIL; 98. SizedThumbnailBitmap sizedThumbnailBitmap = new SizedThumbnailBitmap(); 99. Bitmap bitmap = null; 100. MediaFileType fileType = MediaFile.getFileType(filePath); 101. if (fileType != null && fileType.fileType == MediaFile.FILE_TYPE_JPEG) { 102. createThumbnailFromEXIF(filePath, targetSize, maxPixels, sizedThumbnailBitmap); 103. bitmap = sizedThumbnailBitmap.mBitmap; 104. } 105. 106. if (bitmap == null) { 107. try { 108. FileDescriptor fd = new FileInputStream(filePath).getFD(); 109. BitmapFactory.Options options = new BitmapFactory.Options(); 110. options.inSampleSize = 1; 111. options.inJustDecodeBounds = true; 112. BitmapFactory.decodeFileDescriptor(fd, null, options); 113. if (options.mCancel || options.outWidth == -1 114. || options.outHeight == -1) { 115. return null; 116. } 117. options.inSampleSize = computeSampleSize( 118. options, targetSize, maxPixels); 119. options.inJustDecodeBounds = false; 120. 121. options.inDither = false; 122. options.inPreferredConfig = Bitmap.Config.ARGB_8888; 123. bitmap = BitmapFactory.decodeFileDescriptor(fd, null, options); 124. } catch (IOException ex) { 125. Log.e(TAG, '', ex); 126. } 127. } 128. 129. if (kind == Images.Thumbnails.MICRO_KIND) { 130. // now we make it a 'square thumbnail' for MICRO_KIND thumbnail 131. bitmap = extractThumbnail(bitmap, 132. TARGET_SIZE_MICRO_THUMBNAIL, 133. TARGET_SIZE_MICRO_THUMBNAIL, OPTIONS_RECYCLE_INPUT); 134. } 135. return bitmap; 136. } 137. 138. /** 139. * Create a video thumbnail for a video. May return null if the video is 140. * corrupt or the format is not supported. 141. * 142. * @param filePath the path of video file 143. * @param kind could be MINI_KIND or MICRO_KIND 144. */ 145. public static Bitmap createVideoThumbnail(String filePath, int kind) { 146. Bitmap bitmap = null; 147. MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 148. try { 149. retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY); 150. retriever.setDataSource(filePath); 151. bitmap = retriever.captureFrame(); 152. } catch (IllegalArgumentException ex) { 153. // Assume this is a corrupt video file 154. } catch (RuntimeException ex) { 155. // Assume this is a corrupt video file. 156. } finally { 157. try { 158. retriever.release(); 159. } catch (RuntimeException ex) { 160. // Ignore failures while cleaning up. 161. } 162. } 163. if (kind == Images.Thumbnails.MICRO_KIND && bitmap != null) { 164. bitmap = extractThumbnail(bitmap, 165. TARGET_SIZE_MICRO_THUMBNAIL, 166. TARGET_SIZE_MICRO_THUMBNAIL, 167. OPTIONS_RECYCLE_INPUT); 168. } 169. return bitmap; 170. } 171. 172. /** 173. * Creates a centered bitmap of the desired size. 174. * 175. * @param source original bitmap source 176. * @param width targeted width 177. * @param height targeted height 178. */ 179. public static Bitmap extractThumbnail( 180. Bitmap source, int width, int height) { 181. return extractThumbnail(source, width, height, OPTIONS_NONE); 182. } 183. 184. /** 185. * Creates a centered bitmap of the desired size. 186. * 187. * @param source original bitmap source 188. * @param width targeted width 189. * @param height targeted height 190. * @param options options used during thumbnail extraction 191. */ 192. public static Bitmap extractThumbnail( 193. Bitmap source, int width, int height, int options) { 194. if (source == null) { 195. return null; 196. } 197. 198. float scale; 199. if (source.getWidth() < source.getHeight()) { 200. scale = width / (float) source.getWidth(); 201. } else { 202. scale = height / (float) source.getHeight(); 203. } 204. Matrix matrix = new Matrix(); 205. matrix.setScale(scale, scale); 206. Bitmap thumbnail = transform(matrix, source, width, height, 207. OPTIONS_SCALE_UP | options); 208. return thumbnail; 209. } 210. 211. /* 212. * Compute the sample size as a function of minSideLength 213. * and maxNumOfPixels. 214. * minSideLength is used to specify that minimal width or height of a 215. * bitmap. 216. * maxNumOfPixels is used to specify the maximal size in pixels that is 217. * tolerable in terms of memory usage. 218. * 219. * The function returns a sample size based on the constraints. 220. * Both size and minSideLength can be passed in as IImage.UNCONSTRAINED, 221. * which indicates no care of the corresponding constraint. 222. * The functions prefers returning a sample size that 223. * generates a smaller bitmap, unless minSideLength = IImage.UNCONSTRAINED. 224. * 225. * Also, the function rounds up the sample size to a power of 2 or multiple 226. * of 8 because BitmapFactory only honors sample size this way. 227. * For example, BitmapFactory downsamples an image by 2 even though the 228. * request is 3. So we round up the sample size to avoid OOM. 229. */ 230. private static int computeSampleSize(BitmapFactory.Options options, 231. int minSideLength, int maxNumOfPixels) { 232. int initialSize = computeInitialSampleSize(options, minSideLength, 233. maxNumOfPixels); 234. 235. int roundedSize; 236. if (initialSize <= 8 ) { 237. roundedSize = 1; 238. while (roundedSize < initialSize) { 239. roundedSize <<= 1; 240. } 241. } else { 242. roundedSize = (initialSize + 7) / 8 * 8; 243. } 244. 245. return roundedSize; 246. } 247. 248. private static int computeInitialSampleSize(BitmapFactory.Options options, 249. int minSideLength, int maxNumOfPixels) { 250. double w = options.outWidth; 251. double h = options.outHeight; 252. 253. int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 : 254. (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels)); 255. int upperBound = (minSideLength == UNCONSTRAINED) ? 128 : 256. (int) Math.min(Math.floor(w / minSideLength), 257. Math.floor(h / minSideLength)); 258. 259. if (upperBound < lowerBound) { 260. // return the larger one when there is no overlapping zone. 261. return lowerBound; 262. } 263. 264. if ((maxNumOfPixels == UNCONSTRAINED) && 265. (minSideLength == UNCONSTRAINED)) { 266. return 1; 267. } else if (minSideLength == UNCONSTRAINED) { 268. return lowerBound; 269. } else { 270. return upperBound; 271. } 272. } 273. 274. /** 275. * Make a bitmap from a given Uri, minimal side length, and maximum number of pixels. 276. * The image data will be read from specified pfd if it's not null, otherwise 277. * a new input stream will be created using specified ContentResolver. 278. * 279. * Clients are allowed to pass their own BitmapFactory.Options used for bitmap decoding. A 280. * new BitmapFactory.Options will be created if options is null. 281. */ 282. private static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, 283. Uri uri, ContentResolver cr, ParcelFileDescriptor pfd, 284. BitmapFactory.Options options) { 285. Bitmap b = null; 286. try { 287. if (pfd == null) pfd = makeInputStream(uri, cr); 288. if (pfd == null) return null; 289. if (options == null) options = new BitmapFactory.Options(); 290. 291. FileDescriptor fd = pfd.getFileDescriptor(); 292. options.inSampleSize = 1; 293. options.inJustDecodeBounds = true; 294. BitmapFactory.decodeFileDescriptor(fd, null, options); 295. if (options.mCancel || options.outWidth == -1 296. || options.outHeight == -1) { 297. return null; 298. } 299. options.inSampleSize = computeSampleSize( 300. options, minSideLength, maxNumOfPixels); 301. options.inJustDecodeBounds = false; 302. 303. options.inDither = false; 304. options.inPreferredConfig = Bitmap.Config.ARGB_8888; 305. b = BitmapFactory.decodeFileDescriptor(fd, null, options); 306. } catch (OutOfMemoryError ex) { 307. Log.e(TAG, 'Got oom exception ', ex); 308. return null; 309. } finally { 310. closeSilently(pfd); 311. } 312. return b; 313. } 314. 315. private static void closeSilently(ParcelFileDescriptor c) { 316. if (c == null) return; 317. try { 318. c.close(); 319. } catch (Throwable t) { 320. // do nothing 321. } 322. } 323. 324. private static ParcelFileDescriptor makeInputStream( 325. Uri uri, ContentResolver cr) { 326. try { 327. return cr.openFileDescriptor(uri, 'r'); 328. } catch (IOException ex) { 329. return null; 330. } 331. } 332. 333. /** 334. * Transform source Bitmap to targeted width and height. 335. */ 336. private static Bitmap transform(Matrix scaler, 337. Bitmap source, 338. int targetWidth, 339. int targetHeight, 340. int options) { 341. boolean scaleUp = (options & OPTIONS_SCALE_UP) != 0; 342. boolean recycle = (options & OPTIONS_RECYCLE_INPUT) != 0; 343. 344. int deltaX = source.getWidth() - targetWidth; 345. int deltaY = source.getHeight() - targetHeight; 346. if (!scaleUp && (deltaX < 0 || deltaY < 0)) { 347. /* 348. * In this case the bitmap is smaller, at least in one dimension, 349. * than the target. Transform it by placing as much of the image 350. * as possible into the target and leaving the top/bottom or 351. * left/right (or both) black. 352. */ 353. Bitmap b2 = Bitmap.createBitmap(targetWidth, targetHeight, 354. Bitmap.Config.ARGB_8888); 355. Canvas c = new Canvas(b2); 356. 357. int deltaXHalf = Math.max(0, deltaX / 2); 358. int deltaYHalf = Math.max(0, deltaY / 2); 359. Rect src = new Rect( 360. deltaXHalf, 361. deltaYHalf, 362. deltaXHalf + Math.min(targetWidth, source.getWidth()), 363. deltaYHalf + Math.min(targetHeight, source.getHeight())); 364. int dstX = (targetWidth - src.width()) / 2; 365. int dstY = (targetHeight - src.height()) / 2; 366. Rect dst = new Rect( 367. dstX, 368. dstY, 369. targetWidth - dstX, 370. targetHeight - dstY); 371. c.drawBitmap(source, src, dst, null); 372. if (recycle) { 373. source.recycle(); 374. } 375. return b2; 376. } 377. float bitmapWidthF = source.getWidth(); 378. float bitmapHeightF = source.getHeight(); 379. 380. float bitmapAspect = bitmapWidthF / bitmapHeightF; 381. float viewAspect = (float) targetWidth / targetHeight; 382. 383. if (bitmapAspect > viewAspect) { 384. float scale = targetHeight / bitmapHeightF; 385. if (scale < .9F || scale > 1F) { 386. scaler.setScale(scale, scale); 387. } else { 388. scaler = null; 389. } 390. } else { 391. float scale = targetWidth / bitmapWidthF; 392. if (scale < .9F || scale > 1F) { 393. scaler.setScale(scale, scale); 394. } else { 395. scaler = null; 396. } 397. } 398. 399. Bitmap b1; 400. if (scaler != null) { 401. // this is used for minithumb and crop, so we want to filter here. 402. b1 = Bitmap.createBitmap(source, 0, 0, 403. source.getWidth(), source.getHeight(), scaler, true); 404. } else { 405. b1 = source; 406. } 407. 408. if (recycle && b1 != source) { 409. source.recycle(); 410. } 411. 412. int dx1 = Math.max(0, b1.getWidth() - targetWidth); 413. int dy1 = Math.max(0, b1.getHeight() - targetHeight); 414. 415. Bitmap b2 = Bitmap.createBitmap( 416. b1, 417. dx1 / 2, 418. dy1 / 2, 419. targetWidth, 420. targetHeight); 421. 422. if (b2 != b1) { 423. if (recycle || b1 != source) { 424. b1.recycle(); 425. } 426. } 427. 428. return b2; 429. } 430. 431. /** 432. * SizedThumbnailBitmap contains the bitmap, which is downsampled either from 433. * the thumbnail in exif or the full image. 434. * mThumbnailData, mThumbnailWidth and mThumbnailHeight are set together only if mThumbnail 435. * is not null. 436. * 437. * The width/height of the sized bitmap may be different from mThumbnailWidth/mThumbnailHeight. 438. */ 439. private static class SizedThumbnailBitmap { 440. public byte[] mThumbnailData; 441. public Bitmap mBitmap; 442. public int mThumbnailWidth; 443. public int mThumbnailHeight; 444. } 445. 446. /** 447. * Creates a bitmap by either downsampling from the thumbnail in EXIF or the full image. 448. * The functions returns a SizedThumbnailBitmap, 449. * which contains a downsampled bitmap and the thumbnail data in EXIF if exists. 450. */ 451. private static void createThumbnailFromEXIF(String filePath, int targetSize, 452. int maxPixels, SizedThumbnailBitmap sizedThumbBitmap) { 453. if (filePath == null) return; 454. 455. ExifInterface exif = null; 456. byte [] thumbData = null; 457. try { 458. exif = new ExifInterface(filePath); 459. if (exif != null) { 460. thumbData = exif.getThumbnail(); 461. } 462. } catch (IOException ex) { 463. Log.w(TAG, ex); 464. } 465. 466. BitmapFactory.Options fullOptions = new BitmapFactory.Options(); 467. BitmapFactory.Options exifOptions = new BitmapFactory.Options(); 468. int exifThumbWidth = 0; 469. int fullThumbWidth = 0; 470. 471. // Compute exifThumbWidth. 472. if (thumbData != null) { 473. exifOptions.inJustDecodeBounds = true; 474. BitmapFactory.decodeByteArray(thumbData, 0, thumbData.length, exifOptions); 475. exifOptions.inSampleSize = computeSampleSize(exifOptions, targetSize, maxPixels); 476. exifThumbWidth = exifOptions.outWidth / exifOptions.inSampleSize; 477. } 478. 479. // Compute fullThumbWidth. 480. fullOptions.inJustDecodeBounds = true; 481. BitmapFactory.decodeFile(filePath, fullOptions); 482. fullOptions.inSampleSize = computeSampleSize(fullOptions, targetSize, maxPixels); 483. fullThumbWidth = fullOptions.outWidth / fullOptions.inSampleSize; 484. 485. // Choose the larger thumbnail as the returning sizedThumbBitmap. 486. if (thumbData != null && exifThumbWidth >= fullThumbWidth) { 487. int width = exifOptions.outWidth; 488. int height = exifOptions.outHeight; 489. exifOptions.inJustDecodeBounds = false; 490. sizedThumbBitmap.mBitmap = BitmapFactory.decodeByteArray(thumbData, 0, 491. thumbData.length, exifOptions); 492. if (sizedThumbBitmap.mBitmap != null) { 493. sizedThumbBitmap.mThumbnailData = thumbData; 494. sizedThumbBitmap.mThumbnailWidth = width; 495. sizedThumbBitmap.mThumbnailHeight = height; 496. } 497. } else { 498. fullOptions.inJustDecodeBounds = false; 499. sizedThumbBitmap.mBitmap = BitmapFactory.decodeFile(filePath, fullOptions); 500. } 501. } 502. } |
|
来自: Elaine个人小馆 > 《待分类》