iOS 中的 imageIO 与 image 解码

底层图像处理之GIF图片的合成与解析(三) 阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 GIF的应用场景 GIF在iOS中的使用场景有以下三个方面。 (1)GIF图片分解为单帧图片。 (2)一系列单帧图片合成GIF图片。 (3)iOS系统上展示GIF动画效果。 在GIF的合成和分解方面将会接触到iOS图像处理核心框架ImageIO,作... 阅读详情

ImageIO


ImageIO对外开放的对象有CGImageSourceRef、CGImageDestinationRef,不对外开放的对象有CGImageMetadataRef。CoreGraphics中经常与imageIO打交道的对象有CGImageRef和CGDataProvider,接下来看看这五个对象在创建一个UIImage中担任了哪些角色。

用TimeProfiler一步一步来看创建UIImage过程中内部调用的函数可以帮助我们解决问题,由于TimeProfiler统计函数栈为间隔一段时间统计一次,导致没有记录下所有函数的调用而且每次函数栈还可能不一致,所以没法精确判断函数栈是如何调用的,但是可以大概推测出每步做了什么。

从CFDataRef到UIImage代码如下

NSString *resource = [[NSBundle mainBundle] pathForResource:@"the_red_batman" ofType:@"png"];
NSData *data = [NSData dataWithContentsOfFile:resource options:0 error:nil];
CFDataRef dataRef = (__bridge CFDataRef)data;
CGImageSourceRef source = CGImageSourceCreateWithData(dataRef, nil);
CGImageRef cgImage = CGImageSourceCreateImageAtIndex(source, 0, nil);
UIImage *image = [UIImage imageWithCGImage:cgImage];

img-w600

调用了内部函数_CGImageReadCreate,也就是说CGImageSourceRef跟读取图像数据有关。

CGImageSourceCreateImageAtIndex

img-w600

img-w600

调用了_cg_png_read_info和CGImageMetadataCreateMutable,在构建CGImageRef时,读取了图片的基础数据和元数据,基础数据中包括Image的header chunk,比如png的IHDR。元数据是由CGImageMetadataRef来抽象的。并且没有读取图片的其他数据,更没有做解码的动作。

有趣的是,如果调用CGImageSourceCopyPropertiesAtIndex

img-w600

CGImageSourceCopyPropertiesAtIndex的内部函数调用了CGImageMetadataRef,如果再加上ImageIO/CGImageMetadata.h文件的注释

@description CGImageMetadata APIs allow clients to view and modify metadata
for popular image formats. ImageIO supports the EXIF, IPTC, and XMP
metadata specifications. Please refer to CGImageSource.h for functions to
read metadata from a CGImageSource, and CGImageDestination.h for functions to
write metadata to a CGImageDestination. CGImageDestinationCopyImageSource can
be used to modify metadata without recompressing the image.

说明CGImageMetadataRef抽象出图片中EXIF、IPTC、XMP格式的元数据插入字段,而若想获得CGImageMetadataRef必须要通过CGImageSourceRef。

同样,看看有关CGDataProviderRef的内部函数调用,代码如下

//将CGImageSourceRef改由CGDataProviderRef创建   
CFDataRef dataRef = (__bridge CFDataRef)data;
CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(dataRef);
CGImageSourceRef source = CGImageSourceCreateWithDataProvider(dataProvider, nil);
//测试由CGImageRef获取CGDataProviderRef和由CGDataProviderRef创建CGImageRef
CGDataProviderRef newDataProvider = CGImageGetDataProvider(cgImage);
size_t width = CGImageGetWidth(cgImage);
size_t height = CGImageGetHeight(cgImage);
CGColorSpaceRef space = CGImageGetColorSpace(cgImage);
size_t bitsPerComponent = CGImageGetBitsPerComponent(cgImage);
size_t bitsPerPixel = CGImageGetBitsPerPixel(cgImage);
size_t bytesPerRow = CGImageGetBytesPerRow(cgImage);
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(cgImage);
CGDataProviderRef newDataProvider = CGImageGetDataProvider(cgImage);
CGImageRef newImage = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, space, bitmapInfo, newDataProvider, NULL, false, kCGRenderingIntentDefault);

