原文地址:http://blog.csdn.net/jdsjlzx/article/details/44228935
在网上调查了图片压缩的方法并实装后,大致上可以认为有两类压缩:质量压缩(不改变图片的尺寸)和尺寸压缩(相当于是像素上的压缩);质量压缩一般可用于上传大图前的处理,这样就可以节省一定的流量,毕竟现在的手机拍照都能达到3M左右了,尺寸压缩一般可用于生成缩略图。
两种方法都实装在了我的项目中,结果却发现在质量压缩的模块中,本来1.9M的图片压缩后反而变成3M多了,很是奇怪,再做了进一步调查终于知道原因了。下面这个博客说的比较清晰:

android图片压缩总结

总结来看,图片有三种存在形式:硬盘上时是file,网络传输时是stream,内存中是stream或bitmap,所谓的质量压缩,它其实只能实现对file的影响,你可以把一个file转成bitmap再转成file,或者直接将一个bitmap转成file时,这个最终的file是被压缩过的,但是中间的bitmap并没有被压缩(或者说几乎没有被压缩,我不确定),因为bigmap在内存中的大小是按像素计算的,也就是width * height,对于质量压缩,并不会改变图片的像素,所以就算质量被压缩了,但是bitmap在内存的占有率还是没变小,但你做成file时,它确实变小了;

而尺寸压缩由于是减小了图片的像素,所以它直接对bitmap产生了影响,当然最终的file也是相对的变小了;

最后把自己总结的工具类贴出来:

