package com.luck.picture.lib.compress;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.os.Handler;
import com.yalantis.ucrop.util.FileUtils;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
/**
* author:luck
* project:PictureSelector
* email:893855882@qq.com
* data:16/12/31
*/
public class CompressImageUtil {
private CompressConfig config;
private Context context;
Handler mhHandler = new Handler();
public CompressImageUtil(Context context, CompressConfig config) {
this.context = context;
this.config = config == null ? CompressConfig.ofDefaultConfig() : config;
}
public void compress(String imagePath, CompressListener listener) {
if (config.isEnablePixelCompress()) {
try {
compressImageByPixel(imagePath, listener);
} catch (FileNotFoundException e) {
listener.onCompressFailed(imagePath, String.format("图片压缩失败,%s", e.toString()));
e.printStackTrace();
}
} else {
compressImageByQuality(BitmapFactory.decodeFile(imagePath), imagePath, listener);
}
}
/**
* 多线程压缩图片的质量
*
* @param bitmap 内存中的图片
* @param imgPath 图片的保存路径
* @author JPH
* @date 2014-12-5下午11:30:43
*/
private void compressImageByQuality(final Bitmap bitmap, final String imgPath, final CompressListener listener) {
if (bitmap == null) {
sendMsg(false, imgPath, "像素压缩失败,bitmap is null", listener);
return;
}
new Thread(new Runnable() {//开启多线程进行压缩处理
@Override
public void run() {
// TODO Auto-generated method stub
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int options = 100;
bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);//质量压缩方法,把压缩后的数据存放到baos中 (100表示不压缩,0表示压缩到最小)
while (baos.toByteArray().length > config.getMaxSize()) {//循环判断如果压缩后图片是否大于指定大小,大于继续压缩
baos.reset();//重置baos即让下一次的写入覆盖之前的内容
options -= 5;//图片质量每次减少5
if (options <= 5) options = 5;//如果图片质量小于5,为保证压缩后的图片质量,图片最底压缩质量为5
bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);//将压缩后的图片保存到baos中
if (options == 5) break;//如果图片的质量已降到最低则,不再进行压缩
}
// if(bitmap!=null&&!bitmap.isRecycled()){
// bitmap.recycle();//回收内存中的图片
// }
try {
File thumbnailFile = getThumbnailFile(new File(imgPath));
FileOutputStream fos = new FileOutputStream(thumbnailFile);//将压缩后的图片保存的本地上指定路径中
fos.write(baos.toByteArray());
fos.flush();
fos.close();
sendMsg(true, thumbnailFile.getPath(), null, listener);
} catch (Exception e) {
sendMsg(false, imgPath, "质量压缩失败", listener);
e.printStackTrace();
}
}
}).start();
}
/**
* 按比例缩小图片的像素以达到压缩的目的
*
* @param imgPath
* @return
* @author JPH
* @date 2014-12-5下午11:30:59
*/
private void compressImageByPixel(String imgPath, CompressListener listener) throws FileNotFoundException {
if (imgPath == null) {
sendMsg(false, imgPath, "要压缩的文件不存在", listener);
return;
}
BitmapFactory.Options newOpts = new BitmapFactory.Options();
newOpts.inJustDecodeBounds = true;//只读边,不读内容
BitmapFactory.decodeFile(imgPath, newOpts);
newOpts.inJustDecodeBounds = false;
int width = newOpts.outWidth;
int height = newOpts.outHeight;
float maxSize = config.getMaxPixel();
int be = 1;
if (width >= height && width > maxSize) {//缩放比,用高或者宽其中较大的一个数据进行计算
be = (int) (newOpts.outWidth / maxSize);
be++;
} else if (width < height && height > maxSize) {
be = (int) (newOpts.outHeight / maxSize);
be++;
}
newOpts.inSampleSize = be;//设置采样率
newOpts.inPreferredConfig = Config.ARGB_8888;//该模式是默认的,可不设
newOpts.inPurgeable = true;// 同时设置才会有效
newOpts.inInputShareable = true;//。当系统内存不够时候图片自动被回收
Bitmap bitmap = BitmapFactory.decodeFile(imgPath, newOpts);
if (config.isEnableQualityCompress()) {
compressImageByQuality(bitmap, imgPath, listener);//压缩好比例大小后再进行质量压缩
} else {
File thumbnailFile = getThumbnailFile(new File(imgPath));
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(thumbnailFile));
listener.onCompressSuccess(thumbnailFile.getPath());
}
}
/**
* 发送压缩结果的消息
*
* @param isSuccess 压缩是否成功
* @param imagePath
* @param message
*/
private void sendMsg(final boolean isSuccess, final String imagePath, final String message, final CompressListener listener) {
mhHandler.post(new Runnable() {
@Override
public void run() {
if (isSuccess) {
listener.onCompressSuccess(imagePath);
} else {
listener.onCompressFailed(imagePath, message);
}
}
});
}
private File getThumbnailFile(File file) {
if (file == null || !file.exists()) return file;
return FileUtils.getPhotoCacheDir(context, file);
}
/**
* 压缩结果监听器
*/
public interface CompressListener {
/**
* 压缩成功
*
* @param imgPath 压缩图片的路径
*/
void onCompressSuccess(String imgPath);
/**
* 压缩失败
*
* @param imgPath 压缩失败的图片
* @param msg 失败的原因
*/
void onCompressFailed(String imgPath, String msg);
}
}