1. React Native
  2. VisionCamera Component

React Native

VisionCamera Component

The VisionCamera component is a lightweight, minimal camera component designed for barcode scanning and OCR. Unlike the full VisionSdkView component, it provides a streamlined API without requiring API keys or cloud configuration for basic scanning functionality.

Features

  • Photo capture with quality optimization
  • Barcode & QR code scanning with multiple symbologies
  • OCR (Optical Character Recognition) support
  • Real-time object detection (text, barcodes, QR codes, documents)
  • Flash control with toggle support
  • Zoom control with adjustable levels
  • Auto & Manual capture modes
  • Image sharpness scoring for quality assurance
  • Customizable overlay - render your own UI on top of the camera
  • Camera switching - switch between front and back cameras (iOS)

Basic Usage

        import React, { useRef } from 'react';
import { VisionCamera, VisionCameraRefProps } from 'react-native-vision-sdk';

function CameraScreen() {
  const cameraRef = useRef<VisionCameraRefProps>(null);

  const handleCapture = (event) => {
    console.log('Image captured:', event.image);
    console.log('Sharpness score:', event.sharpnessScore);
  };

  const handleBarcodeDetected = (event) => {
    console.log('Barcodes:', event.codes);
    event.codes.forEach(code => {
      console.log('Value:', code.scannedCode);
      console.log('Type:', code.symbology);
      console.log('Position:', code.boundingBox);
    });
  };

  return (
    <VisionCamera
      ref={cameraRef}
      scanMode="barcode"
      onCapture={handleCapture}
      onBarcodeDetected={handleBarcodeDetected}
    />
  );
}

      

Scan Modes

Photo Mode

Basic photo capture without barcode or text detection:

        <VisionCamera
  scanMode="photo"
  onCapture={(event) => {
    console.log('Image path:', event.image);
    console.log('Sharpness:', event.sharpnessScore);
  }}
/>

      

Barcode Scanning

Detect and scan barcodes with enhanced metadata:

        <VisionCamera
  scanMode="barcode"
  onBarcodeDetected={(event) => {
    event.codes.forEach(code => {
      console.log('Code:', code.scannedCode);
      console.log('Type:', code.symbology);
      console.log('Bounds:', code.boundingBox);
      console.log('GS1:', code.gs1ExtractedInfo);
    });
  }}
/>

      

QR Code Scanning

Specifically scan QR codes:

        <VisionCamera
  scanMode="qrcode"
  onBarcodeDetected={(event) => {
    console.log('QR Codes:', event.codes);
  }}
/>

      

OCR (Text Recognition)

Document and text detection:

        <VisionCamera
  scanMode="ocr"
  autoCapture={true}
  onCapture={(event) => {
    console.log('Document captured:', event.image);
    // Barcodes detected in the image are also available
    if (event.barcodes) {
      console.log('Barcodes in image:', event.barcodes);
    }
  }}
  onRecognitionUpdate={(event) => {
    console.log('Text detected:', event.text);
    console.log('Document detected:', event.document);
  }}
/>

      

Ref Methods

Access camera controls via ref:

        const cameraRef = useRef<VisionCameraRefProps>(null);

// Capture photo
cameraRef.current?.capture();

// Start/stop camera
cameraRef.current?.start();
cameraRef.current?.stop();

      
NOTE

Camera Auto-Start: The camera starts automatically when mounted - you don't need to call start() manually in most cases. Use start() only after you've previously stopped it (e.g., when returning to the camera screen from background).

Method Parameters Description
capture() - Capture a photo manually (when autoCapture is false)
start() - Start the camera (only needed if you previously stopped it)
stop() - Stop the camera (e.g., when screen goes to background)
INFO

Property Control: Flash, zoom, and camera facing are controlled via props (enableFlash, zoomLevel, cameraFacing), not ref methods. Update the prop values to change these settings dynamically.


Event Handlers

Enhanced Barcode Detection

        <VisionCamera
  scanMode="barcode"
  onBarcodeDetected={(event) => {
    // Each barcode includes full metadata
    event.codes.forEach(code => {
      console.log('Barcode Value:', code.scannedCode);
      console.log('Symbology:', code.symbology);
      console.log('Position:', code.boundingBox); // {x, y, width, height}
      console.log('GS1 Data:', code.gs1ExtractedInfo);
    });
  }}
/>

      

Image Capture with Quality Score

        <VisionCamera
  scanMode="photo"
  onCapture={(event) => {
    console.log('Image path:', event.image);
    console.log('Native URI:', event.nativeImage);
    console.log('Sharpness score:', event.sharpnessScore); // 0.0 - 1.0
    console.log('Detected barcodes:', event.barcodes); // Available in all modes
  }}
/>

      

Real-time Recognition Updates

        <VisionCamera
  scanMode="ocr"
  onRecognitionUpdate={(event) => {
    console.log('Text detected:', event.text);
    console.log('Barcode detected:', event.barcode);
    console.log('QR code detected:', event.qrcode);
    console.log('Document detected:', event.document);
  }}
