Android-圖片的壓縮(質量壓縮和尺寸壓縮)

複習一下圖片的壓縮知識,今天來做一個總結。 參考:https://blog.csdn.net/baidu_38477614/article/details/78901107

理論概括

1.圖片存在的幾種形式:

  • File,存在於我們的磁盤中,我們通常說的圖片大小。
  • Stream即流的形式,比如我們上傳網絡圖片。
  • Bitmap,就是我們通常指內存中圖片的大小。

2. 什麼是質量壓縮?

圖片的質量壓縮,會改變圖片在磁盤中的大小(File文件的大小),不能改變圖片在加載時,在內存中的大小。 原理是:通過算法扣掉(同化)了 圖片中的一些某個點附近相近的像素,達到降低質量 減少 文件大小的目的。 應用場景:圖片的上傳。

3.什麼是尺寸壓縮?

圖片的尺寸壓縮是指:按照一定的倍數對圖片減少單位尺寸的像素值,可以改變圖片在內存中的大小,不改變圖片在磁盤中的大小。 原理是:通過減少單位尺寸的像素值,真正意義上的降低像素值。 應用場景:用戶頭像的縮略圖。

實戰

我們的界面也很簡單,就是兩個按鈕,分別是拍照和相冊選擇,一個ImageView,用來顯示壓縮後的圖片,如圖:

image.png

由於我們這裏只講圖片的壓縮,關於再次之前如何獲取圖片返回的URI和高低版本適配7.0等問題,我們這裏不說,我之前寫過文章,Android-圖片的選擇,裁剪,壓縮,適配高版本,這裏就不說了。 我們直接從圖片獲取到拍照或者相冊返回的URI開始說起,上圖:

image.png

質量壓縮

那我們就先看bitmapCompress()這個質量壓縮的方法。

/**
     * 這裏我們生成了一個Pic文件夾,在下面放了我們質量壓縮後的圖片,用於和原圖對比
     * 壓縮圖片使用Bitmap.compress(),這裏是質量壓縮
     */
    public void bitmapCompress(Uri uriClipUri) {
        try {
            //裁剪後的圖像轉成BitMap
            //photoBitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uriClipUri));
            photoBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uriClipUri);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //創建路徑
        String path = Environment.getExternalStorageDirectory()
                .getPath() + "/Pic";
        //獲取外部儲存目錄
        file = new File(path);
        //創建新目錄, 創建此抽象路徑名指定的目錄,包括創建必需但不存在的父目錄。
        file.mkdirs();
        //以當前時間重新命名文件
        long i = System.currentTimeMillis();
        //生成新的文件
        file = new File(file.toString() + "/" + i + ".png");
        Log.e("fileNew", file.getPath());
        //創建輸出流
        OutputStream out = null;
        try {
            out = new FileOutputStream(file.getPath());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        //壓縮文件,返回結果,參數分別是壓縮的格式,壓縮質量的百分比,輸出流
        boolean bCompress = photoBitmap.compress(Bitmap.CompressFormat.JPEG, 50, out);

        try {
            photoBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),Uri.fromFile(file));
        } catch (IOException e) {
            e.printStackTrace();
        }
        imageView.setImageBitmap(photoBitmap);
    }

我們看一眼結果: 結果是Imageview沒有正常加載圖片,怎麼回事?難道圖片沒有生成,文件創建失敗? 我們看一眼原圖片和壓縮目錄(Pic)下有沒有文件: 原文件:

壓縮後的文件:

可以看到原文件和壓縮後的文件都生成了,而且也從6.61M壓縮爲了1.52M,那爲什麼圖片不正常顯示呢?,在看一眼日誌:

image.png

大家明白了吧,這個結果也和我們之前說的質量壓縮只是改變磁盤中的文件大小,並不能改變加載時內存中的圖片大小

尺寸壓縮

尺寸壓縮的方法:

 Bitmap photoBitmap;
    File file;
    /**
     * 壓縮圖片使用,採用BitmapFactory.decodeFile。這裏是尺寸壓縮
     */

    public void bitmapFactory(Uri imageUri){
        String[] filePathColumns = {MediaStore.Images.Media.DATA};
        Cursor c = getContentResolver().query(imageUri, filePathColumns, null, null, null);
        c.moveToFirst();
        int columnIndex = c.getColumnIndex(filePathColumns[0]);
        String imagePath = c.getString(columnIndex);
        c.close();

        // 配置壓縮的參數
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true; //獲取當前圖片的邊界大小,而不是將整張圖片載入在內存中,避免內存溢出
        BitmapFactory.decodeFile(imagePath, options);
        options.inJustDecodeBounds = false;
        ////inSampleSize的作用就是可以把圖片的長短縮小inSampleSize倍,所佔內存縮小inSampleSize的平方
        options.inSampleSize = caculateSampleSize(options,500,50);
        Bitmap bm = BitmapFactory.decodeFile(imagePath, options); // 解碼文件
        imageView.setImageBitmap(bm);
    }

    /**
     * 計算出所需要壓縮的大小
     * @param options
     * @param reqWidth  我們期望的圖片的寬,單位px
     * @param reqHeight 我們期望的圖片的高,單位px
     * @return
     */
    private int caculateSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        int sampleSize = 1;
        int picWidth = options.outWidth;
        int picHeight = options.outHeight;
        if (picWidth > reqWidth || picHeight > reqHeight) {
            int halfPicWidth = picWidth / 2;
            int halfPicHeight = picHeight / 2;
            while (halfPicWidth / sampleSize > reqWidth || halfPicHeight / sampleSize > reqHeight) {
                sampleSize *= 2;
            }
        }
        return sampleSize;
    }

結果:

圖片正常顯示,磁盤中圖片的大小並沒有改變,只是改變了加載時內存中的圖片大小。

補充

  • 質量壓縮無法避免oom,但可以改變圖片在磁盤中或者說是File文件的大小,尺寸壓縮可以避免OOM,但不改變圖片本身的大小,只改變加載是在內存中的大小,即bitmap.
  • 質量壓縮我們的主要方法是:MediaStore.Images.Media.getBitmap或者BitmapFactory.decodeStream;尺寸壓縮我們用到的方法是:BitmapFactory.decodeFile

主要就說完了,我們在實際運用中可以把這兩個方法作爲工具類,隨時調用。 demo上傳github,地址:圖片的質量和尺寸壓縮

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