很可惜,没有找出有关CGDataProviderRef的函数调用。无法得出CGDataProviderRef做了什么。

看看有关CGImageDestinationRef的内部函数调用,代码和内部函数调用如下

CFMutableDataRef buffer = CFDataCreateMutable(kCFAllocatorDefault, 0);      CGImageDestinationRef destination = CGImageDestinationCreateWithData(buffer, kUTTypePNG, 1, NULL);
CGImageDestinationAddImage(destination, cgImage, nil);
CGImageDestinationFinalize(destination);

img-w600

CGImageDestinationRef将图片数据写入目的地,并且负责做图片编码或者说图片压缩。

测试结论

CGImageSourceRef抽象了对读图像数据的通道,读取图像要通过它,它自己本身不读取图像的任何数据,在你调用CGImageSourceCopyPropertiesAtIndex的时候会才去读取图像元数据。

CGImageMetadataRef抽象出图片中EXIF、IPTC、XMP格式的元数据,通过CGImageSourceRef获取。

CGImageRef抽象了图像的基本数据和元数据,创建的时候会通过CGImageSourceRef去读取图像的基础数据和元数据,但没有读取图像的其他数据,没有做图片解码的动作。

CGDataProviderRef没有得出有用信息。

CGImageDestinationRef抽象写入图像数据的通道,写入图像要通过它,在写入图片的时候还负责图片的编码。

Image解码

可以看到从CFDataRef直到创建出UIImage,都没有调用过对图像解码的函数,只读取了一些图像基础数据和元数据。

Image解码发生在什么时候?在ImageIO/CGImageSource.h文件中kCGImageSourceShouldCache的上面其实有明确注释。

Specifies whether image decoding and caching should happen at image creation time.
The value of this key must be a CFBooleanRef. The default value is kCFBooleanFalse (image decoding will happen at rendering time).

如果不手动设置Image只会等到在屏幕上渲染时再解码。经过测试,确实如此。这个kCGImageSourceShouldCacheImmediately还不如起名为kCGImageSourceShouldDecodeImmediately。

Image解码到底在哪里做的?

如果在画布上渲染图片,图片一定是会被解码的。下列代码再跑测试

size_t width = CGImageGetWidth(cgImage);
size_t height = CGImageGetHeight(cgImage);
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(cgImage) & kCGBitmapAlphaInfoMask;
BOOL hasAlpha = NO;
if (alphaInfo == kCGImageAlphaPremultipliedLast ||
    alphaInfo == kCGImageAlphaPremultipliedFirst ||
    alphaInfo == kCGImageAlphaLast ||
    alphaInfo == kCGImageAlphaFirst) {
    hasAlpha = YES;
    }
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;
bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, CGColorSpaceCreateDeviceRGB(), bitmapInfo);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage); 
CGImageRef newImage = CGBitmapContextCreateImage(context);

img-w600

所有调用的函数名中没有明显decompress或者decode字眼。而上面四个函数调用的频率是最高的。根据CGImageDestinationRef调用的png_compress_IDAT,猜测png_read_IDAT_data是做解码的函数。

以上是以png图片作为测试用例,下面看看jpeg图片的

img-w600

img-w600

img-w600

很明显AppleJPEG的decode方法是做解码的函数。jpeg与png调用了两个同样函数,而不同的图片调了不同的解码函数。在画布上画图片的时候,会调用ImageProviderCopyImageBlockSetCallback设置callback,然后调用copyImageBlock,再调用设置的callback,但是解码函数是由copyImageBlock的调用的还是由callback调用的无法验证。

那ImageProviderCopyImageBlockSetCallback与CGDataProviderCopyData是否有关系?经过测试,CGDataProviderCopyData内部也会调用ImageProviderCopyImageBlockSetCallback和copyImageBlock。而且CGDataProviderCopyData得到的CFDataRef是解码过的像素数组。

结论:Image解码发生在CGDataProviderCopyData函数内部调用ImageProviderCopyImageBlockSetCallback设置的callback或者copyImageBlock函数,根据不同的图片格式调用的不同的方法中。

Image的初始化方法

imageWithData从内部函数的调用来看,通过CGImageSourceRef访问图像数据,创建CGImageRef。

imageWithContentsOfFile内部调用如下

