iOS UIImageWriteToSavedPhotosAlb

2020-03-16  本文已影响0人  齐舞647

引子:
需求,把UIImage保存图片到相册。
看似很简单的需求,踩了一个坑,记录一下。

正常步骤:

func addLongPressGestureRecognizer() {
     let longPress = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressClick))
     self.qrImageView.isUserInteractionEnabled = true
     self.qrImageView.addGestureRecognizer(longPress)
}
@objc func longPressClick() {
      let alert = UIAlertController(title: "是否将二维码保存到相册?", message: nil, preferredStyle: .alert)
      let action = UIAlertAction(title: "确定", style: .default) { [weak self] (action) in
          guard let `self` = self else {
              return
          }
          UIImageWriteToSavedPhotosAlbum(image, self, #selector(self.image(image:didFinishSavingWithError:contextInfo:)), nil) // 保存到相册
      }
      let cancel = UIAlertAction(title: "取消", style: .cancel, handler: nil)
      alert.addAction(action)
      alert.addAction(cancel)
      self.present(alert, animated: true, completion: nil)
}
@objc func image(image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {
      if error == nil {
          UIView.makeStaticToast("保存成功")
      } else {
          UIView.makeStaticToast("保存失败")
      }
}

遇到的坑:

原因是该UIImage是通过CIImage转过来的,
而实际上只能识别CGImage转过来的或者本身就是UIImage

let cgImage = CIContext().createCGImage(image.ciImage!, from: image.ciImage!.extent)
let uiImage = UIImage.init(cgImage: cgImage!)
UIImageWriteToSavedPhotosAlbum(uiImage, self, #selector(self.image(image:didFinishSavingWithError:contextInfo:)), nil) // 保存到相册

问题的本质:

UIImage、CGImage、CIImage的本质区别是什么?

A CGImage can only represent bitmaps. Operations in CoreGraphics, such as blend modes and masking require CGImageRefs. If you need to access and change the actual bitmap data, you can use CGImage. It can also be converted to NSBitmapImageReps.
用来描述bitmaps,如果需要访问和更改实际的位图数据,可以使用CGImage。

A CIImage is an immutable object that represents an image. It is not an image. It only has the image data associated with it. It has all the information necessary to produce an image. You typically use CIImage objects in conjunction with other Core Image classes such as CIFilter, CIContext, CIColor, and CIVector. You can create CIImage objects with data supplied from variety of sources such as Quartz 2D images, Core Videos image, etc. It is required to use the various GPU optimized Core Image filters. They can also be converted to NSBitmapImageReps. It can be based on the CPU or the GPU.
对象也是线程安全的,它并不是一张图片。
它包含了所有生成一张图片所有的必要信息。
常用在CIFilter, CIContext, CIColor, CIVector。跟GPU的处理相关。(如滤镜)

UIImage object is a high-level way to display image data. You can create images from files, from Quartz image objects, or from raw image data you receive. They are immutable and must specify an image’s properties at initialization time. This also means that these image objects are safe to use from any thread. Typically you can take NSData object containing a PNG or JPEG representation image and convert it to a UIImage.
UIImage对象是显示图像数据的高级方法。您可以从文件、Quartz图像对象或接收的原始图像数据创建图像。它们是不可变的,必须在初始化时指定图像的属性。这也意味着这些图像对象可以安全地从任何线程中使用。通常你能取得NSData对象包含一个PNG或JPEG表现图像并且转换它到一个UIImage。

主要区别:

1. 使用imageWithCGImage生成的UIImage
2. 使用imageWithCIImage生成的UIImage

PS:关于CGImage与CIImage的详细资料

\ imageWithCGImage imageWithCIImage
1 重新生成UIImage,
会把生成它的CGImageRef保存下来
重新生成UIImage,
会把生成它的CIImage保存下来
2 image.CIImage = nil image.CGImage = nil

猜测UIImageWriteToSavedPhotosAlbum方法底层会使用image.cgImage,转换成照片,再保存照片到相册。

因此,不能直接使用CIImage转换成的UIImage,因为CIImage转成的image.cgImage = nil

所以,最终解决方案是:UIImage -> CIImage -> CGImage -> UIImage

上一篇 下一篇

猜你喜欢

热点阅读