I have a controller that its functions are to open the front camera, show the instructions in the view with a guide for the user to place his face, draw two buttons to capture the selfie photo and cancel the process.
When capturing the photo with that controller, a function is called in a controller called ‘Service Manager’ to send the photo and update the stream’s lifecycle.
The problem occurs in devices like iPhone 7, when tapping on the “CAPTURE SELFIE” button the photo turns out to be dark or bright. Another problem that this driver has, but on all iOS devices, is that if the user minimizes the app and reopens it, the camera freezes and you have to minimize and reopen more than once to get the camera to work. resume and the user can capture the selfie correctly but the instructions are redrawn each time the user minimizes and opens the app again so the camera preview shows black.
What can be caused this?
I attached part of the code.
func setUpAVCapture() {
session.sessionPreset = AVCaptureSession.Preset.hd1280x720
guard let device = AVCaptureDevice.default(AVCaptureDevice.DeviceType.builtInWideAngleCamera, for: .video, position: AVCaptureDevice.Position.front) else { return }
// captureDevice = device
// self.beginSession()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setNeedsStatusBarAppearanceUpdate()
if previewLayer != nil {
self.previewLayer?.frame = self.cameraPreview.layer.bounds
}
if AppConfig.shared.otorgante?.dataset != nil {
for item in AppConfig.shared.otorgante!.dataset! {
if item.idCampo == "INTENTOS_VIDEO_TOKEN" {
self.intentosMaximos = Int(item.valor!)!
}
}
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.instructionsView!.removeFromSuperview()
// Detener la sesión de captura cuando se sale de la vista
self.stopCamera()
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.getFrame = false
}
}
func stopCamera() {
session.stopRunning()
}
@objc func captureButtonTapped() {
guard let captureSession = captureSession else { return }
self.animacion?.isHidden = true
blurView?.addBlurToView()
if self.activityView == nil {
activityView = UIView(frame: CGRect(x: (self.view.frame.width / 2) - 50, y: (self.view.frame.height / 2) - 50, width: 100, height: 100))
activityView!.backgroundColor = UIColor(red:0 , green: 0, blue: 0, alpha: 0.8)
activityView!.layer.cornerRadius = 4
activityIndicator = UIActivityIndicatorView(frame: CGRect(x: (activityView!.frame.width / 2) - 15, y: (activityView!.frame.height / 2) - 15, width: 30, height: 30))
if #available(iOS 13.0, *) {
activityIndicator!.style = .large
activityIndicator?.color = .white
} else {
activityIndicator?.style = .whiteLarge
}
activityView!.addSubview(activityIndicator!)
self.view.addSubview(activityView!)
}
if intentosRealizados == 1 {
if captureSession.canAddOutput(self.photoOutput) {
captureSession.addOutput(self.photoOutput)
}
}
let settings = AVCapturePhotoSettings()
if let connection = photoOutput.connection(with: .video) {
// Ajustar la orientación a vertical
connection.videoOrientation = .portrait
}
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let fileUrl = paths[0].appendingPathComponent("selfie.png")
try? FileManager.default.removeItem(at: fileUrl)
photoOutput.capturePhoto(with: settings, delegate: self)
DispatchQueue.main.asyncAfter(deadline: .now() + 6.0){
self.performSelector(onMainThread: #selector(self.stopSelfie), with: nil, waitUntilDone: false)
}
activityIndicator?.startAnimating()
activityView?.isHidden = false
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
self.maskImage?.image = UIImage(named: "face_yellow")
if let imageData = photo.fileDataRepresentation(), let image = UIImage(data: imageData) {
let compressedData = image.jpegData(compressionQuality: 0.5)
if let compressedImage = UIImage(data: compressedData ?? Data()){
if let compressedData = compressImage(image: compressedImage, maxSizeInBytes: 1 * 1024 * 1024) {
let rotatedImage = UIImage(data: compressedData)?.rotate(radians: .pi / 0.5)
let pngData = rotatedImage?.jpegData(compressionQuality: 1.0)
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = documentDirectory.appendingPathComponent("selfie.png")
if let data = pngData {
do {
try data.write(to: fileURL)
//print("Se guardó la imagen en: \(fileURL)")
} catch {
//print("Error al guardar la imagen: \(error.localizedDescription)")
}
}
}
}
}
}
func compressImage(image: UIImage, maxSizeInBytes: Int) -> Data? {
let maxHeight: CGFloat = 1024.0
let maxWidth: CGFloat = 1024.0
var actualWidth = image.size.width
var actualHeight = image.size.height
if actualWidth <= maxWidth && actualHeight <= maxHeight {
return image.jpegData(compressionQuality: 1.0)
}
let imgRatio = actualWidth / actualHeight
var newWidth: CGFloat
var newHeight: CGFloat
if imgRatio > maxWidth / maxHeight {
newWidth = maxWidth
newHeight = maxWidth / imgRatio
} else {
newHeight = maxHeight
newWidth = maxHeight * imgRatio
}
let renderRect = CGRect(x: 0, y: 0, width: newWidth, height: newHeight)
let renderer = UIGraphicsImageRenderer(size: renderRect.size)
let compressedImage = renderer.image { context in
image.draw(in: renderRect)
}
var compressionQuality: CGFloat = 1.0
var finalImageData = compressedImage.jpegData(compressionQuality: compressionQuality)
while finalImageData?.count ?? 0 > maxSizeInBytes && compressionQuality > 0.1 {
compressionQuality -= 0.1
finalImageData = compressedImage.jpegData(compressionQuality: compressionQuality)
}
return finalImageData
}
That the use of the camera, in the application, is compatible with all devices from iPhone 6+.
The intention of this controller is that the application takes a selfie photo, saves it in png and that the file size is less than 5MB.
Thank you