img-w600

文件通过mmap到内存然后通过CGImageSourceRef访问图像数据,创建CGImageRef。

imageNamed先从Bundle里找到资源路径,然后同样也是将文件mmap到内存,再通过CGImageSourceRef访问图像数据,创建CGImageRef。

Image的缓存

通过调用不同的UIImage初始化方法然后创建UIImageVIew展示到屏幕上,来看看不同方法是否有缓存的行为。

imageNamed在第二次展示相同image的时候没有调用imageIO的任何方法。

imageWithData和imageWithContentsOfFile在第二次在展示相同image的时候均调用了imageIO的解码方法。

而imageWithData和imageWithContentsOfFile初始化方法创建的UIImage只要不被释放,再次渲染不会调用imageIO解码方法。

结论为UIImage有两种缓存,一种是UIImage类的缓存,这种缓存保证imageNamed初始化的UIImage只会被解码一次。另一种是UIImage对象的缓存,这种缓存保证只要UIImage没有被释放,就不会再解码。

CGImageSourceCreateImageAtIndex方法的kCGImageSourceShouldCache选项指的是第二种缓存,而如果设置为false,我测试出来image再次渲染的时候仍没有进行解码,这有些奇怪。如果有同学详细知道怎么回事,还请赐教。

最后附上ImageIO的全家福
img-w600

Java ImageIO图片操作 原文地址:http://blog.youkuaiyun.com/tielan/article/details/43760301 代码块 将源图片中指定颜色变成透明,例如: /** * 将指定颜色变透明 只能保存 png jpg * * @param imageSrc * @param mask * @return */ 阅读详情

相关推荐

Java提取IPA中的png文件, 并进行解码还原png图片

直接解析ipa中的png图片是无法在windows中直接展示的,只能在Safari中显示;需要解码后才能正常在所有平台展示

iOS中的imageIO与image解码

ImageIO对外开放的对象有CGImageSourceRef、CGImageDestinationRef,不对外开放的对象有CGImageMetadataRef。CoreGraphics中经常与imageIO打交道的对象有CGImageRef和CGDataProvider,接下来看看这五个对象在创建一个UIImage中担任了哪些角色。   用TimeProfiler一步一步来看创建UIIma...

weixin_34184158的博客 526

ORB-SLAM3的Euroc数据集测试

(一)测试运行 不同模式测试过程(以MH_03为例) 1、pure mono 运行SLAM: cd ORB-SLAM3/Example #run slam ./Monocular/mono_euroc ../Vocabulary/ORBvoc.txt ./Monocular/EuRoC.yaml "$pathDatasetEuroc"/MH03 ./Monocular/EuRoC_TimeStamps/MH03.txt dataset-MH03_mono 利用ORB-SLAM3自带..

ljtx200888的博客 9145

CGImageSource对图像数据读取任务的抽象

http://www.tanhao.me/pieces/1019.html/ CGImageSource是对图像数据读取任务的抽象,通过它可以获得图像对象、缩略图、图像的属性(包括Exif信息)。 1.创建CGImageSourceRef 1 2 NSString *imagePath = [[NSBundle bundleForCla

david412306524的专栏 733

对称加密和非对称加密,数字签名和证书

在对称加密中,任何人都可以使用公钥进行加密。在数字签名中,任何人都可以使用公钥验证签名。数字签名,其实就是将非对称加密反过来使用。公钥私钥非对称加密发送者加密时使用接收者解密时使用数字签名验证者验证签名时使用签名者生成签名时使用谁持有密钥?只要有需要,任何人都可以持有个人持有既然是加密,那肯定是不希望别人知道我的消息,所以只有我才能解密。公钥负责加密,私钥负责解密。既然是签名,那肯定是不希望有人冒充我发消息,所以只有我才能签名。私钥负责签名,公钥负责验签。

m0_70432049的博客 1409

解读文献(五)------基于阻抗控制

文章目录背景主动柔顺控制阻抗控制基于力的阻抗控制基于位置的阻抗控制力位混合控制 背景 主动柔顺控制 阻抗控制 基于力的阻抗控制 基于位置的阻抗控制 力位混合控制 ...

accumulation 1万+

BufferedImage类、Image类、Graphics类

