Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

ZCamera

React component that renders a native iOS camera preview with hardware-backed C2PA signing.

Usage

import { useRef } from "react";
import { ZCamera, type CaptureInfo } from "@succinctlabs/react-native-zcam1";
 
function CameraScreen({ captureInfo }: { captureInfo: CaptureInfo }) {
  const camera = useRef<ZCamera>(null);
 
  return (
    <ZCamera
      ref={camera}
      captureInfo={captureInfo}
      position="back"
      isActive={true}
      zoom={2.0}
      style={{ flex: 1 }}
    />
  );
}

Props

captureInfo (required)

Capture information from initCapture(). Required for C2PA signing. See initCapture Returns for details.

position

  • Type: "front" | "back"
  • Default: "back"

Which camera to use.

isActive

  • Type: boolean
  • Default: true

Whether the camera is actively running.

captureFormat

  • Type: "jpeg" | "dng"
  • Default: "jpeg"

Desired capture format. When set to "dng", captures RAW DNG file while still producing a C2PA-signed JPEG copy.

zoom

  • Type: number
  • Default: 2.0 (back), 1.0 (front)

Zoom factor. For devices with ultra-wide lens:

  • 1.0 = ultra-wide (0.5x user-facing)
  • 2.0 = wide-angle (1x user-facing)

Use getMinZoom() and getMaxZoom() methods to determine valid range.

torch

  • Type: boolean
  • Default: false

Whether torch (flashlight) is enabled during preview.

exposure

  • Type: number
  • Default: 0

Exposure compensation in EV units.

filmStyle

Film style preset to apply to camera. You can specify a built-in option or a custom film style you defined in customFilmStyles.

filmStyleOverrides

  • Type: Partial<Record<CameraFilmStyle, FilmStyleRecipe>>
  • Optional

Override built-in film style presets with custom recipes. When a preset name is used with filmStyle prop and an override exists, the custom recipe is applied instead.

<ZCamera
  filmStyle="mellow"
  filmStyleOverrides={{
    mellow: [
      { type: "whiteBalance", config: { temperature: 7000, tint: 30 } },
      { type: "saturation", value: 1.3 },
      { type: "contrast", value: 0.85 },
    ]
  }}
/>

customFilmStyles

  • Type: Record<string, FilmStyleRecipe>
  • Optional

Define additional custom film styles by name. Reference them using the filmStyle prop.

<ZCamera
  filmStyle={"myVintage" as CameraFilmStyle}
  customFilmStyles={{
    myVintage: [
      { type: "whiteBalance", config: { temperature: 6800 } },
      { type: "vibrance", value: 0.6 },
      { type: "highlightShadow", config: { highlights: 0.2, shadows: 0.5 } },
    ]
  }}
/>

See FilmStyleEffect for all available effect types.

captureTimestampEnabled

  • Type: boolean
  • Default: false

When true, a trusted GPS timestamp is embedded in the C2PA manifest at capture time. The timestamp is sourced from GPS rather than the device clock, making it tamper-evident. Requires location permission. Stored as trustedTimestamp in PhotoMetadataInfo / VideoMetadataInfo.

captureLocationEnabled

  • Type: boolean
  • Default: false

When true, GPS coordinates are embedded in the C2PA manifest at capture time. Requires location permission. Stored as location (LocationInfo) in photo/video metadata. If retrieval fails, AuthenticityData.isLocationAvailable is set to false and locationRetrievalStatus contains the error reason.

depthEnabled

  • Type: boolean
  • Default: false

Enable depth data capture at session level. When true, depth data can be captured but zoom may be restricted on dual-camera devices.

onOrientationChange

  • Type: (orientation: DeviceOrientation) => void
  • Optional

Callback fired when the device physical orientation changes. Uses accelerometer data, so it works even when iOS orientation lock is enabled. Useful for rotating UI controls to match the device orientation.

<ZCamera
  captureInfo={captureInfo}
  onOrientationChange={(orientation) => {
    // orientation: "portrait" | "landscapeLeft" | "landscapeRight" | "portraitUpsideDown"
    console.log("Device orientation:", orientation);
  }}
/>

See DeviceOrientation for the type definition.

certChain

Certificate chain for signing the C2PA manifest. If not provided, a self-signed certificate is automatically generated.

// Self-signed (default)
type SelfSignedCertChain = {
  signingAlgorithm?: string;  // Default: "ES256"
  tsaUrl?: string;            // Optional timestamp authority URL
}
 
