在Swift中将UIImage转换为NSData并再次转换回UIImage?

171

我正在尝试将一个UIImage保存为NSData,然后在Swift中读取NSData以获取新的UIImage。为了将UIImage转换为NSData,我正在使用以下代码:

let imageData: NSData = UIImagePNGRepresentation(myImage)

我如何将imageData (即NSData) 转换回一个新的 UIImage

10个回答

192

UIImage(data:imageData,scale:1.0) 假设图像的比例为1。

在Swift 4.2中,使用以下代码获取Data()。

image.pngData()

1
问题在于数据被转换为PNG格式,也就是格式改变了。如果您想要检索原始图像的文件大小,这将是一个问题。 - BadmintonCat

77

谢谢,这对我很有帮助。已转换为Swift 3并且能正常工作。

保存图片:

let data = UIImagePNGRepresentation(image)

加载图片:

let image = UIImage(data: data)

2
let imagePt = UIImage(data: caminhodaImagem) 这不够吗? - superarts.org

37

使用imageWithData:方法,它在Swift中被翻译为UIImage(data:)

let image : UIImage = UIImage(data: imageData)

21

现在在 Swift 4.2 中,你可以使用UIImage的新实例方法pngData()来获取图像数据

let profileImage = UIImage(named:"profile")!
let imageData = profileImage.pngData()

Swift 4.2在Beta版中吗?我没有看到这个函数可用。 - user5306470
似乎已被重命名。 - Archy Will He 何魏奇
1
'pngData()'已更名为'UIImagePNGRepresentation(_:)'。 - j2abro

19

细节

  • Xcode 10.2.1 (10E1001), Swift 5

解决方案1

guard let image = UIImage(named: "img") else { return }
let jpegData = image.jpegData(compressionQuality: 1.0)
let pngData = image.pngData()

Solution 2.1

extension UIImage {
    func toData (options: NSDictionary, type: CFString) -> Data? {
        guard let cgImage = cgImage else { return nil }
        return autoreleasepool { () -> Data? in
            let data = NSMutableData()
            guard let imageDestination = CGImageDestinationCreateWithData(data as CFMutableData, type, 1, nil) else { return nil }
            CGImageDestinationAddImage(imageDestination, cgImage, options)
            CGImageDestinationFinalize(imageDestination)
            return data as Data
        }
    }
}

使用解决方案2.1的方法

// about properties: https://developer.apple.com/documentation/imageio/1464962-cgimagedestinationaddimage
let options: NSDictionary =     [
    kCGImagePropertyOrientation: 6,
    kCGImagePropertyHasAlpha: true,
    kCGImageDestinationLossyCompressionQuality: 0.5
]

// https://developer.apple.com/documentation/mobilecoreservices/uttype/uti_image_content_types
guard let data = image.toData(options: options, type: kUTTypeJPEG) else { return }
let size = CGFloat(data.count)/1000.0/1024.0
print("\(size) mb")

Solution 2.2

extension UIImage {

    func toJpegData (compressionQuality: CGFloat, hasAlpha: Bool = true, orientation: Int = 6) -> Data? {
        guard cgImage != nil else { return nil }
        let options: NSDictionary =     [
                                            kCGImagePropertyOrientation: orientation,
                                            kCGImagePropertyHasAlpha: hasAlpha,
                                            kCGImageDestinationLossyCompressionQuality: compressionQuality
                                        ]
        return toData(options: options, type: .jpeg)
    }

    func toData (options: NSDictionary, type: ImageType) -> Data? {
        guard cgImage != nil else { return nil }
        return toData(options: options, type: type.value)
    }
    // about properties: https://developer.apple.com/documentation/imageio/1464962-cgimagedestinationaddimage
    func toData (options: NSDictionary, type: CFString) -> Data? {
        guard let cgImage = cgImage else { return nil }
        return autoreleasepool { () -> Data? in
            let data = NSMutableData()
            guard let imageDestination = CGImageDestinationCreateWithData(data as CFMutableData, type, 1, nil) else { return nil }
            CGImageDestinationAddImage(imageDestination, cgImage, options)
            CGImageDestinationFinalize(imageDestination)
            return data as Data
        }
    }

