Android壓縮圖片到100K以下並保持不失真的高效方法

來源:互聯網
上載者:User

標籤:

在開發Android公司專屬應用程式時,會經常上傳圖片到伺服器,而我們公司目前維護的一個項目便是如此。該項目是通過私人apn與伺服器進行互動的,聯通的還好,但移動的速度實在太慢,客戶在使用軟體的過程中,由於上傳的資訊中可能包含多張圖片,會經常出現上傳圖片失敗的問題,為瞭解決這個問題,我們決定把照片壓縮到100k以下,並且保證圖片不失真(目前圖片經過壓縮後,大約300k左右)。於是我就重新研究了一下Android的圖片壓縮技術。

Android端目錄結構如所示:





使用的第三方庫jar包,如所示:

其中ksoap2-android-xxx.jar是Android用來調用webservice的,gson-xx.jar是把JavaBean轉成Json資料格式的。
本篇部落客要講解圖片壓縮的,核心代碼如下:

 

[java] view plaincopy 
  1. //計算圖片的縮放值  
  2. public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth, int reqHeight) {  
  3.     final int height = options.outHeight;  
  4.     final int width = options.outWidth;  
  5.     int inSampleSize = 1;  
  6.   
  7.     if (height > reqHeight || width > reqWidth) {  
  8.              final int heightRatio = Math.round((float) height/ (float) reqHeight);  
  9.              final int widthRatio = Math.round((float) width / (float) reqWidth);  
  10.              inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;  
  11.     }  
  12.         return inSampleSize;  
  13. }  

 

[java] view plaincopy 
  1. // 根據路徑獲得圖片並壓縮,返回bitmap用於顯示  
  2. public static Bitmap getSmallBitmap(String filePath) {  
  3.         final BitmapFactory.Options options = new BitmapFactory.Options();  
  4.         options.inJustDecodeBounds = true;  
  5.         BitmapFactory.decodeFile(filePath, options);  
  6.   
  7.         // Calculate inSampleSize  
  8.     options.inSampleSize = calculateInSampleSize(options, 480, 800);  
  9.   
  10.         // Decode bitmap with inSampleSize set  
  11.     options.inJustDecodeBounds = false;  
  12.   
  13.     return BitmapFactory.decodeFile(filePath, options);  
  14.     }  

 

[java] view plaincopy 
  1. //把bitmap轉換成String  
  2. public static String bitmapToString(String filePath) {  
  3.   
  4.         Bitmap bm = getSmallBitmap(filePath);  
  5.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  6.         bm.compress(Bitmap.CompressFormat.JPEG, 40, baos);  
  7.         byte[] b = baos.toByteArray();  
  8.         return Base64.encodeToString(b, Base64.DEFAULT);  
  9.     }  

 

 

查看全部源碼,請訪問:
https://github.com/feicien/StudyDemo/tree/master/FileUploadDemo

壓縮原理講解:壓縮一張圖片。我們需要知道這張圖片的原始大小,然後根據我們設定的壓縮比例進行壓縮。
這樣我們就需要做3件事:
1.擷取原始圖片的長和寬

[java] view plaincopy 
  1. BitmapFactory.Options options = new BitmapFactory.Options();  
  2.        options.inJustDecodeBounds = true;  
  3.        BitmapFactory.decodeFile(filePath, options);  
  4.                int height = options.outHeight;  
  5.            int width = options.outWidth;   


以上代碼是對圖片進行解碼,inJustDecodeBounds設定為true,可以不把圖片讀到記憶體中,但依然可以計算出圖片的大小,這正好可以滿足我們第一步的需要。
2.計算壓縮比例

 

[java] view plaincopy 
  1. int height = options.outHeight;  
  2.     int width = options.outWidth;   
  3.     int inSampleSize = 1;  
  4.     int reqHeight=800;  
  5.     int reqWidth=480;  
  6.     if (height > reqHeight || width > reqWidth) {  
  7.    final int heightRatio = Math.round((float) height/ (float) reqHeight);  
  8.    final int widthRatio = Math.round((float) width / (float) reqWidth);              
  9.    inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;  
  10.     }  