// Existing certificate
type ExistingCertChain = {
  pem: string;  // Certificate chain in PEM format
}
Example:
// Use self-signed (automatic)
<ZCamera captureInfo={captureInfo} />
 
// Or provide custom certificate
<ZCamera 
  captureInfo={captureInfo}
  certChain={{ pem: customCertChainPem }}
/>

style

  • Type: StyleProp<ViewStyle>
  • Optional

Style for the underlying native view.

Methods

takePhoto()

Captures a photo and returns a signed ZPhoto. See takePhoto for details.

getMinZoom()

Gets the minimum supported zoom factor. See getMinZoom.

getMaxZoom()

Gets the maximum supported zoom factor. See getMaxZoom.

hasUltraWideCamera()

Checks if device has an ultra-wide camera. See hasUltraWideCamera.

focusAtPoint(x, y)

Focuses at a specific point in the preview. See focusAtPoint.

setZoomAnimated(factor)

Sets zoom with smooth animation. See setZoomAnimated.

isDepthSupported()

Checks if device supports depth data capture. See isDepthSupported.

getSwitchOverZoomFactors()

Gets the zoom factors where the device switches between physical lenses. See getSwitchOverZoomFactors.

startVideoRecording(position?)

Starts recording a video. See startVideoRecording.

stopVideoRecording()

Stops video recording and returns the finalized file. See stopVideoRecording.

getDeviceDiagnostics()

Returns diagnostic information about the current camera device.

const diagnostics = await camera.current?.getDeviceDiagnostics();

Returns: Promise<DeviceDiagnostics>

type DeviceDiagnostics = {
  deviceType: string;          // e.g., "builtInTripleCamera"
  minZoom: number;             // Minimum zoom factor
  maxZoom: number;             // Maximum zoom factor
  currentZoom: number;         // Current zoom factor
  switchOverFactors: number[]; // Lens switch points
  switchingBehavior: number;   // AVFoundation switching behavior
  isVirtualDevice: boolean;    // Whether device is virtual (multi-camera)
  currentExposureBias: number; // Current exposure compensation (EV)
  minExposureBias: number;     // Min supported exposure compensation
  maxExposureBias: number;     // Max supported exposure compensation
  currentISO: number;          // Current ISO value
  exposureDuration: number;    // Current exposure duration (seconds)
}

Useful for debugging zoom issues on different device configurations.

hasDepthZoomLimitations()

Checks if enabling depth would restrict zoom on this device.

const hasLimitations = await camera.current?.hasDepthZoomLimitations();

Returns: Promise<boolean> - true if zoom is limited to discrete levels when depth is enabled (typically dual-camera devices), false for triple-camera devices.

getDepthSupportedZoomRanges()

Gets the zoom ranges supported when depth data delivery is enabled.

const ranges = await camera.current?.getDepthSupportedZoomRanges();
// Example: [[2.0, 2.0], [4.0, 4.0]] for discrete levels
// Example: [[1.0, 6.0]] for continuous zoom

Returns: Promise<number[][]> - Array of [min, max] pairs. If min == max, it's a discrete level.

Example

import { useEffect, useRef, useState } from "react";
import { View, Button, StyleSheet } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { initCapture, ZCamera, type CaptureInfo } from "@succinctlabs/react-native-zcam1";
 
export function CaptureScreen() {
  const camera = useRef<ZCamera>(null);
  const [captureInfo, setCaptureInfo] = useState<CaptureInfo>();
 
  useEffect(() => {
    initCapture({
      appId: process.env.EXPO_PUBLIC_APP_ID!,
      production: false,
    }).then(setCaptureInfo);
  }, []);
 
  const handleCapture = async () => {
    const photo = await camera.current?.takePhoto();
    console.log("Captured:", photo?.path);
  };
 
  if (!captureInfo) return null;
 
  return (
    <SafeAreaView style={styles.container}>
      <ZCamera 
        ref={camera} 
        captureInfo={captureInfo} 
        style={styles.camera}
        filmStyle="mellow"
        zoom={2.0}
      />
      <View style={styles.controls}>
        <Button title="Capture" onPress={handleCapture} />
      </View>
    </SafeAreaView>
  );
}
 
const styles = StyleSheet.create({
  container: { flex: 1 },
  camera: { flex: 1 },
  controls: { padding: 16 },
});