ios 计算图片解压为位图后大小

Posted 想名真难

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ios 计算图片解压为位图后大小相关的知识,希望对你有一定的参考价值。

结论: 在iOS设备上, 位图实际像素点占内存(字节数B) = 宽*高*4

什么是位图?

位图图像(bitmap),亦称为点阵图像或栅格图像,是由称作像素(图片元素)的单个点组成的。这些点可以进行不同的排列和染色以构成图样。当放大位图时,可以看见赖以构成整个图像的无数单个方块。计算机显示属于位图。位图的特点是可以表现色彩的变化和颜色的细微过渡,产生逼真的效果,缺点是在保存时需要记录每一个像素的位置和颜色值,占用较大的存储空间。

位图占用的空间比较大, 直接存贮在磁盘中非常的浪费空间, 所以就有了对位图的压缩方式, 不管是 JPEG 还是 PNG 图片,都是一种压缩的位图图形格式。只不过 PNG 图片是无损压缩,并且支持 alpha 通道,而 JPEG 图片则是有损压缩,可以指定 0-100% 的压缩比。

当需要展示的时候, 需要将压缩的图片数据解码成未压缩的位图形式,这样才能交给渲染层, 由Core Animation 中CALayer使用未压缩的位图数据渲染 UIImageView 的图层。用户才能在屏幕上看到图片.

iOS图片的解压缩,位图,从文件到屏幕上的过程

生成位图: 最核心的函数是 CGBitmapContextCreate :

CGContextRef CGBitmapContextCreate(void * __nullable data,
                                   size_t width,size_t height,
                                   size_t bitsPerComponent,
                                   size_t bytesPerRow,
                                   CGColorSpaceRef space,
                                   uint32_t bitmapInfo);
  • data :如果不为 NULL ,那么它应该指向一块大小至少为 bytesPerRow * height 字节的内存;如果 为 NULL ,那么系统就会为我们自动分配和释放所需的内存,所以一般指定 NULL 即可;
  • width 和height :位图的宽度和高度,分别赋值为图片的像素宽度和像素高度即可;
  • bitsPerComponent :像素的每个颜色分量使用的 bit 数,在 RGB 颜色空间下指定 8 即可;
  • bytesPerRow :位图的每一行使用的字节数,大小至少为 width * bytes per pixel 字节。当我们指定 0/NULL 时,系统不仅会为我们自动计算,而且还会进行 cache line alignment 的优化
  • space :就是我们前面提到的颜色空间,一般使用 RGB 即可;
  • bitmapInfo :位图的布局信息.kCGImageAlphaPremultipliedFirst

bitsPerComponent, 色彩深度

​色彩深度又叫色彩位数,即位图中要用多少个二进制位来表示每个点的颜色,是分辨率的一个重要指标。在ios上一般都是指定为8, 注意,这个8是单个颜色占用的位数, 如果是RGB,那就是24位, 如果是ARGB或者RGBA就是32位.

常用有1位(单色),2位(4色,CGA),4位(16色,VGA),8位(256色),16位(增强色),24位和32位(真彩色)等。色深8位及以上的位图还可以根据其中分别表示RGB三原色或CMYK四原色(有的还包括Alpha通道)的位数进一步分类.​

8位(bit)位图:彩色版中有2^8=256种颜色,具体哪256种颜色可由调色板灵活规定,因此每个像素点最多有256种情况(颜色),故刚好可用两位十六进制码(16^2=256)表示,占1字节。
一幅512×512的8位位图大小计算方法:位图文件头(14字节)+位图信息头(40字节)+调色板(256×彩色表4字节)+实际像素点占内存(512×512×1字节)=263 222字节(Byte)。

24位位图:又名RGB真彩色图, 刚才在bitsPerComponent上指定了8, 标识每个颜色占8位, RGB3个颜色所以是24位,我们平时用来表示RGB时写的0xFFFFFF,  2^8 * 2^8 * 2^8 = 2^24=16 777 216=16M色,这个就没有彩色表了。
蓝、绿、红刚好可用1个字节表示。RGB中每个都占8位, 1 Byte(B字节) = 8 bit(二进制位), 每个像素点由3个字节表示,每个字节负责控制一种颜色。那么每个像素点可能的颜色就有256×256×256=2^24种。一幅256×256的24位位图大小计算方法:位图文件头(14字节)+位图信息头(40字节)+实际像素点占内存(256×256×3字节)=196 662字节(Byte)。    

