Capturing the image read by QRCode

In this app I get access to QRCode.
Reading works perfectly from the camera.

Now I am struggling to get the image that was processed by the built in QRCode reader.

I have found many hints on SO, but cannot make it work.

Here is the code I have now.
It is a bit long, I have to slit in 2 parts

I looked at:
// https://stackoverflow.com/questions/56088575/how-to-get-image-of-qr-code-after-scanning-in-swift-ios
// https://stackoverflow.com/questions/37869963/how-to-use-avcapturephotooutput

Code Block
import UIKit
import AVFoundation
class ScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
fileprivate var captureSession: AVCaptureSession! // use for QRCode reading
fileprivate var previewLayer: AVCaptureVideoPreviewLayer!
// To get the image of the QRCode
private var photoOutputQR: AVCapturePhotoOutput!
private var isCapturing = false
override func viewDidLoad() {
super.viewDidLoad()
var accessGranted = false
// switch AVCaptureDevice.authorizationStatus(for: .video) {
// HERE TEST FOR ACCESS RIGHT. WORKS OK ;
// But is .video enough ?
}
if !accessGranted { return }
captureSession = AVCaptureSession()
photoOutputQR = AVCapturePhotoOutput() // IS IT THE RIGHT PLACE AND THE RIGHT THING TO DO ?
captureSession.addOutput(photoOutputQR) // Goal is to capture an image of QRCode once acquisition is done
guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return }
let videoInput: AVCaptureDeviceInput
do {
videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
} catch { return }
if (captureSession.canAddInput(videoInput)) {
captureSession.addInput(videoInput)
} else {
failed()
return
}
let metadataOutput = AVCaptureMetadataOutput()
if (captureSession.canAddOutput(metadataOutput)) {
captureSession.addOutput(metadataOutput) // SO I have 2 output in captureSession. IS IT RIGHT ?
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
metadataOutput.metadataObjectTypes = [.qr] // For QRCode video acquisition
} else {
failed()
return
}
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer.frame = view.layer.bounds
previewLayer.frame.origin.y += 40
previewLayer.frame.size.height -= 40
previewLayer.videoGravity = .resizeAspectFill
view.layer.addSublayer(previewLayer)
captureSession.startRunning()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if (captureSession?.isRunning == false) {
captureSession.startRunning()
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if (captureSession?.isRunning == true) {
captureSession.stopRunning()
}
}
// MARK: - scan Results
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
captureSession.stopRunning()
if let metadataObject = metadataObjects.first {
guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return }
guard let stringValue = readableObject.stringValue else { return }
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
found(code: stringValue)
}
// ### Get image - IS IT THE RIGHT PLACE TO DO IT ?
// https://stackoverflow.com/questions/37869963/how-to-use-avcapturephotooutput
print("Do I get here ?", isCapturing)
let photoSettings = AVCapturePhotoSettings()
let previewPixelType = photoSettings.availablePreviewPhotoPixelFormatTypes.first!
print("previewPixelType", previewPixelType)
let previewFormat = [kCVPixelBufferPixelFormatTypeKey as String: previewPixelType,
kCVPixelBufferWidthKey as String: 160,
kCVPixelBufferHeightKey as String: 160]
photoSettings.previewPhotoFormat = previewFormat
if !isCapturing {
isCapturing = true
photoOutputQR.capturePhoto(with: photoSettings, delegate: self)
}
dismiss(animated: true)
}
}
extension ScannerViewController: AVCapturePhotoCaptureDelegate {
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
isCapturing = false
print("photo", photo, photo.fileDataRepresentation())
guard let imageData = photo.fileDataRepresentation() else {
print("Error while generating image from photo capture data.");
return
}
}
}


I get the following print on console
Clearly photo is not loaded properly

Do I get here ? false
previewPixelType 875704422
photo <AVCapturePhoto: 0x281973a20 pts:nan 1/1 settings:uid:3 photo:{0x0} time:nan-nan> nil
Error while generating image from photo capture data.

Answered by Claude31 in 651039022
There is a simple fix: regenerate the QRCiode from the decoded QRCode.
It works well, but I would like to get the image itself as read by the camera…
Accepted Answer
There is a simple fix: regenerate the QRCiode from the decoded QRCode.
It works well, but I would like to get the image itself as read by the camera…

Maybe you can try to get a snapshot of "self.view" when the QRCode parses successfully?

Hello @Claude31,

I am facing same issue. Please share your working code if you fix that. Thanks in advance

You need to call captureSession.stopRunning() only after photo was captured.

Capturing the image read by QRCode
 
 
Q