[java]  view plain copy
  1. import java.io.ByteArrayInputStream;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.File;
  4. import java.io.FileNotFoundException;
  5. import java.io.FileOutputStream;
  6. import java.io.IOException;
  7. import android.graphics.Bitmap;
  8. import android.graphics.Bitmap.Config;
  9. import android.graphics.BitmapFactory;
  10. /**
  11. * Image compress factory class
  12. *
  13. * @author
  14. *
  15. */
  16. public class ImageFactory {
  17. /**
  18. * Get bitmap from specified image path
  19. *
  20. * @param imgPath
  21. * @return
  22. */
  23. public Bitmap getBitmap(String imgPath) {
  24. // Get bitmap through image path
  25. BitmapFactory.Options newOpts = new BitmapFactory.Options();
  26. newOpts.inJustDecodeBounds = false;
  27. newOpts.inPurgeable = true;
  28. newOpts.inInputShareable = true;
  29. // Do not compress
  30. newOpts.inSampleSize = 1;
  31. newOpts.inPreferredConfig = Config.RGB_565;
  32. return BitmapFactory.decodeFile(imgPath, newOpts);
  33. }
  34. /**
  35. * Store bitmap into specified image path
  36. *
  37. * @param bitmap
  38. * @param outPath
  39. * @throws FileNotFoundException
  40. */
  41. public void storeImage(Bitmap bitmap, String outPath) throws FileNotFoundException {
  42. FileOutputStream os = new FileOutputStream(outPath);
  43. bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
  44. }
  45. /**
  46. * Compress image by pixel, this will modify image width/height.
  47. * Used to get thumbnail
  48. *
  49. * @param imgPath image path
  50. * @param pixelW target pixel of width
  51. * @param pixelH target pixel of height
  52. * @return
  53. */
  54. public Bitmap ratio(String imgPath, float pixelW, float pixelH) {
  55. BitmapFactory.Options newOpts = new BitmapFactory.Options();
  56. // 开始读入图片,此时把options.inJustDecodeBounds 设回true,即只读边不读内容
  57. newOpts.inJustDecodeBounds = true;
  58. newOpts.inPreferredConfig = Config.RGB_565;
  59. // Get bitmap info, but notice that bitmap is null now
  60. Bitmap bitmap = BitmapFactory.decodeFile(imgPath,newOpts);
  61. newOpts.inJustDecodeBounds = false;
  62. int w = newOpts.outWidth;
  63. int h = newOpts.outHeight;
  64. // 想要缩放的目标尺寸
  65. float hh = pixelH;// 设置高度为240f时,可以明显看到图片缩小了
  66. float ww = pixelW;// 设置宽度为120f,可以明显看到图片缩小了
  67. // 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
  68. int be = 1;//be=1表示不缩放
  69. if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
  70. be = (int) (newOpts.outWidth / ww);
  71. } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
  72. be = (int) (newOpts.outHeight / hh);
  73. }
  74. if (be <= 0) be = 1;
  75. newOpts.inSampleSize = be;//设置缩放比例
  76. // 开始压缩图片,注意此时已经把options.inJustDecodeBounds 设回false了
  77. bitmap = BitmapFactory.decodeFile(imgPath, newOpts);
  78. // 压缩好比例大小后再进行质量压缩
  79. //        return compress(bitmap, maxSize); // 这里再进行质量压缩的意义不大,反而耗资源,删除
  80. return bitmap;
  81. }
  82. /**
  83. * Compress image by size, this will modify image width/height.
  84. * Used to get thumbnail
  85. *
  86. * @param image
  87. * @param pixelW target pixel of width
  88. * @param pixelH target pixel of height
  89. * @return
  90. */
  91. public Bitmap ratio(Bitmap image, float pixelW, float pixelH) {
  92. ByteArrayOutputStream os = new ByteArrayOutputStream();
  93. image.compress(Bitmap.CompressFormat.JPEG, 100, os);
  94. if( os.toByteArray().length / 1024>1024) {//判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出
  95. os.reset();//重置baos即清空baos
  96. image.compress(Bitmap.CompressFormat.JPEG, 50, os);//这里压缩50%,把压缩后的数据存放到baos中
  97. }
  98. ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
  99. BitmapFactory.Options newOpts = new BitmapFactory.Options();
  100. //开始读入图片,此时把options.inJustDecodeBounds 设回true了
  101. newOpts.inJustDecodeBounds = true;
  102. newOpts.inPreferredConfig = Config.RGB_565;
  103. Bitmap bitmap = BitmapFactory.decodeStream(is, null, newOpts);
  104. newOpts.inJustDecodeBounds = false;
  105. int w = newOpts.outWidth;
  106. int h = newOpts.outHeight;
  107. float hh = pixelH;// 设置高度为240f时,可以明显看到图片缩小了
  108. float ww = pixelW;// 设置宽度为120f,可以明显看到图片缩小了
  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. if (be <= 0) be = 1;
  117. newOpts.inSampleSize = be;//设置缩放比例
  118. //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
  119. is = new ByteArrayInputStream(os.toByteArray());
  120. bitmap = BitmapFactory.decodeStream(is, null, newOpts);
  121. //压缩好比例大小后再进行质量压缩
  122. //      return compress(bitmap, maxSize); // 这里再进行质量压缩的意义不大,反而耗资源,删除
  123. return bitmap;
  124. }
  125. /**
  126. * Compress by quality,  and generate image to the path specified
  127. *
  128. * @param image
  129. * @param outPath
  130. * @param maxSize target will be compressed to be smaller than this size.(kb)
  131. * @throws IOException
  132. */
  133. public void compressAndGenImage(Bitmap image, String outPath, int maxSize) throws IOException {
  134. ByteArrayOutputStream os = new ByteArrayOutputStream();
  135. // scale
  136. int options = 100;
  137. // Store the bitmap into output stream(no compress)
  138. image.compress(Bitmap.CompressFormat.JPEG, options, os);
  139. // Compress by loop
  140. while ( os.toByteArray().length / 1024 > maxSize) {
  141. // Clean up os
  142. os.reset();
  143. // interval 10
  144. options -= 10;
  145. image.compress(Bitmap.CompressFormat.JPEG, options, os);
  146. }
  147. // Generate compressed image file
  148. FileOutputStream fos = new FileOutputStream(outPath);
  149. fos.write(os.toByteArray());
  150. fos.flush();
  151. fos.close();
  152. }
  153. /**
  154. * Compress by quality,  and generate image to the path specified
  155. *
  156. * @param imgPath
  157. * @param outPath
  158. * @param maxSize target will be compressed to be smaller than this size.(kb)
  159. * @param needsDelete Whether delete original file after compress
  160. * @throws IOException
  161. */
  162. public void compressAndGenImage(String imgPath, String outPath, int maxSize, boolean needsDelete) throws IOException {
  163. compressAndGenImage(getBitmap(imgPath), outPath, maxSize);
  164. // Delete original file
  165. if (needsDelete) {
  166. File file = new File (imgPath);
  167. if (file.exists()) {
  168. file.delete();
  169. }
  170. }
  171. }
  172. /**
  173. * Ratio and generate thumb to the path specified
  174. *
  175. * @param image
  176. * @param outPath
  177. * @param pixelW target pixel of width
  178. * @param pixelH target pixel of height
  179. * @throws FileNotFoundException
  180. */
  181. public void ratioAndGenThumb(Bitmap image, String outPath, float pixelW, float pixelH) throws FileNotFoundException {
  182. Bitmap bitmap = ratio(image, pixelW, pixelH);
  183. storeImage( bitmap, outPath);
  184. }
  185. /**
  186. * Ratio and generate thumb to the path specified
  187. *
  188. * @param image
  189. * @param outPath
  190. * @param pixelW target pixel of width
  191. * @param pixelH target pixel of height
  192. * @param needsDelete Whether delete original file after compress
  193. * @throws FileNotFoundException
  194. */
  195. public void ratioAndGenThumb(String imgPath, String outPath, float pixelW, float pixelH, boolean needsDelete) throws FileNotFoundException {
  196. Bitmap bitmap = ratio(imgPath, pixelW, pixelH);
  197. storeImage( bitmap, outPath);
  198. // Delete original file
  199. if (needsDelete) {
  200. File file = new File (imgPath);
  201. if (file.exists()) {
  202. file.delete();
  203. }
  204. }
  205. }
  206. }
