UIImagePickerController选择的PNG图片UIImageView不显示透明度

6
我希望我缺少了某些东西,因为我不明白为什么它会以这种方式工作。我有一张PNG图片,它具有完全透明的背景,因为我想将其叠加在UIImageView内的其他图像上。 包含在XCode项目中的PNG图像都能正常工作。问题在于,当我使用UIImagePickerController在运行时选择相同的PNG图像并将其分配给UIImageView时,由于某种非常奇怪的原因,它不将其视为带透明度的PNG图像,而是添加一个白色背景。 有人之前见过这种情况,我该如何解决? *更新#1:我决定尝试一些似乎证实了我的理论的东西。我决定将我保存到设备上的原始PNG图像通过电子邮件发送给自己,结果图片以JPG格式发送给我。看起来,当你将图像保存到iPhone的照片中时,它会将其转换为JPG格式,这对我来说相当震惊。希望有人知道如何解决这个问题。原始图片testImage1.pngtestImage2.png保存到照片中,然后通过电子邮件发回给我,返回为IMG_XXXX.jpgIMG_XXXX.jpg *更新#2:我继续尝试并发现了一些事情,在这个过程中能够回答自己的问题。(1) 我在更新#1中的理论部分正确,但转换不是在保存照片时发生的,似乎是即时进行的。内部照片会存储原始图像扩展名(2) 当我意识到在我的UIImagePickerControllerDelegate中使用时,我能够验证这一点
let imageData = UIImageJPEGRepresentation(image, 1.0)

改为这样

let imageData = UIImagePNGRepresentation(image)

当我使用第二行代码时,它会识别图像的原始透明度属性。

只是为了确认一下:您是否将 UIImageView 的 backgroundColor 设置为 clearColor 了? - palme
是的,我做了。似乎UIImagePickerController忽略透明度或将所选图像转换为JPG格式。我在两种情况下都使用相同的UIImageView,当我通过UIImagePickerController选择相同的图像时,它会添加白色背景,而当我选择作为XCode项目一部分的图像时,它可以正常工作。 - Lavvo
我刚刚做了一些似乎证实了我的理论的事情。我决定将我保存到设备上的原始PNG图像发送到我的电子邮件中,结果这些图像以JPG格式发送给了我。在我看来,当你将一张图片保存到iPhone上的照片中时,它会将其转换为JPG格式。 - Lavvo
3个回答

9
是的,调用 UIImageJPEGRepresentation 方法会将结果图像转换为不支持透明度的 JPEG 格式。
顺便提一句,如果您的目的是获取图像的 NSData 并用于其他用途(例如上传到服务器、通过电子邮件发送等),我建议不要使用 UIImageJPEGRepresentationUIImagePNGRepresentation。它们会丢失元数据,使得资源变得更大,如果设置质量因数小于1,则可能会产生某些图像退化等问题。
相反,我建议返回并从 Photos 框架中获取原始资源。在 Swift 3 中,代码如下:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    if let url = info[UIImagePickerControllerReferenceURL] as? URL {
        let result = PHAsset.fetchAssets(withALAssetURLs: [url], options: nil)
        if let asset = result.firstObject {
            let manager = PHImageManager.default()
            manager.requestImageData(for: asset, options: nil) { imageData, dataUTI, orientation, info in
                if let fileURL = info!["PHImageFileURLKey"] as? URL {
                    let filename = fileURL.lastPathComponent
                    // use filename here
                }

                // use imageData here
            }
        }
    }

    picker.dismiss(animated: true)
}

如果你还需要支持iOS 7,你需要使用等效的ALAssetsLibrary API,但是思路是相同的:获取原始资产而不是通过UIImage再进行回传。
(对于Swift 2版本,请参见这个答案的先前版本。)

谢谢!我终于能够重新访问这个代码并使其工作了。这正是我所需要的,以获取原始照片资产。 - Lavvo
如果使用这种方法,是否有任何方法可以在上传到服务器之前调整图像大小或进一步减小大小?谢谢。 - alionthego
此方法的目的是获取原始资产而不损失质量,并且不会因为使用 UIImagePNGRepresentationUIImageJPEGRepresentation 以 1.0 的质量导致文件变大。如果你需要更小的尺寸,可以获取默认表示的 UIImage,然后应用调整大小函数(例如:http://stackoverflow.com/a/28513086/1271826),然后使用 UIImagePNG/JPEGRepresentation。如果你要调整大小,请按2的幂进行调整大小,这将提供明显更小但不会模糊的图像。 - Rob

0
一个替代方案是使用PHAssetResourceManager而不是PHImageManager。使用Xcode 10,Swift 4.2。
func imageFromResourceData(phAsset:PHAsset) {

    let assetResources = PHAssetResource.assetResources(for: phAsset)

    for resource in assetResources {

        if resource.type == PHAssetResourceType.photo {

            var imageData = Data()

            let options = PHAssetResourceRequestOptions()
            options.isNetworkAccessAllowed = true

            let _ = PHAssetResourceManager.default().requestData(for: resource, options: options, dataReceivedHandler: { (data:Data) in
                imageData.append(data)
            }, completionHandler: { (error:Error?) in
                if error == nil, let picked = UIImage(data: imageData) {
                    self.handlePickedImage(picked: picked)
                }
            })
        }

    }
}

使用方法如下:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

    dismiss(animated: true)

    let mediaType = info[UIImagePickerController.InfoKey.mediaType] as! NSString

    if mediaType == kUTTypeImage || mediaType == kUTTypeLivePhoto {

        if #available(iOS 11.0, *) {

            if let phAsset = info[UIImagePickerController.InfoKey.phAsset] as? PHAsset {
                self.imageFromResourceData(phAsset: phAsset)
            }
            else {
                if let picked = (info[UIImagePickerController.InfoKey.originalImage] as? UIImage) {
                    self.handlePickedImage(picked: picked)
                }
            }

        }
        else if let picked = (info[UIImagePickerController.InfoKey.originalImage] as? UIImage) {
            self.handlePickedImage(picked: picked)
        }
    }
}

0

这是@Rob提供的Swift 3版本答案

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    if let URL = info[UIImagePickerControllerReferenceURL] as? NSURL {
        let result = PHAsset.fetchAssets(withALAssetURLs: [URL as URL], options: nil)
        if let asset:PHAsset = result.firstObject! as PHAsset {
            let manager = PHImageManager.default()
            manager.requestImageData(for: asset, options: nil) { imageData, dataUTI, orientation, info in
                let fileURL = info!["PHImageFileURLKey"] as? NSURL
                let filename = fileURL?.lastPathComponent;

                // use imageData here
            }
        }
    }

    picker.dismiss(animated: true, completion: nil)

}

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