Android图片缩放总结及比较


[日期:2011-08-07]

来源:Linux社区  作者:lincyang

[字体:大 中 小]



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等经过人家一阵加工而成。
效率好像比第二种方法高一点点。

下面是我的例子:


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>



 



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. }


android 图片缩小动画效果 android图片缩放_ide


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.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 == nullreturn 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 == nullreturn;  
  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 == nullreturn;  
  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. }  

引用自:http://www.linuxidc.com/Linux/2011-08/40109p2.htm




----------------------------------------------

参考2:


如何为你的Android应用缩放图片



您的评价:

         


  收藏该经验    




android 图片缩小动画效果 android图片缩放_android_02

很难为你的应用程序得到正确的图像缩放吗?是你的图片过大,造成内存问题?还是图片不正确缩放造成不良用户体验的结果?为了寻求一个好的解决方案,我们咨询了Andreas Agvard(索尼爱立信软件部门),让他分享一些关于这方面的经验。

注意:本文没有完整显示出代码示例。你可以下载本文的PDF,来看完整的代码示例。

android 图片缩小动画效果 android图片缩放_android 图片缩小动画效果_03

在索尼爱立信软件部门工作,我经常遇到需要图片缩放的应用,例如:当处理别人或者网络上提供的图片。缩放是必要的,因为通常情况下的图片不是你想要呈现的那样。

典型的例子,如果你正在为你的应用开发一个LiveView™扩展。大多数人开发应用利用LiveView™和其他第二屏幕设备,可能需要重新调整图片,重要的是要保持适当的缩放比例和图像质量。当然,在很多情况下,改变图片尺寸是一个有点困难,但是很有效的途径。

ImageView解决了许多的图片缩放问题,首先,至少你在设置完一个图片源后,不用去解码或缩放图片。但有时需要你自己去解码控制,这是本教程的用武之地。随着本教程,我写了一个代码示例,下载图片缩放代码示例。在文本中呈现的效果,可以通过编译和运行该项目来看到。

孤立的问题 
我做这个教程,是因为我已经有一些实用方法来实现图片的缩放,为了避免最常见的图片缩放问题。如下面的例子:



1

Bitmap unscaledBitmap = BitmapFactory.decodeResource(getResources(), mSourceId);



2

Bitmap scaledBitmap = Bitmap.createScaledBitmap(unscaledBitmap, wantedWidth, wantedHeight, true);



那么在上面的代码中,什么是正确的,什么是错的?让我们来看看在不同的代码行。

行1:整个源图像解码到一个位图。

  • 这可能会导致内存不足的错误,如果图片太大的话。
  • 这可能会导致在一个高分辨率上解码图像。这可能会很慢,但智能解码器可为解码提高性能。
  • 缩放图片很多时候是,高分辨率位图缩放到低分辨率,会导致锯齿的问题。使用位图过滤(例如,通过传送`true`参数到Bitmap.createScaledBitmap(...))减少了锯齿,但是还是不够。

行2:解码的位图缩放到想要的大小。

  • 源图像的尺寸和想要的图像尺寸在长宽比上可能是不一样的。这将导致图像的拉伸。

android 图片缩小动画效果 android图片缩放_android开发_04

左边的图片:原始图像。右边的图片:缩放后图片。可以看出明显的失真问题,如原图的眼睛非常的鲜明,缩放后就没有了。高度出现拉伸。

创建一个解决方案 
我们的解决方案,将有一个结构类似上述代码,其中的一部分将取代行1,这样为缩放做准备。另一部分将取代行2,做最后的缩放。我们将开始替换行2的部分代码,引入两个新的概念,裁剪和合适。

替换行2 
在这一部分,我们将缩放位图到我们所需要的。这一步很必要,因为之前的解码能力是有限的。此外,在这一步为了避免拉伸,我们可能要重新调整图片到想要的大小。

有两种可能性可以避免拉伸。不管是那种,我们都要调整尺寸,以确保他们有相同的宽高比;即缩放图像作为源图像,直到它适合想要的尺寸,或裁剪具有相同的宽高比的源图像为想要的尺寸。

android 图片缩小动画效果 android图片缩放_android开发_05