延伸阅读

android图片压缩总结

一.图片的存在形式

1.文件形式(即以二进制形式存在于硬盘上)
2.流的形式(即以二进制形式存在于内存中)
3.Bitmap形式
这三种形式的区别: 文件形式和流的形式对图片体积大小并没有影响,也就是说,如果你手机SD卡上的如果是100K,那么通过流的形式读到内存中,也一定是占100K的内存,注意是流的形式,不是Bitmap的形式,当图片以Bitmap的形式存在时,其占用的内存会瞬间变大, 我试过500K文件形式的图片加载到内存,以Bitmap形式存在时,占用内存将近10M,当然这个增大的倍数并不是固定的
检测图片三种形式大小的方法:
文件形式: file.length()
流的形式: 讲图片文件读到内存输入流中,看它的byte数
Bitmap:    bitmap.getByteCount()

二.常见的压缩方式

    特点是:  File形式的图片确实被压缩了, 但是当你重新读取压缩后的file为 Bitmap是,它占用的内存并没有改变   
[java]  view plain copy
  1. public static void compressBmpToFile(Bitmap bmp,File file){
  2. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  3. int options = 80;//个人喜欢从80开始,
  4. bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
  5. while (baos.toByteArray().length / 1024 > 100) {
  6. baos.reset();
  7. options -= 10;
  8. bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
  9. }
  10. try {
  11. FileOutputStream fos = new FileOutputStream(file);
  12. fos.write(baos.toByteArray());
  13. fos.flush();
  14. fos.close();
  15. } catch (Exception e) {
  16. e.printStackTrace();
  17. }
  18. }
方法说明: 该方法是压缩图片的质量, 注意它不会减少图片的像素,比方说, 你的图片是300K的, 1280*700像素的, 经过该方法压缩后, File形式的图片是在100以下, 以方便上传服务器, 但是你BitmapFactory.decodeFile到内存中,变成Bitmap时,它的像素仍然是1280*700, 计算图片像素的方法是 bitmap.getWidth()和bitmap.getHeight(), 图片是由像素组成的, 每个像素又包含什么呢? 熟悉PS的人知道, 图片是有色相,明度和饱和度构成的. 
该方法的官方文档也解释说, 它会让图片重新构造, 但是有可能图像的位深(即色深)和每个像素的透明度会变化,JPEG onlysupports opaque(不透明), 也就是说以jpeg格式压缩后, 原来图片中透明的元素将消失.所以这种格式很可能造成失真

既然它是改变了图片的显示质量, 达到了对File形式的图片进行压缩, 图片的像素没有改变的话, 那重新读取经过压缩 的file为Bitmap时, 它占用的内存并不会少.(不相信的可以试试)

因为: bitmap.getByteCount() 是计算它的像素所占用的内存, 请看官方解释: Returns the number of bytes used to  store this bitmap's pixels.

2.    将图片从本地读到内存时,进行压缩 ,即图片从File形式变为Bitmap形式

       特点: 通过设置采样率, 减少图片的像素, 达到对内存中的Bitmap进行压缩
       先看一个方法: 该方法是对内存中的Bitmap进行质量上的压缩, 由上面的理论可以得出该方法是无效的, 而且也是没有必要的, 因为你已经将它读到内存中了,再压缩多此一举, 尽管在获取系统相册图片时,某些手机会直接返回一个Bitmap, 但是这种情况下, 返回的Bitmap都是经过压缩的, 它不可能直接返回一个原声的Bitmap形式的图片, 后果可想而知
