ThumbnailUtils.extractThumbnail Android圖片縮圖顯示總結及比較

Android移動開發者發表於2015-11-10

部落格源址Android圖片縮放總結及比較

部落格時間2011-08-01 17:42

在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.OptionsMatrix等經過人家一陣加工而成。
效率好像比第二種方法高一點點。

下面是我的例子:

  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 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. /**pic大時(2M+)直接OOM,後面還裁剪個屁啊*/
  40.         Bitmap bitmap = BitmapFactory.decodeResource(getResources(),     
  41.                 R.drawable.pic);  
  42.           
  43.         start=System.currentTimeMillis();  
  44.           
  45. //        imView.setImageDrawable(resizeImage(bitmap, 300, 100));   
  46.           
  47.         imView2.setImageDrawable(resizeImage2("/sdcard/2.jpeg"200100));   
  48.           
  49.         stop=System.currentTimeMillis();  
  50.           
  51.         String theTime= String.format("\n1 iterative: (%d msec)",    
  52.                 stop - start);    
  53.           
  54.         start=System.currentTimeMillis();  
  55.         imView.setImageBitmap(ThumbnailUtils.extractThumbnail(bitmap,200,100));//2.2才加進來的新類,簡單易用  
  56. //        imView.setImageDrawable(resizeImage(bitmap, 30, 30));   
  57.         stop=System.currentTimeMillis();  
  58.           
  59.          theTime+= String.format("\n2 iterative: (%d msec)",    
  60.                 stop - start);   
  61.           
  62.         text.setText(theTime);  
  63.     }  
  64.       
  65.     //使用Bitmap加Matrix來縮放  
  66.     public static Drawable resizeImage(Bitmap bitmap, int w, int h)   
  67.     {    
  68.         Bitmap BitmapOrg = bitmap;    
  69.         int width = BitmapOrg.getWidth();    
  70.         int height = BitmapOrg.getHeight();    
  71.         int newWidth = w;    
  72.         int newHeight = h;    
  73.   
  74.         float scaleWidth = ((float) newWidth) / width;    
  75.         float scaleHeight = ((float) newHeight) / height;    
  76.   
  77.         Matrix matrix = new Matrix();    
  78.         matrix.postScale(scaleWidth, scaleHeight);    
  79.         // if you want to rotate the Bitmap     
  80.         // matrix.postRotate(45);     
  81.         Bitmap resizedBitmap = Bitmap.createBitmap(BitmapOrg, 00, width,    
  82.                         height, matrix, true);    
  83.         return new BitmapDrawable(resizedBitmap);    
  84.     }  
  85.       
  86.     //使用BitmapFactory.Options的inSampleSize引數來縮放  
  87.     public static Drawable resizeImage2(String path,  
  88.             int width,int height)   
  89.     {  
  90.         BitmapFactory.Options options = new BitmapFactory.Options();  
  91.         options.inJustDecodeBounds = true;//不載入bitmap到記憶體中  
  92.         BitmapFactory.decodeFile(path,options);   
  93.         int outWidth = options.outWidth;  
  94.         int outHeight = options.outHeight;  
  95.         options.inDither = false;  
  96.         options.inPreferredConfig = Bitmap.Config.ARGB_8888;  
  97.         options.inSampleSize = 1;  
  98.           
  99.         if (outWidth != 0 && outHeight != 0 && width != 0 && height != 0)   
  100.         {  
  101.             int sampleSize=(outWidth/width+outHeight/height)/2;  
  102.             Log.d(tag, "sampleSize = " + sampleSize);  
  103.             options.inSampleSize = sampleSize;  
  104.         }  
  105.       
  106.         options.inJustDecodeBounds = false;  
  107.         return new BitmapDrawable(BitmapFactory.decodeFile(path, options));       
  108.     }  
  109.   
  110.     //圖片儲存  
  111.     private void saveThePicture(Bitmap bitmap)  
  112.     {  
  113.         File file=new File("/sdcard/2.jpeg");  
  114.         try  
  115.         {  
  116.             FileOutputStream fos=new FileOutputStream(file);  
  117.             if(bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos))  
  118.             {  
  119.                 fos.flush();  
  120.                 fos.close();  
  121.             }  
  122.         }  
  123.         catch(FileNotFoundException e1)  
  124.         {  
  125.             e1.printStackTrace();  
  126.         }  
  127.         catch(IOException e2)  
  128.         {  
  129.             e2.printStackTrace();  
  130.         }  
  131.     }  
  132. }  

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

相關文章