UIImageView 不显示来自 UIImagePickerController 的 PNG 图像的透明度

UIImageView not showing transparency of PNG Images from UIImagePickerController

我当然希望我遗漏了一些东西,因为我不明白为什么它会这样工作。我有一个 PNG 图像,它具有完全透明的背景,因为我想将它覆盖在 UIImageView.

中的其他图像上

XCode 项目中包含的 PNG 图像都可以正常工作。问题是当我使用 UIImagePickerController 动态地 select 这些相同的 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)

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

是的,调用 UIImageJPEGRepresentation 会将生成的图像转换为不支持透明度的 JPEG。

顺便说一句,如果您出于其他原因(例如上传到服务器、发送电子邮件等)打算为图像获取 NSData,我建议不要同时使用 UIImageJPEGRepresentationUIImagePNGRepresentation。他们丢失元数据,可以使资产更大,如果使用小于 1 的质量因数等会导致图像质量下降,等等。

相反,我建议返回并从照片框架中获取原始资产。因此,在 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 版本,请参阅 previous revision of this answer。)

Swift @Rob

回答的第 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)

}

替代解决方案使用 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)
        }
    }
}