问题描述
从“照片”应用程序获取的透明PNG文件遇到一个非常奇怪的问题。
问题是我正在编写一个应用程序,允许用户启动UIImagePickerController
的实例,他们在其中选择图片,然后将该图片通过其{添加到UIImageView
{3}}属性。
很简单,是吗?问题是库中的图像是透明的PNG。
无论出于何种原因,每当我尝试渲染图像时,背景总是白色。
据我所知,图像以透明PNG的形式存储在库中。当我将其拖出并使用图像编辑器进行检查时,就可以了。正是我所期望的。
但是当我以编程方式提取它时,它具有白色背景。我似乎无法使其透明。
func imagePickerController(_ inPicker: UIImagePickerController,didFinishPickingMediawithInfo inInfo: [UIImagePickerController.InfoKey: Any]) {
let info = Dictionary(uniqueKeysWithValues: inInfo.map { key,value in (key.rawValue,value) })
guard let image = (info[UIImagePickerController.InfoKey.editedImage.rawValue] as? UIImage ?? info[UIImagePickerController.InfoKey.originalImage.rawValue] as? UIImage)?.resizeThisImage(toNewWidth: Self.maximumImageWidthAndHeightInPixels) else { return }
organization?.icon = image
inPicker.dismiss(animated: true) { dispatchQueue.main.async { [weak self] in
self?.imageButton?.image = image
self?.imageButton?.alpha = 1.0
self?.imageButton?.tintColor = self?.view.tintColor
self?.updateUI()
}
}
}
它实际上不是UIButton
。这是UIImageView
,带有附加的点击识别器。
resizeThisImage()
方法在我为UIImage
写的扩展中。它工作正常。我一直在使用它:
func resizeThisImage(toNewWidth inNewWidth: CGFloat? = nil,toNewHeight inNewHeight: CGFloat? = nil) -> UIImage? {
guard nil == inNewWidth,nil == inNewHeight else {
var scaleX: CGFloat = (inNewWidth ?? size.width) / size.width
var scaleY: CGFloat = (inNewHeight ?? size.height) / size.height
scaleX = nil == inNewWidth ? scaleY : scaleX
scaleY = nil == inNewHeight ? scaleX : scaleY
let destinationSize = CGSize(width: size.width * scaleX,height: size.height * scaleY)
let destinationRect = CGRect(origin: .zero,size: destinationSize)
UIGraphicsBeginImageContextWithOptions(destinationSize,false,0)
defer { UIGraphicsEndImageContext() } // This makes sure that we get rid of the offscreen context.
draw(in: destinationRect,blendMode: .normal,alpha: 1)
return UIGraphicsGetimageFromCurrentimageContext()
}
return nil
}
无论如何,无论我是否使用resizeThisImage()
方法,都会发生。这不是问题。
有人有什么想法可能导致此问题吗?
更新:我实现了@DonMag的示例,这是我得到的:
请注意,生成的“ A”被白色包围。
我应该注意,我正在使用经典的故事板UIKit应用程序(没有场景的东西)。我认为这不是问题,但我很乐意提供我的小样本应用程序。我认为不值得为其创建GH回购。
解决方法
您的代码似乎没有任何问题,所以我想知道您的图像真的,真的是否具有透明度?
这是一个简单的示例。运行时看起来像这样:
代码使用.contentMode = .center
创建红色和蓝色图像视图。
点击“创建”按钮将使用SF符号(透明背景为绿色,红色图像视图的大小)生成UIImage
,并将其保存为PNG格式的透明照片。
点击“加载”按钮将弹出图像选择器。选择一个图像(例如刚刚创建并保存的图像)将加载该图像,并使用扩展名将其调整为80 x 80
并将其分配给“蓝色图像”视图的.image
属性。>
如您所见,从“照片选取器”加载的图像仍然具有透明度。
您的UIImage扩展名以调整大小
extension UIImage {
func resizeThisImage(toNewWidth inNewWidth: CGFloat? = nil,toNewHeight inNewHeight: CGFloat? = nil) -> UIImage? {
guard nil == inNewWidth,nil == inNewHeight else {
var scaleX: CGFloat = (inNewWidth ?? size.width) / size.width
var scaleY: CGFloat = (inNewHeight ?? size.height) / size.height
scaleX = nil == inNewWidth ? scaleY : scaleX
scaleY = nil == inNewHeight ? scaleX : scaleY
let destinationSize = CGSize(width: size.width * scaleX,height: size.height * scaleY)
let destinationRect = CGRect(origin: .zero,size: destinationSize)
UIGraphicsBeginImageContextWithOptions(destinationSize,false,0)
defer { UIGraphicsEndImageContext() } // This makes sure that we get rid of the offscreen context.
draw(in: destinationRect,blendMode: .normal,alpha: 1)
return UIGraphicsGetImageFromCurrentImageContext()
}
return nil
}
}
UIImage扩展名,以透明的PNG格式保存到照片
extension UIImage {
// save to Photos in PNG format with transparency
func saveToPhotos(completion: @escaping (_ success:Bool) -> ()) {
if let pngData = self.pngData() {
PHPhotoLibrary.shared().performChanges({ () -> Void in
let creationRequest = PHAssetCreationRequest.forAsset()
let options = PHAssetResourceCreationOptions()
creationRequest.addResource(with: PHAssetResourceType.photo,data: pngData,options: options)
},completionHandler: { (success,error) -> Void in
if success == false {
if let errorString = error?.localizedDescription {
print("Photo could not be saved: \(errorString))")
}
completion(false)
} else {
print("Photo saved!")
completion(true)
}
})
} else {
completion(false)
}
}
}
示例视图控制器(基本上)使用您的func imagePickerController
来加载照片
class TestImageViewController: UIViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate {
var imgViewA: UIImageView = UIImageView()
var imgViewB: UIImageView = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
let vStack = UIStackView()
vStack.axis = .vertical
vStack.spacing = 20
let btnStack = UIStackView()
btnStack.axis = .horizontal
btnStack.distribution = .fillEqually
btnStack.spacing = 20
let btnCreate = UIButton()
let btnLoad = UIButton()
btnCreate.setTitle("Create",for: [])
btnLoad.setTitle("Load",for: [])
[btnCreate,btnLoad].forEach { b in
b.setTitleColor(.white,for: .normal)
b.setTitleColor(.lightGray,for: .highlighted)
b.backgroundColor = UIColor(red: 0.0,green: 0.5,blue: 0.75,alpha: 1.0)
btnStack.addArrangedSubview(b)
}
vStack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(vStack)
[btnStack,imgViewA,imgViewB].forEach { v in
vStack.addArrangedSubview(v)
}
[imgViewA,imgViewB].forEach { v in
v.contentMode = .center
}
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
vStack.centerXAnchor.constraint(equalTo: g.centerXAnchor),vStack.centerYAnchor.constraint(equalTo: g.centerYAnchor),vStack.widthAnchor.constraint(equalToConstant: 200.0),imgViewA.heightAnchor.constraint(equalTo: imgViewA.widthAnchor),imgViewB.heightAnchor.constraint(equalTo: imgViewB.widthAnchor),])
imgViewA.backgroundColor = .red
imgViewB.backgroundColor = .blue
btnCreate.addTarget(self,action: #selector(self.createAndSave(_:)),for: .touchUpInside)
btnLoad.addTarget(self,action: #selector(importPicture(_:)),for: .touchUpInside)
}
@objc func createAndSave(_ sender: Any) {
let w = imgViewA.frame.width
// create a Green image with transparent background
if let img = drawSystemImage("a.circle.fill",at: 80,centeredIn: CGSize(width: w,height: w)) {
imgViewA.image = img
// save it to Photos in PNG format with transparency
img.saveToPhotos { (success) in
if success {
// image saved to photos
print("saved")
}
else {
// image not saved
fatalError("save failed")
}
}
}
}
// create UIImage from SF Symbol system image
// at Point Size
// centered in CGSize
// will draw symbol in Green on transparent background
private func drawSystemImage(_ sysName: String,at pointSize: CGFloat,centeredIn size: CGSize) -> UIImage? {
let cfg = UIImage.SymbolConfiguration(pointSize: pointSize)
guard let img = UIImage(systemName: sysName,withConfiguration: cfg)?.withTintColor(.green,renderingMode: .alwaysOriginal) else { return nil }
let x = (size.width - img.size.width) * 0.5
let y = (size.height - img.size.height) * 0.5
let renderer = UIGraphicsImageRenderer(size: size)
return renderer.image { context in
img.draw(in: CGRect(origin: CGPoint(x: x,y: y),size: img.size))
}
}
@objc func importPicture(_ sender: Any) {
let picker = UIImagePickerController()
picker.allowsEditing = true
picker.delegate = self
present(picker,animated: true)
}
func imagePickerController(_ inPicker: UIImagePickerController,didFinishPickingMediaWithInfo inInfo: [UIImagePickerController.InfoKey: Any]) {
let info = Dictionary(uniqueKeysWithValues: inInfo.map { key,value in (key.rawValue,value) })
guard let image = (info[UIImagePickerController.InfoKey.editedImage.rawValue] as? UIImage ?? info[UIImagePickerController.InfoKey.originalImage.rawValue] as? UIImage)?.resizeThisImage(toNewWidth: 80) else { return }
// organization?.icon = image
inPicker.dismiss(animated: true) {
DispatchQueue.main.async { [weak self] in
self?.imgViewB.image = image
//self?.imageButton?.image = image
//self?.imageButton?.alpha = 1.0
//self?.imageButton?.tintColor = self?.view.tintColor
//self?.updateUI()
}
}
}
}