亲爱的同学们,相信我们在软件开发中经常会遇到拍照,选择相册上传的功能。前几天遇到一个这样的一个问题。后台要求我上传的图片不能超过500KB,大家知道我们现在的智能手机像素越来越高,拍照的照片一般都是几兆甚至一二十兆。那么我们改怎么做呢,答案是一定的,那就是先进行压缩,然后在保存压缩后的图片上传。最近在网络上也搜索到了很多关于压缩的内容,相信大家会有和我同感,为什么都写的不清楚,或许我们可以实现我们的功能,但是这是如何实现的,为什么呢。下面我就贴出我的代码,每一步骤都会有详细的注释。希望会帮到大家。
第一,就是压缩图片的方法。在我们选择照片或者拍照之后,将图片路径传入进去就可以进行压缩,然后返回我们一个Bitmap的对象。注释的比较清楚,哪里不明白的可以给我评论留言。
/**
* @param path
* @return
* @throws IOException
* 压缩图片
*/
public static Bitmap revitionImageSize(String path) throws IOException {
//根据文件路径,创建一个字节缓冲输入流
BufferedInputStream in = new BufferedInputStream(new FileInputStream(
new File(path)));
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
//根据流返回一个位图也就是bitmap,当options.inJustDecodeBounds = true的时候不需要完全解码,
// 它仅仅会把它的宽,高取回来给你,这样就不会占用太多的内存,也就不会那么频繁的发生OOM了
BitmapFactory.decodeStream(in, null, options);
//关闭流
in.close();
int i = 0;
Bitmap bitmap = null;
while (true) {
// options.outWidth >> i 。右移运算符,num >> 1,相当于num除以2
if ((options.outWidth >> i <= 1000) && (options.outHeight >> i <= 1000)) {
//得到一个输入流
in = new BufferedInputStream(new FileInputStream(new File(path)));
//为了解决图片解码时候出现SanpleSize错误,设置恰当的inSampleSize可以使BitmapFactory分配更少的空间以消除该错误
//你将 inSampleSize 赋值为2,那就是每隔2行采1行,每隔2列采一列,那你解析出的图片就是原图大小的1/4.
// Math.pow(2.0D, i)次方运算,2的i次方是多少
options.inSampleSize = (int) Math.pow(2.0D, i);
// 这里之前设置为了true,所以要改为false,否则就创建不出图片
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeStream(in, null, options);
break;
}
i += 1;
}
return bitmap;
}
第二、当我们拿到这个Bitmap对象之后,我们就可以进行保存的操作,因为我们这个毕竟是个对象,我们通常的上传过程是需要上传的文件的。
/**
* @param bitmap
* 保存图片到SD卡的方法
*/
public void saveBitmapFile(Bitmap bitmap){
//Environment.getExternalStorageDirectory() 获取Android外部存储的空间,当有外部SD卡就在外部SD卡上建立。
//没有外部SD卡就在内部SD卡的非data/data/目录建立目录。(data/data/目录才是真正的内存目录。)
//IMAGE_NAME文件的名字,随便起。比如(xxx.jpg)
File tempFile = new File(Environment.getExternalStorageDirectory(), IMAGE_NAME );
try {
//创建一个输出流,将数据写入到创建的文件对象中。
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tempFile));
30 是压缩率,表示压缩70%; 如果不压缩是100,
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
/* 为什么要调用flush()方法?当FileOutputStream作为BufferedOutputStream构造函数的参数传入,然后对BufferedOutputStream进行写入操作,才能利用缓冲及flush()。
查看BufferedOutputStream的源代码,发现所谓的buffer其实就是一个byte[]。
BufferedOutputStream的每一次write其实是将内容写入byte[],当buffer容量到达上限时,会触发真正的磁盘写入。
而另一种触发磁盘写入的办法就是调用flush()了。*/
bos.flush();
//关闭流对象
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
最后告诉大家,可以先看看java中的文件流和字节流操作,以及Android的Bitmap对象,对理解上述的代码会很有帮助。希望能帮助到大家。共同进步,欢迎转载和留言。一起探讨。
关注微信公众号: