常备知识之图片下载、图片压缩

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占用内存。

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;

获取计算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 

https://www.codercto.com/a/32923.html


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值