前言:由于公司项目当中需要用到压缩这块的相应技术,之前也做过的图片压缩都不是特别的理想, 所以这次花了很多心思,仔细研究和在网上找到了很多相对应的资料。为了就是 以后再做的时候直接拿来用就可以了!
第一种方式:采用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

下面以我拍摄的图片为例,看下三者的大小区别(所用软件为自己临时开发的小工具);
从图中可以看出: 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个,一,避免占用内存过多。二,可能要上传图片,如果图片太大,浪费流量。(有时候需要上传原图除外)
1、避免内存过多的压缩方法:
归根结底,图片是要显示在界面组件上的,所以还是要用到bitmap,从上面可得出Bitmap的在内存中的大小只和图片尺寸和色彩模式有关,那么要想改变Bitmap在内存中的大小,要么改变尺寸,要么改变色彩模式。
2、避免上传浪费流量的压缩方法:
改变图片尺寸,改变色彩模式,改变图片质量都行。正常情况下,先改变图片尺寸和色彩模式,再改变图片质量。
改变图片质量的压缩方法:
- /**
- *
- * 根据bitmap压缩图片质量
- * @param bitmap 未压缩的bitmap
- * @return 压缩后的bitmap
- */
- public static Bitmap cQuality(Bitmap bitmap){
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
- int beginRate = 100;
- //第一个参数 :图片格式 ,第二个参数: 图片质量,100为最高,0为最差 ,第三个参数:保存压缩后的数据的流
- bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bOut);
- while(bOut.size()/1024/1024>100){ //如果压缩后大于100Kb,则提高压缩率,重新压缩
- beginRate -=10;
- bOut.reset();
- bitmap.compress(Bitmap.CompressFormat.JPEG, beginRate, bOut);
- }
- ByteArrayInputStream bInt = new ByteArrayInputStream(bOut.toByteArray());
- Bitmap newBitmap = BitmapFactory.decodeStream(bInt);
- if(newBitmap!=null){
- return newBitmap;
- }else{
- return bitmap;
- }
- }
- public static boolean getCacheImage(String filePath,String cachePath){
- OutputStream out = null;
- BitmapFactory.Options option = new BitmapFactory.Options();
- option.inJustDecodeBounds = true; //设置为true,只读尺寸信息,不加载像素信息到内存
- Bitmap bitmap = BitmapFactory.decodeFile(filePath, option); //此时bitmap为空
- option.inJustDecodeBounds = false;
- int bWidth = option.outWidth;
- int bHeight= option.outHeight;
- int toWidth = 400;
- int toHeight = 800;
- int be = 1; //be = 1代表不缩放
- if(bWidth/toWidth>bHeight/toHeight&&bWidth>toWidth){
- be = (int)bWidth/toWidth;
- }else if(bWidth/toWidthtoHeight){
- be = (int)bHeight/toHeight;
- }
- option.inSampleSize = be; //设置缩放比例
- bitmap = BitmapFactory.decodeFile(filePath, option);
- try {
- out = new FileOutputStream(new File(cachePath));
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return bitmap.compress(CompressFormat.JPEG, 100, out);
- }
正常情况下我们应该把两者相结合的,所以有了下面的算法(在项目中直接用,清晰度在手机上没问题)
- public static File scal(Uri fileUri){
- String path = fileUri.getPath();
- File outputFile = new File(path);
- long fileSize = outputFile.length();
- final long fileMaxSize = 200 * 1024;
- if (fileSize >= fileMaxSize) {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- BitmapFactory.decodeFile(path, options);
- int height = options.outHeight;
- int width = options.outWidth;
- double scale = Math.sqrt((float) fileSize / fileMaxSize);
- options.outHeight = (int) (height / scale);
- options.outWidth = (int) (width / scale);
- options.inSampleSize = (int) (scale + 0.5);
- options.inJustDecodeBounds = false;
- Bitmap bitmap = BitmapFactory.decodeFile(path, options);
- outputFile = new File(PhotoUtil.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();
- }
- Log.d("", "sss ok " + outputFile.length());
- if (!bitmap.isRecycled()) {
- bitmap.recycle();
- }else{
- File tempFile = outputFile;
- outputFile = new File(PhotoUtil.createImageFile().getPath());
- PhotoUtil.copyFileUsingFileChannels(tempFile, outputFile);
- }
- }
- return outputFile;
- }
上面算法中用到的两个方法:
- public static Uri createImageFile(){
- // Create an image file name
- String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new 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();
- }
- }
- }
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();
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(); } } }