    // https://developer.apple.com/documentation/mobilecoreservices/uttype/uti_image_content_types
    enum ImageType {
        case image // abstract image data
        case jpeg                       // JPEG image
        case jpeg2000                   // JPEG-2000 image
        case tiff                       // TIFF image
        case pict                       // Quickdraw PICT format
        case gif                        // GIF image
        case png                        // PNG image
        case quickTimeImage             // QuickTime image format (OSType 'qtif')
        case appleICNS                  // Apple icon data
        case bmp                        // Windows bitmap
        case ico                        // Windows icon data
        case rawImage                   // base type for raw image data (.raw)
        case scalableVectorGraphics     // SVG image
        case livePhoto                  // Live Photo

        var value: CFString {
            switch self {
            case .image: return kUTTypeImage
            case .jpeg: return kUTTypeJPEG
            case .jpeg2000: return kUTTypeJPEG2000
            case .tiff: return kUTTypeTIFF
            case .pict: return kUTTypePICT
            case .gif: return kUTTypeGIF
            case .png: return kUTTypePNG
            case .quickTimeImage: return kUTTypeQuickTimeImage
            case .appleICNS: return kUTTypeAppleICNS
            case .bmp: return kUTTypeBMP
            case .ico: return kUTTypeICO
            case .rawImage: return kUTTypeRawImage
            case .scalableVectorGraphics: return kUTTypeScalableVectorGraphics
            case .livePhoto: return kUTTypeLivePhoto
            }
        }
    }
}

使用解决方案2.2

let compressionQuality: CGFloat = 0.4
guard let data = image.toJpegData(compressionQuality: compressionQuality) else { return }
printSize(of: data)

let options: NSDictionary =     [
                                    kCGImagePropertyHasAlpha: true,
                                    kCGImageDestinationLossyCompressionQuality: compressionQuality
                                ]
guard let data2 = image.toData(options: options, type: .png) else { return }
printSize(of: data2)

问题

在处理图像时需要耗费大量的CPU和内存资源。因此,在这种情况下,最好遵循以下几条规则:

- 不要在主队列上运行jpegData(compressionQuality:)

- 同时只运行一个jpegData(compressionQuality:)

错误的示例:

for i in 0...50 {
    DispatchQueue.global(qos: .utility).async {
        let quality = 0.02 * CGFloat(i)
        //let data = image.toJpegData(compressionQuality: quality)
        let data = image.jpegData(compressionQuality: quality)
        let size = CGFloat(data!.count)/1000.0/1024.0
        print("\(i), quality: \(quality), \(size.rounded()) mb")
    }
}

正确:

let serialQueue = DispatchQueue(label: "queue", qos: .utility, attributes: [], autoreleaseFrequency: .workItem, target: nil)

for i in 0...50 {
    serialQueue.async {
        let quality = 0.02 * CGFloat(i)
        //let data = image.toJpegData(compressionQuality: quality)
        let data = image.jpegData(compressionQuality: quality)
        let size = CGFloat(data!.count)/1000.0/1024.0
        print("\(i), quality: \(quality), \(size.rounded()) mb")
    }
}

链接


Vasily,非常感谢您的帮助。我已经能够使用您的代码将UIImages转换为bmps。我还需要从bmp中删除alpha通道。我尝试设置选项以删除alpha通道,但似乎无法去除该层。我是这样调用的:let options: NSDictionary = [kCGImagePropertyHasAlpha: false] let convertToBmp = image.toData(options: options, type: .bmp)。 - Gallaugher
@Gallaugher 你确定它不起作用吗?尝试创建没有 alpha 的 png 图像并检查它。也许无法在 bmp 中使用 kCGImagePropertyHasAlpha 属性。 - Vasily Bodnarchuk
@vasily-bodnarchuk 谢谢你的帮助(和早先的代码)。我已经去掉了alpha通道 - 我无法通过png做到这一点,但是我使用了resizedImage.toJpegData,并将alpha设为false,然后将此数据转换回UIImage,然后进行类型为.bmp的toData。选项没有影响,但是这在Photoshop中删除了alpha层并创建了一个较小的文件。仍然无法生成我需要的用于PyPortal的精确16位光栅图形bmp格式。由于某种原因,转换后的数据未显示,但是当我通过在线转换工具进行转换时却可以。谢谢。 - Gallaugher
@vasily-bodnarchuk,使用您提供的有用代码保存的bmp文件,在Photoshop中打开时会出现"翻转行顺序"的bmp选项。如果我在“另存为...”后出现的“BMP选项”屏幕上取消勾选此选项并重新保存,然后加载到PyPortal上,更新的bmp就会显示出来。我没有看到任何类似于“翻转行顺序”的苹果文档,我不确定为什么这会成为默认保存方式,也不知道如何在Swift中进行“撤消”。顺便说一下:我已经在https://stackoverflow.com/questions/57241391/ios-saves-bmp-with-flip-row-order-format-can-this-option-be-removed-in-swift发布了我的问题和相关文件。谢谢! - Gallaugher

