图片压缩_学习笔记
android原生图片压缩方法
private String beforeCompressPath = Environment.getExternalStorageDirectory().getAbsolutePath()+
File.separator + "183" + File.separator + "TestCompress" + File.separator +
"BeforeCompress" + File.separator + "pic.jpg";
private String afterCompressPath = Environment.getExternalStorageDirectory().getAbsolutePath()+
File.separator + "183" + File.separator + "TestCompress" + File.separator +
"AfterCompress" + File.separator + "compressPic.jpg";
private Bitmap mBitmapOrigin;
private Bitmap mBitmapAfter;
private android.widget.ImageView ivprecompress;
private android.widget.ImageView ivaftcompress;
private android.widget.Button btncompress;
/**
* 将图片压缩到1M,quality图片质量每次减1,压缩一张3.9M的图片用了十几秒。该算法不适合在主线程中使用,试试鲁班的。
*/
btncompress.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mBitmapOrigin = BitmapFactory.decodeFile(beforeCompressPath);
try {
//内存输出流,与其他流向硬盘写数据不一样,它向内存中写数据,运算速度更快。
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int quality = 100;
while (true) {
byteArrayOutputStream.reset();
//jpg压缩效果比png好很多
mBitmapOrigin.compress(Bitmap.CompressFormat.JPEG, quality, byteArrayOutputStream);
int size = byteArrayOutputStream.size();
if (size > 1000 * 1024) {
quality -= 1;
} else {
break;
}
Log.e("quality", "quality == " + quality);
}
Log.e("quality", "quality == " + quality);
FileOutputStream fileOutputStream = new FileOutputStream(afterCompressPath);
mBitmapOrigin.compress(Bitmap.CompressFormat.JPEG, quality, fileOutputStream);
mBitmapAfter = BitmapFactory.decodeFile(afterCompressPath);
//将图片以bitmap的形式显示到imageview中
ivprecompress.setImageBitmap(mBitmapOrigin);
ivaftcompress.setImageBitmap(mBitmapAfter);
} catch (Exception e) {
e.printStackTrace();
}
}
});
- 原生核心方法为:Bitmap.compress();
- 压缩的算法有很多种,这里用到的是将图片压缩到1MB,每次图片的质量会减少1%,知道图片小于1MB
- 缺点:耗时很长…
Luban图片压缩第三方框架
GitHub
https://github.com/Curzibn/Luban
集成
implementation 'top.zibin:Luban:1.1.3'
基本用法
GitHub上说的已经很明白了
Luban.with(this) .load(photos) // 传人要压缩的图片列表 .ignoreBy(100) // 忽略不压缩图片的大小 .setTargetDir(getPath()) // 设置压缩后文件存储位置 .setCompressListener(new OnCompressListener() { //设置回调 @Override public void onStart() { // TODO 压缩开始前调用,可以在方法内启动 loading UI } @Override public void onSuccess(File file) { // TODO 压缩成功后调用,返回压缩后的图片文件 } @Override public void onError(Throwable e) { // TODO 当压缩过程出现问题时调用 } }).launch(); //启动压缩
压缩单个图片
private String mBeforeCompressPicPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "183" + File.separator + "TestCompress" + File.separator + "BeforeCompress" + File.separator + "pic2.jpg"; private String mAfterCompressPicPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "183" + File.separator + "TestCompress" + File.separator + "AfterCompress"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.aty_compress_single_picture); Luban.with(this) .load(mBeforeCompressPicPath) // 传人要压缩的图片列表 .ignoreBy(100) // 忽略不压缩图片的大小 .setTargetDir(mAfterCompressPicPath) // 设置压缩后文件存储位置 .setCompressListener(new OnCompressListener() { //设置回调 @Override public void onStart() { // TODO 压缩开始前调用,可以在方法内启动 loading UI LogUtil.e("开始图片压缩,这里可以启动loading UI"); } @Override public void onSuccess(File file) { // TODO 压缩成功后调用,返回压缩后的图片文件 LogUtil.e("压缩成功,返回压缩后图片文件,文件大小:" + file.length() / 1000 + "KB"); file.renameTo(new File(mAfterCompressPicPath, "compressPic2.jpg")); } @Override public void onError(Throwable e) { // TODO 当压缩过程出现问题时调用 LogUtil.e("压缩出现问题:" + e.getMessage()); } }).launch(); //启动压缩 }
打印结果:
04-07 10:43:47.923 7000-7000/com.tupobi.testlubancompresspictuer E/AtyCompressSinglePicture 1.onStart(Line:40):开始图片压缩,这里可以启动loadingUI04−0710:43:48.2017000−7000/com.tupobi.testlubancompresspictuerE/AtyCompressSinglePicture 1. o n S t a r t ( L i n e : 40 ) : 开 始 图 片 压 缩 , 这 里 可 以 启 动 l o a d i n g U I 04 − 07 10 : 43 : 48.201 7000 − 7000 / c o m . t u p o b i . t e s t l u b a n c o m p r e s s p i c t u e r E / A t y C o m p r e s s S i n g l e P i c t u r e 1.onSuccess(Line:46): 压缩成功,返回压缩后图片文件,文件大小:221KB
压缩一组图片
private int mPictureIndex; private List<String> mOriginPictureLists; private String mAfterCompressPicPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "183" + File.separator + "TestCompress" + File.separator + "AfterCompressList"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.aty_compress_list_pictures); mOriginPictureLists = new ArrayList<>(); String originPic1 = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "183" + File.separator + "TestCompress" + File.separator + "BeforeCompress" + File.separator + "pic.jpg"; String originPic2 = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "183" + File.separator + "TestCompress" + File.separator + "BeforeCompress" + File.separator + "pic2.jpg"; mOriginPictureLists.add(originPic1); mOriginPictureLists.add(originPic2); Luban.with(this) .load(mOriginPictureLists) // 传人要压缩的图片列表 .ignoreBy(100) // 忽略不压缩图片的大小 .setTargetDir(mAfterCompressPicPath) // 设置压缩后文件存储位置 .setCompressListener(new OnCompressListener() { //设置回调 @Override public void onStart() { // TODO 压缩开始前调用,可以在方法内启动 loading UI LogUtil.e("开始压缩,调用loadingUI"); } @Override public void onSuccess(File file) { // TODO 压缩成功后调用,返回压缩后的图片文件 // 可以用图片列表下标来判断是否为最后一张图片,并停止loading UI File newFile = new File(mAfterCompressPicPath, "lzj" + System.currentTimeMillis()); file.renameTo(newFile); mPictureIndex++; LogUtil.e("压缩第" + mPictureIndex + "张成功!" + "文件名:" + newFile.getName() + ", 大小" + newFile.length() / 1000 +"KB"); } @Override public void onError(Throwable e) { // TODO 当压缩过程出现问题时调用 LogUtil.e("压缩第" + mPictureIndex + "失败!"); } }).launch(); //启动压缩 }
打印结果:
04-07 10:43:54.829 7000-7000/com.tupobi.testlubancompresspictuer E/AtyCompressListPictures$1.onStart(Line:54): 开始压缩,调用loadingUI
04-07 10:43:55.128 7000-7000/com.tupobi.testlubancompresspictuer E/AtyCompressListPictures$1.onSuccess(Line:63): 压缩第1张成功!文件名:lzj1523069035127, 大小246KB
04-07 10:43:55.128 7000-7000/com.tupobi.testlubancompresspictuer E/AtyCompressListPictures$1.onStart(Line:54): 开始压缩,调用loadingUI
04-07 10:43:55.446 7000-7000/com.tupobi.testlubancompresspictuer E/AtyCompressListPictures$1.onSuccess(Line:63): 压缩第2张成功!文件名:lzj1523069035446, 大小221KB
PS:这里.load(mOriginPictureLists) 传入的是一个图片路径的列表,对于每一张图片的处理都有回调。所以当要批量压缩图片时,可以判断图片列表的下标是否是最后一个了,然后停止loading UI
总结
现在android手机拍一张图片动辄3MB往上走,如果要将图片上传至服务器势必需要压缩。当然上传一张原图一张压缩后的更好,根据需求和资源而定。
采用Luban压缩图片的第三方框架很简洁,默认是异步执行。同步执行可以与RxJava1.x一起使用,不过好像还不支持2.x,使用RxJava最好也尽量避免在主线程调用以免阻塞主线程,下面以rxJava调用为例
Flowable.just(photos) .observeOn(Schedulers.io()) .map(new Function<List<String>, List<File>>() { @Override public List<File> apply(@NonNull List<String> list) throws Exception { // 同步方法直接返回压缩后的文件 return Luban.with(MainActivity.this).load(list).get(); } }) .observeOn(AndroidSchedulers.mainThread()) .subscribe();