Я занимаюсь разработкой приложения с использованием Swift 4 и iOS 11.
Проблема в том, что я могу отобразить UIImage в UIImageView, но не могу сохранить его в фотоальбом своего 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)
}
}
}
Я использовал переход от ViewController к PreviewViewController и передал изображение в ViewController в imageView в PreviewViewController. Но почему он не сохраняет изображение в фотоальбоме?
Кстати, я добавил все авторизации конфиденциальности в info.plist
.