Android選擇圖庫照片并尺寸與質量壓縮注意事項

huur8097 8年前發布 | 7K 次閱讀 安卓開發 Android開發 移動開發

0x01-從圖庫中選擇圖片

這點不難,通過隱式意圖跳轉到圖庫,然后在onActivityResult中拿到返回結果

這里面需要注意以下幾點:

1、選擇圖庫中的照片在6.0之后個別手機需要權限,如華為;你會發現圖庫可以跳轉進去,但是選中圖片之后會報沒有相關權限,這里主要是存儲權限,華為手機比較特殊,需要去申請運行時權限。

2、onActivityResult中返回的是一個Uri,需要根據Uri翻查圖片的真實路徑,在Android4.4之后對圖庫做了調整,需要通過不同的方式進行查詢;正常情況下Uri是以content開頭但是有一種情況是特例,比如小米云相冊(這個現在不知道是否已經統一),返回的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;
}</code></pre> 

0x02-尺寸壓縮之inSampleSize

這個都知道是為了防止加載圖片時內存溢出,需要先計算采樣率,然后再去加載圖片這里要說的也有兩點:

1、inSampleSize只能是2的次方,如計算結果是7會按4進行壓縮,計算結果是15會按8進行壓縮。

2、存在兩種算法:

算法一:圖片長與目標長比,圖片寬與目標寬比,取最大值(不過也有人取最小值,怕壓縮的太多嗎?取最小值會遇到的問題舉個例子,滿屏加載長截圖的時候,圖片寬與屏幕寬為1:1,這樣inSampleSize就為1,沒有壓縮那么很容易就內存溢出了),不管怎么都欠妥;因為如果手機是橫屏拍攝,或者是拍攝的全景圖,那么圖片寬與目標寬的比例會很增大,這樣壓縮的比例會偏大。

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;
}</code></pre> 

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

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;
    }

0x03-質量壓縮之quality

發現很多人有一個錯誤認識,本人曾經也不例外,就是誤以為,這個比例是文件壓縮前后大小的比值,因此會用目標大小/目前文件大小,來計算這個quality,其實這是錯誤的。因為這完全是兩碼事,比如壓縮前是1.5M,目標大小是1M,好大概計算一下是60左右,壓完了之后你可能會發現圖片只有100多k;好像沒有可以直接算出來這個比例的方法,常見的都是嘗試式的算法,如從100開始,每次減少6,壓縮一次比較一次,直到滿足條件,當然這個可以自己調整。

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);
}

0x04-圖片的旋轉角度之ExifInterface

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

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;
    }

 

 

來自:http://www.jianshu.com/p/f0b43be628cf

 

 本文由用戶 huur8097 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!