Android加载大图片OOM、图片压缩

https://www.jianshu.com/p/1a9602c60e03

  • 图像:一个一个像素点构成。所有不同的颜色像素点构成一幅完整图像。
  • 位图表示图像的方法:记录一幅图像中所有像素点(pixels)信息
  • 图像(位图)的深度:表示一个像素点用多少个bit位
    • 单色位图:用1bit描述一个像素点信息。
    • 256色位图:用8bits描述一个像素点信息
    • 24位位图:用24bits描述一个像素点信息
view.getWidth获取的是像素px

加载大图片产生OOM问题

在使用BitmapFactory的decodeStream,decodeFile,decodeResource方法时,超出系统分配的内存大小(一般是8M),报出OOM。

  • 解决方法,设置采样率inSampleSize,用于减少要加载像素个数

    //加载sd卡上jpg图片显示在imageView
    
    //Bitmap bm = BitmapFactory.decodeFile("/sdcard/biger.jpg");
    //加载大图片,产生OOM问题,解决办法:想方设法减少像素个数
    
    Options opts = new Options();
    opts.inSampleSize = 8;//设置采样率,成倍数减少像素点。inSamleSize = 8 总像素点是原图像的1/64
    Bitmap bm = BitmapFactory.decodeFile("/sdcard/biger.jpg", opts);
    
    //Bitmap.Config.ARGB_8888 描述一个像素用32bits,Alpha R G B
    
    iv.setImageBitmap(bm);
    
  • 采样率一般设置方法:分别获得屏幕的分辨率(宽方向像素个数 X 高方向像素个数)和图片分辨率(宽方向像素个数 X 高方向像素个数)。用图片的宽方向上像素个数除以屏幕的宽方向上像素个数,用图片的高方向上像素个数除以屏幕的高方向上像素个数。取两个比值中最大值或均值作为采样率。

  • 采样率设置之后的宽高应该大于ImageView期望的宽高,否则会被拉伸而变模糊

  • 屏幕分辨率

    //获得屏幕分辨率
    //1.获得窗口管理器
    WindowManager manager = (WindowManager) getSystemService(WINDOW_SERVICE);
    
    //2.获得默认显示对象
    Display display = manager.getDefaultDisplay();
    
    //在api13之下使用
    //int windowWidth = display.getWidth();
    //int windowHeight = display.getHeight();
    
    //在api13以上使用
    Point outSize = new Point();
    display.getSize(outSize);//先传入对象,方法中将数据再填入对象中
    
    int windowWidth = outSize.x;
    int windowHeight = outSize.y;
    
    System.out.println(windowWidth + " * " + windowHeight);
    
  • 获得jpg图片的分辨率

    int sampleWidth = 0;
    int samleHeight = 0;
    //获得jpg图片分辨率
    try {
        //获得Exif接口对象
        ExifInterface exif = new ExifInterface("/sdcard/biger.jpg");
    
        //获得图片的宽方向像素个数
        int width = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, -1);
        //获得图片的高方向像素个数
        int height = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, -1);
    
        System.out.println(width + " X " + height);
    
        sampleWidth = width / windowWidth;
        samleHeight = height / windowHeight;
    
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    
  • 其它类型图片png,bmp获得分辨率(也可以获取JPG的)

  • /*
    //其它类型图片png,bmp获得分辨率方法
    Options opt = new Options();
    opt.inJustDecodeBounds = true;//仅获得图片的分辨率,宽和高。并不会将文件转成bitmap对象
    
    BitmapFactory.decodeFile("/sdcard/biger.png", opt );
    
    int width = opt.outWidth;
    int height = opt.outHeight;
    */
    
  • 计算采样率

    opts.inSampleSize = sampleWidth > samleHeight ? sampleWidth : samleHeight;
    
  • 采样率设置应遵循如下原则

    1、BitmapFactory.Options的inJustDecodeBounds 设置为true,并加载图片
    2、从BitmapFactory.Options中获取图片的原始宽高,outHeight、outWidth
    3、计算采样率inSampleSize
    4、BitmapFactory.Options的inJustDecodeBounds 设置为false,然后重新加载图片

