在开发的过程中有时候会遇到一个异常:OOM 异常,对于造成OOM异常的原因 其中有一条“内存压力过大:图片资源加载过多,超过内存使用空间,例如Bitmap 的使用”,那么这时候我们就要想办法把图片给压缩了。但是这个压缩并不是随便的压缩,不能压缩后图片的形状就改变了,那么怎么压缩图片呢?大家请看这里:
在这之前,我们先参考下压缩图片的资料:
http://blog.csdn.net/u014045181/article/details/51567176
http://blog.csdn.net/jdsjlzx/article/details/44228935
http://www.oschina.net/code/snippet_216465_36833
之后我们看下整体代码:
* 图片压缩工具类 ,先比例压缩,再质量压缩
*/
public class CompressImgUtil {
/**
* 质量压缩
* @param image
* @return
*/
public static Bitmap compressImgQuality(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
int options = 100;
while ( baos.toByteArray().length / 1024 > 512) { //循环判断如果压缩后图片是否大于512kb,大于继续压缩
if (options >= 10){
baos.reset();//重置baos即清空baos
image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中
options -= 10;//每次都减少10
}
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片
return bitmap;
}
/**
* 图片按比例大小压缩方法(根据Bitmap图片压缩)
* @param image
* @return
*/
public static Bitmap compressImg(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
if( baos.toByteArray().length / 1024>1024) {//判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出
baos.reset();//重置baos即清空baos
image.compress(Bitmap.CompressFormat.JPEG, 40, baos);//这里压缩50%,把压缩后的数据存放到baos中
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
BitmapFactory.Options newOpts = new BitmapFactory.Options();
//开始读入图片,此时把options.inJustDecodeBounds 设回true了
newOpts.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
//现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
float hh = 800f;//这里设置高度为800f
float ww = 480f;//这里设置宽度为480f
//缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
int be = 1;//be=1表示不缩放
if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
be = (int) (newOpts.outWidth / ww);
} else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
be = (int) (newOpts.outHeight / hh);
}
if (be <= 0)
be = 1;
newOpts.inSampleSize = be;//设置缩放比例
//重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
isBm = new ByteArrayInputStream(baos.toByteArray());
bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
return compressImgQuality(bitmap);//压缩好比例大小后再进行质量压缩
}
/**
* 图片按比例大小压缩方法(根据Bitmap图片压缩)
* @param srcPath
* @return bitmap
*/
public static Bitmap compressImg(String srcPath) {
BitmapFactory.Options newOpts = new BitmapFactory.Options();
//开始读入图片,此时把options.inJustDecodeBounds 设回true了
newOpts.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(srcPath,newOpts); //此时返回bm为空
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
// 想要缩放的目标尺寸
//现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
float hh = 1280f;//这里设置高度为1200f
float ww = 720f;//这里设置宽度为720f
//缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
int be = 1;//be=1表示不缩放
if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
be = (int) (newOpts.outWidth / ww);
} else if (w < h && h > hh) {//如果高度高的话根据高度固定大小缩放
be = (int) (newOpts.outHeight / hh);
}
if (be <= 0)
be = 1;
newOpts.inSampleSize = be;//设置缩放比例
//重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
return compressImgQuality(bitmap);//压缩好比例大小后再进行质量压缩
}
// Bitmap对象保存为图片文件
public static File saveBitmapFile(Bitmap bitmap){
File file = new File(MyApp.context.getFilesDir().getAbsolutePath().toString() +"/jh_cach_compressed_img.png") ;
if(file.exists()){
file.delete();
}
try {
file.createNewFile() ;
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
bos.flush();
bos.close();
long filele = file.length();
// if (file.length() >= 512*1024){//只要图片大于512k就 继续压缩
// //递归 压缩
// String pt = file.getAbsolutePath();
// compressImg(file.getAbsolutePath());
// }else {
// Log.d("--->", "压缩后图片大小 returned: " + filele);
// }
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
}
图片压缩包括质量压缩和尺寸压缩:质量压缩(不改变图片的尺寸)和尺寸压缩(相当于是像素上的压缩)。
尺寸压缩:
/**
* 图片按比例大小压缩方法(根据Bitmap图片压缩)
* @param srcPath
* @return bitmap
*/
public static Bitmap compressImg(String srcPath) {
BitmapFactory.Options newOpts = new BitmapFactory.Options();
//开始读入图片,此时把options.inJustDecodeBounds 设回true了
newOpts.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(srcPath,newOpts); //此时返回bm为空
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
// 想要缩放的目标尺寸
//现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
float hh = 1280f;//这里设置高度为1200f
float ww = 720f;//这里设置宽度为720f
//缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
int be = 1;//be=1表示不缩放
if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
be = (int) (newOpts.outWidth / ww);
} else if (w < h && h > hh) {//如果高度高的话根据高度固定大小缩放
be = (int) (newOpts.outHeight / hh);
}
if (be <= 0)
be = 1;
newOpts.inSampleSize = be;//设置缩放比例
//重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
return compressImgQuality(bitmap);//压缩好比例大小后再进行质量压缩
}
质量压缩:
/**
* 质量压缩
* @param image
* @return
*/
public static Bitmap compressImgQuality(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
int options = 100;
while ( baos.toByteArray().length / 1024 > 512) { //循环判断如果压缩后图片是否大于512kb,大于继续压缩
if (options >= 10){
baos.reset();//重置baos即清空baos
image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中
options -= 10;//每次都减少10
}
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片
return bitmap;
}
上传图片时,有时小上传图片文件, 将bitmap转化为文件: 参考:
http://blog.csdn.net/baidu_29835301/article/details/50394516
// Bitmap对象保存为图片文件
public static File saveBitmapFile(Bitmap bitmap){
File file = new File(MyApp.context.getFilesDir().getAbsolutePath().toString() +"/jh_cach_compressed_img.png") ;
if(file.exists()){
file.delete();
}
try {
file.createNewFile() ;
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
bos.flush();
bos.close();
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
本篇文章可以结合着上篇
http://blog.csdn.net/lijinweii/article/details/73468085更容易理解