0

我正在使用 Swift 4 和 iOS 11 开发我的应用程序。

问题是我可以在 UIImageView 中显示 UIImage,但我无法将它保存到 iPhone 的相册中。我一直在寻找很长时间,但不知道如何解决它。

这是我的代码的一部分:

将所有 videoCapture 代码放入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.

4

1 回答 1

1

我相信 UIImageWriteToSavedPhotosAlbum() 是一个相当古老的 api。您可能想使用 Photos 框架来保存图像。以下代码将请求访问照片库,然后保存您的图像。

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
于 2018-05-30T13:55:23.123 回答