图片相关的问题
# 图片显示原理
图片其实是由很多个像素点组成的,每个像素点描述了该点的颜色信息。这样的数据是可以被直接渲染在屏幕上的,称之为 Image Buffer。
事实上,由于图片源文件占用的存储空间非常大,一般在存储时候都会进行压缩,非常常见的就是 JPEG 和 PNG 算法压缩的图片。
因此当图片存储在硬盘中的时候,它是经过压缩后的数据。经过解码后的数据才能用于渲染,因此需要将图片显示在屏幕上的话,需要先经过解码。解码后的数据就是 Image Buffer 。
当图片显示在屏幕上时,会复制显示区域的 Image Buffer 去进行渲染。
图片渲染到屏幕的过程: 读取文件->计算Frame->图片解码->解码后纹理图片位图数据通过数据总线交给GPU->GPU获取图片Frame->顶点变换计算->光栅化->根据纹理坐标获取每个像素点的颜色值(如果出现透明值需要将每个像素点的颜色*透明度值)->渲染到帧缓存区->渲染到屏幕
# 图片相关的问题
Q1:一张 png 格式的图片,图片文件大小为 55.8KB,那么它加载进内存时所占的大小是多少?
Q2:为什么有时候,同一个 app,app 内的同个界面,界面上同张图片,但在不同设备上所耗内存却不一样?
Q3:同一张图片,在界面上显示的控件大小不同时,它的内存大小也会跟随着改变吗?
Q4:图片占用的内存大小公式:图片分辨率 * 每个像素点大小,这种说法正确吗,或者严谨吗?
Q5:优化图片的内存大小有哪些方向可以着手?
# 一张图片的大小是如何计算的,当加载进内存中时,占用的空间又是多少?
一 张图片的大小是如何计算的,当加载进内存中时,占用的空间又是多少? 比如一张1024*1024在32位机子上占用的内存:
首先需要知道几个公式:
1、1像素 = 32位 = 4B
2、1M = 1024KB = 1024*1024B
因此1024*1024的图片内存大小为
1024*1024*4B = 4M
图片占用内存的计算公式:图片高度 * 图片宽度 * 一个像素占用的内存大小
先来看张图片:
分辨率为 1080*452 的 png 格式的图片,图片文件本身大小 56KB
看见没有,明明都是同一张图片,但在不同场景下,所占用的内存大小却是有可能不一样的,具体稍后分析。以上场景中列出了图片的不同来源,不同 Android 设备,显示控件的不同大小这几种考虑点下的场景。我们继续来看一种场景:同一张图片,保存成不同格式的文件(不是重命名,可借助ps);
# 总结
最后,来稍微总结一下:
一张图片占用的内存大小的计算公式:分辨率 * 像素点大小;但分辨率不一定是原图的分辨率,需要结合一些场景来讨论,像素点大小就几种情况:ARGB_8888(4B)、RGB_565(2B) 等等。
同个 app,在不同 dpi 设备中,同个界面的相同图片所占的内存大小有可能不一样。
# iOS图片问题
SDWebImage加载网络图片过大/加载本地高清大图导致内存溢出的解决办法在 didReceiveMemoryWarning方法中释放SDImage的缓存
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
[[SDWebImageManager sharedManager] cancelAll];
[[SDImageCache sharedImageCache] clearDisk];
}
2
3
4
5
6
# 如果加载的是项目本地的大图导致的内存溢出,解决办法如下:
建议使用该方法获取图片
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"xds"ofType:@"png"];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:imagePath];
而不要使用下面的方法,图片过大容易造成内存溢出
UIImage *image = [UIImage imageNamed:@"xds.png"];
2
3
4
# 给UIImage 写一个类目. 类目中添加以下方法按照你需要的大小重绘UIImage, 实现图片压缩
-(UIImage*)scaleToSize:(CGSize)size
{
// 创建一个bitmap的context
// 并把它设置成为当前正在使用的context
UIGraphicsBeginImageContext(size);
// 绘制改变大小的图片
[self drawInRect:CGRectMake(0, 0, size.width, size.height)];
// 从当前context中创建一个改变大小后的图片
UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
// 使当前的context出堆栈
UIGraphicsEndImageContext();
// 返回新的改变大小后的图片
return scaledImage;
}
2
3
4
5
6
7
8
9
10
11
12
13
14