Android圖片壓縮

最近項目需求中,有對圖片上傳需求,既不能壓縮過小導致不清晰,又不能原圖上傳,導致上傳過慢,不僅浪費了流量,體驗上也不好

影響圖片大小的一個是圖片質量,一個是圖片像素。壓縮方法無非是,採樣率壓縮和質量壓縮,還有一個是微信壓縮(這個請自行學習,涉及到jni層面)

圖片像素:圖片像素大家應該都知道,不知道的請自行百度。爲了解決大圖片在控件上引起崩潰,我們通常的做法就是修改採樣率,採樣率是什麼?可以簡單理解,它與像素有關。修改採樣率即修改了像素

圖片質量:這個可以理解成圖片的飽和度,感光率等等吧!它很大程度上影響了圖片的大小,但是不能夠無限壓縮,因爲就算質量壓縮沒了,也不會影響像素,這是兩個概念。

那麼在app上傳圖片的時候,如何保證圖片清晰且壓縮的較小?

經過多輪測試,最後得出的結果就是,用長寬比率進行採樣率的等比壓縮,然後進行質量壓縮,循環判斷是否小於100k,如果不是,那麼繼續壓縮,一直到小於100k

附上代碼
這是採樣率的等比壓縮

/**
 * 修改圖片的採樣率
 * @param reqWidth
 * @param reqHeight
 * @return
 */
public static Bitmap decodeSampledBitmapFromData(String imgPath,int reqWidth, int reqHeight) {
   try {
      // 第一次解析將inJustDecodeBounds設置爲true,來獲取圖片大小
       final BitmapFactory.Options options = new BitmapFactory.Options();
       options.inJustDecodeBounds = true;
       BitmapFactory.decodeFile(imgPath, options);

      int minSize = options.outWidth > options.outHeight ? options.outHeight : options.outWidth;
      if (minSize > reqWidth) {
         // 調用上面定義的方法計算inSampleSize值
         options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
      }
       // 使用獲取到的inSampleSize值再次解析圖片
       options.inJustDecodeBounds = false;
       return BitmapFactory.decodeFile(imgPath, options);
   } catch (Exception e) {
      e.printStackTrace();
      return null;
   }
}

/**
 * 計算圖片縮放的比例
 * @param options
 * @param reqWidth
 * @param reqHeight
 * @return
 */
public static int calculateInSampleSize(BitmapFactory.Options options,
   int reqWidth, int reqHeight) {
   // 源圖片的高度和寬度
   final int height = options.outHeight;
   final int width = options.outWidth;
   int inSampleSize = 1;
   if (height > reqHeight || width > reqWidth) {
      // 計算出實際寬高和目標寬高的比率
      final int heightRatio = Math.round((float) height / (float) reqHeight);
      final int widthRatio = Math.round((float) width / (float) reqWidth);
      // 選擇寬和高中最小的比率作爲inSampleSize的值,這樣可以保證最終圖片的寬和高
      // 一定都會大於等於目標的寬和高。
      inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
   }
   return inSampleSize;
}
這是圖片的質量壓縮(借用下別人的代碼)
  1. private Bitmap compressImage(Bitmap image) {  
  2.   
  3.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  4.         image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//質量壓縮方法,這裏100表示不壓縮,把壓縮後的數據存放到baos中  
  5.         int options = 100;  
  6.         while ( baos.toByteArray().length / 1024>100) {  //循環判斷如果壓縮後圖片是否大於100kb,大於繼續壓縮         
  7.             baos.reset();//重置baos即清空baos  
  8.             image.compress(Bitmap.CompressFormat.JPEG, options, baos);//這裏壓縮options%,把壓縮後的數據存放到baos中  
  9.             options -= 10;//每次都減少10  
  10.         }  
  11.         ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把壓縮後的數據baos存放到ByteArrayInputStream中  
  12.         Bitmap bitmap = BitmapFactory.decodeStream(isBm, nullnull);//把ByteArrayInputStream數據生成圖片  
  13.         return bitmap;  
  14.     }  

附一個壓縮後本地保存方法

/**
     * 將壓縮後的圖片寫入sd卡
     *
     */
    public static  String inputPicTosdcard(Bitmap bitmap, String picName) {
        String path = "";
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
//            bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);

            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);//質量壓縮方法,這裏100表示不壓縮,把壓縮後的數據存放到baos中
            int options = 80;
            while ( baos.toByteArray().length / 1024>200) {  //循環判斷如果壓縮後圖片是否大於100kb,大於繼續壓縮
                baos.reset();//重置baos即清空baos
                bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);//這裏壓縮options%,把壓縮後的數據存放到baos中
                if(options>=10){
                    options -= 10;//每次都減少10
                }else {
                    break;
                }
            }

            File SDFile = Environment.getExternalStorageDirectory();
            File destDir = new File(SDFile.getAbsolutePath() + "/文件夾名稱/");//文件目錄

            if (!destDir.exists()) {//判斷目錄是否存在,不存在創建
                destDir.mkdir();//創建目錄
            }
            File pic = new File(destDir.getPath() + File.separator +picName);
            path = pic.getAbsolutePath();
            if (!pic.exists()) {
                try {
                    pic.createNewFile();//創建文件
                    FileOutputStream outputStream = new FileOutputStream(pic, true);
                    outputStream.write(baos.toByteArray());//寫入內容
                    outputStream.close();//關閉流
                } catch (IOException e) {
                    e.printStackTrace();

                }
            }

        }
        return path;

    }

注意:如果光進行質量壓縮,壓縮到一定程度就壓縮不下去了啊!光採樣率壓縮,可能會造成失真啊。

大概能看懂就行,然後根據自己的需求去改。


參照博客:http://blog.csdn.net/maqianli23/article/details/53980798
http://104zz.iteye.com/blog/1694762
http://blog.csdn.net/eiuly/article/details/46648215

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章