常備知識之圖片下載、圖片壓縮

1、圖片壓縮

知識點:

inDensity  原始密度:爲0則設置爲默認 160dpi; 文件夾代表密度

inTargetDensity 顯示目標圖片密度

inScreenDensity 屏幕密度

原因:

直接顯示Bitmap佔用內存會過大導致內存溢出OOM問題:

粗略方式:
計算公式:圖片長 * 寬 * 4bytes/ARG_8888 - 不正確Native 方法中,mBitmapWidth = mOriginalWidth * (scale = opts.inTargetDensity / opts.inDensity) * 1/inSampleSize,
mBitmapHeight = mOriginalHeight * (scale = opts.inTargetDensity / opts.inDensity) * 1/inSampleSize

例如:

將一張 720x1080圖片放在 drawable-xhdpi 目錄下(inDensity = 320),

  • 在 720x1080 手機上加載(inTargetDensity = 320),圖片不會被壓縮;
  • 在 480x800 手機上加載(inTargetDensity = 240),圖片會被壓縮 9/16;
  • 在 1080x1920 手機上加載(inTargetDensity = 480),圖片會被放大 2.25;

手機屏幕大小 1280 x 720(inTarget = 320),加載 xxhdpi (inDensity = 480)中的圖片 1920 x 1080,scale = 320 / 480,inSampleSize = 1,最終獲得的 Bitmap 的圖像大小是 :

mBitmapWidth = opts.outWidth = 1080 * (320 / 480) * 1/1 = 720,
mBitmapHeight = opt.outHeight = 1920 * (320 / 480) * 1/1 = 1280,
getAllocatedMemory() = mBitmapWidth * mBitmapHeight * 4 = Bitmap佔用內存。

圖片壓縮

BitmapFactory.Options

2、利用inJustDecodeBounds參數不分配bitmap獲取原始圖片寬、高:

inJustDecodeBounds:爲true時僅返回 Bitmap 寬高等屬性,返回bmp=null,爲false時才返回佔內存的 bmp;

 BitmapFactory.Options options = new BitmapFactory.Options();
 options.inJustDecodeBounds = true;//不分配bitmap內存:不會造成內存溢出OOM
 /**
 * decodeFile 本地文件
 * decodeStream 網絡上的圖片
 * decodeResource 資源文件中圖片
 */
 BitmapFactory.decodeFile(path, options);
 int outHeight = options.outHeight;
 int outWidth = options.outWidth;

2、獲取計算inSampleSize對寬、高,壓縮

inSampleSize:表示 Bitmap 的壓縮比例,值必須 > 1 & 是2的冪次方。inSampleSize = 2 時,表示壓縮寬高各1/2,最後返回原始圖1/4大小的Bitmap;

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

3、最終代碼:

public class TestActivity extends RootActivity {

    private ImageView imageView;

    private Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    imageView.setImageBitmap(bitmap);
                    break;
                case 2:
                    RingToast.show("bitmap= null");
                    break;
            }
            return false;
        }
    });

    @Override
    protected void onInit() {
        super.onInit();
        setContentView(R.layout.activity_test);
    }

    @Override
    protected void onFindViews() {
        super.onFindViews();

        imageView = findViewById(R.id.imageView);
    }


    public void onClick(View view) {
        RingToast.show("下載");
        if (view.getId() == R.id.localBtn) {
            showResources();
        } else
            new DownloadImage("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1585219233084&di=3f992df116687f73f7174be2d602389b&imgtype=0&src=http%3A%2F%2Fa3.att.hudong.com%2F68%2F61%2F300000839764127060614318218_950.jpg").start();
    }

    private Bitmap bitmap;

    private class DownloadImage extends Thread {

        String path;

        public DownloadImage(String path) {
            this.path = path;
        }

        @Override
        public void run() {
            super.run();
            HttpURLConnection urlConnection = null;
            InputStream inputStream = null;
            try {
                URL url = new URL(path);

                //保存本地
                urlConnection = (HttpURLConnection) url.openConnection();
                inputStream = urlConnection.getInputStream();
                File file = createDir(Config.CAMERA_CLASS_PATH + File.separator + "原始圖片" + ".jpg");
                FileOutputStream outputStream = new FileOutputStream(file);
                int hasRead = 0;
                while ((hasRead = inputStream.read()) != -1) {
                    outputStream.write(hasRead);
                }
                outputStream.close();

                //獲取原圖片尺寸
                urlConnection = (HttpURLConnection) url.openConnection();
                inputStream = urlConnection.getInputStream();
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = true;
                BitmapFactory.decodeStream(inputStream, null, options);
                inputStream.close();

                //獲取壓縮係數
                BitmapFactory.Options options2 = new BitmapFactory.Options();
                options2.inSampleSize = ImageToolsUtils.calculateInSampleSize(options, ScreenUtils.getScreenWidth(TestActivity.this), ScreenUtils.getScreenHeight(TestActivity.this));
//                options2.inSampleSize = 1;
                options2.inJustDecodeBounds = false;
                //獲取最終壓縮圖片bitmap
                urlConnection = (HttpURLConnection) url.openConnection();
                inputStream = urlConnection.getInputStream();
                bitmap = BitmapFactory.decodeStream(inputStream, null, options2);
                FileUtil.saveBitmap(bitmap);

                if (bitmap != null) {
                    Message message = new Message();
                    message.what = 1;
                    handler.sendMessage(message);
                } else {
                    Message message = new Message();
                    message.what = 2;
                    handler.sendMessage(message);
                }
            } catch (Exception e) {
                RingLog.e("訪問網絡異常:" + e.getMessage());
            } finally {
                if (urlConnection != null) {
                    urlConnection.disconnect();
                }
                try {
                    if (inputStream != null) {
                        inputStream.close();
                    }
                } catch (IOException e) {
                }
            }
        }
    }

    private void showResources() {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = false;
        Bitmap bm = BitmapFactory.decodeResource(getResources(), R.mipmap.launch_welcome, options);
        FileUtil.saveBitmap(bm);

        //獲取壓縮係數
        options.inSampleSize = ImageToolsUtils.calculateInSampleSize(options, 300, 300);
        options.inJustDecodeBounds = false;
        //獲取最終壓縮圖片bitmap
        bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.launch_welcome, options);
        FileUtil.saveBitmap(bitmap);
        if (bitmap != null) {
            Message message = new Message();
            message.what = 1;
            handler.sendMessage(message);
        } else {
            Message message = new Message();
            message.what = 2;
            handler.sendMessage(message);
        }
    }
}

參考:

https://www.jianshu.com/p/4ba3e63c8cdc

https://www.tuicool.com/articles/3eMNr2n

https://blog.csdn.net/guolin_blog/article/details/9316683


 

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