Android图片的加载与压缩
目录
- 图片加载
- 图片压缩
- Bitmap(位图)的压缩
- 色位深度
- 图片文件与Bitmap
- 压缩--位图读取
- 压缩--位图写入
- 对compress的使用反思
- 注意事项
图片加载
在了解图片压缩前,先简单介绍常用的几种图片加载 方式,在BitmapFactory
类中提供了decodeFile
、decodeResource
、decodeStream
、decodeByteArray
、decodeFileDescriptor
几种静态方法,通过使用这些静态方法可以将具体的文件、流、比特数组、文件描述符加载成为Bitmap
对象。
图片压缩
老实说“图片压缩”这个词,太过于含糊;
在运行过程中考虑到Bitmap内存问题,则需要在对Bitmap(位图对象)是进行压缩(通常通过设置色阶深度或
Bitmap
高宽来实现)。在传输或存储过程中为了降低图片文件(最终的
.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
文件是一种无损压缩的位图图像存储格式, 它利用特殊的编码方法标记重复出现的数据,而jpg
、jpeg
则是有损压缩的位图图像存储格式。在每个像素点的描述上png图片要多一个alpa透明通道,当时所以相同高宽和清晰度的图像,保存为png
文件的文件大小不一定要比jpg
、jpeg
文件要大。
此处强烈推荐《你的bitmap究竟有多大》
通过调用BitmapFactory
的图片文件解析加载函数可将图片文件加载进入内存当中成为Bitmap
对象,由于png
、jpg
、jpeg
图片文件均是Bitmap
压缩以后写入的文件,所以通常Bitmap
对象的大小大于文件大小。
压缩–位图读取
由于Bitmap
所占内存的大小主要取决于图片宽度
、图片高度
、色位深度
、图片所在文件夹
、设备像素密度
,故而在加载图片时为避免OOM的产生,可通过缩减宽高与减少色位深度的bit位数来达到压缩Bitmap
所需空间。
- 通过设置加载选项
BitmapFactory.Options
的inSampleSize
实现高宽等比缩小达到压缩效果,在第一次解析码时,并不需要将文件全部解码成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;}
- 通过设置色位深度减少
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的使用反思
- 为何
compress
这样处理得到的OutputStream
,再经过解析后不能达到降低内存的效果内?
compress
是按照压缩算法(算法根据第一个参数而定,PNG则是采用无损压缩算法,JPEG则是采用有损压缩算法)对bitmap对象中的信息进行压缩然后写入OutputStream
,具体压缩率则取决于quality
(0~100,当采用无损压缩PNG时,此参数被忽略),但是此时的bitmap
对象任然是原来的bitmap
对象,当使用decodeStream
对compress
产生的OutputStream
进行解析时,解析得到的新Bitmap
高宽与原来的Bitmap
高宽相等,不选择色位深度的话,则时默认色位深度,新的Bitmap
的内存占用甚至更高,所以这种处理方式会在内存中存在两个bitmap
对象,还多申请了一份ByteArrayOutputStream
空间。 - 那质量压缩
compress
什么时候用呢?
compress
只是将一个bitmap
对象的信息压缩进一个OutputStream
,如果选择有损压缩则在压缩的过程中还会选择性放弃一些图片信息,无损压缩则会保留图片的全部信息,但是无损压缩后的文件任然会比Bitmap
在内存中占用的内存大小要小。所以,在网络传输或者在存储时使用compress
显然是可行的。同时,如果Bitmap
是再加载过程中使用了压缩,在compress
使用完成以后,由于Bitmap
所含信息减少,质量压缩得到的数据流将会变得更小。对数据流进行解析的得到的Bitmap
的内存占用也随之降低。
注意事项
- 图片加载需要考虑是否需要缓存
- 在对文件流进行解析时,应考虑是否一步解析,如果需要多步读取流,应考虑到文件流的有序性,经过读取后,流的起始位置发生变化,导致再次读取为
null
,此时建议使用文件描述符进行操作 - 位图压缩读取与压缩写入为IO操作,不应在主线程中进行
Android图片的加载与压缩相关推荐
- Android 图片异步加载的体会,SoftReference已经不再适用
在网络上搜索Android图片异步加载的相关文章,目前大部分提到的解决方案,都是采用Map<String, SoftReference<Drawable>> 这样软引用的方式 ...
- android图片异步加载图片,Android 异步加载图片分析总结
研究了android从网络上异步加载图像,现总结如下: (1)由于android UI更新支持单一线程原则,所以从网络上取数据并更新到界面上,为了不阻塞主线程首先可能会想到以下方法. 在主线程中new ...
- Android 图片异步加载
所谓图片异步加载,意思是不用一次把图片全部加载完,你可以叫它延迟加载,缓冲加载都行. 看看你有没有这种需求:某篇文章图片很多,如果在载入文章时就载入所有图片,无疑会延缓载入速度,让用户等更久,所以,我 ...
- android图片获取加载小结
获取方式 1.内存 内存缓存主要使用LRU缓存算法,引用support-v4中的LruCache, 通过键值对的形式获取到相应的bitmap,配置如下: //初始化缓存策略int maxMem = ( ...
- android图片异步加载解决步骤
Android – Asynchronous image loading in ListView Problem: How to load images in ListView asynchronou ...
- Android 高清加载巨图方案 拒绝压缩图片
Android 高清加载巨图方案 拒绝压缩图片 转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/49300989: 本文出自: ...
- Android开发解决加载图片OOM问题(非常全面 兼顾4 0以下系统)(by 星空武哥)
转载请标明:http://blog.csdn.net/lsyz0021/article/details/51295402 我们项目中经常会加载图片,有时候如果加载图片过多的话,小则导致程序很卡,重则O ...
- android复位机器人图片_Universal-Image-Loader 图片异步加载类库还不熟?
码个蛋(codeegg) 第 824 次推文 作者:欢醉 博客:https://cloud.tencent.com/developer/article/1026386 码妞看世界 写在前面 这个图片异 ...
- Android 自定义ImageView加载图片
自定义imageview功能: 可以实现设置图片显示的时候,依据本身的比例进行图片的缩放 加载图片效果: 使用ImageLoader来加载 图片: 首先将ImageLoader的jar包关联到项目中 ...
最新文章
- 讨论:对于神经网络,不需要弄明白原理,只需要应用,是这样吗?
- 杭电oj2035c语言答案,杭电oj 2035
- c# 扩展方法奇思妙用高级篇六:WinForm 控件选择器
- 编写 matlab怎么调用 8 点和 16 点的 fft,8点基于DIT的FFT的实现
- 简单粗暴的肢体语言解读攻略 | 今日最佳
- 腾讯offer是什么样子_月薪35K:2020腾讯Java后端开发详细面试流程
- 密码学专题 文件编码格式
- 全国python工程师有多少_2019年Python工程师的平均薪资是多少?
- Guice依赖注入(接口多实现)
- 各种分类算法的优缺点
- stm8s单片机2位数码管显示_AT89S52单片机,实现功能两位数码管显示数字,按下
- 【矢量图】PyEcharts导出图片并矢量化
- Dev cpp 手动开栈
- TF卡格式化了怎么办?tf卡数据恢复,看这3个方法
- GPS涉及到的各种时间转换(年月日,年积日,儒略日,GPS周及周内日或周内秒,星期几)python
- VMware创建虚拟机时出现 network bot from intel e1000
- 工程伦理 第三章习题 答案
- 使用openCV标定摄像机的各种参数
- 基于matlab的动态机器人轨迹模拟仿真
- Deep Learning ---Ian Goodfellow