目录

  • 图片加载
    • 图片压缩
    • Bitmap(位图)的压缩
      • 色位深度
      • 图片文件与Bitmap
    • 压缩--位图读取
    • 压缩--位图写入
      • 对compress的使用反思
      • 注意事项

图片加载

在了解图片压缩前,先简单介绍常用的几种图片加载 方式,在BitmapFactory类中提供了decodeFiledecodeResourcedecodeStreamdecodeByteArraydecodeFileDescriptor几种静态方法,通过使用这些静态方法可以将具体的文件、流、比特数组、文件描述符加载成为Bitmap对象。

图片压缩

老实说“图片压缩”这个词,太过于含糊;

  1. 在运行过程中考虑到Bitmap内存问题,则需要在对Bitmap(位图对象)是进行压缩(通常通过设置色阶深度或Bitmap高宽来实现)。

  2. 在传输或存储过程中为了降低图片文件(最终的.jpg.jpeg)大小,会通过舍弃部分图片信息进行图片的压缩(通常指质量压缩),也就是有损压缩,然后减少文件的大小。
    前一种压缩和后一种压缩往往被混淆一谈。

Bitmap(位图)的压缩

在介绍Bitmap的压缩前,应该了解Bitmap的内存占用,这样才能更好地去理解Bitmap的压缩。

色位深度

首先,需要了解色阶深度。
屏幕上的每个像素点,在内存中都有一块空间用来描述该像素点的颜色信息。同样每张显示在屏幕上的图像,都有一个对应的Bitmap对象用来存储图像上每个像素点的信息,所以在Bitmap中有一块大小为:(图像像素高 x 图像像素宽 x 描述单个像素点需要的位)的空间去存储图像中所有像素点的信息。描述单个像素点需要的位数空间指的就是色位深度。Bitmap中使用Bitmap.Config来决定色位深度,目前Config有四个值:ALPHA_8、RGB_565、ARGB_4444、ARGB_8888。
(A:透明度 、R:红、G:绿、B:蓝)。

Config 每个像素占用的字节 说明
ALPHA_8 1 bytes 每个像素仅仅储存透明度通道
RGB_565 2 bytes 每个像素的RGB通道会保存,透明度不会保存,红色通道5位,有25=32种表现形式;绿色通道6位,有26=64种表现形式;蓝色通道5位,有2^5=32种表现形式
ARGB_4444 2 bytes 每个像素的ARGB通道都会保存,透明度/红色/绿色/蓝色通道4位,有2^4=16种表现形式
ARGB_8888 4 bytes 每个像素的ARGB通道都会保存,透明度/红色/绿色/蓝色通道8位,有2^8=256种表现形式

图片文件与Bitmap

Android中常用的图片文件通常以.png.jpeg.jpg格式进行存储。png文件是一种无损压缩的位图图像存储格式, 它利用特殊的编码方法标记重复出现的数据,而jpgjpeg则是有损压缩的位图图像存储格式。在每个像素点的描述上png图片要多一个alpa透明通道,当时所以相同高宽和清晰度的图像,保存为png文件的文件大小不一定要比jpgjpeg文件要大。
此处强烈推荐《你的bitmap究竟有多大》
通过调用BitmapFactory的图片文件解析加载函数可将图片文件加载进入内存当中成为Bitmap对象,由于pngjpgjpeg图片文件均是Bitmap压缩以后写入的文件,所以通常Bitmap对象的大小大于文件大小。

压缩–位图读取

