portrait 모드가 아니라면 너비와 높이를 바꾸어서 좌표를 계산해야한다. 또한 좌우 flutter에서 발생한 좌표를 y축 반전해야 올바른 좌표가 나온다.
kotlin 코드
/**
* Set the focus point of the camera.
*/
fun setFocus(point: Map<String, Double>) {
val x = point["x"]!!.toFloat()
val y = point["y"]!!.toFloat()
val portrait = camera!!.cameraInfo.sensorRotationDegrees % 180 == 0
val resolution = preview!!.resolutionInfo!!.resolution
val width = resolution.width.toFloat()
val height = resolution.height.toFloat()
val meteringPoint = SurfaceOrientedMeteringPointFactory(
if (portrait) width else height,
if (portrait) height else width
).createPoint(x, y)
// Prepare focus action to be triggered.
val action = FocusMeteringAction.Builder(meteringPoint).build()
// Execute focus action
camera!!.cameraControl.startFocusAndMetering(action)
}
swift 코드
func setFocus(_ point: Dictionary<String, Double>) throws {
if (device == nil) {
throw MobileScannerError.focusWhenStopped
}
do {
try device.lockForConfiguration()
var size = latestBuffer.image.size
var portrait = UIDevice.current.orientation.isPortrait
var width = portrait ? size.width : size.height
var height = portrait ? size.height : size.width
var touch_x = (point["x"] ?? 0.0)
var touch_y = (point["y"] ?? 0.0)
var x = touch_x / width
var y = touch_y / height
var point = CGPoint(x: x, y: y)
if device.isFocusPointOfInterestSupported {
device.focusPointOfInterest = point
}
if device.isExposurePointOfInterestSupported{
device.exposurePointOfInterest = point
}
if device.isFocusModeSupported(.continuousAutoFocus) {
device.focusMode = .continuousAutoFocus
}
if device.isExposureModeSupported(.continuousAutoExposure){
device.exposureMode = .continuousAutoExposure
}
device.unlockForConfiguration()
} catch {
throw MobileScannerError.cameraError(error)
}
}
화면 회전 여부에 따른 값 변경 외에는 크게 로직이 들어있지는 않다.
dart 코드
GestureDetector(
//플러터에서 터치된 위치를 계산한다.
onTapDown: (details) {
final position = details.globalPosition;
var x = position.dx * ratio;
var y = (position.dy - top) * ratio;
final controller = qrController.controller.value;
final arguments = controller?.startArguments.value;
//실제 기기의 픽셀 사이즈를 계산한다.
final fullWidth = size.width * ratio;
final fullHeight =
(size.height + top + bottom) * ratio + kToolbarHeight;
final image = arguments?.size ?? const Size(0, 0);
final device = Size(fullWidth, fullHeight);
final preview = image * device.width / image.width;
//플러터에서 옮겨준 위치를 계산한다.
y = y - (101 + upperRest) * ratio;
//프리뷰에서 확장된 이미지의 터치 위치를 계산한다.
y = preview.height / device.height * y;
//좌우 반전된 터치 영역을 계산한다.
x = device.width - x;
//90도 회전된 터치 영역을 넘겨준다.
qrController.focus(y, x);
},
),
실질적인 좌표 계산은 Flutter에서 해서 넘기는 방향으로 개발을 진행하였다. 플러그인에 로직이 녹아 있으면 범용적으로 쓰이기 어렵다고 판단했기 때문이다.
참고
Github repo
AOS camerax tap to focus
AOS focus point
iOS focus point