-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathImageCaptureSample.swift
More file actions
85 lines (70 loc) · 3.49 KB
/
Copy pathImageCaptureSample.swift
File metadata and controls
85 lines (70 loc) · 3.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
//
// ImageCaptureSample.swift
// MachinDataMatrix
//
// Created by Anthony Stanners on 17/08/2025.
//
import Foundation
import AVFoundation
import UIKit
class BarcodeScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate, AVCaptureVideoDataOutputSampleBufferDelegate {
var captureSession: AVCaptureSession!
var videoPreviewLayer: AVCaptureVideoPreviewLayer!
var lastBarcodeImage: UIImage?
var captureImageNextFrame = false
override func viewDidLoad() {
super.viewDidLoad()
captureSession = AVCaptureSession()
guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return }
let videoInput = try! AVCaptureDeviceInput(device: videoCaptureDevice)
captureSession.addInput(videoInput)
let metadataOutput = AVCaptureMetadataOutput()
captureSession.addOutput(metadataOutput)
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
metadataOutput.metadataObjectTypes = [.ean8, .ean13, .qr]
let videoDataOutput = AVCaptureVideoDataOutput()
videoDataOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoQueue"))
captureSession.addOutput(videoDataOutput)
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
videoPreviewLayer.frame = view.layer.bounds
view.layer.addSublayer(videoPreviewLayer)
captureSession.startRunning()
}
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
guard let _ = metadataObjects.first as? AVMetadataMachineReadableCodeObject else { return }
captureImageNextFrame = true
}
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
guard captureImageNextFrame else { return }
captureImageNextFrame = false
if let image = imageFromSampleBuffer(sampleBuffer) {
lastBarcodeImage = image
// Use lastBarcodeImage as needed
}
}
func imageFromSampleBuffer(_ sampleBuffer: CMSampleBuffer) -> UIImage? {
guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return nil }
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
let context = CIContext()
if let cgImage = context.createCGImage(ciImage, from: ciImage.extent) {
return UIImage(cgImage: cgImage)
}
return nil
}
}
func cropImageLeftOfBarcode(barcodeObject: AVMetadataMachineReadableCodeObject, sampleBuffer: CMSampleBuffer, previewLayer: AVCaptureVideoPreviewLayer) -> UIImage? {
guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return nil }
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
let context = CIContext()
// Convert barcode bounds to image coordinates
let transformedObject = previewLayer.transformedMetadataObject(for: barcodeObject)
guard let barcodeBounds = transformedObject?.bounds else { return nil }
// Define crop rect to the left of the barcode
let cropWidth = barcodeBounds.origin.x
let cropRect = CGRect(x: 0, y: barcodeBounds.origin.y, width: cropWidth, height: barcodeBounds.height)
// Crop the image
if let cgImage = context.createCGImage(ciImage, from: cropRect) {
return UIImage(cgImage: cgImage)
}
return nil
}