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/