8

图片转数据:-

    if let img = UIImage(named: "xxx.png") {
        let pngdata = img.pngData()
    }

   if let img = UIImage(named: "xxx.jpeg") {
        let jpegdata = img.jpegData(compressionQuality: 1)
    }

数据到图片:

guard let image = UIImage(data: pngData) else { return }

8

保存数据:

如果您想在MainStoryBoard的imageView上保存“image”数据,可以在StoryBoard中使用以下代码来实现。

let image = UIImagePNGRepresentation(imageView.image!) as NSData?

将“图像”加载到imageView中: 仔细看感叹号“!”和问号“?”是否与这个非常相似。

imageView.image = UIImage(data: image as! Data)

在此过程中,“NSData”类型会自动转换为“Data”类型。

当我尝试时,这会返回一个nil值。有什么建议吗? - Michael Szabo
为了澄清,我已将一个Excel文件保存为PDF格式。我知道我的函数是有效的,因为我能够将该PDF附加到电子邮件中,并在应用程序之外的手机“PDF查看器”中查看它。该PDF以NSData形式存储。如果我打印(my data.thePDF),我会得到一个值,但在使用上述脚本进行转换后,它返回nil。我还尝试过将NSData转换为data,这将打印一个值,但是当我将Data转换为UIImage时,它返回nil。 :( - Michael Szabo

6

为了安全地执行代码,请使用带有 Dataif-let 块来防止应用程序崩溃,因为函数 UIImagePNGRepresentation 返回一个可选值。

if let img = UIImage(named: "TestImage.png") {
    if let data:Data = UIImagePNGRepresentation(img) {
       // Handle operations with data here...         
    }
}

注意: Data 是Swift 3+的类。在Swift 3+中请使用Data代替NSData。

通用图像操作(例如png和jpg):

if let img = UIImage(named: "TestImage.png") {  //UIImage(named: "TestImage.jpg")
        if let data:Data = UIImagePNGRepresentation(img) {
               handleOperationWithData(data: data)     
        } else if let data:Data = UIImageJPEGRepresentation(img, 1.0) {
               handleOperationWithData(data: data)     
        }
}

*******
func handleOperationWithData(data: Data) {
     // Handle operations with data here...
     if let image = UIImage(data: data) {
        // Use image...
     }
}

通过使用扩展功能:

extension UIImage {

    var pngRepresentationData: Data? {
        return UIImagePNGRepresentation(self)
    }

    var jpegRepresentationData: Data? {
        return UIImageJPEGRepresentation(self, 1.0)
    }
}

*******
if let img = UIImage(named: "TestImage.png") {  //UIImage(named: "TestImage.jpg")
      if let data = img.pngRepresentationData {
              handleOperationWithData(data: data)     
      } else if let data = img.jpegRepresentationData {
              handleOperationWithData(data: data)     
     }
}

*******
func handleOperationWithData(data: Data) {
     // Handle operations with data here...
     if let image = UIImage(data: data) {
        // Use image...
     }
}

2

Swift 5

让您创建的图像作为UIImage成为图像

image.pngData() as NSData? 

请花点时间阅读[编辑帮助](//stackoverflow.com/editing-help)中的内容。在[帮助]中,Stack Overflow的格式与其他网站不同。 - Dharman

0

使用此方法可获得简单的解决方案

static var UserProfilePhoto = UIImage()
guard let image = UIImage(named: "Photo") else { return }
guard let pngdata = image.pngData() else { return }
UserProfilePhoto = UIImage(data: pngdata)!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接