Android圖片壓縮尺寸和質量

Android在處理圖片時,如果不進行壓縮處理,很容易就出現OOM內存溢出(OutOfMemory)問題,所以無論是第三方圖片加載還是自己在處理圖片時,都要進行壓縮處理。

Android系統中,一張圖片所佔用的內存大小與圖片尺寸(像素點)和色彩格式(質量)有關,所以Android圖片壓縮分爲尺寸壓縮和質量壓縮:

  • 尺寸壓縮:一張1920*1080的圖片尺寸壓縮一半後,即960*540,尺寸和像素點是未壓縮前的1/4,所佔內存也會變成1/4;
  • 質量壓縮:

    • 1.圖片的色彩格式壓縮即:
      -Bitmap.Config ARGB_8888:每個像素佔四位,即A=8,R=8,G=8,B=8,那麼一個像素點佔8+8+8+8=32位
      -Bitmap.Config ARGB_4444:每個像素佔四位,即A=4,R=4,G=4,B=4,那麼一個像素點佔4+4+4+4=16位
      -Bitmap.Config RGB_565:每個像素佔四位,即R=5,G=6,B=5,沒有透明度,那麼一個像素點佔5+6+5=16位
      -Bitmap.Config ALPHA_8:每個像素佔四位,只有透明度,沒有顏色。

    • 2.通過 bitmap.compress(CompressFormat format, int quality, OutputStream stream)方法進行壓縮,壓縮過程可能會損失透明度;

代碼

    /**
     * 壓縮圖片分辨率
     *
     * @param imgpath 文件路徑
     * @param width 最大輸出寬度
     * @param height 最大輸出高度
     * @return
     */
    public static Bitmap decodeBitmap(String imgpath, int width, int height) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;//解碼bitmap時可以只返回其高、寬和Mime類型,而不必爲其申請內存,從而節省了內存空間。
        options.inPreferredConfig = Bitmap.Config.RGB_565;//圖像質量,565不帶透明度
        BitmapFactory.decodeFile(imgpath, options);
        //縮放倍數計算
        int outHeight = options.outHeight;
        int outWidth = options.outWidth;
        if (outHeight / height > outWidth / width) {
            int heightScale = outHeight / height;
            if (outHeight % height == 0) {
                options.inSampleSize = heightScale;
            } else {
                options.inSampleSize = heightScale + 1;
            }
        } else {
            int widthScale = outWidth / width;
            if (outWidth % width == 0) {
                options.inSampleSize = widthScale;
            } else {
                options.inSampleSize = widthScale + 1;
            }
        }
        LogUtil.e("options.inSampleSize:" + options.inSampleSize);
        options.inJustDecodeBounds = false;//加載到內存中
        Bitmap bitmap = BitmapFactory.decodeFile(imgpath, options);
        return compressBitmap(bitmap);
//        return Bitmap.createScaledBitmap(bitmap, width, height, filter);//將圖片縮放到指定大小
    }

     /**
     * 壓縮圖片質量
     */
    public static Bitmap compressBitmap(Bitmap bitmap) {

        int maxSize = 300 * 1024;//最大文件大小300kb
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);// 質量壓縮方法,這裏100表示不壓縮,把壓縮後的數據存放到baos中
        int quality = 90;
        while (byteArrayOutputStream.toByteArray().length > maxSize) { // 循環判斷如果壓縮後圖片是否大於maxSize字節,大於繼續壓縮
            byteArrayOutputStream.reset(); // 重置baos即清空baos
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, byteArrayOutputStream);// 這裏壓縮quality%,把壓縮後的數據存放到byteArrayOutputStream中
            quality -= 5;
        }
        LogUtil.e(byteArrayOutputStream.toByteArray().length/1024+"kb");
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());

        Bitmap decodeBitmap = BitmapFactory.decodeStream(byteArrayInputStream, null, null);// 把ByteArrayInputStream數據生成bitmap
        try {
            byteArrayInputStream.close();
            byteArrayOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return decodeBitmap;

    }
================================下面是處理圖片時用得到的方法===========================
    /**
     * 保存bitmap到文件
     *
     * @param bitmap
     * @param filePath
     */
    public static void saveBitmapToFile(Bitmap bitmap, String filePath) {
        File file = new File(filePath);
        if (file.exists()) {
            file.delete();
        }
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(filePath);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
            out.flush();
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        } catch (IOException e2) {
            e2.printStackTrace();
        } finally {
            try {
                if (out != null)
                    out.close();
            } catch (Exception e3) {
                e3.printStackTrace();
            }

        }

    }
    /**
     * 讀取圖片屬性:旋轉的角度
     *
     * @param path 圖片絕對路徑
     * @return degree旋轉的角度
     */
    public static int readPictureDegree(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;
    }

    /**
     * 旋轉圖片
     *
     * @param angle
     * @param bitmap
     * @return Bitmap
     */
    public static Bitmap rotaingImageView(int angle, Bitmap bitmap) {
        //旋轉圖片 動作
        Matrix matrix = new Matrix();
        matrix.postRotate(angle);
        // 創建新的圖片
        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        return resizedBitmap;
    }

    /**
     * 旋轉圖片
     *
     * @param imagePath
     * @return true:旋轉成功;false:無需旋轉
     */
    public static boolean rotaingImageView(String imagePath) {
        int degree = ImageUtils.readPictureDegree(imagePath);

        if (degree != 0) {
            Bitmap decodeBitmap = decodeBitmap(imagePath, 1000, 1000);
            //把圖片旋轉爲正的方向
            Bitmap newbitmap = rotaingImageView(degree, decodeBitmap);
            //同步保存文件(文件過大,同步保存會出現ANR異常,可採用異步保存)
            saveBitmapToFile(newbitmap, imagePath);
            decodeBitmap.recycle();
            newbitmap.recycle();
//            new Thread(new Runnable() {
//                @Override
//                public void run() {
//                    //異步保存文件
//                    saveBitmapToFile(newbitmap, new File(curimgpath));
//                    handler.sendEmptyMessage(0);
//                }
//            }).start();
            return true;
        }
        return false;
    }
發佈了69 篇原創文章 · 獲贊 72 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章