Android圖片尺寸與質(zhì)量壓縮你用對了嗎?

0x00-從圖庫中選擇圖片

這點不難,通過隱式意圖跳轉(zhuǎn)到圖庫耗啦,然后在onActivityResult中拿到返回結(jié)果
這里面需要注意以下幾點:
1凿菩、選擇圖庫中的照片在6.0之后個別手機需要權(quán)限,如華為帜讲;你會發(fā)現(xiàn)圖庫可以跳轉(zhuǎn)進去衅谷,但是選中圖片之后會報沒有相關(guān)權(quán)限,這里主要是存儲權(quán)限似将,華為手機比較特殊获黔,需要去申請運行時權(quán)限。
2在验、onActivityResult中返回的是一個Uri玷氏,需要根據(jù)Uri翻查圖片的真實路徑,在Android4.4之后對圖庫做了調(diào)整腋舌,需要通過不同的方式進行查詢盏触;正常情況下Uri是以content開頭但是有一種情況是特例,比如小米云相冊(這個現(xiàn)在不知道是否已經(jīng)統(tǒng)一)块饺,返回的Uri是file開頭的赞辩,需要單獨處理。代碼如下:

Intent intent = new Intent(Intent.ACTION_PICK, null);
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
startActivityForResult(intent, REQUEST_CODE_NATIVE_PHOTO);
 public static String getPhotoPath(Context context, Uri uri) {
        String filePath = "";
        if (uri != null) {
            Log.d(TAG, uri.toString());
            String scheme = uri.getScheme();
            if (TextUtils.equals("content", scheme)) {// android 4.4以上版本處理方式
                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT
                        && DocumentsContract.isDocumentUri(context, uri)) {
                    String wholeID = DocumentsContract.getDocumentId(uri);
                    String id = wholeID.split(":")[1];
                    String[] column = { MediaStore.Images.Media.DATA };
                    String sel = MediaStore.Images.Media._ID + "=?";
                    Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                            column, sel, new String[] { id }, null);
                    if (cursor != null && cursor.moveToFirst()) {
                        int columnIndex = cursor.getColumnIndex(column[0]);
                        filePath = cursor.getString(columnIndex);
                        cursor.close();
                    }
                } else {// android 4.4以下版本處理方式
                    String[] filePathColumn = { MediaStore.Images.Media.DATA };
                    Cursor cursor = context.getContentResolver().query(uri, filePathColumn, null, null, null);
                    if (cursor != null && cursor.moveToFirst()) {
                        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                        filePath = cursor.getString(columnIndex);
                        Log.d(TAG, "filePath" + filePath);
                        cursor.close();
                    }
                }
            } else if (TextUtils.equals("file", scheme)) {// 小米云相冊處理方式
                filePath = uri.getPath();
            }

        }
        return filePath;
    }

0x01-尺寸壓縮之inSampleSize

這個都知道是為了防止加載圖片時內(nèi)存溢出授艰,需要先計算采樣率辨嗽,然后再去加載圖片這里要說的也有兩點:
1、inSampleSize只能是2的次方淮腾,如計算結(jié)果是7會按4進行壓縮糟需,計算結(jié)果是15會按8進行壓縮。
2来破、存在兩種算法:
算法一:圖片長與目標長比篮灼,圖片寬與目標寬比,取最大值(不過也有人取最小值徘禁,怕壓縮的太多嗎诅诱?取最小值會遇到的問題舉個例子,滿屏加載長截圖的時候送朱,圖片寬與屏幕寬為1:1娘荡,這樣inSampleSize就為1,沒有壓縮那么很容易就內(nèi)存溢出了)驶沼,不管怎么都欠妥炮沐;因為如果手機是橫屏拍攝,或者是拍攝的全景圖回怜,那么圖片寬與目標寬的比例會很增大大年,這樣壓縮的比例會偏大。

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        final int width = options.outWidth;
        final int height = options.outHeight;
        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;
    }

算法二:取目標長寬的最大值來計算,這樣會減少過度的尺寸壓縮翔试,

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        final int width = options.outWidth;
        final int height = options.outHeight;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            //使用需要的寬高的最大值來計算比率
            final int suitedValue = reqHeight > reqWidth ? reqHeight : reqWidth;
            final int heightRatio = Math.round((float) height / (float) suitedValue);
            final int widthRatio = Math.round((float) width / (float) suitedValue);

            inSampleSize = heightRatio > widthRatio ? heightRatio : widthRatio;//用最大
        }

        return inSampleSize;
    }

