iOS. UIImage 转 NSData 方案

发布时间 2023-07-28 15:51:08作者: ACM_Someone like you

使用场景:需要把image 转为二进制data  进行存储 压缩  上传 

常用方案1

// 加载图片
UIImage *image = [UIImage imageNamed:@"test1.jpg"];
// 将图片转换为NSData对象
NSData *imageData = UIImageJPEGRepresentation(image, 1); 

  参数解释:

  1. image:要转换的UIImage对象。

    • 这是需要转换为JPEG数据的原始图像对象。
  2. compressionQuality:表示JPEG压缩质量的参数,范围为0.0到1.0。

    • compressionQuality值为0.0表示最高压缩,图像质量最低。
    • compressionQuality值为1.0表示无压缩,图像质量最高。 (⚠️ 1.0 不代表当前获取的data 和 原始data 一样大,甚至远远大于原始data
    • compressionQuality值在0.0和1.0之间表示不同程度的压缩和图像质量权衡。

关键点:

  1. 当压缩参数越接近1 图像质量越高,那么转换后的JPEG数据将保留较高的图像质量,但会占用更多的空间。
  2. 图像内容复杂度:如果原始图像包含复杂的纹理、细节和颜色变化等特征,JPEG压缩算法会产生较大的数据文件。这是因为JPEG是一种有损压缩格式,会在压缩过程中舍弃部分图像细节,但仍然需要更多的数据来表示复杂的图像内容。
  3. 原始图像已经是JPEG格式:如果原始图像已经是JPEG格式,再次进行JPEG转换可能会导致数据的进一步损失,并且文件大小可能会变大。这是因为每次重新压缩JPEG图像时,会引入额外的压缩失真和冗余数据。
  4. 原始图像的压缩方式不同:UIImageJPEGRepresentation使用的是系统的JPEG压缩算法,而原始图像可能是使用其他方式进行压缩或存储的(如其他图像编辑软件或网络服务)。不同的压缩方式可能会导致文件大小的差异。

总而言之,JPEG图像的文件大小取决于多个因素,包括压缩质量、图像内容复杂度和压缩算法等。因此,如果发现使用UIImageJPEGRepresentation转换后的JPEG数据比原始图像大很多,可以适当调整压缩质量参数,或尝试其他的图像压缩方法来优化文件大小。

常用方案2

// 加载图片
UIImage *image = [UIImage imageNamed:@"test1.png"];

// 将图片转换为NSData对象
NSData *imageData = UIImagePNGRepresentation(image);

 关键点:

  1. 透明性PNG格式支持图像的透明性,而JPEG格式不支持。因此,如果原始图像包含透明通道或需要保留透明性,则应选择使用UIImagePNGRepresentation来保持图像的完整性。
  2. 压缩质量与JPEG不同,PNG是一种无损压缩格式,不会对图像数据进行压缩或丢失。因此,UIImagePNGRepresentation函数不接受关于压缩质量的参数,转换后的PNG数据的大小与原始图像保持一致,可能会比JPEG数据更大。
  3. 色彩空间:将UIImage对象转换为PNG数据时,保留了原始图像的色彩空间和位深度信息。即使原始图像采用了较高的位深度(例如16位),转换后的PNG数据也能够保持相同的位深度,以保留更多的颜色信息。这在需要更精确色彩表示的应用场景中是重要的。
  4. 内存消耗:由于PNG数据是无损压缩的,转换大尺寸或高分辨率的UIImage对象时可能会占用相对较大的内存空间。因此,在处理大型图像时,要确保内存使用情况合理控制,避免出现内存警告或崩溃。
  5. 其他格式转换考虑:除了PNG格式,如果需要在应用程序中处理图像的其他用途,如网络传输、显示在UIImageView中,或者在支持的图像编辑库中进行处理,可能需要将UIImage对象转换为其他合适的格式,如JPEG或HEIC等。

总之,通过理解UIImagePNGRepresentation的一些特性和限制,可以根据具体需求合理选择使用和处理PNG格式的图像数据。

方案3:CGImageDestinationCreateWithData

+ (NSData *)kfz_rawData:(UIImage *)image
{
    NSDictionary *options = @{(__bridge NSString *)kCGImageSourceShouldCache : @NO,
                              (__bridge NSString *)kCGImageSourceShouldCacheImmediately : @NO
                              };//目的是不期望图片有缓存和解码行为
    NSMutableData *data = [NSMutableData data];
    CGImageDestinationRef destRef = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)data, kUTTypeJPEG, 1, (__bridge CFDictionaryRef)options);
    CGImageDestinationAddImage(destRef, image.CGImage, (__bridge CFDictionaryRef)options);
    CGImageDestinationFinalize(destRef);
    CFRelease(destRef);
    return data;
}

 参数解释:

