前言:由于公司项目当中需要用到压缩这块的相应技术,之前也做过的图片压缩都不是特别的理想,
所以这次花了很多心思,仔细研究和在网上找到了很多相对应的资料。为了就是
以后再做的时候直接拿来用就可以了!
第一种方式:采用JNI调用libjpeg库来进行压缩
介绍Android图片压缩结合多种压缩方式,常用的有尺寸压缩、质量压缩以及通过JNI调用libjpeg库来进行压缩,三种方式结合使用实现指定图片内存大小,清晰度达到最优。
使用
- 导入lib-bither-compress
NativeUtil.compressBitmap(bitmap, savePath);
NativeUtil.compressBitmap(bitmap, savePath, maxByte, quality);
- 图像建议尺寸
public final static int QUALITY_320P = 320;//480, 320
public final static int QUALITY_360P = 360;//640, 360
public final static int QUALITY_480P = 480;//640, 480
public final static int QUALITY_720P = 720;//1280, 720
public final static int QUALITY_1080P = 1080;//1920, 1080
public final static int QUALITY_2K = 1440;//2560, 1440
public final static int QUALITY_4K = 2160;//3840, 2160
- 图像默认品质
//见 NativeUtil 中 compressBitmap(bitmap, savePath, maxByte, quality) 方法
int options = 80;//100不压缩品质
注意:默认将图像压缩到 1280*720 的尺寸,品质为 80 ,图像大小为 1 MB。其他配置可在 lib-bither-compress 中 NativeUtil 下自己配置。
对比
原图 5.5M
项目的下载地址:https://github.com/jeanboydev/Android-BitherCompress
第二种方式:使用系统自带的压缩,并做相应的修改
1.文件形式(即以二进制形式存在于硬盘上) 获取大小(Byte):File.length()2.流的形式(即以二进制形式存在于内存中) 获取大小(Byte):new FileInputStream(File).available()3.Bitmap形式 获取大小(Byte):Bitmap.getByteCount()
下面以我拍摄的图片为例,看下三者的大小区别(所用软件为自己临时开发的小工具);
从图中可以看出:
1、拍摄完的照片文件大小和读取到内存中的文件流大小是一样的,说明文件形式和流的形式对图片体积大小并没有影响。
2、当图片以Bitmap形式存在时,占用的内存就大的多了,为什么 呢,首先我们需要知道Bitmap大小计算的方式
bitmap大小=图片长度(px)*图片宽度(px)*单位像素占用的字节数
单位像素所占字节数又是什么鬼,说白了就是图片的色彩模式。
在BitmapFactory.Options.inPreferredConfig这里可以找到,一共有4种, ARGB代表:A 透明度 , R 红色, G 绿色, B 蓝色
上面的bitmap在内存中的大小就可以计算了(默认色彩模式为ARGB_8888),
2368*4224*4/1024/1024=38.15625
看到bitmap占用这么大,所以用完调用Bitmap.recycle()是个好习惯(推荐),不调用也没关系,因为GC进程会自动回收。
二 图片的压缩形式
问:我们从本地对图片操作的目的。是
答:上传(比如设置头像,发表图片)。
上传的基本步骤
那么问题来了
问:我们为什么要压缩图片呢
2个,一,避免占用内存过多。二,可能要上传图片,如果图片太大,浪费流量。(有时候需要上传原图除外)
、避免内存过多的压缩方法:
归根结底,图片是要显示在界面组件上的,所以还是要用到bitmap,从上面可得出Bitmap的在内存中的大小只和图片尺寸和色彩模式有关,那么要想改变Bitmap在内存中的大小,要么改变尺寸,要么改变色彩模式。
2、避免上传浪费流量的压缩方法:
改变图片尺寸,改变色彩模式,改变图片质量都行。正常情况下,先改变图片尺寸和色彩模式,再改变图片质量。
改变图片质量的压缩方法:
1. /**
2. *
3. * 根据bitmap压缩图片质量
4. * @param bitmap 未压缩的bitmap
5. * @return 压缩后的bitmap
6. */
7. public static Bitmap cQuality(Bitmap bitmap){
8. new ByteArrayOutputStream();
9. int beginRate = 100;
10. //第一个参数 :图片格式 ,第二个参数: 图片质量,100为最高,0为最差 ,第三个参数:保存压缩后的数据的流
11. 100, bOut);
12. while(bOut.size()/1024/1024>100){ //如果压缩后大于100Kb,则提高压缩率,重新压缩
13. 10;
14. bOut.reset();
15. bitmap.compress(Bitmap.CompressFormat.JPEG, beginRate, bOut);
16. }
17. new ByteArrayInputStream(bOut.toByteArray());
18. Bitmap newBitmap = BitmapFactory.decodeStream(bInt);
19. if(newBitmap!=null){
20. return newBitmap;
21. else{
22. return bitmap;
23. }
24. }
改变图片大小的压缩算法:
1. public static boolean getCacheImage(String filePath,String cachePath){
2. null;
3. new BitmapFactory.Options();
4. true; //设置为true,只读尺寸信息,不加载像素信息到内存
5. //此时bitmap为空
6. false;
7. int bWidth = option.outWidth;
8. int bHeight= option.outHeight;
9. int toWidth = 400;
10. int toHeight = 800;
11. int be = 1; //be = 1代表不缩放
12. if(bWidth/toWidth>bHeight/toHeight&&bWidth>toWidth){
13. int)bWidth/toWidth;
14. else if(bWidth/toWidth<bHeight/toHeight&&bHeight>toHeight){
15. int)bHeight/toHeight;
16. }
17. //设置缩放比例
18. bitmap = BitmapFactory.decodeFile(filePath, option);
19. try {
20. new FileOutputStream(new File(cachePath));
21. catch (IOException e) {
22. // TODO Auto-generated catch block
23. e.printStackTrace();
24. }
25. return bitmap.compress(CompressFormat.JPEG, 100, out);
26. }
正常情况下我们应该把两者相结合的,所以有了下面的算法(在项目中直接用,清晰度在手机上没问题)
1. public static File scal(Uri fileUri){
2. String path = fileUri.getPath();
3. new File(path);
4. long fileSize = outputFile.length();
5. final long fileMaxSize = 200 * 1024;
6. if (fileSize >= fileMaxSize) {
7. new BitmapFactory.Options();
8. true;
9. BitmapFactory.decodeFile(path, options);
10. int height = options.outHeight;
11. int width = options.outWidth;
12.
13. double scale = Math.sqrt((float) fileSize / fileMaxSize);
14. int) (height / scale);
15. int) (width / scale);
16. int) (scale + 0.5);
17. false;
18.
19. Bitmap bitmap = BitmapFactory.decodeFile(path, options);
20. new File(PhotoUtil.createImageFile().getPath());
21. null;
22. try {
23. new FileOutputStream(outputFile);
24. 50, fos);
25. fos.close();
26. catch (IOException e) {
27. // TODO Auto-generated catch block
28. e.printStackTrace();
29. }
30. "", "sss ok " + outputFile.length());
31. if (!bitmap.isRecycled()) {
32. bitmap.recycle();
33. else{
34. File tempFile = outputFile;
35. new File(PhotoUtil.createImageFile().getPath());
36. PhotoUtil.copyFileUsingFileChannels(tempFile, outputFile);
37. }
38.
39. }
40. return outputFile;
41.
42. }
上面算法中用到的两个方法:
1. public static Uri createImageFile(){
2. // Create an image file name
3. new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
4. "JPEG_" + timeStamp + "_";
5. File storageDir = Environment.getExternalStoragePublicDirectory(
6. Environment.DIRECTORY_PICTURES);
7. null;
8. try {
9. image = File.createTempFile(
10. /* prefix */
11. ".jpg", /* suffix */
12. /* directory */
13. );
14. catch (IOException e) {
15. // TODO Auto-generated catch block
16. e.printStackTrace();
17. }
18.
19. // Save a file: path for use with ACTION_VIEW intents
20. return Uri.fromFile(image);
21. }
22. public static void copyFileUsingFileChannels(File source, File dest){
23. null;
24. null;
25. try {
26. try {
27. new FileInputStream(source).getChannel();
28. new FileOutputStream(dest).getChannel();
29. 0, inputChannel.size());
30. catch (IOException e) {
31. // TODO Auto-generated catch block
32. e.printStackTrace();
33. }
34. finally {
35. try {
36. inputChannel.close();
37. outputChannel.close();
38. catch (IOException e) {
39. // TODO Auto-generated catch block
40. e.printStackTrace();
41. }
42. }
43. }
该项目的下载地址:https://github.com/lbool/Android-Image-Upload
三。自己搞的一种
public File compress(String srcPath) { File imageFile = new File(srcPath); uri = Uri.fromFile(imageFile);
float oldSize = (float)new File(uri.getPath()).length()/1024/1024; //以文件的形式
System.out.println("进来大小"+oldSize);
DisplayMetrics dm =new DisplayMetrics();
WindowManager manager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
manager.getDefaultDisplay().getMetrics(dm);
float hh = dm.heightPixels;
float ww = dm.widthPixels;
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(srcPath, opts);
opts.inJustDecodeBounds = false;
int w = opts.outWidth;
int h = opts.outHeight;
int size = 0;
if (w <= ww && h <= hh) {
size = 1;
} else {
double scale = w >= h ? w / ww : h / hh;
double log = Math.log(scale) / Math.log(2);
double logCeil = Math.ceil(log);
size = (int) Math.pow(2, logCeil);
}
opts.inSampleSize = size;
bitmap = BitmapFactory.decodeFile(srcPath, opts);
File outputFile = new File(createImageFile().getPath());
FileOutputStream fileOutputStream;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int quality = 100;
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
System.out.println("实际的大小"+baos.toByteArray().length/1024);
while (baos.toByteArray().length > 30 * 1024) {
baos.reset();
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
quality -= 20;
System.out.println("完成的大小"+baos.toByteArray().length/1024);
}
try {
fileOutputStream=new FileOutputStream(outputFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
baos.writeTo(fileOutputStream);
fileOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
baos.flush();
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return outputFile;
}
public static Uri createImageFile(){
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new java.util.Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File image = null;
try {
image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Save a file: path for use with ACTION_VIEW intents
return Uri.fromFile(image);
}
public static void copyFileUsingFileChannels(File source, File dest){
FileChannel inputChannel = null;
FileChannel outputChannel = null;
try {
try {
inputChannel = new FileInputStream(source).getChannel();
outputChannel = new FileOutputStream(dest).getChannel();
outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} finally {
try {
inputChannel.close();
outputChannel.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
第四种(最接近微信的一个)
Luban
项目描述
目前做App
开发总绕不开图片这个元素。但是随着手机拍照分辨率的提升,图片的压缩成为一个很重要的问题。单纯对图片进行裁切,压缩已经有很多文章介绍。但是裁切成多少,压缩成多少却很难控制好,裁切过头图片太小,质量压缩过头则显示效果太差。于是自然想到App
巨头“微信”会是怎么处理,Luban
(鲁班)就是通过在微信朋友圈发送近100张不同分辨率图片,对比原图与微信压缩后的图片逆向推算出来的压缩算法。因为有其他语言也想要实现Luban
,所以描述了一遍算法步骤。
因为是逆向推算,效果还没法跟微信一模一样,但是已经很接近微信朋友圈压缩后的效果,具体看以下对比!
效果与对比
内容 | 原图 | Luban | Wechat |
截屏 720P | 720*1280,390k | 720*1280,87k | 720*1280,56k |
截屏 1080P | 1080*1920,2.21M | 1080*1920,104k | 1080*1920,112k |
拍照 13M(4:3) | 3096*4128,3.12M | 1548*2064,141k | 1548*2064,147k |
拍照 9.6M(16:9) | 4128*2322,4.64M | 1032*581,97k | 1032*581,74k |
滚动截屏 | 1080*6433,1.56M | 1080*6433,351k | 1080*6433,482k |
导入
compile 'top.zibin:Luban:1.1.2'
使用
异步调用
Luban
内部采用IO
线程进行图片压缩,外部调用只需设置好结果监听即可:
Luban.with(this)
.load(File) //传人要压缩的图片
.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(); //启动压缩
同步调用
同步方法请尽量避免在主线程调用以免阻塞主线程,下面以rxJava调用为例
Flowable.just(file)
.observeOn(Schedulers.io())
.map(new Function<File, File>() {
@Override public File apply(@NonNull File file) throws Exception {
// 同步方法直接返回压缩后的文件
return Luban.with(MainActivity.this).load(file).get();
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe();
项目下载地址:https://github.com/Curzibn/Luban
最后添加几个压缩工具类
BitmapUtils类
public class BitmapUtils {
/**
* 从本地读取图片
*
* @param path
* @return
*/
public static Bitmap getBitmapForPath(String path) {
try {
FileInputStream in = new FileInputStream(path);
Bitmap bitmap = BitmapFactory.decodeStream(in);
in.close();
return bitmap;
} catch (Exception e) {
}
return null;
}
/**
* 获取资源文件中的图片
*
* @param context
* @param resourcesId
* @return
*/
public static Drawable getDrawableFormResources(Context context, int resourcesId) {
Resources resources = context.getResources();
return new BitmapDrawable(resources, BitmapFactory.decodeResource(resources, resourcesId));
}
/**
* 从资源文件中获取bitmap对象
*
* @param context
* @param resourcesId
* @return
*/
public static Bitmap getBitmapFromResources(Context context, int resourcesId) {
return BitmapFactory.decodeResource(context.getResources(), resourcesId);
}
/**
* bitmap转byte数组
*
* @param bitmap
* @return
*/
public static byte[] getBitmapbyte(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] datas = baos.toByteArray();
try {
baos.flush();
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
return datas;
}
/**
* bitmap转byte数组
*
* @param bitmap
* @return
*/
public static String getBitmapBase64byte(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] datas = baos.toByteArray();
String encodeToString = Base64.encodeToString(datas, Base64.DEFAULT);
try {
baos.flush();
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
return encodeToString;
}
/**
* byte转bitmap数组
*
* @param b
* @return
*/
public static Bitmap getBitmaoFrombyte(byte[] b) {
return BitmapFactory.decodeByteArray(b, 0, b.length);
}
/**
* 压缩0
*
* @param srcPath
* @return
*/
public static Bitmap getimageIcon(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 = 312f;//这里设置高度为800f
float ww = 650f;//这里设置宽度为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了
bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
return compressImage(bitmap);//压缩好比例大小后再进行质量压缩
}
/**
* 压缩1
*
* @param srcPath
* @return
*/
public static Bitmap getimage(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 = 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了
bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
return compressImage(bitmap);//压缩好比例大小后再进行质量压缩
}
//把bitmap转换成String
// public static String bitmapToString(String filePath) {
//
// Bitmap bm = getSmallBitmap(filePath);
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
// bm.compress(Bitmap.CompressFormat.JPEG, 40, baos);
// byte[] b = baos.toByteArray();
// return Base64.encodeToString(b, Base64.DEFAULT);
// }
/**
* 压缩2
*
* @param image
* @return
*/
public static Bitmap comp(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, 30, 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;//设置缩放比例
newOpts.inPreferredConfig = Bitmap.Config.RGB_565;//降低图片从ARGB888到RGB565
//重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
isBm = new ByteArrayInputStream(baos.toByteArray());
bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
return compressImage(bitmap);//压缩好比例大小后再进行质量压缩
}
/**
* 质量压缩
*
* @param image
* @return
*/
public static Bitmap compressImage(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
int options = 100;
while (baos.toByteArray().length / 1024 > 100) { //循环判断如果压缩后图片是否大于100kb,大于继续压缩
baos.reset();//重置baos即清空baos
options -= 20;//每次都减少10
image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片
return bitmap;
}
/**
* 获取图片大小
*
* @param bitmap
* @return
*/
public static long getBitmapsize(Bitmap bitmap) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
return bitmap.getByteCount();
}
return bitmap.getRowBytes() * bitmap.getHeight();
}
/**
* 对图片进行模糊处理
*
* @param bitmap
* @param context
* @return
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public static Bitmap blurBitmap(Bitmap bitmap, Context context) {
Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
RenderScript rs = RenderScript.create(context.getApplicationContext());
ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
Allocation allIn = Allocation.createFromBitmap(rs, bitmap);
Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);
blurScript.setRadius(25f);
blurScript.setInput(allIn);
blurScript.forEach(allOut);
allOut.copyTo(outBitmap);
bitmap.recycle();
rs.destroy();
return outBitmap;
}
public static Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap = Bitmap.createBitmap(
drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(),
drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
//canvas.setBitmap(bitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
drawable.draw(canvas);
return bitmap;
}
/**
* 水平方向模糊度
*/
private static float hRadius = 10;
/**
* 竖直方向模糊度
*/
private static float vRadius = 10;
/**
* 模糊迭代度
*/
private static int iterations = 7;
private static float a = 1.3f;
/**
* 模糊图片
*
* @param bmp
* @return
*/
public static Drawable BoxBlurFilter(Bitmap bmp) {
hRadius = hRadius * a;
vRadius = vRadius * a;
iterations = (int) (iterations * a);
int width = bmp.getWidth();
int height = bmp.getHeight();
int[] inPixels = new int[width * height];
int[] outPixels = new int[width * height];
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bmp.getPixels(inPixels, 0, width, 0, 0, width, height);
for (int i = 0; i < iterations; i++) {
blur(inPixels,
outPixels, width, height, hRadius);
blur(outPixels,
inPixels, height, width, vRadius);
}
blurFractional(inPixels,
outPixels, width, height, hRadius);
blurFractional(outPixels,
inPixels, height, width, vRadius);
bitmap.setPixels(inPixels,
0,
width, 0,
0,
width, height);
Drawable drawable = new BitmapDrawable(bitmap);
return drawable;
}
public static void blur(int[] in, int[] out, int width, int height, float radius) {
int widthMinus1 = width - 1;
int r = (int) radius;
int tableSize = 2 * r + 1;
int divide[] = new int[256 * tableSize];
for (int i = 0; i < 256 * tableSize; i++)
divide[i] = i / tableSize;
int inIndex = 0;
for (int y = 0; y < height; y++) {
int outIndex = y;
int ta = 0, tr = 0, tg = 0, tb = 0;
for (int i = -r; i <= r; i++) {
int rgb = in[inIndex + clamp(i, 0, width - 1)];
ta += (rgb >> 24) & 0xff;
tr += (rgb >> 16) & 0xff;
tg += (rgb >> 8) & 0xff;
tb += rgb & 0xff;
}
for (int x = 0; x < width; x++) {
out[outIndex] = (divide[ta] << 24) | (divide[tr] << 16) | (divide[tg] << 8)
| divide[tb];
int i1 = x + r + 1;
if (i1 > widthMinus1)
i1 = widthMinus1;
int i2 = x - r;
if (i2 < 0)
i2 = 0;
int rgb1 = in[inIndex + i1];
int rgb2 = in[inIndex + i2];
ta += ((rgb1 >> 24) & 0xff) - ((rgb2 >> 24) & 0xff);
tr += ((rgb1 & 0xff0000) - (rgb2 & 0xff0000)) >> 16;
tg += ((rgb1 & 0xff00) - (rgb2 & 0xff00)) >> 8;
tb += (rgb1 & 0xff) - (rgb2 & 0xff);
outIndex += height;
}
inIndex += width;
}
}
public static void blurFractional(int[] in, int[] out, int width, int height, float radius) {
radius -= (int) radius;
float f = 1.0f / (1 + 2 * radius);
int inIndex = 0;
for (int y = 0; y < height; y++) {
int outIndex = y;
out[outIndex] = in[0];
outIndex += height;
for (int x = 1; x < width - 1; x++) {
int i = inIndex + x;
int rgb1 = in[i - 1];
int rgb2 = in[i];
int rgb3 = in[i + 1];
int a1 = (rgb1 >> 24)
& 0xff;
int r1
= (rgb1 >> 16)
& 0xff;
int g1
= (rgb1 >> 8)
& 0xff;
int b1
= rgb1 & 0xff;
int a2
= (rgb2 >> 24)
& 0xff;
int r2
= (rgb2 >> 16)
& 0xff;
int g2
= (rgb2 >> 8)
& 0xff;
int b2
= rgb2 & 0xff;
int a3
= (rgb3 >> 24)
& 0xff;
int r3
= (rgb3 >> 16)
& 0xff;
int g3
= (rgb3 >> 8)
& 0xff;
int b3
= rgb3 & 0xff;
a1
= a2 + (int)
((a1 + a3) * radius);
r1
= r2 + (int)
((r1 + r3) * radius);
g1
= g2 + (int)
((g1 + g3) * radius);
b1
= b2 + (int)
((b1 + b3) * radius);
a1
*= f;
r1
*= f;
g1
*= f;
b1
*= f;
out[outIndex]
= (a1 << 24)
| (r1 << 16)
| (g1 << 8)
| b1;
outIndex
+= height;
}
out[outIndex]
= in[width - 1];
inIndex
+= width;
}
}
public static int clamp(int x,
int a,
int b) {
return (x
< a) ? a : (x > b) ? b : x;
}
public static String getImageUrl(Context context, Uri photoUri) {
String res = null;
String[] proj = {MediaStore.Images.Media.DATA};
Cursor cursor = context.getContentResolver().query(photoUri, proj, null, null, null);
if (cursor.moveToFirst()) {
;
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
res = cursor.getString(column_index);
}
cursor.close();
return res;
}
/**
* 将Bitmap转换成文件
* 保存文件
*
* @param bm
* @param fileName
* @throws IOException
*/
public static File saveFile(Bitmap bm, String path, String fileName) throws IOException {
File dirFile = new File(path);
if (!dirFile.exists()) {
dirFile.mkdir();
}
File myCaptureFile = new File(path, fileName);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile));
bm.compress(Bitmap.CompressFormat.JPEG, 80, bos);
bos.flush();
bos.close();
return myCaptureFile;
}
/**
* 路径转换成file
*
* @param filePath
* @return
*/
public static File BetyToFile(String filePath) {
File file = new File(filePath);
BufferedOutputStream stream = null;
FileOutputStream fstream = null;
byte[] data = new byte[(int) file.length()];
try {
fstream = new FileOutputStream(file);
stream = new BufferedOutputStream(fstream);
stream.write(data);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (stream != null) {
stream.close();
}
if (null != fstream) {
fstream.close();
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
return file;
}
ImageCompress类
public class ImageCompress {
public static final String CONTENT = "content";
public static final String FILE = "file";
/**
* 调用
ImageCompress compress = new ImageCompress();
ImageCompress.CompressOptions options = new ImageCompress.CompressOptions();
options.uri = Uri.fromFile(new File(sourcePath));
options.maxWidth=Constants.RESIZEBITMAP_WIDTH;
options.maxHeight=Constants.RESIZEBITMAP_HEIGHT;
Bitmap bitmap = compress.compressFromUri(UploadWithPhotoBaseActivity.this, options);*/
/**
* 图片压缩参数
*
* @author Administrator
*/
public static class CompressOptions {
public static final int DEFAULT_WIDTH = 400;
public static final int DEFAULT_HEIGHT = 800;
public int maxWidth = DEFAULT_WIDTH;
public int maxHeight = DEFAULT_HEIGHT;
/**
* 压缩后图片保存的文件
*/
public File destFile;
/**
* 图片压缩格式,默认为jpg格式
*/
public Bitmap.CompressFormat imgFormat = Bitmap.CompressFormat.JPEG;
/**
* 图片压缩比例 默认为30
*/
public int quality = 30;
public Uri uri;
}
/**
* 返回bitmap
* @param context
* @param compressOptions
* @return
*/
public Bitmap compressFromUri(Context context, CompressOptions compressOptions) {
// uri指向的文件路径
String filePath = getFilePath(context, compressOptions.uri);
if (null == filePath) {
return null;
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap temp = BitmapFactory.decodeFile(filePath, options);
int actualWidth = options.outWidth;
int actualHeight = options.outHeight;
int desiredWidth = getResizedDimension(compressOptions.maxWidth,
compressOptions.maxHeight, actualWidth, actualHeight);
int desiredHeight = getResizedDimension(compressOptions.maxHeight,
compressOptions.maxWidth, actualHeight, actualWidth);
options.inJustDecodeBounds = false;
options.inSampleSize = findBestSampleSize(actualWidth, actualHeight,
desiredWidth, desiredHeight);
Bitmap bitmap = null;
Bitmap destBitmap = BitmapFactory.decodeFile(filePath, options);
// If necessary, scale down to the maximal acceptable size.
if (destBitmap.getWidth() > desiredWidth
|| destBitmap.getHeight() > desiredHeight) {
bitmap = Bitmap.createScaledBitmap(destBitmap, desiredWidth,
desiredHeight, true);
destBitmap.recycle();
} else {
bitmap = destBitmap;
}
// compress file if need
if (null != compressOptions.destFile) {
compressFile(compressOptions, bitmap);
}
return bitmap;
}
/**
* 返回file形式
* @param context
* @param compressOptions
* @return
*/
public File compressFromUriFile(Context context, CompressOptions compressOptions) {
// uri指向的文件路径
String filePath = getFilePath(context, compressOptions.uri);
File outputFile = new File(filePath);
Log.i("INFO", "路径" + filePath);
if (null == filePath) {
return null;
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap temp = BitmapFactory.decodeFile(filePath, options);
int actualWidth = options.outWidth;
int actualHeight = options.outHeight;
int desiredWidth = getResizedDimension(compressOptions.maxWidth,
compressOptions.maxHeight, actualWidth, actualHeight);
int desiredHeight = getResizedDimension(compressOptions.maxHeight,
compressOptions.maxWidth, actualHeight, actualWidth);
options.inJustDecodeBounds = false;
options.inSampleSize = findBestSampleSize(actualWidth, actualHeight,
desiredWidth, desiredHeight);
Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
outputFile = new File(createImageFile().getPath());
FileOutputStream fos = null;
try {
fos = new FileOutputStream(outputFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, fos);
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (!bitmap.isRecycled()) {
bitmap.recycle();
} else {
File tempFile = outputFile;
outputFile = new File(createImageFile().getPath());
copyFileUsingFileChannels(tempFile, outputFile);
}
// compress file if need
if (null != compressOptions.destFile) {
// compressFile(compressOptions, bitmap);
File tempFile = outputFile;
outputFile = new File(createImageFile().getPath());
copyFileUsingFileChannels(tempFile, outputFile);
}
return outputFile;
}
/**
* compress file from bitmap with compressOptions
*
* @param compressOptions
* @param bitmap
*/
private void compressFile(CompressOptions compressOptions, Bitmap bitmap) {
OutputStream stream = null;
try {
stream = new FileOutputStream(compressOptions.destFile);
} catch (FileNotFoundException e) {
Log.e("ImageCompress", e.getMessage());
}
bitmap.compress(compressOptions.imgFormat, compressOptions.quality,
stream);
}
private static int findBestSampleSize(int actualWidth, int actualHeight,
int desiredWidth, int desiredHeight) {
double wr = (double) actualWidth / desiredWidth;
double hr = (double) actualHeight / desiredHeight;
double ratio = Math.min(wr, hr);
float n = 1.0f;
while ((n * 2) <= ratio) {
n *= 2;
}
return (int) n;
}
private static int getResizedDimension(int maxPrimary, int maxSecondary,
int actualPrimary, int actualSecondary) {
// If no dominant value at all, just return the actual.
if (maxPrimary == 0 && maxSecondary == 0) {
return actualPrimary;
}
// If primary is unspecified, scale primary to match secondary's scaling
// ratio.
if (maxPrimary == 0) {
double ratio = (double) maxSecondary / (double) actualSecondary;
return (int) (actualPrimary * ratio);
}
if (maxSecondary == 0) {
return maxPrimary;
}
double ratio = (double) actualSecondary / (double) actualPrimary;
int resized = maxPrimary;
if (resized * ratio > maxSecondary) {
resized = (int) (maxSecondary / ratio);
}
return resized;
}
/**
* 获取文件的路径
*
* @param
* @return
*/
private String getFilePath(Context context, Uri uri) {
String filePath = null;
if (CONTENT.equalsIgnoreCase(uri.getScheme())) {
Cursor cursor = context.getContentResolver().query(uri,
new String[]{MediaStore.Images.Media.DATA}, null, null, null);
if (null == cursor) {
return null;
}
try {
if (cursor.moveToNext()) {
filePath = cursor.getString(cursor
.getColumnIndex(MediaStore.Images.Media.DATA));
}
} finally {
cursor.close();
}
}
// 从文件中选择
if (FILE.equalsIgnoreCase(uri.getScheme())) {
filePath = uri.getPath();
}
return filePath;
}
/**
* 创建一个新的文件夹,保存压缩后的图片
* @return
*/
public static Uri createImageFile() {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new java.util.Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File image = null;
try {
image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Save a file: path for use with ACTION_VIEW intents
return Uri.fromFile(image);
}
public static void copyFileUsingFileChannels(File source, File dest) {
FileChannel inputChannel = null;
FileChannel outputChannel = null;
try {
try {
inputChannel = new FileInputStream(source).getChannel();
outputChannel = new FileOutputStream(dest).getChannel();
outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} finally {
try {
inputChannel.close();
outputChannel.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
好了,大概就总结到这了。