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

第一种方式:采用JNI调用libjpeg库来进行压缩

介绍
Android图片压缩结合多种压缩方式,常用的有尺寸压缩、质量压缩以及通过JNI调用libjpeg库来进行压缩,三种方式结合使用实现指定图片内存大小,清晰度达到最优。

使用

  • 导入lib-bither-compress
  1. NativeUtil.compressBitmap(bitmap, savePath);
  2.  
  3. NativeUtil.compressBitmap(bitmap, savePath, maxByte, quality);
  • 图像建议尺寸
  1. public final static int QUALITY_320P = 320;//480, 320
  2. public final static int QUALITY_360P = 360;//640, 360
  3. public final static int QUALITY_480P = 480;//640, 480
  4. public final static int QUALITY_720P = 720;//1280, 720
  5. public final static int QUALITY_1080P = 1080;//1920, 1080
  6. public final static int QUALITY_2K = 1440;//2560, 1440
  7. public final static int QUALITY_4K = 2160;//3840, 2160
  • 图像默认品质
  1. //见 NativeUtil 中 compressBitmap(bitmap, savePath, maxByte, quality) 方法
  2. int options = 80;//100不压缩品质

注意:默认将图像压缩到 1280*720 的尺寸,品质为 80 ,图像大小为 1 MB。其他配置可在 lib-bither-compress 中 NativeUtil 下自己配置。

对比

原图 5.5M


个,一,避免占用内存过多。二,可能要上传图片,如果图片太大,浪费流量。(有时候需要上传原图除外)

1、避免内存过多的压缩方法:

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

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

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

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

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

