我正在使用 Swift 4 和 iOS 11 开发我的应用程序。
问题是我可以在UIImageView中显示UIImage,但我无法将其保存到iPhone的相册中。我已经寻找了很长时间,但不知道如何解决它。
这是我代码的一部分:
将所有视频捕获代码放入VideoCapture.swift
。
public class VideoCapture: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate {
public var previewLayer: AVCaptureVideoPreviewLayer?
public var fps = 15
let captureSession = AVCaptureSession()
let videoOutput = AVCaptureVideoDataOutput()
let queue = DispatchQueue(label: "net.machine.cameraqueue")
var photoOutput: AVCapturePhotoOutput?
var image: UIImage?
public func setUp(sessionPreset: AVCaptureSession.Preset = .medium, completion: @escaping (Bool) -> Void) {
queue.async {
let success = self.setUpCamera(sessionPreset: sessionPreset)
DispatchQueue.main.async {
completion(success)
}
}
}
public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
image = sampleBuffer.image()
}
func setUpCamera(sessionPreset: AVCaptureSession.Preset) -> Bool {
captureSession.beginConfiguration() // begin configuration (not commited yet)
captureSession.sessionPreset = sessionPreset
guard let captureDevice = AVCaptureDevice.default(for: AVMediaType.video) else { //set to video mode
print("Error: No video devices available")
return false
}
guard let videoInput = try? AVCaptureDeviceInput(device: captureDevice) else { //set device input
print("Error: could not create AVCaptureDeviceInput")
return false
}
if captureSession.canAddInput(videoInput) { // add device input
captureSession.addInput(videoInput)
}
// previewLayer setup
let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer.videoGravity = AVLayerVideoGravity.resizeAspect
previewLayer.connection?.videoOrientation = .portrait
self.previewLayer = previewLayer
// video output setup
let settings: [String: Any] = [kCVPixelBufferPixelFormatTypeKey as String: NSNumber(value: kCVPixelFormatType_32BGRA),]
videoOutput.videoSettings = settings
videoOutput.alwaysDiscardsLateVideoFrames = true
videoOutput.setSampleBufferDelegate(self, queue: queue)
if captureSession.canAddOutput(videoOutput) {
captureSession.addOutput(videoOutput)
}
videoOutput.connection(with: AVMediaType.video)?.videoOrientation = .portrait
captureSession.commitConfiguration()
return true
}
public func toggleRunning() {
if captureSession.isRunning {
captureSession.stopRunning()
} else {
captureSession.startRunning()
}
}
}
extension CMSampleBuffer {
func image(orientation: UIImageOrientation = .up, scale: CGFloat = 1.0) -> UIImage? {
if let buffer = CMSampleBufferGetImageBuffer(self) {
let ciImage = CIImage(cvPixelBuffer: buffer)
return UIImage(ciImage: ciImage, scale: scale, orientation: orientation)
}
return nil
}
}
ViewController.swift
文件为:
class ViewController: UIViewController {
@IBOutlet weak var videoPreview: UIView!
var videoCapture: VideoCapture!
let semaphore = DispatchSemaphore(value: 2)
override func viewDidLoad() {
super.viewDidLoad()
setUpCamera()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showPhotoSegue" {
let previewVC = segue.destination as! PreviewViewController
previewVC.image = videoCapture.image
}
}
@IBAction func toggleCamera(_ sender: Any) {
performSegue(withIdentifier: "showPhotoSegue", sender: nil)
}
func setUpCamera() {
videoCapture = VideoCapture()
videoCapture.fps = 50
videoCapture.setUp(sessionPreset: AVCaptureSession.Preset.vga640x480) { success in
if success {
if let previewLayer = self.videoCapture.previewLayer {
self.videoPreview.layer.addSublayer(previewLayer)
self.resizePreviewLayer()
}
self.videoCapture.toggleRunning()
}
}
}
func resizePreviewLayer() {
videoCapture.previewLayer?.frame = videoPreview.bounds
}
}
}
PreviewViewController.swift
如下:
class PreviewViewController: UIViewController {
var image: UIImage?
@IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = self.image
}
@IBAction func cancelButton(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
@IBAction func saveButton(_ sender: Any) {
print(type(of: self.imageView.image!))
UIImageWriteToSavedPhotosAlbum(self.imageView.image!, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
}
@objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
if let error = error {
let ac = UIAlertController(title: "Save error", message: error.localizedDescription, preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac,animated: true)
} else {
let ac = UIAlertController(title: "Saved!", message: "Your altered image has been saved!", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac,animated: true)
}
}
}
我使用了一个segue从ViewController转到PreviewViewController,并将ViewController中的图像传递给PreviewViewController中的imageView。但是为什么它不将图像存储在相册中呢?
顺便说一下,我已经在info.plist
中添加了所有隐私授权。
我相信UIImageWriteToSavedPhotosAlbum()是一个非常古老的API。您可能希望使用"照片"框架来保存图像。以下代码将请求访问照片库,然后保存您的图像。
func saveImage(image : UIImage) {
let data = UIImageJPEGRepresentation(image, 0.9)
PHPhotoLibrary.requestAuthorization { [unowned self] status in
if status == .authorized {
PHPhotoLibrary.shared().performChanges({
let creationRequest = PHAssetCreationRequest.forAsset()
creationRequest.addResource(with: .photo, data: data, options: nil)
}, completionHandler: { success, error in
if let error = error {
print("Error occured while saving photo to photo library: (error)")
}
})
}
}
}
确保将此作为文件的顶部
import Photos