需要注意的是,系统有“补零”的习惯!即要求位图的每一行像素所占字节数必须被4整除。若不能倍4整除,则在该位图每一行的十六进制码末尾“补”1至3个字节的“00”。例如:一幅宽253×高256的24位位图,系统在生成该图为实际位图时,计算每一行像素所占字节=宽253×3字节=759字节,检验其被4除余1,则在每行的十六进制码末尾加1个字节,补“00”,变为760字节。因此我们计算该图大小时应先判断是否“补零”,再得出算法:该图大小=位图文件头(14字节)+位图信息头(40字节)+实际像素点占内存(高256×每行760字节)=194614字节(Byte)。   

有趣的是,“补零”只针对位图的宽进行检验,一幅宽256×高253的24位位图,其大小=位图文件头(14字节)+位图信息头(40字节)+实际像素点占内存(高253×每行768字节)=194358字节(Byte)< 196 662字节(Byte)。这样,只是把此图像的宽和高颠倒,图像所占内存竟然变小了。

32位位图:相当于RGB的 24位 再加上 8bits的透明颜色通道,就相当于R(红)、G(绿)、B(蓝)、A(透明)。

R(0~255),G(0~255),B(0~255),A(0~255)。比24位位图多了一个Alpha通道(透明),也就是说PNG 32能表示跟PNG 24一样多的色彩,并且还支持256种透明的颜色,能表示更加丰富的图片颜色类型。


每行占用大小 = 宽 * 色彩深度/8

位图实际像素点占内存 = 高 × 每行占用大小 =  宽*高*色彩深度/8

由于iOS上色彩深度都是24位/32位, 经过对齐后都是4字节, 所以可以简化为

位图实际像素点占内存(字节数B) = 宽*高*4

理论部分完成, 下面找几个图计算一下: 

  • 只有图片的宽高会影响位图大小
  • 图片格式不会影响位图大小, 同样大小的PNG,jpg对应的位图大小一致
  • jpg的压缩质量不会影响位图大小,只会影响文件大小
- (void)viewDidLoad 
    [super viewDidLoad];

    UIImage *image = nil;
    // 图片的宽高会影响大小, 拼接参数后能减少约3.3M的内存占用
    // 1242*1000*4=4968000 约等于 4851K
//    image = [UIImage imageNamed:@"backPic"];
    // 708*570*4=1614240 约等于 1576K
//    image = [UIImage imageNamed:@"backPic-1"];

    // 质量参数不会影响内存
    // 原图,没有压缩质量  13.5M  bitMap  901*901*4=3247204 约等于 3171K
//    image = [UIImage imageNamed:@"jpg"];
    // 压缩了质量, 13.5M    bitMap  901*901*4=3247204 约等于  3171K
//    image = [UIImage imageNamed:@"jpg-1"];


    // 同样尺寸大小的PNG和JPG, 比较位图大小
    // jpg大小: 1242*1000*4=4968000 约等于 4851K
    image = [UIImage imageNamed:@"backPic"];
    [self getImageBitmapSize:image];
    // png大小: 1242*1000*4=4968000 约等于 4851K
    image = [UIImage imageNamed:@"pngBg"];
    [self getImageBitmapSize:image];



/// 计算出UIImage生成的位图大小
- (size_t)getImageBitmapSize:(UIImage *)image 

    CGImageRef imageRef = image.CGImage;
    size_t width = CGImageGetWidth(imageRef);
    size_t height = CGImageGetHeight(imageRef);
    CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
    CGContextRef ctx = CGBitmapContextCreate(NULL, width, height, 8, 0, space, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrderDefault);
    CGContextDrawImage(ctx, CGRectMake( 0, 0, width, height), imageRef);
    size_t perRow = CGImageGetBytesPerRow(imageRef);
    size_t size = perRow * height;
    CFRelease(ctx);
    NSLog(@"size %@B,  %@K, %@M",@(size), @(size/1024), @(size/1024/1024));
    return size;

最后又找了一下SD的计算位图大小, 对比确认了一下,计算单张图片和SD的一致, 但是SD考虑的比较全面,处理了gif图片的情况.

YY的计算位图占用大小, 

以上是关于ios 计算图片解压为位图后大小的主要内容,如果未能解决你的问题,请参考以下文章

计算机图形

Android初级教程图片信息

vc中如何让背景图片随窗体的大小变化而改变 mfc

计算机视觉数字图像与机器视觉基础

解码后的位图字节大小?

android中如何动态修改ImageView中图片的大小 比如说点击该图片后图片能变大