[java]  view plain copy
  1. private Bitmap compressBmpFromBmp(Bitmap image) {
  2. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  3. int options = 100;
  4. image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
  5. while (baos.toByteArray().length / 1024 > 100) {
  6. baos.reset();
  7. options -= 10;
  8. image.compress(Bitmap.CompressFormat.JPEG, options, baos);
  9. }
  10. ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
  11. Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
  12. return bitmap;
  13. }

再看一个方法:

[java]  view plain copy
  1. private Bitmap compressImageFromFile(String srcPath) {
  2. BitmapFactory.Options newOpts = new BitmapFactory.Options();
  3. newOpts.inJustDecodeBounds = true;//只读边,不读内容
  4. Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
  5. newOpts.inJustDecodeBounds = false;
  6. int w = newOpts.outWidth;
  7. int h = newOpts.outHeight;
  8. float hh = 800f;//
  9. float ww = 480f;//
  10. int be = 1;
  11. if (w > h && w > ww) {
  12. be = (int) (newOpts.outWidth / ww);
  13. } else if (w < h && h > hh) {
  14. be = (int) (newOpts.outHeight / hh);
  15. }
  16. if (be <= 0)
  17. be = 1;
  18. newOpts.inSampleSize = be;//设置采样率
  19. newOpts.inPreferredConfig = Config.ARGB_8888;//该模式是默认的,可不设
  20. newOpts.inPurgeable = true;// 同时设置才会有效
  21. newOpts.inInputShareable = true;//。当系统内存不够时候图片自动被回收
  22. bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
  23. //      return compressBmpFromBmp(bitmap);//原来的方法调用了这个方法企图进行二次压缩
  24. //其实是无效的,大家尽管尝试
  25. return bitmap;
  26. }
方法说明: 该方法就是对Bitmap形式的图片进行压缩, 也就是通过设置采样率, 减少Bitmap的像素, 从而减少了它所占用的内存
分享个按照图片尺寸压缩:
[java]  view plain copy
  1. public static void compressPicture(String srcPath, String desPath) {
  2. FileOutputStream fos = null;
  3. BitmapFactory.Options op = new BitmapFactory.Options();
  4. // 开始读入图片,此时把options.inJustDecodeBounds 设回true了
  5. op.inJustDecodeBounds = true;
  6. Bitmap bitmap = BitmapFactory.decodeFile(srcPath, op);
  7. op.inJustDecodeBounds = false;
  8. // 缩放图片的尺寸
  9. float w = op.outWidth;
  10. float h = op.outHeight;
  11. float hh = 1024f;//
  12. float ww = 1024f;//
  13. // 最长宽度或高度1024
  14. float be = 1.0f;
  15. if (w > h && w > ww) {
  16. be = (float) (w / ww);
  17. } else if (w < h && h > hh) {
  18. be = (float) (h / hh);
  19. }
  20. if (be <= 0) {
  21. be = 1.0f;
  22. }
  23. op.inSampleSize = (int) be;// 设置缩放比例,这个数字越大,图片大小越小.
  24. // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
  25. bitmap = BitmapFactory.decodeFile(srcPath, op);
  26. int desWidth = (int) (w / be);
  27. int desHeight = (int) (h / be);
  28. bitmap = Bitmap.createScaledBitmap(bitmap, desWidth, desHeight, true);
  29. try {
  30. fos = new FileOutputStream(desPath);
  31. if (bitmap != null) {
  32. bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
  33. }
  34. } catch (FileNotFoundException e) {
  35. e.printStackTrace();
  36. }
  37. }

