Android 图片压缩各种方式

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

第一种方式:采用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个,一,避免占用内存过多。二,可能要上传图片,如果图片太大,浪费流量。(有时候需要上传原图除外)

 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.     }  


改变图片大小的压缩算法:

[java]  view plain  copy
  1. public static boolean getCacheImage(String filePath,String cachePath){  
  2.         OutputStream out = null;  
  3.         BitmapFactory.Options option = new BitmapFactory.Options();  
  4.         option.inJustDecodeBounds = true;  //设置为true,只读尺寸信息,不加载像素信息到内存  
  5.         Bitmap bitmap = BitmapFactory.decodeFile(filePath, option);  //此时bitmap为空  
  6.         option.inJustDecodeBounds = 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.             be = (int)bWidth/toWidth;  
  14.         }else if(bWidth/toWidth<bHeight/toHeight&&bHeight>toHeight){  
  15.             be = (int)bHeight/toHeight;  
  16.         }  
  17.         option.inSampleSize = be; //设置缩放比例  
  18.         bitmap  = BitmapFactory.decodeFile(filePath, option);  
  19.         try {  
  20.             out = 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.     }  


正常情况下我们应该把两者相结合的,所以有了下面的算法(在项目中直接用,清晰度在手机上没问题)

[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.   
  13.                 double scale = Math.sqrt((float) fileSize / fileMaxSize);  
  14.                 options.outHeight = (int) (height / scale);  
  15.                 options.outWidth = (int) (width / scale);  
  16.                 options.inSampleSize = (int) (scale + 0.5);  
  17.                 options.inJustDecodeBounds = false;  
  18.   
  19.                 Bitmap bitmap = BitmapFactory.decodeFile(path, options);  
  20.                 outputFile = new File(PhotoUtil.createImageFile().getPath());  
  21.                 FileOutputStream fos = null;  
  22.                 try {  
  23.                     fos = new FileOutputStream(outputFile);  
  24.                     bitmap.compress(Bitmap.CompressFormat.JPEG, 50, fos);  
  25.                     fos.close();  
  26.                 } catch (IOException e) {  
  27.                     // TODO Auto-generated catch block  
  28.                     e.printStackTrace();  
  29.                 }  
  30.                 Log.d("""sss ok " + outputFile.length());  
  31.                 if (!bitmap.isRecycled()) {  
  32.                     bitmap.recycle();  
  33.                 }else{  
  34.                     File tempFile = outputFile;  
  35.                     outputFile = new File(PhotoUtil.createImageFile().getPath());  
  36.                     PhotoUtil.copyFileUsingFileChannels(tempFile, outputFile);  
  37.                 }  
  38.                   
  39.             }  
  40.          return outputFile;  
  41.           
  42.     }  


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

[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.   
  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.         FileChannel inputChannel = null;  
  24.         FileChannel outputChannel = null;  
  25.         try {  
  26.             try {  
  27.                 inputChannel = new FileInputStream(source).getChannel();  
  28.                 outputChannel = new FileOutputStream(dest).getChannel();  
  29.                 outputChannel.transferFrom(inputChannel, 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,所以描述了一遍算法步骤

因为是逆向推算,效果还没法跟微信一模一样,但是已经很接近微信朋友圈压缩后的效果,具体看以下对比!

效果与对比

内容原图LubanWechat
截屏 720P720*1280,390k720*1280,87k720*1280,56k
截屏 1080P1080*1920,2.21M1080*1920,104k1080*1920,112k
拍照 13M(4:3)3096*4128,3.12M1548*2064,141k1548*2064,147k
拍照 9.6M(16:9)4128*2322,4.64M1032*581,97k1032*581,74k
滚动截屏1080*6433,1.56M1080*6433,351k1080*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();
            }
        }
    }


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


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值