0x02-質(zhì)量壓縮之quality

發(fā)現(xiàn)很多人有一個錯誤認識轻要,本人曾經(jīng)也不例外,就是誤以為垦缅,這個比例是文件壓縮前后大小的比值冲泥,因此會用目標大小/目前文件大小,來計算這個quality壁涎,其實這是錯誤的凡恍。因為這完全是兩碼事,比如壓縮前是1.5M,目標大小是1M,好大概計算一下是60左右怔球,壓完了之后你可能會發(fā)現(xiàn)圖片只有100多k;好像沒有可以直接算出來這個比例的方法嚼酝,常見的都是嘗試式的算法,如從100開始竟坛,每次減少6革半,壓縮一次比較一次,直到滿足條件,當然這個可以自己調(diào)整流码。

ByteArrayOutputStream baos = new ByteArrayOutputStream();
int option = 100;
bitmap.compress(Bitmap.CompressFormat.JPEG, option, baos);
while (baos.toByteArray().length / 1024 > maxSize&&option>6) {
    baos.reset();
    option -= 6;
    bitmap.compress(Bitmap.CompressFormat.JPEG, option, baos);
}

0x03-圖片的旋轉(zhuǎn)角度之ExifInterface

圖片的旋轉(zhuǎn)角度在很多人做壓縮的時候都會加上一筆,這個說實話我沒有太多的研究延刘,因為我用的手機不管怎么弄旋轉(zhuǎn)角度都是0漫试;如我們豎著拍照,圖庫里面的照片是豎著顯示的碘赖;橫著拍照驾荣,之后發(fā)現(xiàn)圖庫里面的照片是橫著顯示的(寬>高的形式展示),但是旋轉(zhuǎn)角度都是0普泡;然后我又把其中一張照片編輯一下 讓它旋轉(zhuǎn)一下保存播掷,發(fā)現(xiàn)之后的旋轉(zhuǎn)角度依然是0『嘲啵可能是我的手機的問題歧匈,也可能是這個旋轉(zhuǎn)角度會在個別手機上有體現(xiàn)。廢話不多說貼上代碼

private int getImageSpinAngle(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

0x04-延伸

介紹一些github知名的壓縮算法砰嘁,luban算法
https://github.com/Curzibn/Luban
https://github.com/shaohui10086/AdvancedLuban
當然這都是從參數(shù)上的優(yōu)化件炉,star很多問題也很多,說明并非所有需求都適用矮湘,最重要的還是能夠滿足項目需求的算法才是最好的斟冕。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市缅阳,隨后出現(xiàn)的幾起案子磕蛇,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秀撇,死亡現(xiàn)場離奇詭異超棺,居然都是意外死亡,警方通過查閱死者的電腦和手機捌袜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門说搅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人虏等,你說我怎么就攤上這事弄唧。” “怎么了霍衫?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵候引,是天一觀的道長。 經(jīng)常有香客問我敦跌,道長澄干,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任柠傍,我火速辦了婚禮麸俘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘惧笛。我一直安慰自己从媚,他們只是感情好,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布患整。 她就那樣靜靜地躺著拜效,像睡著了一般。 火紅的嫁衣襯著肌膚如雪各谚。 梳的紋絲不亂的頭發(fā)上紧憾,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音昌渤,去河邊找鬼赴穗。 笑死,一個胖子當著我的面吹牛膀息,可吹牛的內(nèi)容都是我干的望抽。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼履婉,長吁一口氣:“原來是場噩夢啊……” “哼煤篙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起毁腿,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤辑奈,失蹤者是張志新(化名)和其女友劉穎苛茂,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鸠窗,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡妓羊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了稍计。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片躁绸。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖臣嚣,靈堂內(nèi)的尸體忽然破棺而出净刮,到底是詐尸還是另有隱情,我是刑警寧澤硅则,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布淹父,位于F島的核電站,受9級特大地震影響怎虫,放射性物質(zhì)發(fā)生泄漏暑认。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一大审、第九天 我趴在偏房一處隱蔽的房頂上張望蘸际。 院中可真熱鬧,春花似錦徒扶、人聲如沸捡鱼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至缠诅,卻和暖如春溶浴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背管引。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工士败, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人褥伴。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓谅将,卻偏偏與公主長得像,于是被迫代替她去往敵國和親重慢。 傳聞我的和親對象是個殘疾皇子饥臂,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容