写个demo测试一下:
传送门:https://github.com/jiaweizeng/LoadPhotoOOM

package cn.hzjk.loadphotooom;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity {

    private Bitmap mBitmap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final ImageView iv = findViewById(R.id.iv_load);
        Button btn = findViewById(R.id.btn_load);


        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                /*mBitmap = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().
                        getPath() + "/IMG_2509.JPG");*/
                mBitmap = getMySampleBitmap(Environment.getExternalStorageDirectory().
                        getPath() + "/IMG_2509.JPG",iv.getWidth(),iv.getHeight());
                iv.setImageBitmap(mBitmap);

            }
        });
}
    /**   设置采样率,防止图片太大,解析OOM
     *
     * @param file_path 图片路径
     * @return
     */
    public  Bitmap getMySampleBitmap(String file_path, int width, int height) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(file_path, options);
        options.inSampleSize = getMySampleSize(width, height, options);
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(file_path, options);
    }
    private  int getMySampleSize(int reqWidth, int reqHeight, BitmapFactory.Options options) {
        int inSampleSize = 1;
        if (options.outWidth > reqWidth || options.outHeight > reqHeight) {
            int widthRatio = Math.round((float) options.outWidth / (float) reqWidth);
            int heightRatio = Math.round((float) options.outHeight / (float) reqHeight);
            inSampleSize = Math.min(widthRatio, heightRatio);
        }
        return inSampleSize;
    }
}

测试图片大小8M

设置采样率之前的内存变化:

设置采样率之后的内存变化:

压缩bitmap

private Bitmap imageZoom(Bitmap bitMap) {
    //图片允许最大空间   单位:KB
    double maxSize =1000.00;
    //将bitmap放至数组中,意在bitmap的大小(与实际读取的原文件要大)
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    bitMap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
    byte[] b = baos.toByteArray();
    //将字节换成KB
    double mid = b.length/1024;
    //判断bitmap占用空间是否大于允许最大空间  如果大于则压缩 小于则不压缩
    if (mid > maxSize) {
        //获取bitmap大小 是允许最大大小的多少倍
        double i = mid / maxSize;
        //开始压缩  此处用到平方根 将宽带和高度压缩掉对应的平方根倍 (1.保持刻度和高度和原bitmap比率一致,压缩后也达到了最大大小占用空间的大小)
        bitMap = zoomImage(bitMap, bitMap.getWidth() / Math.sqrt(i),
                bitMap.getHeight() / Math.sqrt(i));
    }
    return bitMap;
}

/***
 * 图片的缩放方法
 *
 * @param bgimage
 *            :源图片资源
 * @param newWidth
 *            :缩放后宽度
 * @param newHeight
 *            :缩放后高度
 * @return
 */
public static Bitmap zoomImage(Bitmap bgimage, double newWidth,
                               double newHeight) {
    // 获取这个图片的宽和高
    float width = bgimage.getWidth();
    float height = bgimage.getHeight();
    // 创建操作图片用的matrix对象
    Matrix matrix = new Matrix();
    // 计算宽高缩放率
    float scaleWidth = ((float) newWidth) / width;
    float scaleHeight = ((float) newHeight) / height;
    // 缩放图片动作
    matrix.postScale(scaleWidth, scaleHeight);
    Bitmap bitmap = Bitmap.createBitmap(bgimage, 0, 0, (int) width,
            (int) height, matrix, true);
    return bitmap;
}

/压缩图片框架/ compile ‘top.zibin:Luban:1.1.1’ compile ‘id.zelory:compressor:2.0.0’

压缩网站:https://tinypng.com/

猜你喜欢

转载自blog.csdn.net/weixin_37165769/article/details/80568052