【问题标题】:Taking a square photo with Camera App使用相机应用程序拍摄方形照片
【发布时间】:2018-04-05 04:27:50
【问题描述】:

我目前正在构建一个相机应用程序,并希望让相机像 Instagram 一样拍摄一张 375x375 的方形图像并将其保存。

我可以调整相机的取景器,但拍摄方式不正确,当我保存它时,它也会以全视图保存。我查看了那里的其他问答,但它们似乎都不适用于我的代码。

谁能帮我解决这个问题。

import Foundation
import UIKit
import AVFoundation

class CameraViewController: UIViewController{

var captureSession = AVCaptureSession()
var frontCameraDeviceInput: AVCaptureDeviceInput?
var backCameraDeviceInput: AVCaptureDeviceInput?
var currentCamera: AVCaptureDevice?

var photoOutput: AVCapturePhotoOutput?

var cameraPreviewLayer: AVCaptureVideoPreviewLayer?

var image: UIImage?

override func viewDidLoad() {
    super.viewDidLoad()

    setupCaptureSession()
    setupDevice()
    setupInputOutput()
    setupPreviewLayer()
    startRunningCaptureSession()
}

func setupCaptureSession() {
    captureSession.sessionPreset = AVCaptureSession.Preset.photo
}

func setupDevice() {
    let frontCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front)
    let backCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)

    frontCameraDeviceInput = try? AVCaptureDeviceInput(device: frontCamera!)
    backCameraDeviceInput = try? AVCaptureDeviceInput(device: backCamera!)
}

func setupInputOutput() {
    captureSession.addInput(backCameraDeviceInput!)
    photoOutput = AVCapturePhotoOutput()
    photoOutput?.isHighResolutionCaptureEnabled = true
    photoOutput?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format:[AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil)
    captureSession.addOutput(photoOutput!)
}

func setupPreviewLayer() {
    cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
    cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
    cameraPreviewLayer?.frame = self.view.frame
    self.view.layer.insertSublayer(cameraPreviewLayer!, at: 0)
}

func startRunningCaptureSession() {
    captureSession.startRunning()
}

@IBAction func camerButton(_ sender: Any) {
    let settings = AVCapturePhotoSettings()
    photoOutput?.capturePhoto(with: settings, delegate: self)
}

@IBAction func switchCamera(_ sender: Any) {
    captureSession.beginConfiguration()
    //Change camera device inputs from back to front or opposite
    if captureSession.inputs.contains(frontCameraDeviceInput!) == true {
        captureSession.removeInput(frontCameraDeviceInput!)
        captureSession.addInput(backCameraDeviceInput!)
    } else if captureSession.inputs.contains(backCameraDeviceInput!) == true {
        captureSession.removeInput(backCameraDeviceInput!)
        captureSession.addInput(frontCameraDeviceInput!)
    }

    //Commit all the configuration changes at once
    captureSession.commitConfiguration();
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "previewCameraPhoto" {
        let previewVC = segue.destination as! PreviewViewController
        previewVC.image = self.image
    }
}
}

extension CameraViewController: AVCapturePhotoCaptureDelegate {
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
    if let imageData = photo.fileDataRepresentation() {
        image = UIImage(data: imageData)
        performSegue(withIdentifier: "previewCameraPhoto", sender: nil)
    }
}

override var prefersStatusBarHidden: Bool
{
    return true
}
}

【问题讨论】:

    标签: swift avfoundation avcapturesession


    【解决方案1】:

    以下代码行用于捕获图像。我在点击捕获按钮时执行它们。在你的情况下是

    func cameraButton(_ sender: Any)

    使用的方法的定义也在下面。

    DispatchQueue.global(qos: .default).async {
                let videoConnection = self.imageOutput.connection(with: AVMediaType.video)
                let orientation: UIDeviceOrientation = UIDevice.current.orientation
                switch orientation {
                case .portrait:
                    videoConnection?.videoOrientation = .portrait
                case .portraitUpsideDown:
                    videoConnection?.videoOrientation = .portraitUpsideDown
                case .landscapeRight:
                    videoConnection?.videoOrientation = .landscapeLeft
                case .landscapeLeft:
                    videoConnection?.videoOrientation = .landscapeRight
                default:
                    videoConnection?.videoOrientation = .portrait
                }
    
                self.imageOutput.captureStillImageAsynchronously(from: videoConnection!) { buffer, _ in
                    self.session.stopRunning()
    
                    guard let b = buffer
                        else { return }
    
                    let data = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(b)
    
                    if var image = UIImage(data: data!) {
    
                        // Crop the image if the output needs to be square.
                        if self.configuration.onlySquareImagesFromCamera {
                            image = self.cropImageToSquare(image)
                        }
    
                        // Flip image if taken form the front camera.
                        if let device = self.device, device.position == .front {
                            image = self.flipImage(image: image)
                        }
    
                        DispatchQueue.main.async {
                            self.didCapturePhoto?(image)
                        }
                    }
                }
            }
    

    这个函数中用到的两种方法——

    func cropImageToSquare(_ image: UIImage) -> UIImage {
                let orientation: UIDeviceOrientation = UIDevice.current.orientation
                var imageWidth = image.size.width
                var imageHeight = image.size.height
                switch orientation {
                case .landscapeLeft, .landscapeRight:
                    // Swap width and height if orientation is landscape
                    imageWidth = image.size.height
                    imageHeight = image.size.width
                default:
                    break
                }
    
                // The center coordinate along Y axis
                let rcy = imageHeight * 0.5
                let rect = CGRect(x: rcy - imageWidth * 0.5, y: 0, width: imageWidth, height: imageWidth)
                let imageRef = image.cgImage?.cropping(to: rect)
                return UIImage(cgImage: imageRef!, scale: 1.0, orientation: image.imageOrientation)
            }
    
    
    // Used when image is taken from the front camera.
    func flipImage(image: UIImage!) -> UIImage! {
            let imageSize: CGSize = image.size
            UIGraphicsBeginImageContextWithOptions(imageSize, true, 1.0)
            let ctx = UIGraphicsGetCurrentContext()!
            ctx.rotate(by: CGFloat(Double.pi/2.0))
            ctx.translateBy(x: 0, y: -imageSize.width)
            ctx.scaleBy(x: imageSize.height/imageSize.width, y: imageSize.width/imageSize.height)
            ctx.draw(image.cgImage!, in: CGRect(x: 0.0,
                                                y: 0.0,
                                                width: imageSize.width,
                                                height: imageSize.height))
            let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
            UIGraphicsEndImageContext()
            return newImage
    }
    

    我不应该忘记感谢这个库的开发者 - https://github.com/Yummypets/YPImagePicker/blob/2.5.1/Source/Camera/YPCameraVC.swift

    【讨论】:

    • 好的,我在视图控制器中添加了该功能,但对保存的图像没有影响
    • 好的,让我添加我用来调用这个函数的函数
    • 谢谢,等待
    • 它似乎很顽固,到处都是错误。这些农作物的东西已经让我忙了好几天了。
    • 为什么不使用上述库?
    【解决方案2】:

    只需将其添加到图像选择器中,用户就可以选择他们喜欢的裁剪比例。默认是你想要的..方形照片

    self.ImagePicker.allowsEditing = true

    【讨论】:

    • 我不希望用户对裁剪有任何控制权。它需要硬编码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-11
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-20
    相关资源
    最近更新 更多