左边的图片:图像通过fit方法缩放。图片已被缩小到适合的尺寸和高度,结果是小于想要的高度。右边的图像:图像crop方法缩放。图像已被缩放到适应至少想要的尺寸。因此原图已被裁剪,切割了成左边和右边二部分。

为了缩放这样的效果,我们的实现代码如下:



1

publicstatic Bitmap createScaledBitmap(Bitmap unscaledBitmap, int dstWidth, intdstHeight, ScalingLogic scalingLogic) {



2

Rect srcRect = calculateSrcRect(unscaledBitmap.getWidth(), unscaledBitmap.getHeight(), dstWidth, dstHeight, scalingLogic);



3

Rect dstRect = calculateDstRect(unscaledBitmap.getWidth(), unscaledBitmap.getHeight(), dstWidth, dstHeight, scalingLogic);



4

Bitmap scaledBitmap = Bitmap.createBitmap(dstRect.width(), dstRect.height(), Config.ARGB_8888);



5

Canvas canvas = new Canvas(scaledBitmap);



6

canvas.drawBitmap(unscaledBitmap, srcRect, dstRect, newPaint(Paint.FILTER_BITMAP_FLAG));return scaledBitmap;



7

}



在上面的代码,我们使用canvas.drawBitmap(...)做缩放。这种方法的裁剪区域是从源图像的规模面积定义画布的矩形为指定的目标矩形区域。为了避免拉伸,这两个矩形需要有相同的长宽比。我们还调用了两个实用的方法,一个为创建源矩形和另一个为创建目标矩形。方法如下:



01