/>

      

Sharpness Score Monitoring

        <VisionCamera
  scanMode="photo"
  onSharpnessScoreUpdate={(event) => {
    console.log('Sharpness:', event.sharpnessScore); // 0.0 to 1.0
    // Values above 0.7 generally indicate sharp images
  }}
/>

      

Error Handling

        <VisionCamera
  scanMode="barcode"
  onError={(event) => {
    console.error('Error:', event.message);
    console.error('Error code:', event.code); // Numeric error code
  }}
/>

      
INFO

iOS Error Filtering: On iOS, error codes 13, 14, 15, and 16 are automatically filtered and won't trigger the onError callback.


Advanced Examples

Custom Overlay with Controls

        import React, { useRef, useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { VisionCamera, VisionCameraRefProps } from 'react-native-vision-sdk';

function CustomCameraOverlay() {
  const cameraRef = useRef<VisionCameraRefProps>(null);
  const [sharpness, setSharpness] = useState(0);

  return (
    <View style={styles.container}>
      <VisionCamera
        ref={cameraRef}
        scanMode="ocr"
        style={styles.camera}
        onSharpnessScoreUpdate={(event) => setSharpness(event.sharpnessScore)}
      />

      {/* Custom overlay positioned absolutely */}
      <View style={styles.overlay}>
        <View style={styles.header}>
          <Text style={styles.sharpnessText}>
            Sharpness: {(sharpness * 100).toFixed(0)}%
          </Text>
        </View>

        <View style={styles.footer}>
          <TouchableOpacity
            style={styles.captureButton}
            onPress={() => cameraRef.current?.capture()}
          >
            <Text style={styles.captureText}>Capture</Text>
          </TouchableOpacity>
        </View>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  camera: {
    flex: 1,
  },
  overlay: {
    ...StyleSheet.absoluteFillObject,
    justifyContent: 'space-between',
  },
  header: {
    padding: 20,
    backgroundColor: 'rgba(0, 0, 0, 0.5)',
  },
  sharpnessText: {
    color: 'white',
    fontSize: 16,
    fontWeight: 'bold',
  },
  footer: {
    padding: 20,
    alignItems: 'center',
  },
  captureButton: {
    backgroundColor: '#007AFF',
    paddingHorizontal: 30,
    paddingVertical: 15,
    borderRadius: 30,
  },
  captureText: {
    color: 'white',
    fontSize: 18,
    fontWeight: 'bold',
  },
});

      

Barcode Scanner with Flash and Zoom

        function AdvancedBarcodeScanner() {
  const [flash, setFlash] = useState(false);
  const [zoom, setZoom] = useState(1.0);
  const [codes, setCodes] = useState([]);

  return (
    <View style={{ flex: 1 }}>
      <VisionCamera
        scanMode="barcode"
        enableFlash={flash}
        zoomLevel={zoom}
        style={{ flex: 1 }}
        onBarcodeDetected={(event) => {
          setCodes(event.codes);
        }}
      />

      {/* Controls positioned absolutely */}
      <View style={styles.controls}>
        <TouchableOpacity onPress={() => setFlash(!flash)}>
          <Text style={styles.controlText}>
            {flash ? ' Flash ON' : ' Flash OFF'}
          </Text>
        </TouchableOpacity>

        <View style={styles.zoomControl}>
          <TouchableOpacity onPress={() => setZoom(Math.max(1.0, zoom - 0.5))}>
            <Text style={styles.controlText}>-</Text>
          </TouchableOpacity>
          <Text style={styles.controlText}>Zoom: {zoom.toFixed(1)}x</Text>
          <TouchableOpacity onPress={() => setZoom(Math.min(5.0, zoom + 0.5))}>
            <Text style={styles.controlText}>+</Text>
          </TouchableOpacity>
        </View>
      </View>

      {codes.length > 0 && (
        <View style={styles.results}>
          <Text style={styles.resultsTitle}>Detected Barcodes:</Text>
          {codes.map((code, index) => (
            <View key={index} style={styles.resultItem}>
              <Text style={styles.resultText}>
                {code.symbology}: {code.scannedCode}
              </Text>
            </View>
          ))}
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  controls: {
    position: 'absolute',
    top: 20,
    left: 20,
    right: 20,
    backgroundColor: 'rgba(0, 0, 0, 0.7)',
    padding: 15,
    borderRadius: 10,
  },
  controlText: {
    color: 'white',
    fontSize: 16,
  },
  zoomControl: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    marginTop: 10,
  },
  results: {
    position: 'absolute',
    bottom: 20,
    left: 20,
    right: 20,
    backgroundColor: 'rgba(0, 0, 0, 0.8)',
    padding: 15,
    borderRadius: 10,
  },
  resultsTitle: {
    color: 'white',
    fontSize: 16,
    fontWeight: 'bold',
    marginBottom: 10,
  },
  resultItem: {
    marginVertical: 5,
  },
  resultText: {
    color: 'white',
    fontSize: 14,
  },
});

      

Document Scanner with Auto-Capture

        function DocumentScanner() {
  const [documentDetected, setDocumentDetected] = useState(false);
  const [capturedImages, setCapturedImages] = useState([]);

  return (
    <View style={{ flex: 1 }}>
      <VisionCamera
        scanMode="ocr"
        autoCapture={true}
        style={{ flex: 1 }}
        onRecognitionUpdate={(event) => {
          setDocumentDetected(event.document);
        }}
        onCapture={(event) => {
          console.log('Document captured:', event.image);
          setCapturedImages(prev => [...prev, {
            uri: event.image,
            sharpness: event.sharpnessScore
          }]);
        }}
      />

      {documentDetected && (
        <View style={styles.detectionIndicator}>
          <Text style={styles.indicatorText}>
             Document Detected - Auto-capturing...
          </Text>
        </View>
      )}

      {capturedImages.length > 0 && (
        <View style={styles.captureCount}>
          <Text style={styles.countText}>
            Captured: {capturedImages.length} documents
          </Text>
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  detectionIndicator: {
    position: 'absolute',
    top: 50,
    left: 20,
    right: 20,
    backgroundColor: 'rgba(76, 175, 80, 0.9)',
    padding: 15,
    borderRadius: 10,
    alignItems: 'center',
  },
  indicatorText: {
    color: 'white',
    fontSize: 16,
    fontWeight: 'bold',
  },
  captureCount: {
    position: 'absolute',
    bottom: 30,
    alignSelf: 'center',
    backgroundColor: 'rgba(0, 0, 0, 0.8)',
    padding: 10,
    borderRadius: 8,
  },
  countText: {
    color: 'white',
    fontSize: 14,
  },
});

      

Scan Area Restriction

        function RestrictedScanArea() {
  const screenWidth = Dimensions.get('window').width;
  const screenHeight = Dimensions.get('window').height;

  const scanAreaWidth = 200;
  const scanAreaHeight = 100;
  const scanAreaX = (screenWidth - scanAreaWidth) / 2;
  const scanAreaY = (screenHeight - scanAreaHeight) / 2;

  return (
    <View style={{ flex: 1 }}>
      <VisionCamera
        scanMode="barcode"
        style={{ flex: 1 }}
        scanArea={{
          x: scanAreaX,
          y: scanAreaY,
          width: scanAreaWidth,
          height: scanAreaHeight
        }}
        frameSkip={10} // Process every 10th frame
        onBarcodeDetected={(event) => {
          console.log('Barcode detected in scan area:', event.codes);
        }}
      />

      {/* Visualize scan area */}
      <View style={[styles.scanAreaOverlay, {
        position: 'absolute',
        left: scanAreaX,
        top: scanAreaY,
        width: scanAreaWidth,
        height: scanAreaHeight,
        borderWidth: 2,
        borderColor: '#00FF00',
        backgroundColor: 'transparent',
      }]} />
    </View>
  );
}

      

Performance Tips

  1. Throttle high-frequency events like onSharpnessScoreUpdate and onRecognitionUpdate:

            const lastUpdate = useRef(0);
    const throttleMs = 200;
    
    const handleSharpnessUpdate = (event) => {
      const now = Date.now();
      if (now - lastUpdate.current >= throttleMs) {
        lastUpdate.current = now;
        setSharpness(event.sharpnessScore);
      }
    };
    
          
  2. Use frameSkip to process fewer frames:

            <VisionCamera frameSkip={10} /> // Process every 10th frame
    
          
  3. Use autoCapture={false} for manual control to reduce processing

  4. Cleanup on unmount: The camera automatically stops when unmounted

  5. Avoid hot reload during development: Kill and restart the app for best results


Platform Support

iOS

  • Auto-starts camera when view is mounted
  • Supports all scan modes
  • Flash control available on supported devices
  • Zoom range depends on device capabilities
  • Camera switching fully supported (front/back)

Android

  • Auto-starts camera when view is attached to window
  • Supports all scan modes
  • Flash control available on supported devices
  • Zoom range depends on device capabilities
  • Camera switching placeholder (not yet functional)


Troubleshooting

Camera feed not showing

  • Ensure camera permissions are granted
  • Check that the component has proper dimensions (flex: 1)
  • Verify device has a working camera

Events not firing after hot reload

  • This is a known React Native limitation with native views
  • Workaround: Kill and restart the app instead of hot reloading
  • Note: This does NOT affect production builds

Barcodes not detected

  • Ensure good lighting conditions
  • Check that scanMode is set correctly
  • Verify barcode is within camera view and properly focused

Poor image quality

  • Monitor onSharpnessScoreUpdate - values above 0.7 are generally good
  • Ensure adequate lighting
  • Keep device steady during capture