[Android]Android图片压缩(质量压缩和尺寸压缩)相关推荐

  1. 【jquery】通过降低图片的质量(或尺寸)压缩图片大小

    生产上图片太大除了用户体验不好,上传等待时间过长,还可能会引发用户缓存丢失,导致必要参数缺失请求失败,或者超时引起的请求失败,查找资料,原理是经过一系列的转化过程file文件=>base64=& ...

  2. android 不压缩保存图片格式,Android中图片的压缩方法

    Bitmap Android中图片是以Bitmap(位图)形式存在,位图常见的文件格式有:.bmp .jpg .png .gif . Bitmap的大小计算 = 图片的长度图片的宽度单位像素所占用的字 ...

  3. 性能优化之图片压缩(质量压缩、尺寸压缩)

    前言 作为开发者的我们,经常会做一些上传图片和和保存图片啦 但是由于一些图片非常大,我们在上传或者保存的时候会占用大量的网络资源和本地资源,那么我们需要做的就是对图片就行压缩.以下介绍常见的两种压缩方 ...

  4. 图像的压缩算法--尺寸压缩、格式压缩和品质压缩

    图像分辨率指图像中存储的信息量,是每英寸图像内有多少个像素点,分辨率的单位为PPI(Pixels Per Inch),通常叫做像素每英寸.图像分辨率一般被用于ps中,用来改变图像的清晰度. 一个影像可 ...

  5. Android图片压缩(质量压缩和尺寸压缩)

    在网上调查了图片压缩的方法并实装后,大致上可以认为有两类压缩:质量压缩(不改变图片的尺寸)和尺寸压缩(相当于是像素上的压缩):质量压缩一般可用于上传大图前的处理,这样就可以节省一定的流量,毕竟现在的手 ...

  6. Android图片压缩(质量压缩和尺寸压缩)Bitmap转成字符串上传

    在网上调查了图片压缩的方法并实装后,大致上可以认为有两类压缩:质量压缩(不改变图片的尺寸)和尺寸压缩(相当于是像素上的压缩):质量压缩一般可用于上传大图前的处理,这样就可以节省一定的流量,毕竟现在的手 ...

  7. 【Android 内存优化】图片文件压缩 ( Android 原生 API 提供的图片压缩功能能 | 图片质量压缩 | 图片尺寸压缩 )

    文章目录 一. 图片压缩 二. 图片文件压缩类型 三. Android 原生 API 提供的质量压缩 四. Android 原生 API 提供的尺寸压缩 一. 图片压缩 图片压缩 : ① 文件压缩 : ...

  8. android bitmap 无损压缩,详解Bitmap尺寸压缩与质量压缩

    转载请注明出自flowsky37的博客,尊重他人辛苦劳动! 在Android系统中,关于图片处理的是一个既常见又比较棘手的问题.一个应用中,存在需要展示大量的图片的布局,那我们必须要小心翼翼的处理了, ...

  9. 【Android 内存优化】Android 原生 API 图片压缩代码示例 ( PNG 格式压缩 | JPEG 格式压缩 | WEBP 格式压缩 | 动态权限申请 | Android10 存储策略 )

    文章目录 一. 图片质量压缩 二. 图片尺寸压缩 三. Android 10 文件访问 四. 完整源码示例 上一篇博客 [Android 内存优化]图片文件压缩 ( Android 原生 API 提供 ...

最新文章

  1. 关于前后端交互的一些基础知识点
  2. 微软发布 VS Code Java 安装程序,一键安装所有 Java 开发环境
  3. 前端学习(2697):重读vue电商网站18之监听图片删除事件
  4. Grafana文档(在Centos / Redhat上安装)
  5. python安装后无法使用_Python在终端通过pip安装好包以后在Pycharm中依然无法使用的问题(三种解决方案)...
  6. 面试题11. 旋转数组的最小数字
  7. jdbc事物提交,回滚不起作用的解决方案
  8. Windows 10 全新界面来了:焕然一新!
  9. android 人脸相似度,微软“我们”正式发布 :测试人脸相似度
  10. firefox改html内容,Firefox 中的 HTML5 音视频
  11. WIN7 VS2005 安装wince6.0教程(不管是X86还是X64,我都尝试成功了)
  12. 三维扫描用于3D打印技术
  13. (Java实现) 工作分配问题
  14. Windows 8/8.1/10 删除微软拼音、微软五笔输入法的方法
  15. android型号的平板电脑,AUTOID Pad /Air-(win)/Air-(android)工业级平板电脑
  16. 年薪30W+的IC验证工程师究竟是做什么的?一文为你讲解清楚
  17. 考试周刊杂志考试周刊杂志社考试周刊编辑部2022年第39期目录
  18. 求斐波那契数列c++实现
  19. html无序站点,html有序无序定义列表详解(案例介绍)
  20. Qt实现一个简易截图工具(支持缩放、移动、保存、复制到粘贴板)

热门文章

  1. ipsec技术isakmp(动态)应用
  2. python读取docx文件_Python读写docx文件
  3. 多方案满足户外电源A口、C口、大功率PD快充等需求
  4. openGL学习笔记十四: 透视投影
  5. java图片上传代码_java 图片上传
  6. Oracle进阶(二)存储过程(Procedure)
  7. 手把手教你SQL Server 2019的下载安装配置
  8. MongoDB 备份恢复
  9. pdf格式怎么压缩变小?压缩pdf在线的方法
  10. 2010系统下载(新春贺岁系统大集合)