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.png
和 testImage2.png
保存到照片,然后通过电子邮件发回给我,返回为 IMG_XXXX.jpg
和 IMG_XXXX.jpg
* 更新 #2: 我一直在玩这个,发现了一些东西,并且在这个过程中能够回答我自己的问题。 (1) 我在更新 #1 中的理论是部分正确的,但在保存照片时转换不会发生,似乎它是在运行中。内部照片存储原始图像扩展名 (2) 当我在我的 UIImagePickerControllerDelegate
中意识到我正在使用
时,我能够验证这一点
let imageData = UIImageJPEGRepresentation(image, 1.0)
而不是这个
let imageData = UIImagePNGRepresentation(image)
当我使用第二行代码时,它正在识别图像的原始透明度属性。
是的,调用 UIImageJPEGRepresentation
会将生成的图像转换为不支持透明度的 JPEG。
顺便说一句,如果您出于其他原因(例如上传到服务器、发送电子邮件等)打算为图像获取 NSData
,我建议不要同时使用 UIImageJPEGRepresentation
和 UIImagePNGRepresentation
。他们丢失元数据,可以使资产更大,如果使用小于 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)
}
}
}
我当然希望我遗漏了一些东西,因为我不明白为什么它会这样工作。我有一个 PNG 图像,它具有完全透明的背景,因为我想将它覆盖在 UIImageView
.
XCode 项目中包含的 PNG 图像都可以正常工作。问题是当我使用 UIImagePickerController
动态地 select 这些相同的 PNG 图像,然后将其分配给 UIImageView
时,出于某些非常奇怪的原因,它没有将其视为 PNG 图像具有透明度,而是添加白色背景。
有人以前见过这个吗?我该如何解决这个问题?
* 更新 #1: 我决定尝试一些似乎可以证实我的理论的东西。我决定通过电子邮件将我保存到设备中的原始 PNG 图片发送给自己,你瞧,这些图片以 JPG 格式发送给我。在我看来,当您将图像保存到 iPhone 上的照片时,它会将其转换为 JPG,这让我感到相当震惊。希望有人有办法解决这个问题。原始图像 testImage1.png
和 testImage2.png
保存到照片,然后通过电子邮件发回给我,返回为 IMG_XXXX.jpg
和 IMG_XXXX.jpg
* 更新 #2: 我一直在玩这个,发现了一些东西,并且在这个过程中能够回答我自己的问题。 (1) 我在更新 #1 中的理论是部分正确的,但在保存照片时转换不会发生,似乎它是在运行中。内部照片存储原始图像扩展名 (2) 当我在我的 UIImagePickerControllerDelegate
中意识到我正在使用
let imageData = UIImageJPEGRepresentation(image, 1.0)
而不是这个
let imageData = UIImagePNGRepresentation(image)
当我使用第二行代码时,它正在识别图像的原始透明度属性。
是的,调用 UIImageJPEGRepresentation
会将生成的图像转换为不支持透明度的 JPEG。
顺便说一句,如果您出于其他原因(例如上传到服务器、发送电子邮件等)打算为图像获取 NSData
,我建议不要同时使用 UIImageJPEGRepresentation
和 UIImagePNGRepresentation
。他们丢失元数据,可以使资产更大,如果使用小于 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)
}
}
}