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

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 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();
 - }
 - }
 - }
 
该项目的下载地址: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
最后添加几个压缩工具类
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();
            }
        }
    }
好了,大概就总结到这了。
Android 图片压缩各种方式的更多相关文章
- Android图片压缩上传(二)
		
之前有用到libjpeg,还是有一定的局限性,最近用了一个新的方式,效果还是挺不错,随着作者的版本更新,Bug也随之变少,目前项目中运用已上线. 1.之前的方式Android图片压缩,不失真,上线项目 ...
 - Android  图片压缩、照片选择、裁剪,上传、一整套图片解决方案
		
1.Android一整套图片解决方案 http://mp.weixin.qq.com/s?__biz=MzAxMTI4MTkwNQ==&mid=2650820998&idx=1& ...
 - android图片压缩方法
		
android 图片压缩方法: 第一:质量压缩法: private Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = ...
 - android图片压缩的3种方法实例
		
android 图片压缩方法: 第一:质量压缩法: private Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = ...
 - Android 图片压缩器
		
概述 Android 图片压缩器:一款高效的图片压缩器库,支持批量压缩,异步压缩.多线程多任务压缩,压缩比设置等特性. 详细 代码下载:http://www.demodashi.com/demo/12 ...
 - 性能优化——Android图片压缩与优化的几种方式
		
图片优化压缩方式大概可以分为以下几类:更换图片格式,质量压缩,采样率压缩,缩放压缩,调用jpeg压缩等1.设置图片格式Android目前常用的图片格式有png,jpeg和webp,png:无损压缩图片 ...
 - Android图片压缩
		
import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java ...
 - android图片压缩总结
		
一.bitmap 图片格式介绍 android中图片是以bitmap形式存在的,那么bitmap所占内存,直接影响到了应用所占内存大小,首先要知道bitmap所占内存大小计算方式: bitmap内存大 ...
 - Android图片压缩方法总结
		
本文总结Android应用开发中三种常见的图片压缩方法,分别是:质量压缩法.比例压缩法(根据路径获取图片并压缩)和比例压缩法(根据Bitmap图片压缩). 第一:质量压缩方法: ? 1 2 3 ...
 
随机推荐
- 20145329 《Java程序设计》课程总结
			
每周读书笔记链接汇总 •第一周读书笔记 http://www.cnblogs.com/jdy1453/p/5248592.html •第二周读书笔记 http://www.cnblogs.com/jd ...
 - 20135302魏静静——linux课程第四周实验及总结
			
linux课程第四周实验及总结 一.实验 我选择的是第20号系统调用,getpid 代码如下: /* getpid.c */ #include <unistd.h> #include &l ...
 - Hive查询Join
			
Select a.val,b.val From a [Left|Right|Full Outer] Join b On (a.key==b.key); 现有两张表:sales 列出了人名及其所购商品的 ...
 - MySQL——修改数据表
			
1.添加单列: ALERT TABLE tbl_name ADD [COLUMN] col_name column_definition [FIRST|AFTER col_name 其中tbl_nam ...
 - LeetCode——Decode String
			
Question Given an encoded string, return it's decoded string. The encoding rule is: k[encoded_string ...
 - LeetCode——Unique Binary Search Trees
			
Question Given n, how many structurally unique BST's (binary search trees) that store values 1...n? ...
 - 【Network Architecture】Densely Connected Convolutional Networks 论文解析
			
目录 0. Paper link 1. Overview 2. DenseNet Architecture 2.1 Analogy to ResNet 2.2 Composite function 2 ...
 - hdu 5696  区间的价值   单调栈+rmq
			
区间的价值 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem D ...
 - poi 取excel单元格内容时,需要判断单元格的类型,才能正确取出
			
以下内容非原创,原文链接http://blog.sina.com.cn/s/blog_4b5bc01101015iuq.html ate String getCellValue(HSSFCell ce ...
 - angular $q的学习笔记转帖
			
http://blog.segmentfault.com/bornkiller/1190000000402555 angular $q的一个不错的学习笔记