一般手機的解析度為 480*800 ,所以我們壓縮後圖片期望的寬頻定為480,高度設為800,這2個值只是期望的寬度與高度,實際上壓縮後的實際寬度也高度會比期望的要大。如果圖片的原始高度或者寬頻大約我們期望的寬頻和高度,我們需要計算出縮放比例的數值。否則就不縮放。heightRatio是圖片原始高度與壓縮後高度的倍數,widthRatio是圖片原始寬度與壓縮後寬度的倍數。inSampleSize為heightRatio與widthRatio中最小的那個,inSampleSize就是縮放值。 inSampleSize為1表示寬度和高度不縮放,為2表示壓縮後的寬度與高度為原來的1/2
3.縮放並壓縮圖片

 

 

[java] view plaincopy 
  1. //在記憶體中建立bitmap對象,這個對象按照縮放大小建立的  
  2.             options.inSampleSize = calculateInSampleSize(options, 480, 800);  
  3.        options.inJustDecodeBounds = false;  
  4.        Bitmap bitmap= BitmapFactory.decodeFile(filePath, options);  
  5.   
  6.        ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  7.        bm.compress(Bitmap.CompressFormat.JPEG, 60, baos);  
  8.        byte[] b = baos.toByteArray();  

 

 

前3行的代碼其實已經得到了一個縮放的bitmap對象,如果你在應用中顯示圖片,就可以使用這個bitmap對象了。由於考慮到網路流量的問題。我們好需要犧牲圖片的品質來換取一部分空間,這裡調用bm.compress()方法進行壓縮,這個方法的第二個參數,如果是100,表示不壓縮,我這裡設定的是60,你也可以更加你的需要進行設定,在實驗的過程中我設定為30,圖片都不會失真。

壓縮效果:本demo可以把1.5M左右的圖片壓縮到100K左右,並且沒有失真。
如下:

更新:

[java] view plaincopy 
  1. /* 
  2. 壓縮圖片,處理某些手機拍照角度旋轉的問題 
  3. */  
  4. public static String compressImage(Context context,String filePath,String fileName,int q) throws FileNotFoundException {  
  5.   
  6.         Bitmap bm = getSmallBitmap(filePath);  
  7.   
  8.         int degree = readPictureDegree(filePath);  
  9.   
  10.         if(degree!=0){//旋轉照片角度  
  11.             bm=rotateBitmap(bm,degree);  
  12.         }  
  13.   
  14.         File imageDir = SDCardUtils.getImageDir(context);  
  15.   
  16.         File outputFile=new File(imageDir,fileName);  
  17.   
  18.         FileOutputStream out = new FileOutputStream(outputFile);  
  19.   
  20.         bm.compress(Bitmap.CompressFormat.JPEG, q, out);  
  21.   
  22.         return outputFile.getPath();  
  23.     }  


判斷照片角度

 

[java] view plaincopy 
  1. public static int readPictureDegree(String path) {  
  2.         int degree = 0;  
  3.         try {  
  4.             ExifInterface exifInterface = new ExifInterface(path);  
  5.             int orientation = exifInterface.getAttributeInt(  
  6.                     ExifInterface.TAG_ORIENTATION,  
  7.                     ExifInterface.ORIENTATION_NORMAL);  
  8.             switch (orientation) {  
  9.             case ExifInterface.ORIENTATION_ROTATE_90:  
  10.                 degree = 90;  
  11.                 break;  
  12.             case ExifInterface.ORIENTATION_ROTATE_180:  
  13.                 degree = 180;  
  14.                 break;  
  15.             case ExifInterface.ORIENTATION_ROTATE_270:  
  16.                 degree = 270;  
  17.                 break;  
  18.             }  
  19.         } catch (IOException e) {  
  20.             e.printStackTrace();  
  21.         }  
  22.         return degree;  
  23.     }  


旋轉照片

 

 

[java] view plaincopy 
    1. public static Bitmap rotateBitmap(Bitmap bitmap,int degress) {  
    2.         if (bitmap != null) {  
    3.             Matrix m = new Matrix();  
    4.             m.postRotate(degress);   
    5.             bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),  
    6.                     bitmap.getHeight(), m, true);  
    7.             return bitmap;  
    8.         }  
    9.         return bitmap;  
    10.     }  

Android壓縮圖片到100K以下並保持不失真的高效方法

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.