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();
- }
- }
- }
- 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 ...
随机推荐
- ArchLinux基本系统到XFCE4桌面搭建
Keep It Simple, Stupid 这是ArchLinux的哲学,更是一种人生哲学 好久没用linux了,这段时间因为一点点"破坏性"需求重新拾起linux用了一把 ...
- Java 面试题基础概念收集(高级)
JVM垃圾回收: GC又分为 minor GC 和 Full GC (也称为 Major GC ).Java 堆内存分为新生代和老年代,新生代中又分为1个 Eden 区域 和两个 Survivor 区 ...
- jquery 报错 $.cookie is not a function()
jquery 报错 $.cookie is not a function() ——我是之前可以运行的项目,突然报这个错误,很奇怪. 这是jquery的cookie插件报错. 插件名: jquery.c ...
- jqGrid入门简单使用
jqGrid中文API:https://blog.mn886.net/jqGrid/ 这里没有请求后台,是直接读取本地.json文件 就两个文件,一个html.一个json文件,jquery是jqgr ...
- NPM Scripts 2 -- rimraf copyfiles imagemin usemin htmlmin uglifyjs
NPM Scripts Part 2 Objectives and Outcomes In this exercise you will learn to build a distribution f ...
- 监控控制台是否运行的bat
@echo offrem set secs=5set srvname="TRS.Export.Scheduler.exe" echo.echo ================== ...
- java高级特性(1)--理解面向对象思想
前言: 优秀的代码具备:高性能.可重用.可扩展.易维护.易理解 具体实现: 高性能:合理使用算法,数据结构等等 可重用:封装.继承 可扩展:多态 易维护.易理解:命名规范 + 注解 面向对象是一种思想 ...
- Vue-cli add sass modules
终端cd至要安装的文件夹中 再执行以下命令 安装node-sass 和 sass-loader npm i node-sass sass-loader --save-dev 在需要使用scss地方引入 ...
- CountDownLatch await可能存在的问题
执行countdown的某个子线程可能会因为某些原因无法执行countdown,这样就会导致await线程一直阻塞下去. 在线程池中多次调用await方法,因为await方法会阻塞一段时间,有可能导致 ...
- 在Web API 2 中实现带JSON的Patch请求
译文:http://www.cnblogs.com/kexxxfeng/p/the-patch-verb-in-web-api-2-with-json.html 原文:https://carly.io ...