由于Bitmap所占内存的大小主要取决于图片宽度图片高度色位深度图片所在文件夹设备像素密度,故而在加载图片时为避免OOM的产生,可通过缩减宽高与减少色位深度的bit位数来达到压缩Bitmap所需空间。

  1. 通过设置加载选项BitmapFactory.OptionsinSampleSize实现高宽等比缩小达到压缩效果,在第一次解析码时,并不需要将文件全部解码成Bitmap对象,这里只需要Bitmap的原始高宽,所以Options.isJustDecodeBounds设置为true。在计算得到合适的比例后,再设置采样率参数inSampleSize来得到适当大小的bitmap对象;
    /*** 取样(尺寸等比)压缩,由于reqWidth和reqHeight通常取* ImageView的大小,为了使图片将ImageView填充满避免出现* 黑色空白区域,故而选取小比例作为压缩比值** @param resources* @param resId* @param reqWidth request width* @param reqHeight request height* */public static Bitmap compressInSampleSize(Resources resources, int resId, int >reqWidth, int reqHeight) {BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;Bitmap bitmap = BitmapFactory.decodeResource(resources, resId, options);options.inSampleSize = getInSampleSize(bitmap, reqWidth, reqHeight);options.inJustDecodeBounds = false;bitmap.recycle();Bitmap resultBitmap = BitmapFactory.decodeResource(resources, resId, options);return resultBitmap;}private static int getInSampleSize(Bitmap bitmap, int reqWidth, int reqHeight){int bitmapWidth = bitmap.getWidth();int bitmapHeight = bitmap.getHeight();int inSampleSize = 1;//若希望更改比例选择策略,将'&&'改为'||'即可while (bitmapWidth/inSampleSize > reqWidth && bitmapHeight/inSampleSize > reqHeight){inSampleSize *= 2;}return inSampleSize;}
  1. 通过设置色位深度减少Bitmap的占用内存
    /*** 选择色阶深度加载图片** @param resources* @param resId* @param config Color order depth* */public static Bitmap compressInPixColorBit(Resources resources, int resId, Bitmap.Config config) {BitmapFactory.Options options = new BitmapFactory.Options();options.inPreferredConfig = config == null? Bitmap.Config.RGB_565 : config;Bitmap resultBitmap = BitmapFactory.decodeResource(resources, resId, options);return resultBitmap;}

高宽等比缩小与设置色位深度实现内存占用降低可以联合使用,使Bitmap占用内存更低,但同时也意味着更多信息的缺失,例如:如果采用RGB_565则图片将没有透明度通道。

压缩–位图写入

网上很多博客均将质量压缩作为图片加载防止OOM的一种解决方案,然而这是对“质量压缩”的误解。他们给出的质量压缩方案,通常如下:

    /*** 质量压缩** @param bitmap* @param targetSize target size equal to targetSize(kb)* */public static Bitmap compressInQuality(Bitmap bitmap, int targetSize) {ByteArrayOutputStream resultBitmapStream = new ByteArrayOutputStream();int quality = 100;do{resultBitmapStream.reset();bitmap.compress(Bitmap.CompressFormat.JPEG, quality, resultBitmapStream);quality -= 10;}while (resultBitmapStream.toByteArray().length/1024 > targetSize  && quality > 0);bitmap.recycle();return BitmapFactory.decodeStream(new ByteArrayInputStream(resultBitmapStream.toByteArray()));}

然后,如果把这个理解成“可以按质量quality压缩bitmap对象”便是大错特错。直接使用这样的方案来试图降低Bitmap非但达不到效果,还会使内存提前用完。

对compress的使用反思

  1. 为何compress这样处理得到的OutputStream,再经过解析后不能达到降低内存的效果内?
    compress是按照压缩算法(算法根据第一个参数而定,PNG则是采用无损压缩算法,JPEG则是采用有损压缩算法)对bitmap对象中的信息进行压缩然后写入OutputStream,具体压缩率则取决于quality(0~100,当采用无损压缩PNG时,此参数被忽略),但是此时的bitmap对象任然是原来的bitmap对象,当使用decodeStreamcompress产生的OutputStream进行解析时,解析得到的新Bitmap高宽与原来的Bitmap高宽相等,不选择色位深度的话,则时默认色位深度,新的Bitmap的内存占用甚至更高,所以这种处理方式会在内存中存在两个bitmap对象,还多申请了一份ByteArrayOutputStream空间。
  2. 那质量压缩compress什么时候用呢?
    compress只是将一个bitmap对象的信息压缩进一个OutputStream,如果选择有损压缩则在压缩的过程中还会选择性放弃一些图片信息,无损压缩则会保留图片的全部信息,但是无损压缩后的文件任然会比Bitmap在内存中占用的内存大小要小。所以,在网络传输或者在存储时使用compress显然是可行的。同时,如果Bitmap是再加载过程中使用了压缩,在compress使用完成以后,由于Bitmap所含信息减少,质量压缩得到的数据流将会变得更小。对数据流进行解析的得到的Bitmap的内存占用也随之降低。

注意事项

  • 图片加载需要考虑是否需要缓存
  • 在对文件流进行解析时,应考虑是否一步解析,如果需要多步读取流,应考虑到文件流的有序性,经过读取后,流的起始位置发生变化,导致再次读取为null,此时建议使用文件描述符进行操作
  • 位图压缩读取与压缩写入为IO操作,不应在主线程中进行

Android图片的加载与压缩相关推荐

  1. Android 图片异步加载的体会,SoftReference已经不再适用

    在网络上搜索Android图片异步加载的相关文章,目前大部分提到的解决方案,都是采用Map<String, SoftReference<Drawable>>  这样软引用的方式 ...

  2. android图片异步加载图片,Android 异步加载图片分析总结

    研究了android从网络上异步加载图像,现总结如下: (1)由于android UI更新支持单一线程原则,所以从网络上取数据并更新到界面上,为了不阻塞主线程首先可能会想到以下方法. 在主线程中new ...

  3. Android 图片异步加载

    所谓图片异步加载,意思是不用一次把图片全部加载完,你可以叫它延迟加载,缓冲加载都行. 看看你有没有这种需求:某篇文章图片很多,如果在载入文章时就载入所有图片,无疑会延缓载入速度,让用户等更久,所以,我 ...

  4. android图片获取加载小结

    获取方式 1.内存 内存缓存主要使用LRU缓存算法,引用support-v4中的LruCache, 通过键值对的形式获取到相应的bitmap,配置如下: //初始化缓存策略int maxMem = ( ...

  5. android图片异步加载解决步骤

    Android – Asynchronous image loading in ListView Problem: How to load images in ListView asynchronou ...

  6. Android 高清加载巨图方案 拒绝压缩图片

    Android 高清加载巨图方案 拒绝压缩图片 转载请标明出处:  http://blog.csdn.net/lmj623565791/article/details/49300989:  本文出自: ...

  7. Android开发解决加载图片OOM问题(非常全面 兼顾4 0以下系统)(by 星空武哥)

    转载请标明:http://blog.csdn.net/lsyz0021/article/details/51295402 我们项目中经常会加载图片,有时候如果加载图片过多的话,小则导致程序很卡,重则O ...

  8. android复位机器人图片_Universal-Image-Loader 图片异步加载类库还不熟?

    码个蛋(codeegg) 第 824 次推文 作者:欢醉 博客:https://cloud.tencent.com/developer/article/1026386 码妞看世界 写在前面 这个图片异 ...

  9. Android 自定义ImageView加载图片

    自定义imageview功能: 可以实现设置图片显示的时候,依据本身的比例进行图片的缩放 加载图片效果: 使用ImageLoader来加载 图片: 首先将ImageLoader的jar包关联到项目中 ...

最新文章

  1. 讨论:对于神经网络,不需要弄明白原理,只需要应用,是这样吗?
  2. 杭电oj2035c语言答案,杭电oj 2035
  3. c# 扩展方法奇思妙用高级篇六:WinForm 控件选择器
  4. 编写 matlab怎么调用 8 点和 16 点的 fft,8点基于DIT的FFT的实现
  5. 简单粗暴的肢体语言解读攻略 | 今日最佳
  6. 腾讯offer是什么样子_月薪35K:2020腾讯Java后端开发详细面试流程
  7. 密码学专题 文件编码格式
  8. 全国python工程师有多少_2019年Python工程师的平均薪资是多少?
  9. Guice依赖注入(接口多实现)
  10. 各种分类算法的优缺点
  11. stm8s单片机2位数码管显示_AT89S52单片机,实现功能两位数码管显示数字,按下
  12. 【矢量图】PyEcharts导出图片并矢量化
  13. Dev cpp 手动开栈
  14. TF卡格式化了怎么办?tf卡数据恢复,看这3个方法
  15. GPS涉及到的各种时间转换(年月日,年积日,儒略日,GPS周及周内日或周内秒,星期几)python
  16. VMware创建虚拟机时出现 network bot from intel e1000
  17. 工程伦理 第三章习题 答案
  18. 使用openCV标定摄像机的各种参数
  19. 基于matlab的动态机器人轨迹模拟仿真
  20. Deep Learning ---Ian Goodfellow

热门文章

  1. 最详细记录minikube部署第一个Kubernete应用
  2. 权限系统--角色管理
  3. git提交本地项目gitlab合并分支提交代码合并分支时的冲突解决git拉取新项目
  4. ROS学习VScode常用快捷键
  5. ConfigurationManager
  6. linux 给目录权限命令,Linux命令之文件及目录权限
  7. android系统旋转方向定制问题
  8. macmini和imac哪个好?
  9. 按电源键休眠流程(framework层)
  10. 要说搜狐一手好牌打到烂,那百度又是如何沦落到如今境地的?