【问题标题】:Saving CGImageRef to a png file?将 CGImageRef 保存为 png 文件?
【发布时间】:2010-11-22 04:50:47
【问题描述】:

在我的 Cocoa 应用程序中,我从磁盘加载一个 .jpg 文件并对其进行操作。现在需要将其作为 .png 文件写入磁盘。你怎么能这样做?

感谢您的帮助!

【问题讨论】:

    标签: swift objective-c cocoa core-graphics cgimage


    【解决方案1】:

    Swift 5+ 采用的版本

    import Foundation
    import CoreGraphics
    import CoreImage
    import ImageIO
    import MobileCoreServices
    
    extension CIImage {
      
      public func convertToCGImage() -> CGImage? {
        let context = CIContext(options: nil)
        if let cgImage = context.createCGImage(self, from: self.extent) {
          return cgImage
        }
        return nil
      }
      
      public func data() -> Data? {
        convertToCGImage()?.pngData()
      }
    }
    
    extension CGImage {
      
      public func pngData() -> Data? {
        let cfdata: CFMutableData = CFDataCreateMutable(nil, 0)
        if let destination = CGImageDestinationCreateWithData(cfdata, kUTTypePNG as CFString, 1, nil) {
          CGImageDestinationAddImage(destination, self, nil)
          if CGImageDestinationFinalize(destination) {
            return cfdata as Data
          }
        }
        
        return nil
      }
    }
    

    【讨论】:

      【解决方案2】:

      这是一个适用于 macOS 的 Swift 3 和 4 示例:

      @discardableResult func writeCGImage(_ image: CGImage, to destinationURL: URL) -> Bool {
          guard let destination = CGImageDestinationCreateWithURL(destinationURL as CFURL, kUTTypePNG, 1, nil) else { return false }
          CGImageDestinationAddImage(destination, image, nil)
          return CGImageDestinationFinalize(destination)
      }
      

      【讨论】:

        【解决方案3】:

        使用CGImageDestination 并传递kUTTypePNG 是正确的方法。这是一个快速的 sn-p:

        @import MobileCoreServices; // or `@import CoreServices;` on Mac
        @import ImageIO;
        
        BOOL CGImageWriteToFile(CGImageRef image, NSString *path) {
            CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:path];
            CGImageDestinationRef destination = CGImageDestinationCreateWithURL(url, kUTTypePNG, 1, NULL);
            if (!destination) {
                NSLog(@"Failed to create CGImageDestination for %@", path);
                return NO;
            }
        
            CGImageDestinationAddImage(destination, image, nil);
        
            if (!CGImageDestinationFinalize(destination)) {
                NSLog(@"Failed to write image to %@", path);
                CFRelease(destination);
                return NO;
            }
        
            CFRelease(destination);
            return YES;
        }
        

        您需要将ImageIOCoreServices(或iOS 上的MobileCoreServices)添加到您的项目并包含标题。


        如果您使用的是 iOS 并且不需要也适用于 Mac 的解决方案,则可以使用更简单的方法:

        // `image` is a CGImageRef
        // `path` is a NSString with the path to where you want to save it
        [UIImagePNGRepresentation([UIImage imageWithCGImage:image]) writeToFile:path atomically:YES];
        

        在我的测试中,ImageIO 方法比我的 iPhone 5s 上的 UIImage 方法快了大约 10%。在模拟器中,UIImage 方法更快。如果您真的关心性能,可能值得针对您在设备上的特定情况进行测试。

        【讨论】:

          【解决方案4】:

          创建一个CGImageDestination,传递kUTTypePNG 作为要创建的文件类型。添加图片,然后确定目的地。

          【讨论】:

          • ivanceras: developer.apple.com/mac/library/documentation/GraphicsImaging/… 如果您想要一个更具体的答案,您应该提出一个更具体的问题(并且您应该作为一个单独的问题这样做)。
          • 只是一个注释。我们必须添加ImageIO.framework 来引用函数,即使文档说它位于ApplicationServices/ImageIO
          • @Eonil:这取决于您要构建的平台。 Cocoa Touch 没有伞式框架,因此在为 iOS 构建时,您确实需要直接链接到 ImageIO。在为 Mac OS X 构建时,您链接到 ApplicationServices 并获取其中的所有内容。
          • 查看我的答案以获取执行此操作的示例。