CGImageDestinationCreateWithData函数是Core Graphics框架中用于创建一个基于数据的目标对象的函数。他接受三个参数:

  1. data: 一个可变的CFMutableData对象,用于存储输出图像数据。该参数是通过__bridge方式将NSMutableData对象转换为CFMutableDataRef对象。

  2. uti: 表示输出图像类型的Uniform Type Identifier (UTI)。在这个方法的示例中,使用kUTTypeJPEG表示输出图像的类型为JPEG格式。其他常见的UTI值包括kUTTypePNG (PNG格式)、kUTTypeGIF (GIF格式)、kUTTypeTIFF (TIFF格式)等。

  3. count: 表示期望最终图像输出包含的图像数量。在这个方法的示例中,指定为1,表示输出中只包含一个图像。

最终,该函数会返回一个CGImageDestinationRef对象,该对象可以用于将图像数据添加到目标中,并完成最终的图像输出。

关键特点:

  1. 目标类型灵活性:CGImageDestinationCreateWithData允许你选择将图像数据写入的目标类型。你可以使用不同的图像容器类型,如JPEG、PNG、GIF等,根据需要选择适合的目标。

  2. 减少内存占用:使用CGImageDestinationCreateWithData,你可以逐步将图像数据写入目标,而不需要一次性将整个图像数据加载到内存中。这对于处理大型图像或内存受限的环境非常有用

  3. 动画支持:CGImageDestinationCreateWithData还支持创建一个包含多个帧的图像目标,从而创建一个具有动画效果的图像文件。你可以按顺序添加多个图像帧到目标中,并设置每个帧的压缩参数和属性。

  4. 自定义选项:你可以通过提供自定义的属性键值对来自定义图像写入过程。可以控制图像的压缩质量、元数据、缩放、字节对齐等参数和属性。

  5. 错误处理:如果在图像写入过程中出现错误,CGImageDestinationCreateWithData可以提供错误处理功能。你可以检查状态来获取有关错误的信息或状态码,并根据需要进行适当的错误处理。

综上所述,CGImageDestinationCreateWithData提供了一种灵活且可定制的方式,用于将图像数据写入指定目标。它的特点包括目标类型的选择、内存占用的减少、动画支持、自定义选项和错误处理。这使得它成为处理图像写入操作时的有效工具。

和方案2的比较:

CGImageDestinationCreateWithDataUIImageJPEGRepresentation这两种方法都可以将UIImage对象转换为JPEG格式的NSData数据,但它们有一些不同之处。

  1. 灵活性和控制性
    • CGImageDestinationCreateWithData方法允许你指定更多的选项和参数来控制输出图像的质量、缓存行为以及其他属性。你可以使用选项字典来自定义编码过程,并根据需求进行优化。
    • UIImageJPEGRepresentation方法相对简单,只需传入一个UIImage对象和一个质量参数(0.0到1.0之间的值)即可。它提供了一个简便的方式来进行图像转换,但没有提供对更多选项的直接访问。
  1. 性能和效率
    • CGImageDestinationCreateWithData方法在处理大尺寸图像时可能会更加高效,因为它可以逐步写入数据而不需要完全加载整个图像到内存中。这对于处理内存受限的情况或处理大型图像时可能是一个优势。
    • UIImageJPEGRepresentation方法会将整个UIImage对象加载到内存中,并一次性转换为NSData数据。对于小型图像和常规用途,这可能没有明显影响,但处理大图像时可能会占用更多的内存。

因此,选择哪种方法取决于你的具体需求。如果你需要更多的控制权和灵活性,以及能够处理大型图像,那么CGImageDestinationCreateWithData可能更适合。如果你需要一个简单且易于使用的方法来转换图像,并且对性能和内存使用没有过多要求,那么UIImageJPEGRepresentation可以是一个很好的选择。

参考链接:

1、https://www.jianshu.com/p/dac08fa1704a (UIImage 转 NSData调研)

2、https://www.jianshu.com/p/ea475f608526 (iOS UIImage图片文件大小)