为什么要将inSampleSize Matrix组合使用?
1.inSampleSize(采样率)
优点:效率较高,解析速度快
缺点:采样率inSampleSize的取值只能是2的次方数(例如:inSampleSize=15,实际取值为8;inSampleSize=17,实际取值为16;实际取值会往2的次方结算),因此该方法不能精确的指定图片的大小
2.Matrix
优点:可以精确地指定图片的缩放大小
缺点:是在原bitmap的基础之上生成的,占内存,效率低.
- 可以从1、2看到,单独使用
inSampleSize
的话,无法将图片进行精确的压缩,因为inSampleSize
实际取值会往2的次方结算。例如:当inSampleSize = 3
时实际为inSampleSize = 2
- 单独使用
Matrix
呢又因为占内存,效率低.常常会出现bitmap size exceeds 32bits
所以要将inSampleSize Matrix进行组合使用
public CompressModel compressImage(final String filePath) {
int i = readPictureDegree(filePath);
TLog.e(TAG,"filePath : " + i);
final CompressModel compressModel = new CompressModel();
try {
BitmapFactory.Options newOpts = new BitmapFactory.Options();
//开始读入图片,此时把options.inJustDecodeBounds 设回true了
newOpts.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(filePath, newOpts);//此时返回bm为空
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
TLog.d(TAG,"w : " + w);
TLog.d(TAG,"h : " + h);
float standardLength = compressLength;
//scale = 1 表示不需要缩放
int scale = 1;
**1**
if (w > standardLength || h > standardLength) {
//需要压缩
int maxL = Math.max(w, h);
TLog.d(TAG,"maxL : " + maxL);
float scaleF = (float) (maxL / standardLength);
TLog.d(TAG,"will scaleF : " + scaleF);
scale = (int) Math.floor(scaleF);
TLog.d(TAG,"will scale : " + scale);
}else {
compressModel.setFilePath(filePath);
return compressModel;
}
if (scale <= 0) {
scale = 1;
}
newOpts.inSampleSize = scale;//设置缩放比例
TLog.d(TAG,"newOpts.inSampleSize : " + newOpts.inSampleSize);
//重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
bitmap = BitmapFactory.decodeFile(filePath, newOpts);
int ow = newOpts.outWidth;
int oh = newOpts.outHeight;
TLog.d(TAG,"ow : " + ow);
TLog.d(TAG,"oh : " + oh);
**2**
if (ow > standardLength || oh > standardLength) {
int maxL = Math.max(ow, oh);
TLog.d(TAG,"maxL : " + maxL);
float scaleF = (float) (maxL / standardLength);
TLog.d(TAG,"will scaleF : " + scaleF);
Matrix matrix = new Matrix();
/*int scaleW = (int) Math.floor(ow / scaleF);
int scaleH = (int) Math.floor(oh / scaleF);
TLog.d(TAG,"scaleW : " + scaleW);
TLog.d(TAG,"scaleH : " + scaleH);
float matrixScaleW = (float) (scaleW / ow);
float matrixScaleH = (float) (scaleH / oh);
TLog.d(TAG,"matrixScaleW : " + matrixScaleW);
TLog.d(TAG,"matrixScaleH : " + matrixScaleH);*/
TLog.d(TAG,"1/scaleF : " + 1/scaleF);
matrix.postScale(1/scaleF,1/scaleF);
Bitmap resizeBitmap = Bitmap.createBitmap(bitmap, 0, 0, ow, oh, matrix, true);
int rbWidth = resizeBitmap.getWidth();
int rbHeight = resizeBitmap.getHeight();
TLog.d(TAG,"rbWidth : " + rbWidth);
TLog.d(TAG,"rbHeight : " + rbHeight);
bitmap = resizeBitmap;
}
// 图片尺寸大小方面压缩完毕
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, baos);//质量压缩方法,压缩至80%
int options = 80;
while (baos.toByteArray().length / 1024 > compressKB) { //循环判断如果压缩后图片是否大于300kb,大于继续压缩
baos.reset();//重置baos即清空baos
bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中
options -= 10;//每次都减少10
if (options < 70) { //若质量系数小于0.7则不再压缩
break;
}
}
BitmapFactory.Options option = new BitmapFactory.Options();
option.inPreferredConfig = Bitmap.Config.RGB_565;
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
Bitmap bit = BitmapFactory.decodeStream(isBm, null, option);//把ByteArrayInputStream数据生成图片
String fileName = ImageUtils.saveToFile(Constants.APP_IMAGE, true, bit);
compressModel.setFilePath(fileName);
baos.close();
bit.recycle();
isBm.close();
bitmap.recycle();
} catch (IOException e) {
e.printStackTrace();
}
return compressModel;
}
- 标记1处使用inSampleSize
最大限度缩放至理想尺寸
- 标签2,如果经过inSampleSize
缩放的尺寸大于理想尺寸,那么需要使用Matrix
进行精确缩放。
易错点:为什么会出现bitmap size exceeds 32 bits??
我正经缩放图片,为什么要这样对我?
matrix.postScale(1/scaleF,1/scaleF);
这两个参数为需要缩放的倍数,大部分同学将参数理解为理想尺寸,图片一下扩大了几百上千倍,结果一下就BOOM了。
注释很详细,大家仔细看看就好。
代码用代码片括起来变得乱七八糟,完全不能格式化啊,有高手懂请告诉我下~~
standardLength = 1280