BufferedImage Image是一个抽象类,BufferedImage是其实现类,是一个带缓冲区图像类,主要作用是将一幅图片加载到内存中(BufferedImage生成的图片在内存里有一个图像缓冲区,利用这个缓冲区我们可以很方便地操作这个图片),提供获得绘图对象、图像缩放、选择图像平滑度等功能,通常用来做图片大小变换、图片变灰、设置透明不透明等。 public abstract Graphics getGraphics(); //获得在图像上绘图的Graphics对象 Java将一幅图片

TwcatL 1012

AXI backpressure反压机制代码

本文将xilinx的axi读写代码进行修改,实现吞吐量达到50%

m0_64636251的博客 1764

iOS图像解码

一、解码方式: 1、CGContextDrawImage方式(CoreGraphics)     它接受一个原始的位图参数 imageRef ,最终返回一个新的解压缩后的位图 newImage ,中间主要经过了以下三个步骤: 使用 CGBitmapContextCreate 函数创建一个位图上下文; 使用 CGContextDrawImage 函数将原始位图绘制到上下文中; 使用 CGB

bravegogo的专栏 3330

CANoe.Diva实战:基于CDD的UDS诊断自动化测试全流程解析

本文详细解析了使用CANoe.Diva进行基于CDD的UDS诊断自动化测试的全流程,包括环境搭建、CDD文件配置、测试范围设置、用例生成与验证、CANoe集成测试及报告分析。通过实战经验分享,帮助工程师快速掌握诊断自动化测试技巧,提升测试效率与质量。

weixin_29258297的博客 218

威纶通触摸屏与S7-1200以太网通信的具体方法和步骤(非常详细)

威纶通触摸屏与S7-1200以太网通信的具体方法和步骤(非常详细)

Robot_PLC_HMI_Automation 1万+

iOS由ImageIO.framework实现gif的系统解码

首先先简单介绍一下gif的几个算是术语吧: frame(帧):一个gif可以简单认为是多张image组成的动画,一帧就是其中一张图片image. frameCount(帧数): 就是一个gif有多少帧 loopCount(播放次数):有些gif播放到一定次数就停止了,如果为0就代表gif一直循环播放。 delayTime(延迟时间):每一帧播放的时间,也就是说这帧显示到delayTime就

shx_yi的专栏 3187

嵌入式工程师成长之路(1)——元件基础(完整版)

为什么你的电路总是“玄学”故障?答案藏在这些元件里! 0欧电阻竟能引发信号反射?5V转3.3V电平匹配失败导致MCU烧毁?电容降压设计让电源“滋滋”响?——这些坑,本文全填平! 优快云硬件领域头部博主十年踩坑经验汇总,覆盖电阻、电容、电感核心难点+高频实战问题,让你从“调试地狱”直通“一次成功”!

云轩阁 2万+

Image解码

Image解码 可以看到从CFDataRef直到创建出UIImage,都没有调用过对图像解码的函数,只读取了一些图像基础数据和元数据。 Image解码发生在什么时候?在ImageIO/CGImageSource.h文件中kCGImageSourceShouldCache的上面其实有明确注释。 Specifies whether image decoding and cachin...

diaoju3333的博客 308

9篇9章1节:认识 SHARE 数据库

SHARE数据库是欧洲最大的跨国老龄化追踪调查项目,覆盖28个欧洲国家和以色列的50岁及以上人群。自2004年启动以来,已完成14-16万受访者的50-60万次访谈,形成跨度20年的纵向数据。该数据库采用标准化的多阶段抽样方法,收集健康、经济和社会关系等领域的多维度信息,具有高度的跨国可比性。SHARE与美国HRS、英国ELSA等调查对接,构成全球老龄化研究网络。数据免费向科研人员开放,但需注册并承诺仅用于非商业性研究。该项目由欧盟委员会等多方资助,为老龄化研究和政策制定提供了重要实证依据。

MD Code 900

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

源码解读:AnimatedGIFImageSerialization 如何用 ImageIO 实现 GIF 解码(含帧时长计算原理)