publicstatic Rect calculateSrcRect(int srcWidth, int srcHeight, int dstWidth, intdstHeight, ScalingLogic scalingLogic) {



02

if (scalingLogic == ScalingLogic.CROP) {



03

finalfloat srcAspect = (float)srcWidth / (float)srcHeight;



04

finalfloat dstAspect = (float)dstWidth / (float)dstHeight;



05

if (srcAspect > dstAspect) {



06

finalint srcRectWidth = (int)(srcHeight * dstAspect);



07

finalint srcRectLeft = (srcWidth - srcRectWidth) / 2;



08

returnnew Rect(srcRectLeft, 0, srcRectLeft + srcRectWidth, srcHeight);



09

else {



10

finalint srcRectHeight = (int)(srcWidth / dstAspect);



11

finalint scrRectTop = (int)(srcHeight - srcRectHeight) / 2;



12

returnnew Rect(0, scrRectTop, srcWidth, scrRectTop + srcRectHeight);



13

}



14

else {



15

returnnew Rect(00, srcWidth, srcHeight);



16

}



17

}



18

publicstatic Rect calculateDstRect(int srcWidth, int srcHeight, int dstWidth, intdstHeight, ScalingLogic scalingLogic) {



19

if (scalingLogic == ScalingLogic.FIT) {



20

finalfloat srcAspect = (float)srcWidth / (float)srcHeight;



21

finalfloat dstAspect = (float)dstWidth / (float)dstHeight;



22

if (srcAspect > dstAspect) {



23

returnnew Rect(00, dstWidth, (int)(dstWidth / srcAspect));



24

else {



25

returnnew Rect(00, (int)(dstHeight * srcAspect), dstHeight);



26

}



27

else {



28

returnnew Rect(00, dstWidth, dstHeight);



29

}



30

}



在刚好合适的情况下源矩形会包含整个源尺寸。在需要裁剪的情况下,它会计算好具有相同宽高比的目标图像,来裁剪源图像的宽度或高度,以达到你想要的尺寸。而刚好在合适的情况下,将有相同宽高比的源图像,调整成你想要的尺寸的宽度或高度。

替换行1 
解码器很智能,特别是用于JPEG和PNG的格式。这些解码器在图片解码时可以进行缩放,并且性能也有所改善,这样锯齿问题也可以避免。此外,由于图片解码后变小了,需要的内存也会较少。

缩放解码的时候,只要简单设置上BitmapFactory.Options对象的inSampleSize参数,并把它传递给BitmapFactory。样本大小指定一个缩放图像大小的抽象因素,例如2是640×480图像在320×240图像上解码的因素。样本大小设置时,你不能保证严格按照这个数字,图像将被缩减,但至少它不会更小。例如,3倍640×480的图像可能会导致在一个320×240图像不支持值。通常情况下,至少2的一次方支持[1,2,4,8,...]。

下一步是指定一个合适的样本大小。合适的样本大小将产生最大的缩放,但仍然是大于等于你想要的图像尺寸。如下面代码:



01

publicstatic Bitmap decodeFile(String pathName, int dstWidth, int dstHeight, ScalingLogic scalingLogic) {



02

Options options = new Options();



03

options.inJustDecodeBounds = true;



04

BitmapFactory.decodeFile(pathName, options);



05

options.inJustDecodeBounds = false;



06

options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, dstWidth, dstHeight, scalingLogic);



07

Bitmap unscaledBitmap = BitmapFactory.decodeFile(pathName, options);



08

return unscaledBitmap;



09

}



10

publicstaticint calculateSampleSize(int srcWidth, int srcHeight, int dstWidth, intdstHeight, ScalingLogic scalingLogic) {



11

if (scalingLogic == ScalingLogic.FIT) {



12

finalfloat srcAspect = (float)srcWidth / (float)srcHeight;



13

finalfloat dstAspect = (float)dstWidth / (float)dstHeight;



14

if (srcAspect > dstAspect) {



15

return srcWidth / dstWidth;



16

else {



17

return srcHeight / dstHeight;



18

}



19

else {



20

finalfloat srcAspect = (float)srcWidth / (float)srcHeight;



21

finalfloat dstAspect = (float)dstWidth / (float)dstHeight;



22

if (srcAspect > dstAspect) {



23

return srcHeight / dstHeight;



24

else {



25

return srcWidth / dstWidth;



26

}



27

}



28

}



在decodeFile(...)方法中,我们解码一个文件进行了最终缩放尺度。这是首先要通过解码源图片尺寸,然后使用calculateSampleSize(...)计算最佳样本大小,最后使用此样本的大小解码图像。如果你有兴趣的话,你可以更深入了解calculateSampleSize(...)方法,但以上方法基本可确保图片进行缩放。

全部放在一起 
根据上面我们指定的方法的,现在可以执行替换最初的代码行:



1

Bitmap unscaledBitmap = decodeFile(pathname, dstWidth, dstHeight, scalingLogic);



2

Bitmap scaledBitmap = createScaledBitmap(unscaledBitmap, dstWidth, dstHeight, scalingLogic);



android 图片缩小动画效果 android图片缩放_android_06

左边的图像:原始解决方案,解码消耗6693 KB的内存和1/4秒左右。结果被拉长失真。中间的图像:同比缩放解决方案,解码消耗418 KB的内存和1/10秒左右。右边的图像:裁剪解决方案,解码消耗418 KB的内存和1/10秒左右。

想要了解更多信息,请下载我们的代码示例。有了这个源码项目,你可以看到你的Android手机上运行的结果。

引用自:http://www.open-open.com/lib/view/open1329994992015.html

---------------------------

参考3:

http://wenku.baidu.com/view/9ab59c0690c69ec3d5bb750e.html

http://wenku.baidu.com/link?url=8LPD7R0QEUHpybZ4xmw5WckufpCOc_N9EZTb9-lo-27aBn12vogDZfSURw-NM3HLseXrGXU1GIyq9vWbId-3P71Elh8nSC_x5hjt6SuV5RS

-----------------------------

参考4:


[Android实例] 图片察看程序,支持缩放,滚动  [复制链接]



| 来自  51CTO网页

[只看他] 楼主









java:
01.package snowfox.android;

02.

03.import android.app.Activity;

04.import android.graphics.Bitmap;

05.import android.graphics.BitmapFactory;

06.import android.graphics.Matrix;

07.import android.graphics.drawable.BitmapDrawable;

08.import android.os.Bundle;

09.import android.util.Log;

10.import android.view.KeyEvent;

11.import android.widget.ImageView;

12.

13.public class MainActivity extends Activity {

14.    /** Called when the activity is first created. */

15.        private ImageView v1;

16.        private int widthOrg, heightOrg, w;

17.        float scale = 1;

18.        float scaleWidth, scaleHeight;

19.        Bitmap OrgMap, newMap;

20.        BitmapDrawable bmd;

21.        Matrix matrix = new Matrix();

22.         @Override

23.    public void onCreate(Bundle savedInstanceState) {

24.        super.onCreate(savedInstanceState);

25.        setContentView(R.layout.main);

26.        v1 = (ImageView)findViewById(R.id.image01);

27.        OrgMap = BitmapFactory.decodeResource(getResources(), R.drawable.test);

28.        widthOrg = OrgMap.getWidth();

29.        heightOrg = OrgMap.getHeight();

30.        //确定图片初始缩放比例,一般以适应屏幕宽度为准

31.        w = 320;        

32.        scale = (float)w/widthOrg;

33.  

34.        matrix = new Matrix();

35.        matrix.postScale(scale, scale);

36.        newMap = Bitmap.createBitmap(OrgMap, 0, 0, widthOrg, heightOrg, matrix, true);

37.        

38.        bmd = new BitmapDrawable(newMap);

39.        v1.setImageDrawable(bmd);

40.    }

41.         @Override

42.        public boolean onKeyDown(int keyCode, KeyEvent event)

43.        {

44.                //放大图片

45.                if(keyCode == KeyEvent.KEYCODE_VOLUME_UP)

46.                {

47.                        //设置放大尺寸,若大于2倍,则停止放大,另外,小于1200是为了防止因图片太大造成内存泄露

48.                        if(scale < 2.0 && w < 1200)

49.                        {

50.                                scale += 0.1;

51.                                matrix.reset();                                                //重置矩阵

52.                                matrix.postScale(scale, scale);                //设置矩阵属性

53.                                //重新绘图

54.                                newMap = Bitmap.createBitmap(OrgMap, 0, 0, widthOrg, heightOrg, matrix, true);

55.                        

56.                                //转化为drawable图像,使其可以显示在imageview中

57.                                bmd = new BitmapDrawable(newMap);

58.                                v1.setImageDrawable(bmd);

59.                                w = newMap.getWidth();

60.                                int h = newMap.getHeight();

61.                                Log.i("ta==========", w + " " +h);

62.                        }

63.                        return true;

64.                }

65.                

66.                //缩小图片

67.                if(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)

68.                {

69.                        //设置缩放尺寸,若小于0.1倍,则停止缩小

70.                        if(scale > 0.1)

71.                        {

72.                                scale -= 0.05;

73.                        

74.                                matrix.reset();                                                //重置矩阵

75.                                matrix.postScale(scale, scale);                //设置矩阵属性

76.                                //重新绘图

77.                                newMap = Bitmap.createBitmap(OrgMap, 0, 0, widthOrg, heightOrg, matrix, true);

78.                        

79.                                //转化为drawable图像,使其可以显示在imageview中

80.                        bmd = new BitmapDrawable(newMap);

81.                        v1.setImageDrawable(bmd);

82.                        

83.                        w = newMap.getWidth();

84.                        int h = newMap.getHeight();

85.                        Log.i("ta==========", w + " " +h);

86.                        }

87.                        return true;

88.                }

89.                else

90.                        return super.onKeyDown(keyCode, event);        //在其他情况下才调用super是为了屏蔽音量按键原来的功能,同时保证其他按键原功能可用

91.        }

92.}
复制代码

01.<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" 

02.    android:layout_width="fill_parent" android:layout_height="fill_parent" 

03.    android:fillViewport="true"> 

04.    <HorizontalScrollView 

05.            android:layout_width = "fill_parent" 

06.            android:layout_height = "fill_parent"

07.            android:fillViewport = "true">

08.            <LinearLayout 

09.                    android:gravity ="center"

10.                    android:orientation="horizontal" 

11.                android:layout_width="fill_parent" android:layout_height="fill_parent"> 

12.                <ImageView

13.                        android:id = "@+id/image01"

14.                        android:layout_width="wrap_content" 

15.                    android:layout_height="wrap_content"

16.                    android:scaleType ="fitCenter"/>

17.                   </LinearLayout> 

18.    </HorizontalScrollView>

19.</ScrollView>
复制代码

引用自:http://bbs.51cto.com/thread-834394-1.html

--------------------------------------

参考5:

SimpleTouchImageView一个支持缩放平移及多点缩放的显示图片的Activi...





收藏人:shaobin0604@163.com 2012-01-12 | 阅:1736  转:0  |  分享   来源  


 


参考6: