洋仔的博客 洋仔的博客
首页
  • 个人心法总结

    • 价值心法
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • iOS基础知识
  • 前端
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 投资体系
  • 毛选
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

洋仔

奋斗的小青年
首页
  • 个人心法总结

    • 价值心法
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • iOS基础知识
  • 前端
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 投资体系
  • 毛选
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 技术文档

  • GitHub技巧

  • Nodejs

  • 博客搭建

  • iOS基础知识

    • iOS底层相关

    • Runloop系列

    • Runtime系列

    • 内存管理系列

    • Block系列

    • 线程系列

    • KVC跟KVO系列以及通知中心

    • UI系列

    • 离屏渲染系列

      • 离屏渲染
      • 图片相关的问题
        • 图片显示原理
        • 图片相关的问题
        • 一张图片的大小是如何计算的,当加载进内存中时,占用的空间又是多少?
          • 总结
        • iOS图片问题
        • 如果加载的是项目本地的大图导致的内存溢出,解决办法如下:
        • 给UIImage 写一个类目. 类目中添加以下方法按照你需要的大小重绘UIImage, 实现图片压缩
    • 组件化系列跟架构

    • OC跟webview交互系列

    • 持久化系列

    • APP编译系列

    • APP性能优化系列

    • cocoapods系列

    • swift系列

    • Git系列

    • 网络相关

    • 三方库系列

    • 系统原理

    • 总结系列

    • 算法系列

    • 数据结构系列

  • 前端

  • 技术
  • iOS基础知识
  • 离屏渲染系列
洋仔
2023-09-26
目录

图片相关的问题

# 图片显示原理

图片其实是由很多个像素点组成的,每个像素点描述了该点的颜色信息。这样的数据是可以被直接渲染在屏幕上的,称之为 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];
}
1
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"];
1
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
编辑 (opens new window)
上次更新: 2024/10/23, 23:26:17
离屏渲染
iOS组件化系列

← 离屏渲染 iOS组件化系列→

最近更新
01
数组
10-25
02
数组双指针系列之对撞指针
10-25
03
数组双指针系列之快慢指针
10-25
更多文章>
Theme by Vdoing | Copyright © 2019-2024 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式