[iOS/swift] barcode scanner zoom기능 구현

SujiPark·2025년 2월 11일

iOS

목록 보기
2/3

barcode scanner zoom기능 구현

개요

관리하는 어플 내 barcode scanner 에서 아이폰 14 pro, 15 pro와 같이 카메라가 3개 이상인, 즉 광각모드를 지원하는 기기의 경우 바코드를 가까이 댔을 때 초점을 잃어 스캔하지 못하는 기기자체의 오류 발생
→ 멀리서 초점은 맞춰지지만 바코드끼리 겹쳐져서 인식이 안되는 문제가 발생하는 것

그래서 든 생각은?

  • 가까이서 인식이 안되면 멀리서 인식해서 zoom in 하는 것은 어떨까? 였다!

가장 먼저, 카메라 기본 권한설정 필수 (info-필요권한주기)

  • (key 지정 후 value 공란 비워두면 주의 메일 옴! 주의)

그래서 내가 선택한 방법은,

1. 광각카메라를 인식하여 광각카메라인 경우 카메라 입력에 추가하여 예외처리하기

구현했지만 카메라를 제대로 인식하지 못해 보류 (코드엔 넣어놓음)

     // 광각 카메라 찾기
     guard let wideAngleCamera = AVCaptureDevice.DiscoverySession(
         deviceTypes: [.builtInWideAngleCamera],
         mediaType: .video,
         position: .back).devices.first else {
         fatalError("광각 카메라를 찾을 수 없습니다.")
     }
     captureDevice = wideAngleCamera
     

2. auto-focusing 구현

자동으로 초점을 맞추도록 구현하려고 했으나 어플에 해당 코드를 집어넣으면 코드에 오류 발생, 문제를 해결하지 못해 해당 방법은 기각함

3. touch-focusing 구현

  • 터치하면 focusing 되도록 구현했고 작동은 하지만 문제를 해결할만큼 확실히 작동하는 것 같지는 않음

1. 터치, 포커스 구현 코드

// 터치 제스처 설정
private func setupTapGestureRecognizer() {
    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapToFocus(_:)))
    view.addGestureRecognizer(tapGestureRecognizer)
}

@objc private func handleTapToFocus(_ tap: UITapGestureRecognizer) {
    let location = tap.location(in: view)
    let devicePoint = previewLayer.captureDevicePointConverted(fromLayerPoint: location)

    guard let device = captureDevice else { return }

    do {
        try device.lockForConfiguration()

        if device.isFocusPointOfInterestSupported {
            device.focusPointOfInterest = devicePoint
            device.focusMode = .autoFocus
        }

        if device.isExposurePointOfInterestSupported {
            device.exposurePointOfInterest = devicePoint
            device.exposureMode = .autoExpose
        }

        device.unlockForConfiguration()

        // 포커스 애니메이션
        focusView.center = location
        focusView.isHidden = false
        UIView.animate(withDuration: 0.3, animations: {
            self.focusView.transform = CGAffineTransform(scaleX: 1.25, y: 1.25)
        }) { _ in
            UIView.animate(withDuration: 0.3) {
                self.focusView.transform = CGAffineTransform.identity
            }
        }

    } catch {
        print("포커스 설정 중 오류 발생: \\(error.localizedDescription)")
    }
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    // 카메라 포커스 모드 설정
    if let videoCaptureDevice = captureDevice {
        do {
            try videoCaptureDevice.lockForConfiguration()
            if videoCaptureDevice.isFocusModeSupported(.continuousAutoFocus) {
                videoCaptureDevice.focusMode = .continuousAutoFocus
            }
            if videoCaptureDevice.isAutoFocusRangeRestrictionSupported {
                videoCaptureDevice.autoFocusRangeRestriction = .near
            }
            videoCaptureDevice.unlockForConfiguration()
        } catch {
            print("카메라 포커스 설정에 실패했습니다.")
        }
    }
}

2. viewDidLoad 내에서 터치제스처 인식하는 함수 불러오기

setupTapGestureRecognizer() // 터치 제스처 설정 추가

3. focus animation

// 포커스 뷰 선언
private var focusView: UIView!

4. viewDidLoad 내 설정

// 포커스 애니메이션 뷰 설정
focusView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
focusView.layer.borderWidth = 1.0
focusView.layer.borderColor = UIColor.yellow.cgColor
focusView.backgroundColor = UIColor.clear
focusView.isHidden = true
view.addSubview(focusView)

4. zoom 기능 구현

차라리 멀리서 초점을 맞춰서 확대하자!

1. pinch 기능(swift내부에 o), zoomFactor 사용

  • 핀치 제스처 설정
private func setupPinchGestureRecognizer() {
       let pinchGestureRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(handlePinchCamera(_:)))
       view.addGestureRecognizer(pinchGestureRecognizer)
  • 핀치 제스처 핸들러
@objc private func handlePinchCamera(_ pinch: UIPinchGestureRecognizer) {
       guard let device = captureDevice else { return }
    
       let minZoomFactor: CGFloat = 1.0
       let maxZoomFactor: CGFloat = device.maxAvailableVideoZoomFactor
    
       switch pinch.state {
       case .began:
           lastZoomFactor = device.videoZoomFactor
       case .changed:
           var newZoomFactor = lastZoomFactor * pinch.scale
           newZoomFactor = min(max(newZoomFactor, minZoomFactor), maxZoomFactor)
           do {
               try device.lockForConfiguration()
               device.videoZoomFactor = newZoomFactor
               device.unlockForConfiguration()
           } catch {
               print("줌 조절 중 오류 발생: \\(error.localizedDescription)")
           }
       case .ended, .cancelled:
           pinch.scale = 1.0
       default:
           break
       }
   }

Finally

zoom 기능 구현 후 touch-focusing 보완해서 두 기능을 넣어 어플 배포 완료

0개의 댓글