AnimatedGIFImageSerialization 是一个为 iOS 提供完整 GIF 支持的知名开源库:它基于 ImageIO 框架实现 GIF 解码与编码,API 风格模仿 `NSJSONSerialization`,还可以通过方法交换(Swizzling)让 `[UIImage imageNamed:]` 直接加载动图。本文从源码层面拆解它的 GIF 解码全流程,并重点讲解帧时长(d

gitblog_00020的博客 453

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

AnimatedGIFImageSerialization 解码实战:一行代码让 UIImageView 播放动画 GIF

在 iOS 开发中,让 UIImageView 播放动画 GIF 是很多新手遇到的第一个"坑":系统默认的 `UIImage` 并不支持 GIF 动图解码,网上各种方案又难维护。**AnimatedGIFImageSerialization** 正是为解决这个问题而生的轻量级 GIF 解码库,能为 iOS 提供完整的动画 GIF 支持,只需一行代码就能让 UIImageView 播放动画 GIF。

gitblog_00374的博客 752

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

iOS的图片:解码(CPU)与内存(缓存)

图片的数据:资源数据(地址)、原始数据(Data)、显示数据(解码后的数据) 解压图片 - PNG或者JPEG压缩之后的图片文件会比同质量的位图小得多。但是在图片绘制到屏幕上之前,必须把它扩展成完整的未解压的尺寸(通常等同于图片宽 x 长 x 4个字节)。为了节省内存,iOS通常直到真正绘制的时候才去解码图片(14章“图片IO”会更详细讨论)。根据你加载图片的方式,第一次对图...

diaoju3333的博客 739

imageIO---完成渐进加载图片

转载自:http://www.cnblogs.com/smileEvday/p/IncrementallyLoadImage.html  前面有一篇《使用imageIO获取和修改图片的exif信息》介绍了使用imageIO获取图片的exif信息,在看到Image I/O Programming Guide的时候注意到了,文档中提到了可以使用CGImageSource实现渐进加

Nero的专栏 2354

iOS 图片解码

为甚要解码?你问我为啥要解码?事实上,不管是 JPEG 还是 PNG 图片,都是一种压缩的位图图形格式。只不过 PNG 图片是无损压缩,并且支持 alpha 通道,而 JPEG 图片则是有损压缩,可以指定 0-100% 的压缩比,因此,在将磁盘中的图片渲染到屏幕之前,必须先要得到图片的原始像素数据,才能执行后续的绘制操作,这就是为什么需要对图片解压缩的原因。详见 谈谈 iOS 中图片的解压缩 ...

weixin_33721344的博客 929

iOS中ImageIO框架详解与应用分析

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34236869的博客 685

解决iOS图像加载卡顿:SDWebImage强制解码技术详解

你是否遇到过这样的情况:滑动列表时图片加载导致界面卡顿,或者动画播放时帧率突然下降?这些问题往往与图像的延迟解码(Lazy Decoding)有关。SDWebImage作为iOS开发中最流行的图片加载库,提供了强制解码(Force Decode)功能来解决这一痛点。本文将深入解析强制解码的原理、实现方式以及最佳实践,帮助你彻底消除图像加载带来的性能瓶颈。 ## 什么是强制解码? 强制解码是一种...

gitblog_00950的博客 760

ImageIO

ImageIO 在阅读有关gif编解码相关的内容时,有见到使用ImageIO相关的内容 iOS中ImageIO框架详解与应用分析 Image I/O Programming Guide 参考Accessing Image Properties Without Loading the Image Into Memory提到其一些应用 比如说你想获取图片的一些属性,比如图片的尺寸和一些其他...

了凡 1050

YLGIFImage:iOS高效GIF解码器的终极指南

YLGIFImage是一款专为iOS平台设计的异步GIF图片解码器和图片查看器,支持GIF图片的播放与暂停功能,其最大亮点在于极低的内存占用。对于通常需要600MB内存才能完全解码的800x600分辨率GIF,使用YLGIFImage仅需约30MB内存,有效解决了iOS应用中GIF播放导致的内存溢出问题。 ## 为什么选择YLGIFImage? 在移动应用开发中,GIF图片的高效处理一直是开发

gitblog_00247的博客 1008
上一篇: swfit自定义LOG
下一篇: 介绍CGImageRef的基本概念及方法说明
Philm_iOS
博客等级 码龄8年 74粉丝 53原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值