Skip to content

feat: Manual Focus point #284

@CmdrDats

Description

@CmdrDats

Plugin(s)

  • Barcode Scanning
  • Face Detection
  • Face Mesh Detection
  • Selfie Segmentation
  • Subject Segmentation
  • Translation

Current problem

When we're using the barcode scanner, our camera view needs to be in the top 30% of the screen, leaving the rest of the screen for other UI elements. The focal point of the camera remains in the center of the screen under the UI which makes focussing barcodes on smaller products difficult.

Preferred solution

Add a setFocusPoint method that accepts normalized coordinates (0.0-1.0) and maps them to native camera focus points on both Android and iOS.

Alternative options

If we could control the underlying camera viewport position and size, that might also work but seems a lot more fiddly.

Additional context

Cursor provides this as a possible implementation plan - I am happy to implement, test and PR this after feedback and if approved.

API Design

TypeScript Interface:

interface BarcodeScannerPlugin {
  /**
   * Set the camera's focus point using normalized coordinates.
   * @param options { x: number, y: number } - Screen coordinates (0.0-1.0)
   */
  setFocusPoint(options: SetFocusPointOptions): Promise<void>;
}

interface SetFocusPointOptions {
  /** X coordinate (0.0 = left, 1.0 = right) */
  x: number;
  /** Y coordinate (0.0 = top, 1.0 = bottom) */  
  y: number;
}

Implementation Plan

1. Android (CameraX)

File: BarcodeScanner.java

  • Add method to convert normalized coordinates to MeteringPoint
  • Use existing getCameraControl().startFocusAndMetering() API
  • Implementation:
public void setFocusPoint(float x, float y) {
    if (camera == null || previewView == null) return;
    
    MeteringPointFactory factory = previewView.getMeteringPointFactory();
    MeteringPoint point = factory.createPoint(x * previewView.getWidth(), 
                                            y * previewView.getHeight());
    FocusMeteringAction action = new FocusMeteringAction.Builder(point).build();
    camera.getCameraControl().startFocusAndMetering(action);
}

File: BarcodeScannerPlugin.java

  • Add @PluginMethod for setFocusPoint
  • Parse coordinates and validate range [0.0-1.0]

2. iOS (AVFoundation)

File: BarcodeScanner.swift

  • Add method using existing getCaptureDevice() pattern
  • Convert normalized coordinates to camera coordinate system
  • Implementation:
@objc public func setFocusPoint(_ options: SetFocusPointOptions) throws {
    guard let device = cameraView?.getCaptureDevice(),
          let previewLayer = cameraView?.getPreviewLayer() else { return }
    
    guard device.isFocusPointOfInterestSupported else {
        throw RuntimeError("Focus point not supported")
    }
    
    let point = CGPoint(x: options.getX(), y: options.getY())
    let devicePoint = previewLayer.captureDevicePointConverted(fromLayerPoint: point)
    
    try device.lockForConfiguration()
    device.focusPointOfInterest = devicePoint
    device.focusMode = .autoFocus
    device.unlockForConfiguration()
}

3. TypeScript Updates

  • Add interfaces to definitions.ts
  • Export method in index.ts
  • Add comprehensive JSDoc documentation

4. Coordinate System

  • Input: Normalized coordinates (0.0-1.0)
  • Mapping:
    • Android: Multiply by preview dimensions for MeteringPoint
    • iOS: Use captureDevicePointConverted(fromLayerPoint:) for proper transformation
  • Benefits: Resolution-independent, orientation-agnostic, cross-platform consistent

Before submitting

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions