在Android中对大图片进行缩放真的很不尽如人意,不知道是不是我的方法不对。下面我列出3种对图片缩放的方法,并给出相应速度。请高人指教。
第一种是BitmapFactory和BitmapFactory.Options。
首先,BitmapFactory.Options有几个Fields很有用:
inJustDecodeBounds:If set to true, the decoder will return null (no bitmap), but the out...
也就是说,当inJustDecodeBounds设成true时,bitmap并不加载到内存,这样效率很高哦。而这时,你可以获得bitmap的高、宽等信息。
outHeight:The resulting height of the bitmap, set independent of the state of inJustDecodeBounds.
outWidth:The resulting width of the bitmap, set independent of the state of inJustDecodeBounds.
看到了吧,上面3个变量是相关联的哦。
inSampleSize :
If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory.
这就是用来做缩放比的。这里有个技巧:
inSampleSize=(outHeight/Height+outWidth/Width)/2
实践证明,这样缩放出来的图片还是很好的。
最后用BitmapFactory.decodeFile(path, options)生成。
由于只是对bitmap加载到内存一次,所以效率比较高。解析速度快。
第二种是使用Bitmap加Matrix来缩放。
首先要获得原bitmap,再从原bitmap的基础上生成新图片。这样效率很低。
第三种是用2.2新加的类ThumbnailUtils来做。
让我们新看看这个类,从API中来看,此类就三个静态方法:createVideoThumbnail、extractThumbnail(Bitmap source, int width, int height, int options)、extractThumbnail(Bitmap source, int width, int height)。
我这里使用了第三个方法。再看看它的源码,下面会附上。是上面我们用到的BitmapFactory.Options和Matrix等经过人家一阵加工而成。
效率好像比第二种方法高一点点。
下面是我的例子:
[html]
view plain
copy
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:orientation="vertical"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. >
7.
8. <ImageView
9. android:id="@+id/imageShow"
10. android:layout_width="wrap_content"
11. android:layout_height="wrap_content"
12. />
13. <ImageView
14. android:id="@+id/image2"
15. android:layout_width="wrap_content"
16. android:layout_height="wrap_content"
17. />
18. <TextView
19. android:id="@+id/text"
20. android:layout_width="fill_parent"
21. android:layout_height="wrap_content"
22. android:text="@string/hello"
23. />
24. </LinearLayout>
[java]
view plain
copy
1. package
2.
3. import
4. import
5. import
6. import
7.
8. import
9. import
10. import
11. import
12. import
13. import
14. import
15. import
16. import
17. import
18. import
19.
20. public class ResolvePicture extends
21. private static String tag="ResolvePicture";
22. Drawable bmImg;
23. ImageView imView;
24. ImageView imView2;
25. TextView text;
26. String theTime;
27. long
28. /** Called when the activity is first created. */
29. @Override
30. public void
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. "/sdcard/2.jpeg", 200, 100));
47.
48. stop=System.currentTimeMillis();
49.
50. "\n1 iterative: (%d msec)",
51. stop - start);
52.
53. start=System.currentTimeMillis();
54. 200,100));//2.2才加进来的新类,简单易用
55. // imView.setImageDrawable(resizeImage(bitmap, 30, 30));
56. stop=System.currentTimeMillis();
57.
58. "\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
66. {
67. Bitmap BitmapOrg = bitmap;
68. int
69. int
70. int
71. int
72.
73. float scaleWidth = ((float) newWidth) / width;
74. float scaleHeight = ((float) newHeight) / height;
75.
76. new
77. matrix.postScale(scaleWidth, scaleHeight);
78. // if you want to rotate the Bitmap
79. // matrix.postRotate(45);
80. 0, 0, width,
81. true);
82. return new
83. }
84.
85. //使用BitmapFactory.Options的inSampleSize参数来缩放
86. public static
87. int width,int
88. {
89. new
90. true;//不加载bitmap到内存中
91. BitmapFactory.decodeFile(path,options);
92. int
93. int
94. false;
95. options.inPreferredConfig = Bitmap.Config.ARGB_8888;
96. 1;
97.
98. if (outWidth != 0 && outHeight != 0 && width != 0 && height != 0)
99. {
100. int sampleSize=(outWidth/width+outHeight/height)/2;
101. "sampleSize = "
102. options.inSampleSize = sampleSize;
103. }
104.
105. false;
106. return new
107. }
108.
109. //图片保存
110. private void
111. {
112. new File("/sdcard/2.jpeg");
113. try
114. {
115. new
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源码:
[java]
view plain
copy
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.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.
17. package
18.
19. import
20. import
21. import
22. import
23. import
24. import
25. import
26. import
27. import
28. import
29. import
30. import
31. import
32. import
33. import
34. import
35. import
36.
37. import
38. import
39. import
40. import
41.
42. /**
43. * Thumbnail generation routines for media provider.
44. */
45.
46. public class
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
91. boolean
92. int
93. ? TARGET_SIZE_MINI_THUMBNAIL
94. : TARGET_SIZE_MICRO_THUMBNAIL;
95. int
96. ? MAX_NUM_PIXELS_THUMBNAIL
97. : MAX_NUM_PIXELS_MICRO_THUMBNAIL;
98. new
99. null;
100. MediaFileType fileType = MediaFile.getFileType(filePath);
101. if (fileType != null
102. createThumbnailFromEXIF(filePath, targetSize, maxPixels, sizedThumbnailBitmap);
103. bitmap = sizedThumbnailBitmap.mBitmap;
104. }
105.
106. if (bitmap == null) {
107. try
108. new
109. new
110. 1;
111. true;
112. null, options);
113. if (options.mCancel || options.outWidth == -1
114. 1) {
115. return null;
116. }
117. options.inSampleSize = computeSampleSize(
118. options, targetSize, maxPixels);
119. false;
120.
121. false;
122. options.inPreferredConfig = Bitmap.Config.ARGB_8888;
123. null, options);
124. catch
125. "", ex);
126. }
127. }
128.
129. if
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
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
146. null;
147. new
148. try
149. retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
150. retriever.setDataSource(filePath);
151. bitmap = retriever.captureFrame();
152. catch
153. // Assume this is a corrupt video file
154. catch
155. // Assume this is a corrupt video file.
156. finally
157. try
158. retriever.release();
159. catch
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
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
180. int width, int
181. return
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
193. int width, int height, int
194. if (source == null) {
195. return null;
196. }
197.
198. float
199. if
200. float) source.getWidth();
201. else
202. float) source.getHeight();
203. }
204. new
205. matrix.setScale(scale, scale);
206. Bitmap thumbnail = transform(matrix, source, width, height,
207. OPTIONS_SCALE_UP | options);
208. return
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
231. int minSideLength, int
232. int
233. maxNumOfPixels);
234.
235. int
236. if (initialSize <= 8
237. 1;
238. while
239. 1;
240. }
241. else
242. 7) / 8 * 8;
243. }
244.
245. return
246. }
247.
248. private static int
249. int minSideLength, int
250. double
251. double
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
260. // return the larger one when there is no overlapping zone.
261. return
262. }
263.
264. if
265. (minSideLength == UNCONSTRAINED)) {
266. return 1;
267. else if
268. return
269. else
270. return
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
283. Uri uri, ContentResolver cr, ParcelFileDescriptor pfd,
284. BitmapFactory.Options options) {
285. null;
286. try
287. if (pfd == null) pfd = makeInputStream(uri, cr);
288. if (pfd == null) return null;
289. if (options == null) options = new
290.
291. FileDescriptor fd = pfd.getFileDescriptor();
292. 1;
293. true;
294. null, options);
295. if (options.mCancel || options.outWidth == -1
296. 1) {
297. return null;
298. }
299. options.inSampleSize = computeSampleSize(
300. options, minSideLength, maxNumOfPixels);
301. false;
302.
303. false;
304. options.inPreferredConfig = Bitmap.Config.ARGB_8888;
305. null, options);
306. catch
307. "Got oom exception ", ex);
308. return null;
309. finally
310. closeSilently(pfd);
311. }
312. return
313. }
314.
315. private static void
316. if (c == null) return;
317. try
318. c.close();
319. catch
320. // do nothing
321. }
322. }
323.
324. private static
325. Uri uri, ContentResolver cr) {
326. try
327. return cr.openFileDescriptor(uri, "r");
328. catch
329. return null;
330. }
331. }
332.
333. /**
334. * Transform source Bitmap to targeted width and height.
335. */
336. private static
337. Bitmap source,
338. int
339. int
340. int
341. boolean scaleUp = (options & OPTIONS_SCALE_UP) != 0;
342. boolean recycle = (options & OPTIONS_RECYCLE_INPUT) != 0;
343.
344. int
345. int
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. new
356.
357. int deltaXHalf = Math.max(0, deltaX / 2);
358. int deltaYHalf = Math.max(0, deltaY / 2);
359. new
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. new
367. dstX,
368. dstY,
369. targetWidth - dstX,
370. targetHeight - dstY);
371. null);
372. if
373. source.recycle();
374. }
375. return
376. }
377. float
378. float
379.
380. float
381. float viewAspect = (float) targetWidth / targetHeight;
382.
383. if
384. float
385. if
386. scaler.setScale(scale, scale);
387. else
388. null;
389. }
390. else
391. float
392. if
393. scaler.setScale(scale, scale);
394. else
395. 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. 0, 0,
403. true);
404. else
405. b1 = source;
406. }
407.
408. if
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. 2,
418. 2,
419. targetWidth,
420. targetHeight);
421.
422. if
423. if
424. b1.recycle();
425. }
426. }
427.
428. return
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
440. public byte[] mThumbnailData;
441. public
442. public int
443. public int
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
452. int
453. if (filePath == null) return;
454.
455. null;
456. byte [] thumbData = null;
457. try
458. new
459. if (exif != null) {
460. thumbData = exif.getThumbnail();
461. }
462. catch
463. Log.w(TAG, ex);
464. }
465.
466. new
467. new
468. int exifThumbWidth = 0;
469. int fullThumbWidth = 0;
470.
471. // Compute exifThumbWidth.
472. if (thumbData != null) {
473. true;
474. 0, thumbData.length, exifOptions);
475. exifOptions.inSampleSize = computeSampleSize(exifOptions, targetSize, maxPixels);
476. exifThumbWidth = exifOptions.outWidth / exifOptions.inSampleSize;
477. }
478.
479. // Compute fullThumbWidth.
480. 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
487. int
488. int
489. false;
490. 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. false;
499. sizedThumbBitmap.mBitmap = BitmapFactory.decodeFile(filePath, fullOptions);
500. }
501. }
502. }