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

第一种方式:采用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、避免内存过多的压缩方法:

归根结底,图片是要显示在界面组件上的,所以还是要用到bitmap,从上面可得出Bitmap的在内存中的大小只和图片尺寸和色彩模式有关,那么要想改变Bitmap在内存中的大小,要么改变尺寸,要么改变色彩模式。

2、避免上传浪费流量的压缩方法:

改变图片尺寸,改变色彩模式,改变图片质量都行。正常情况下,先改变图片尺寸和色彩模式,再改变图片质量。

改变图片质量的压缩方法:

[java] view plain copy
  1. /**
  2. *
  3. * 根据bitmap压缩图片质量
  4. * @param bitmap 未压缩的bitmap
  5. * @return 压缩后的bitmap
  6. */
  7. public static Bitmap cQuality(Bitmap bitmap){
  8. ByteArrayOutputStream bOut = new ByteArrayOutputStream();
  9. int beginRate = 100;
  10. //第一个参数 :图片格式 ,第二个参数: 图片质量,100为最高,0为最差  ,第三个参数:保存压缩后的数据的流
  11. bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bOut);
  12. while(bOut.size()/1024/1024>100){  //如果压缩后大于100Kb,则提高压缩率,重新压缩
  13. beginRate -=10;
  14. bOut.reset();
  15. bitmap.compress(Bitmap.CompressFormat.JPEG, beginRate, bOut);
  16. }
  17. ByteArrayInputStream bInt = new ByteArrayInputStream(bOut.toByteArray());
  18. Bitmap newBitmap = BitmapFactory.decodeStream(bInt);
  19. if(newBitmap!=null){
  20. return newBitmap;
  21. }else{
  22. return bitmap;
  23. }
  24. }

;

  • int toHeight = 800;
  • int be = 1;  //be = 1代表不缩放
  • if(bWidth/toWidth>bHeight/toHeight&&bWidth>toWidth){
  • be = (int)bWidth/toWidth;
  • }else if(bWidth/toWidth<bHeight/toHeight&&bHeight>toHeight){
  • 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);
  • }
  • 正常情况下我们应该把两者相结合的,所以有了下面的算法(在项目中直接用,清晰度在手机上没问题)

    [java] view plain copy
    1. public static File scal(Uri fileUri){
    2. String path = fileUri.getPath();
    3. File outputFile = new File(path);
    4. long fileSize = outputFile.length();
    5. final long fileMaxSize = 200 * 1024;
    6. if (fileSize >= fileMaxSize) {
    7. BitmapFactory.Options options = new BitmapFactory.Options();
    8. options.inJustDecodeBounds = true;
    9. BitmapFactory.decodeFile(path, options);
    10. int height = options.outHeight;
    11. int width = options.outWidth;
    12. double scale = Math.sqrt((float) fileSize / fileMaxSize);
    13. options.outHeight = (int) (height / scale);
    14. options.outWidth = (int) (width / scale);
    15. options.inSampleSize = (int) (scale + 0.5);
    16. options.inJustDecodeBounds = false;
    17. Bitmap bitmap = BitmapFactory.decodeFile(path, options);
    18. outputFile = new File(PhotoUtil.createImageFile().getPath());
    19. FileOutputStream fos = null;
    20. try {
    21. fos = new FileOutputStream(outputFile);
    22. bitmap.compress(Bitmap.CompressFormat.JPEG, 50, fos);
    23. fos.close();
    24. } catch (IOException e) {
    25. // TODO Auto-generated catch block
    26. e.printStackTrace();
    27. }
    28. Log.d("", "sss ok " + outputFile.length());
    29. if (!bitmap.isRecycled()) {
    30. bitmap.recycle();
    31. }else{
    32. File tempFile = outputFile;
    33. outputFile = new File(PhotoUtil.createImageFile().getPath());
    34. PhotoUtil.copyFileUsingFileChannels(tempFile, outputFile);
    35. }
    36. }
    37. return outputFile;
    38. }

    上面算法中用到的两个方法:

    [java] view plain copy
    1. public static Uri createImageFile(){
    2. // Create an image file name
    3. String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    4. String imageFileName = "JPEG_" + timeStamp + "_";
    5. File storageDir = Environment.getExternalStoragePublicDirectory(
    6. Environment.DIRECTORY_PICTURES);
    7. File image = null;
    8. try {
    9. image = File.createTempFile(
    10. imageFileName,  /* prefix */
    11. ".jpg",         /* suffix */
    12. storageDir      /* directory */
    13. );
    14. } catch (IOException e) {
    15. // TODO Auto-generated catch block
    16. e.printStackTrace();
    17. }
    18. // Save a file: path for use with ACTION_VIEW intents
    19. return Uri.fromFile(image);
    20. }
    21. public static void copyFileUsingFileChannels(File source, File dest){
    22. FileChannel inputChannel = null;
    23. FileChannel outputChannel = null;
    24. try {
    25. try {
    26. inputChannel = new FileInputStream(source).getChannel();
    27. outputChannel = new FileOutputStream(dest).getChannel();
    28. outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
    29. } catch (IOException e) {
    30. // TODO Auto-generated catch block
    31. e.printStackTrace();
    32. }
    33. } finally {
    34. try {
    35. inputChannel.close();
    36. outputChannel.close();
    37. } catch (IOException e) {
    38. // TODO Auto-generated catch block
    39. e.printStackTrace();
    40. }
    41. }
    42. }

    该项目的下载地址: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();
                }
            }
        }

    好了,大概就总结到这了。