;

  • int toHeight = 800;
  • int be = 1;  //be = 1代表不缩放
  • if(bWidth/toWidth>bHeight/toHeight&&bWidth>toWidth){
  • be = (int)bWidth/toWidth;
  • }else if(bWidth/toWidth<bHeight/toHeight&&bHeight>toHeight){
  • be = (int)bHeight/toHeight;
  • }
  • option.inSampleSize = be; //设置缩放比例
  • bitmap  = BitmapFactory.decodeFile(filePath, option);
  • try {
  • out = new FileOutputStream(new File(cachePath));
  • } catch (IOException e) {
  • // TODO Auto-generated catch block
  • e.printStackTrace();
  • }
  • return bitmap.compress(CompressFormat.JPEG, 100, out);
  • }
  • 正常情况下我们应该把两者相结合的,所以有了下面的算法(在项目中直接用,清晰度在手机上没问题)

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

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

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

    该项目的下载地址:https://github.com/lbool/Android-Image-Upload


    三。自己搞的一种

    1. public File compress(String srcPath) {
    2. File imageFile = new File(srcPath);
    3. uri = Uri.fromFile(imageFile);
    4. float oldSize = (float)new File(uri.getPath()).length()/1024/1024; //以文件的形式
    5. System.out.println("进来大小"+oldSize);
    6.  
    7. DisplayMetrics dm =new DisplayMetrics();
    8. WindowManager manager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
    9. manager.getDefaultDisplay().getMetrics(dm);
    10.  
    11. float hh = dm.heightPixels;
    12. float ww = dm.widthPixels;
    13. BitmapFactory.Options opts = new BitmapFactory.Options();
    14. opts.inJustDecodeBounds = true;
    15. Bitmap bitmap = BitmapFactory.decodeFile(srcPath, opts);
    16. opts.inJustDecodeBounds = false;
    17. int w = opts.outWidth;
    18. int h = opts.outHeight;
    19. int size = 0;
    20. if (w <= ww && h <= hh) {
    21. size = 1;
    22. } else {
    23. double scale = w >= h ? w / ww : h / hh;
    24. double log = Math.log(scale) / Math.log(2);
    25. double logCeil = Math.ceil(log);
    26. size = (int) Math.pow(2, logCeil);
    27. }
    28. opts.inSampleSize = size;
    29. bitmap = BitmapFactory.decodeFile(srcPath, opts);
    30.  
    31. File outputFile = new File(createImageFile().getPath());
    32. FileOutputStream fileOutputStream;
    33. ByteArrayOutputStream baos = new ByteArrayOutputStream();
    34. int quality = 100;
    35. bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
    36. System.out.println("实际的大小"+baos.toByteArray().length/1024);
    37. while (baos.toByteArray().length > 30 * 1024) {
    38. baos.reset();
    39. bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
    40. quality -= 20;
    41. System.out.println("完成的大小"+baos.toByteArray().length/1024);
    42. }
    43. try {
    44. fileOutputStream=new FileOutputStream(outputFile);
    45. bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
    46. baos.writeTo(fileOutputStream);
    47. fileOutputStream.close();
    48. } catch (Exception e) {
    49. e.printStackTrace();
    50. } finally {
    51. try {
    52.  
    53. baos.flush();
    54. baos.close();
    55. } catch (IOException e) {
    56. e.printStackTrace();
    57. }
    58. }
    59.  
    60. return outputFile;
    61. }
    62.  
    63. public static Uri createImageFile(){
    64. // Create an image file name
    65. String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new java.util.Date());
    66. String imageFileName = "JPEG_" + timeStamp + "_";
    67. File storageDir = Environment.getExternalStoragePublicDirectory(
    68. Environment.DIRECTORY_PICTURES);
    69. File image = null;
    70. try {
    71. image = File.createTempFile(
    72. imageFileName, /* prefix */
    73. ".jpg", /* suffix */
    74. storageDir /* directory */
    75. );
    76. } catch (IOException e) {
    77. // TODO Auto-generated catch block
    78. e.printStackTrace();
    79. }
    80.  
    81. // Save a file: path for use with ACTION_VIEW intents
    82. return Uri.fromFile(image);
    83. }
    84. public static void copyFileUsingFileChannels(File source, File dest){
    85. FileChannel inputChannel = null;
    86. FileChannel outputChannel = null;
    87. try {
    88. try {
    89. inputChannel = new FileInputStream(source).getChannel();
    90. outputChannel = new FileOutputStream(dest).getChannel();
    91. outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
    92. } catch (IOException e) {
    93. // TODO Auto-generated catch block
    94. e.printStackTrace();
    95. }
    96. } finally {
    97. try {
    98. inputChannel.close();
    99. outputChannel.close();
    100. } catch (IOException e) {
    101. // TODO Auto-generated catch block
    102. e.printStackTrace();
    103. }
    104. }
    105. }

    第四种(最接近微信的一个)

    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

    导入

    1. compile 'top.zibin:Luban:1.1.2'

    使用

    异步调用

    Luban内部采用IO线程进行图片压缩,外部调用只需设置好结果监听即可:

    1. Luban.with(this)
    2. .load(File) //传人要压缩的图片
    3. .setCompressListener(new OnCompressListener() { //设置回调
    4. @Override
    5. public void onStart() {
    6. // TODO 压缩开始前调用,可以在方法内启动 loading UI
    7. }
    8. @Override
    9. public void onSuccess(File file) {
    10. // TODO 压缩成功后调用,返回压缩后的图片文件
    11. }
    12.  
    13. @Override
    14. public void onError(Throwable e) {
    15. // TODO 当压缩过程出现问题时调用
    16. }
    17. }).launch(); //启动压缩

    同步调用

    同步方法请尽量避免在主线程调用以免阻塞主线程,下面以rxJava调用为例

    1. Flowable.just(file)
    2. .observeOn(Schedulers.io())
    3. .map(new Function<File, File>() {
    4. @Override public File apply(@NonNull File file) throws Exception {
    5. // 同步方法直接返回压缩后的文件
    6. return Luban.with(MainActivity.this).load(file).get();
    7. }
    8. })
    9. .observeOn(AndroidSchedulers.mainThread())
    10. .subscribe();

    项目下载地址:https://github.com/Curzibn/Luban
    最后添加几个压缩工具类

    BitmapUtils类
    1. public class BitmapUtils {
    2. /**
    3. * 从本地读取图片
    4. *
    5. * @param path
    6. * @return
    7. */
    8. public static Bitmap getBitmapForPath(String path) {
    9. try {
    10. FileInputStream in = new FileInputStream(path);
    11. Bitmap bitmap = BitmapFactory.decodeStream(in);
    12. in.close();
    13. return bitmap;
    14. } catch (Exception e) {
    15. }
    16. return null;
    17. }
    18.  
    19. /**
    20. * 获取资源文件中的图片
    21. *
    22. * @param context
    23. * @param resourcesId
    24. * @return
    25. */
    26. public static Drawable getDrawableFormResources(Context context, int resourcesId) {
    27. Resources resources = context.getResources();
    28. return new BitmapDrawable(resources, BitmapFactory.decodeResource(resources, resourcesId));
    29. }
    30.  
    31. /**
    32. * 从资源文件中获取bitmap对象
    33. *
    34. * @param context
    35. * @param resourcesId
    36. * @return
    37. */
    38. public static Bitmap getBitmapFromResources(Context context, int resourcesId) {
    39. return BitmapFactory.decodeResource(context.getResources(), resourcesId);
    40. }
    41.  
    42. /**
    43. * bitmap转byte数组
    44. *
    45. * @param bitmap
    46. * @return
    47. */
    48. public static byte[] getBitmapbyte(Bitmap bitmap) {
    49. ByteArrayOutputStream baos = new ByteArrayOutputStream();
    50. bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
    51. byte[] datas = baos.toByteArray();
    52.  
    53. try {
    54. baos.flush();
    55. baos.close();
    56. } catch (IOException e) {
    57. e.printStackTrace();
    58. }
    59. return datas;
    60. }
    61.  
    62. /**
    63. * bitmap转byte数组
    64. *
    65. * @param bitmap
    66. * @return
    67. */
    68. public static String getBitmapBase64byte(Bitmap bitmap) {
    69. ByteArrayOutputStream baos = new ByteArrayOutputStream();
    70. bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
    71. byte[] datas = baos.toByteArray();
    72. String encodeToString = Base64.encodeToString(datas, Base64.DEFAULT);
    73. try {
    74. baos.flush();
    75. baos.close();
    76. } catch (IOException e) {
    77. e.printStackTrace();
    78. }
    79. return encodeToString;
    80. }
    81.  
    82. /**
    83. * byte转bitmap数组
    84. *
    85. * @param b
    86. * @return
    87. */
    88. public static Bitmap getBitmaoFrombyte(byte[] b) {
    89. return BitmapFactory.decodeByteArray(b, 0, b.length);
    90. }
    91.  
    92. /**
    93. * 压缩0
    94. *
    95. * @param srcPath
    96. * @return
    97. */
    98. public static Bitmap getimageIcon(String srcPath) {
    99. BitmapFactory.Options newOpts = new BitmapFactory.Options();
    100. //开始读入图片,此时把options.inJustDecodeBounds 设回true了
    101. newOpts.inJustDecodeBounds = true;
    102. Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);//此时返回bm为空
    103. newOpts.inJustDecodeBounds = false;
    104. int w = newOpts.outWidth;
    105. int h = newOpts.outHeight;
    106. //现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
    107. float hh = 312f;//这里设置高度为800f
    108. float ww = 650f;//这里设置宽度为480f
    109. //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
    110. int be = 1;//be=1表示不缩放
    111. if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
    112. be = (int) (newOpts.outWidth / ww);
    113. } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
    114. be = (int) (newOpts.outHeight / hh);
    115. }
    116.  
    117. if (be <= 0)
    118. be = 1;
    119. newOpts.inSampleSize = be;//设置缩放比例
    120. //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
    121. bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
    122. return compressImage(bitmap);//压缩好比例大小后再进行质量压缩
    123. }
    124.  
    125. /**
    126. * 压缩1
    127. *
    128. * @param srcPath
    129. * @return
    130. */
    131. public static Bitmap getimage(String srcPath) {
    132. BitmapFactory.Options newOpts = new BitmapFactory.Options();
    133. //开始读入图片,此时把options.inJustDecodeBounds 设回true了
    134. newOpts.inJustDecodeBounds = true;
    135. Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);//此时返回bm为空
    136.  
    137. newOpts.inJustDecodeBounds = false;
    138. int w = newOpts.outWidth;
    139. int h = newOpts.outHeight;
    140. //现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
    141. float hh = 800f;//这里设置高度为800f
    142. float ww = 480f;//这里设置宽度为480f
    143. //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
    144. int be = 1;//be=1表示不缩放
    145. if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
    146. be = (int) (newOpts.outWidth / ww);
    147. } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
    148. be = (int) (newOpts.outHeight / hh);
    149. }
    150. if (be <= 0)
    151. be = 1;
    152. newOpts.inSampleSize = be;//设置缩放比例
    153. //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
    154. bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
    155. return compressImage(bitmap);//压缩好比例大小后再进行质量压缩
    156. }
    157. //把bitmap转换成String
    158. // public static String bitmapToString(String filePath) {
    159. //
    160. // Bitmap bm = getSmallBitmap(filePath);
    161. // ByteArrayOutputStream baos = new ByteArrayOutputStream();
    162. // bm.compress(Bitmap.CompressFormat.JPEG, 40, baos);
    163. // byte[] b = baos.toByteArray();
    164. // return Base64.encodeToString(b, Base64.DEFAULT);
    165. // }
    166.  
    167. /**
    168. * 压缩2
    169. *
    170. * @param image
    171. * @return
    172. */
    173. public static Bitmap comp(Bitmap image) {
    174.  
    175. ByteArrayOutputStream baos = new ByteArrayOutputStream();
    176. image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
    177. if (baos.toByteArray().length / 1024 > 1024) {//判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出
    178. baos.reset();//重置baos即清空baos
    179. image.compress(Bitmap.CompressFormat.JPEG, 30, baos);//这里压缩50%,把压缩后的数据存放到baos中
    180. }
    181. ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
    182. BitmapFactory.Options newOpts = new BitmapFactory.Options();
    183. //开始读入图片,此时把options.inJustDecodeBounds 设回true了
    184. newOpts.inJustDecodeBounds = true;
    185. Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
    186. newOpts.inJustDecodeBounds = false;
    187. int w = newOpts.outWidth;
    188. int h = newOpts.outHeight;
    189. //现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
    190. float hh = 800f;//这里设置高度为800f
    191. float ww = 480f;//这里设置宽度为480f
    192. //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
    193. int be = 1;//be=1表示不缩放
    194. if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
    195. be = (int) (newOpts.outWidth / ww);
    196. } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
    197. be = (int) (newOpts.outHeight / hh);
    198. }
    199. if (be <= 0)
    200. be = 1;
    201. newOpts.inSampleSize = be;//设置缩放比例
    202. newOpts.inPreferredConfig = Bitmap.Config.RGB_565;//降低图片从ARGB888到RGB565
    203. //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
    204. isBm = new ByteArrayInputStream(baos.toByteArray());
    205. bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
    206. return compressImage(bitmap);//压缩好比例大小后再进行质量压缩
    207. }
    208.  
    209. /**
    210. * 质量压缩
    211. *
    212. * @param image
    213. * @return
    214. */
    215. public static Bitmap compressImage(Bitmap image) {
    216. ByteArrayOutputStream baos = new ByteArrayOutputStream();
    217. image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
    218. int options = 100;
    219. while (baos.toByteArray().length / 1024 > 100) { //循环判断如果压缩后图片是否大于100kb,大于继续压缩
    220. baos.reset();//重置baos即清空baos
    221. options -= 20;//每次都减少10
    222. image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中
    223.  
    224. }
    225. ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
    226. Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片
    227. return bitmap;
    228. }
    229.  
    230. /**
    231. * 获取图片大小
    232. *
    233. * @param bitmap
    234. * @return
    235. */
    236. public static long getBitmapsize(Bitmap bitmap) {
    237. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
    238. return bitmap.getByteCount();
    239. }
    240. return bitmap.getRowBytes() * bitmap.getHeight();
    241. }
    242.  
    243. /**
    244. * 对图片进行模糊处理
    245. *
    246. * @param bitmap
    247. * @param context
    248. * @return
    249. */
    250. @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    251. public static Bitmap blurBitmap(Bitmap bitmap, Context context) {
    252. Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
    253. RenderScript rs = RenderScript.create(context.getApplicationContext());
    254. ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
    255. Allocation allIn = Allocation.createFromBitmap(rs, bitmap);
    256. Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);
    257. blurScript.setRadius(25f);
    258. blurScript.setInput(allIn);
    259. blurScript.forEach(allOut);
    260. allOut.copyTo(outBitmap);
    261. bitmap.recycle();
    262. rs.destroy();
    263. return outBitmap;
    264. }
    265.  
    266. public static Bitmap drawableToBitmap(Drawable drawable) {
    267. Bitmap bitmap = Bitmap.createBitmap(
    268. drawable.getIntrinsicWidth(),
    269. drawable.getIntrinsicHeight(),
    270. drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
    271. Canvas canvas = new Canvas(bitmap);
    272. //canvas.setBitmap(bitmap);
    273. drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
    274. drawable.draw(canvas);
    275. return bitmap;
    276. }
    277.  
    278. /**
    279. * 水平方向模糊度
    280. */
    281. private static float hRadius = 10;
    282. /**
    283. * 竖直方向模糊度
    284. */
    285. private static float vRadius = 10;
    286. /**
    287. * 模糊迭代度
    288. */
    289. private static int iterations = 7;
    290. private static float a = 1.3f;
    291.  
    292. /**
    293. * 模糊图片
    294. *
    295. * @param bmp
    296. * @return
    297. */
    298. public static Drawable BoxBlurFilter(Bitmap bmp) {
    299. hRadius = hRadius * a;
    300. vRadius = vRadius * a;
    301. iterations = (int) (iterations * a);
    302.  
    303. int width = bmp.getWidth();
    304. int height = bmp.getHeight();
    305. int[] inPixels = new int[width * height];
    306. int[] outPixels = new int[width * height];
    307. Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    308. bmp.getPixels(inPixels, 0, width, 0, 0, width, height);
    309. for (int i = 0; i < iterations; i++) {
    310. blur(inPixels,
    311. outPixels, width, height, hRadius);
    312. blur(outPixels,
    313. inPixels, height, width, vRadius);
    314. }
    315. blurFractional(inPixels,
    316. outPixels, width, height, hRadius);
    317. blurFractional(outPixels,
    318. inPixels, height, width, vRadius);
    319. bitmap.setPixels(inPixels,
    320. 0,
    321. width, 0,
    322. 0,
    323. width, height);
    324. Drawable drawable = new BitmapDrawable(bitmap);
    325. return drawable;
    326. }
    327.  
    328. public static void blur(int[] in, int[] out, int width, int height, float radius) {
    329. int widthMinus1 = width - 1;
    330. int r = (int) radius;
    331. int tableSize = 2 * r + 1;
    332. int divide[] = new int[256 * tableSize];
    333. for (int i = 0; i < 256 * tableSize; i++)
    334. divide[i] = i / tableSize;
    335. int inIndex = 0;
    336. for (int y = 0; y < height; y++) {
    337. int outIndex = y;
    338. int ta = 0, tr = 0, tg = 0, tb = 0;
    339. for (int i = -r; i <= r; i++) {
    340. int rgb = in[inIndex + clamp(i, 0, width - 1)];
    341. ta += (rgb >> 24) & 0xff;
    342. tr += (rgb >> 16) & 0xff;
    343. tg += (rgb >> 8) & 0xff;
    344. tb += rgb & 0xff;
    345. }
    346. for (int x = 0; x < width; x++) {
    347. out[outIndex] = (divide[ta] << 24) | (divide[tr] << 16) | (divide[tg] << 8)
    348. | divide[tb];
    349. int i1 = x + r + 1;
    350. if (i1 > widthMinus1)
    351. i1 = widthMinus1;
    352. int i2 = x - r;
    353. if (i2 < 0)
    354. i2 = 0;
    355. int rgb1 = in[inIndex + i1];
    356. int rgb2 = in[inIndex + i2];
    357. ta += ((rgb1 >> 24) & 0xff) - ((rgb2 >> 24) & 0xff);
    358. tr += ((rgb1 & 0xff0000) - (rgb2 & 0xff0000)) >> 16;
    359. tg += ((rgb1 & 0xff00) - (rgb2 & 0xff00)) >> 8;
    360. tb += (rgb1 & 0xff) - (rgb2 & 0xff);
    361. outIndex += height;
    362. }
    363. inIndex += width;
    364. }
    365. }
    366.  
    367. public static void blurFractional(int[] in, int[] out, int width, int height, float radius) {
    368. radius -= (int) radius;
    369. float f = 1.0f / (1 + 2 * radius);
    370. int inIndex = 0;
    371. for (int y = 0; y < height; y++) {
    372. int outIndex = y;
    373. out[outIndex] = in[0];
    374. outIndex += height;
    375. for (int x = 1; x < width - 1; x++) {
    376. int i = inIndex + x;
    377. int rgb1 = in[i - 1];
    378. int rgb2 = in[i];
    379. int rgb3 = in[i + 1];
    380. int a1 = (rgb1 >> 24)
    381. & 0xff;
    382. int r1
    383. = (rgb1 >> 16)
    384. & 0xff;
    385. int g1
    386. = (rgb1 >> 8)
    387. & 0xff;
    388. int b1
    389. = rgb1 & 0xff;
    390. int a2
    391. = (rgb2 >> 24)
    392. & 0xff;
    393. int r2
    394. = (rgb2 >> 16)
    395. & 0xff;
    396. int g2
    397. = (rgb2 >> 8)
    398. & 0xff;
    399. int b2
    400. = rgb2 & 0xff;
    401. int a3
    402. = (rgb3 >> 24)
    403. & 0xff;
    404. int r3
    405. = (rgb3 >> 16)
    406. & 0xff;
    407. int g3
    408. = (rgb3 >> 8)
    409. & 0xff;
    410. int b3
    411. = rgb3 & 0xff;
    412. a1
    413. = a2 + (int)
    414. ((a1 + a3) * radius);
    415. r1
    416. = r2 + (int)
    417. ((r1 + r3) * radius);
    418. g1
    419. = g2 + (int)
    420. ((g1 + g3) * radius);
    421. b1
    422. = b2 + (int)
    423. ((b1 + b3) * radius);
    424. a1
    425. *= f;
    426. r1
    427. *= f;
    428. g1
    429. *= f;
    430. b1
    431. *= f;
    432. out[outIndex]
    433. = (a1 << 24)
    434. | (r1 << 16)
    435. | (g1 << 8)
    436. | b1;
    437. outIndex
    438. += height;
    439. }
    440. out[outIndex]
    441. = in[width - 1];
    442. inIndex
    443. += width;
    444. }
    445. }
    446.  
    447. public static int clamp(int x,
    448. int a,
    449. int b) {
    450. return (x
    451. < a) ? a : (x > b) ? b : x;
    452. }
    453.  
    454. public static String getImageUrl(Context context, Uri photoUri) {
    455. String res = null;
    456. String[] proj = {MediaStore.Images.Media.DATA};
    457. Cursor cursor = context.getContentResolver().query(photoUri, proj, null, null, null);
    458. if (cursor.moveToFirst()) {
    459. ;
    460. int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    461. res = cursor.getString(column_index);
    462. }
    463. cursor.close();
    464. return res;
    465. }
    466.  
    467. /**
    468. * 将Bitmap转换成文件
    469. * 保存文件
    470. *
    471. * @param bm
    472. * @param fileName
    473. * @throws IOException
    474. */
    475. public static File saveFile(Bitmap bm, String path, String fileName) throws IOException {
    476. File dirFile = new File(path);
    477. if (!dirFile.exists()) {
    478. dirFile.mkdir();
    479. }
    480. File myCaptureFile = new File(path, fileName);
    481. BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile));
    482. bm.compress(Bitmap.CompressFormat.JPEG, 80, bos);
    483. bos.flush();
    484. bos.close();
    485. return myCaptureFile;
    486. }
    487.  
    488. /**
    489. * 路径转换成file
    490. *
    491. * @param filePath
    492. * @return
    493. */
    494. public static File BetyToFile(String filePath) {
    495. File file = new File(filePath);
    496. BufferedOutputStream stream = null;
    497. FileOutputStream fstream = null;
    498. byte[] data = new byte[(int) file.length()];
    499. try {
    500. fstream = new FileOutputStream(file);
    501. stream = new BufferedOutputStream(fstream);
    502. stream.write(data);
    503. } catch (Exception e) {
    504. e.printStackTrace();
    505. } finally {
    506. try {
    507. if (stream != null) {
    508. stream.close();
    509. }
    510. if (null != fstream) {
    511. fstream.close();
    512. }
    513. } catch (IOException e1) {
    514. e1.printStackTrace();
    515. }
    516. }
    517. return file;
    518. }

    1. ImageCompress

    1. public class ImageCompress {
    2.  
    3. public static final String CONTENT = "content";
    4. public static final String FILE = "file";
    5.  
    6. /**
    7. * 调用
    8. ImageCompress compress = new ImageCompress();
    9. ImageCompress.CompressOptions options = new ImageCompress.CompressOptions();
    10. options.uri = Uri.fromFile(new File(sourcePath));
    11. options.maxWidth=Constants.RESIZEBITMAP_WIDTH;
    12. options.maxHeight=Constants.RESIZEBITMAP_HEIGHT;
    13. Bitmap bitmap = compress.compressFromUri(UploadWithPhotoBaseActivity.this, options);*/
    14.  
    15. /**
    16. * 图片压缩参数
    17. *
    18. * @author Administrator
    19. */
    20. public static class CompressOptions {
    21. public static final int DEFAULT_WIDTH = 400;
    22. public static final int DEFAULT_HEIGHT = 800;
    23.  
    24. public int maxWidth = DEFAULT_WIDTH;
    25. public int maxHeight = DEFAULT_HEIGHT;
    26. /**
    27. * 压缩后图片保存的文件
    28. */
    29. public File destFile;
    30. /**
    31. * 图片压缩格式,默认为jpg格式
    32. */
    33. public Bitmap.CompressFormat imgFormat = Bitmap.CompressFormat.JPEG;
    34.  
    35. /**
    36. * 图片压缩比例 默认为30
    37. */
    38. public int quality = 30;
    39.  
    40. public Uri uri;
    41. }
    42.  
    43. /**
    44. * 返回bitmap
    45. * @param context
    46. * @param compressOptions
    47. * @return
    48. */
    49. public Bitmap compressFromUri(Context context, CompressOptions compressOptions) {
    50. // uri指向的文件路径
    51. String filePath = getFilePath(context, compressOptions.uri);
    52.  
    53. if (null == filePath) {
    54. return null;
    55. }
    56. BitmapFactory.Options options = new BitmapFactory.Options();
    57. options.inJustDecodeBounds = true;
    58.  
    59. Bitmap temp = BitmapFactory.decodeFile(filePath, options);
    60.  
    61. int actualWidth = options.outWidth;
    62. int actualHeight = options.outHeight;
    63.  
    64. int desiredWidth = getResizedDimension(compressOptions.maxWidth,
    65. compressOptions.maxHeight, actualWidth, actualHeight);
    66. int desiredHeight = getResizedDimension(compressOptions.maxHeight,
    67. compressOptions.maxWidth, actualHeight, actualWidth);
    68.  
    69. options.inJustDecodeBounds = false;
    70. options.inSampleSize = findBestSampleSize(actualWidth, actualHeight,
    71. desiredWidth, desiredHeight);
    72.  
    73. Bitmap bitmap = null;
    74.  
    75. Bitmap destBitmap = BitmapFactory.decodeFile(filePath, options);
    76.  
    77. // If necessary, scale down to the maximal acceptable size.
    78. if (destBitmap.getWidth() > desiredWidth
    79. || destBitmap.getHeight() > desiredHeight) {
    80. bitmap = Bitmap.createScaledBitmap(destBitmap, desiredWidth,
    81. desiredHeight, true);
    82. destBitmap.recycle();
    83. } else {
    84. bitmap = destBitmap;
    85. }
    86.  
    87. // compress file if need
    88. if (null != compressOptions.destFile) {
    89. compressFile(compressOptions, bitmap);
    90. }
    91.  
    92. return bitmap;
    93. }
    94.  
    95. /**
    96. * 返回file形式
    97. * @param context
    98. * @param compressOptions
    99. * @return
    100. */
    101. public File compressFromUriFile(Context context, CompressOptions compressOptions) {
    102. // uri指向的文件路径
    103. String filePath = getFilePath(context, compressOptions.uri);
    104. File outputFile = new File(filePath);
    105. Log.i("INFO", "路径" + filePath);
    106.  
    107. if (null == filePath) {
    108. return null;
    109. }
    110. BitmapFactory.Options options = new BitmapFactory.Options();
    111. options.inJustDecodeBounds = true;
    112.  
    113. Bitmap temp = BitmapFactory.decodeFile(filePath, options);
    114.  
    115. int actualWidth = options.outWidth;
    116. int actualHeight = options.outHeight;
    117.  
    118. int desiredWidth = getResizedDimension(compressOptions.maxWidth,
    119. compressOptions.maxHeight, actualWidth, actualHeight);
    120. int desiredHeight = getResizedDimension(compressOptions.maxHeight,
    121. compressOptions.maxWidth, actualHeight, actualWidth);
    122.  
    123. options.inJustDecodeBounds = false;
    124. options.inSampleSize = findBestSampleSize(actualWidth, actualHeight,
    125. desiredWidth, desiredHeight);
    126.  
    127. Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
    128. outputFile = new File(createImageFile().getPath());
    129. FileOutputStream fos = null;
    130. try {
    131. fos = new FileOutputStream(outputFile);
    132. bitmap.compress(Bitmap.CompressFormat.JPEG, 50, fos);
    133. fos.close();
    134. } catch (IOException e) {
    135. // TODO Auto-generated catch block
    136. e.printStackTrace();
    137. }
    138.  
    139. if (!bitmap.isRecycled()) {
    140. bitmap.recycle();
    141. } else {
    142. File tempFile = outputFile;
    143. outputFile = new File(createImageFile().getPath());
    144. copyFileUsingFileChannels(tempFile, outputFile);
    145. }
    146.  
    147. // compress file if need
    148. if (null != compressOptions.destFile) {
    149. // compressFile(compressOptions, bitmap);
    150. File tempFile = outputFile;
    151. outputFile = new File(createImageFile().getPath());
    152. copyFileUsingFileChannels(tempFile, outputFile);
    153. }
    154.  
    155. return outputFile;
    156. }
    157.  
    158. /**
    159. * compress file from bitmap with compressOptions
    160. *
    161. * @param compressOptions
    162. * @param bitmap
    163. */
    164. private void compressFile(CompressOptions compressOptions, Bitmap bitmap) {
    165. OutputStream stream = null;
    166. try {
    167. stream = new FileOutputStream(compressOptions.destFile);
    168. } catch (FileNotFoundException e) {
    169. Log.e("ImageCompress", e.getMessage());
    170. }
    171.  
    172. bitmap.compress(compressOptions.imgFormat, compressOptions.quality,
    173. stream);
    174. }
    175.  
    176. private static int findBestSampleSize(int actualWidth, int actualHeight,
    177. int desiredWidth, int desiredHeight) {
    178. double wr = (double) actualWidth / desiredWidth;
    179. double hr = (double) actualHeight / desiredHeight;
    180. double ratio = Math.min(wr, hr);
    181. float n = 1.0f;
    182. while ((n * 2) <= ratio) {
    183. n *= 2;
    184. }
    185.  
    186. return (int) n;
    187. }
    188.  
    189. private static int getResizedDimension(int maxPrimary, int maxSecondary,
    190. int actualPrimary, int actualSecondary) {
    191. // If no dominant value at all, just return the actual.
    192. if (maxPrimary == 0 && maxSecondary == 0) {
    193. return actualPrimary;
    194. }
    195.  
    196. // If primary is unspecified, scale primary to match secondary's scaling
    197. // ratio.
    198. if (maxPrimary == 0) {
    199. double ratio = (double) maxSecondary / (double) actualSecondary;
    200. return (int) (actualPrimary * ratio);
    201. }
    202.  
    203. if (maxSecondary == 0) {
    204. return maxPrimary;
    205. }
    206.  
    207. double ratio = (double) actualSecondary / (double) actualPrimary;
    208. int resized = maxPrimary;
    209. if (resized * ratio > maxSecondary) {
    210. resized = (int) (maxSecondary / ratio);
    211. }
    212. return resized;
    213. }
    214.  
    215. /**
    216. * 获取文件的路径
    217. *
    218. * @param
    219. * @return
    220. */
    221. private String getFilePath(Context context, Uri uri) {
    222.  
    223. String filePath = null;
    224.  
    225. if (CONTENT.equalsIgnoreCase(uri.getScheme())) {
    226.  
    227. Cursor cursor = context.getContentResolver().query(uri,
    228. new String[]{MediaStore.Images.Media.DATA}, null, null, null);
    229.  
    230. if (null == cursor) {
    231. return null;
    232. }
    233.  
    234. try {
    235. if (cursor.moveToNext()) {
    236. filePath = cursor.getString(cursor
    237. .getColumnIndex(MediaStore.Images.Media.DATA));
    238. }
    239. } finally {
    240. cursor.close();
    241. }
    242. }
    243.  
    244. // 从文件中选择
    245. if (FILE.equalsIgnoreCase(uri.getScheme())) {
    246. filePath = uri.getPath();
    247. }
    248.  
    249. return filePath;
    250. }
    251.  
    252. /**
    253. * 创建一个新的文件夹,保存压缩后的图片
    254. * @return
    255. */
    256. public static Uri createImageFile() {
    257. // Create an image file name
    258. String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new java.util.Date());
    259. String imageFileName = "JPEG_" + timeStamp + "_";
    260. File storageDir = Environment.getExternalStoragePublicDirectory(
    261. Environment.DIRECTORY_PICTURES);
    262. File image = null;
    263. try {
    264. image = File.createTempFile(
    265. imageFileName, /* prefix */
    266. ".jpg", /* suffix */
    267. storageDir /* directory */
    268. );
    269. } catch (IOException e) {
    270. // TODO Auto-generated catch block
    271. e.printStackTrace();
    272. }
    273.  
    274. // Save a file: path for use with ACTION_VIEW intents
    275. return Uri.fromFile(image);
    276. }
    277.  
    278. public static void copyFileUsingFileChannels(File source, File dest) {
    279. FileChannel inputChannel = null;
    280. FileChannel outputChannel = null;
    281. try {
    282. try {
    283. inputChannel = new FileInputStream(source).getChannel();
    284. outputChannel = new FileOutputStream(dest).getChannel();
    285. outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
    286. } catch (IOException e) {
    287. // TODO Auto-generated catch block
    288. e.printStackTrace();
    289. }
    290. } finally {
    291. try {
    292. inputChannel.close();
    293. outputChannel.close();
    294. } catch (IOException e) {
    295. // TODO Auto-generated catch block
    296. e.printStackTrace();
    297. }
    298. }
    299. }

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