react-native-vision-camera
Version:
VisionCamera is the fastest and most powerful Camera for react-native.
363 lines (352 loc) • 12 kB
text/typescript
import type { Image } from 'react-native-nitro-image'
import type { usePhotoOutput } from '../../hooks/usePhotoOutput'
import type { TargetPhotoContainerFormat } from '../common-types/PhotoContainerFormat'
import type { QualityPrioritization } from '../common-types/QualityPrioritization'
import type { Size } from '../common-types/Size'
import type { CameraDevice } from '../inputs/CameraDevice.nitro'
import type { Photo } from '../instances/Photo.nitro'
import type { Location } from '../location/Location.nitro'
import type { CameraSession } from '../session/CameraSession.nitro'
import type { CameraSessionConfig } from '../session/CameraSessionConfig.nitro'
import type { CameraOutput } from './CameraOutput.nitro'
// TODO: Move depth data into configuration upfront, I think we need to prepare the Photo Output for that natively.
// TODO: I think there is no way to get `containerFormat` upfront - we dont know what formats are supported! We need to expose that probably via `CameraDevice.supportedPhotoContainerFormats`
/**
* Configuration options for a {@linkcode CameraPhotoOutput}.
*
* @see {@linkcode CameraPhotoOutput}
* @see {@linkcode usePhotoOutput | usePhotoOutput(...)}
*/
export interface PhotoOutputOptions {
/**
* The target Photo Resolution to use.
*
* @discussion
* The {@linkcode CameraSession} will negotiate all
* output {@linkcode targetResolution}s and constraints (such
* as HDR, FPS, etc) in a {@linkcode CameraSessionConfig} to
* finalize the Resolution used for the Output.
* This is therefore merely a resolution _target_, and may
* not be exactly met.
*
* If the given {@linkcode targetResolution} cannot be met
* exactly, its aspect ratio (computed by
* {@linkcode Size.width} / {@linkcode Size.height}) will
* be prioritized over pixel count.
*/
targetResolution: Size
/**
* Specifies the {@linkcode TargetPhotoContainerFormat} to
* shoot the {@linkcode Photo} in.
*/
containerFormat: TargetPhotoContainerFormat
/**
* Defines the compression quality for processed photo formats.
*
* The value must be within the normalized range from `0.0` to `1.0`,
* where `1.0` is the highest quality and `0.0` is the strongest compression.
*
* RAW photo formats such as {@linkcode TargetPhotoContainerFormat | 'dng'}
* ignore this option.
*
* @default 0.9 in {@linkcode usePhotoOutput | usePhotoOutput(...)}
*/
quality: number
/**
* Specifies the balance between speed or image quality for
* the photo capture pipeline.
*
* The currently selected {@linkcode CameraDevice} must support
* {@linkcode QualityPrioritization} {@linkcode QualityPrioritization | 'speed'}
* (see {@linkcode CameraDevice.supportsSpeedQualityPrioritization | supportsSpeedQualityPrioritization}),
* otherwise an error will be thrown.
*
* @see {@linkcode CameraDevice.supportsSpeedQualityPrioritization}
*/
qualityPrioritization: QualityPrioritization
/**
* When this is set to a specific {@linkcode Size},
* a ready to display {@linkcode Image} will be delivered
* just before the resulting {@linkcode Photo} is available.
*
* Preview Image delivery requires additional processing,
* so this is disabled by default.
*
* If this is `undefined` (the default), no preview Image
* will be supplied.
*
* It is recommended to set this to a {@linkcode Size}
* that is as low as possible to avoid unnecessary overhead.
*
* @see {@linkcode CapturePhotoCallbacks.onPreviewImageAvailable}
* @default undefined
*/
previewImageTargetSize?: Size
}
/**
* Callbacks for a {@linkcode CameraPhotoOutput.capturePhoto | capturePhoto(...)}
* call.
*
* @see {@linkcode CameraPhotoOutput}
*/
export interface CapturePhotoCallbacks {
/**
* Called when the pipeline starts
* the capture.
*/
onWillBeginCapture?: () => void
/**
* Called just before the pipeline
* starts capturing the photo.
*/
onWillCapturePhoto?: () => void
/**
* Called just after the pipeline
* captured a photo.
*/
onDidCapturePhoto?: () => void
/**
* Called just after {@linkcode onWillBeginCapture}
* with an {@linkcode Image} suitable for preview
* or thumbnail updates.
*
* This will only be called if a preview image
* size is set via {@linkcode PhotoOutputOptions.previewImageTargetSize},
* and the {@linkcode CameraDevice} supports preview
* images (see {@linkcode CameraDevice.supportsPreviewImage}).
*/
onPreviewImageAvailable?: (previewImage: Image) => void
}
/**
* Configures flash for photo capture.
*
* @see {@linkcode CameraPhotoOutput.capturePhoto | capturePhoto(...)}
*/
export type FlashMode = 'off' | 'on' | 'auto'
/**
* Configuration options for a
* {@linkcode CameraPhotoOutput.capturePhoto | capturePhoto(...)} call.
*
* @see {@linkcode CameraPhotoOutput}
*/
export interface CapturePhotoSettings {
/**
* Configures the {@linkcode FlashMode} for this Photo
* capture.
*
* @throws If {@linkcode FlashMode} is `'on'`, but
* the {@linkcode CameraDevice} does not have a
* flash - see {@linkcode CameraDevice.hasFlash}
* @default 'off'
*/
flashMode?: FlashMode
/**
* Enables or disables the system shutter sound.
* The shutter sound is fired exactly when a photo will be captured.
*
* The OS may choose to override this behaviour, e.g. if
* regional sound-suppression settings are applied.
*
* @default true
*/
enableShutterSound?: boolean
// TODO: separate enableDepthData with embedsDepthDataInPhoto
/**
* Enables or disables depth data delivery in the resulting
* {@linkcode Photo}.
*
* Depth data will be embedded in the Photo and can be accessed
* via {@linkcode Photo.depth}.
*
* {@linkcode enableDepthData} can only be enabled if the
* {@linkcode CameraPhotoOutput} supports depth data - see
* {@linkcode CameraPhotoOutput.supportsDepthDataDelivery}.
*
* @default false
*/
enableDepthData?: boolean
/**
* Specifies whether red-eye reduction should be applied
* automatically on flash captures.
*
* When {@linkcode flashMode} is {@linkcode FlashMode | 'off'},
* red eye reduction is automataically disabled.
*
* @default true
*/
enableRedEyeReduction?: boolean
/**
* Specifies whether the capture pipeline should
* deliver Camera calibration data.
*
* A {@linkcode Photo}'s calibration data can be accessed via
* {@linkcode Photo.calibrationData | Photo.calibrationData}.
*
* @platform iOS
* @default false
*/
enableCameraCalibrationDataDelivery?: boolean
/**
* Specifies whether the capture pipeline should
* automatically correct lens distortion.
*
* @note If enabled, captured photos will look
* slightly different compared to the Preview
* because the field-of-view might be narrower.
*
* @default false
*/
enableDistortionCorrection?: boolean
/**
* Enables or disables virtual device image fusion.
*
* If enabled, the Camera pipeline may capture photos
* from multiple constituent physical Camera devices at once
* (if using a Camera device that has multiple physical devices)
* to improve still image quality.
*
* When capturing RAW photos, this is disabled.
*
* @default true
*/
enableVirtualDeviceFusion?: boolean
/**
* Sets the given {@linkcode Location} to be embedded
* into the EXIF data of the captured {@linkcode Photo}.
*
* @default undefined
*/
location?: Location
}
/**
* Represents a Photo written to a File.
*/
export interface PhotoFile {
/**
* The path of the file.
* This is a filesystem path, not a `file://` URL.
*/
filePath: string
}
/**
* The {@linkcode CameraPhotoOutput} allows capturing {@linkcode Photo}s
* in-memory, as well as directly to a file.
*
* In-memory {@linkcode Photo}s can be converted to Images for immediate
* display, and/or saved to a file (or the media gallery) later on.
*
* @see {@linkcode PhotoOutputOptions}
* @see {@linkcode CapturePhotoSettings}
* @see {@linkcode usePhotoOutput | usePhotoOutput(...)}
* @example
* Creating a `CameraPhotoOutput` via the Hooks API:
* ```ts
* const photoOutput = usePhotoOutput()
* ```
*
* @example
* Creating a `CameraPhotoOutput` via the Imperative API:
* ```ts
* const photoOutput = VisionCamera.createPhotoOutput({
* targetResolution: CommonResolutions.UHD_4_3,
* containerFormat: 'native',
* quality: 0.9,
* qualityPrioritization: 'balanced',
* })
* ```
*/
export interface CameraPhotoOutput extends CameraOutput {
/**
* Get whether this {@linkcode CameraPhotoOutput} supports
* capturing depth data alongside with a normal {@linkcode Photo},
* e.g. for portrait effects matte.
* @see {@linkcode CapturePhotoSettings.enableDepthData}
*/
readonly supportsDepthDataDelivery: boolean
/**
* get whether this {@linkcode CameraPhotoOutput} supports
* delivering camera calibration data, e.g. for reconstructing
* lens-distortion or geometry.
* @see {@linkcode CapturePhotoSettings.enableCameraCalibrationDataDelivery}
*/
readonly supportsCameraCalibrationDataDelivery: boolean
// TODO: Add prepareSettings(...)
/**
* Captures a {@linkcode Photo} using the given
* {@linkcode CapturePhotoSettings}.
*
* @note
* On Android, it is recommended to use
* {@linkcode capturePhoto | capturePhoto(...)} only
* for {@linkcode TargetPhotoContainerFormat | 'jpeg'} images, and use
* {@linkcode capturePhotoToFile | capturePhotoToFile(...)}
* for any other formats (such as RAW ({@linkcode TargetPhotoContainerFormat | 'dng'}),
* as CameraX does not properly support in-memory Photos for formats like RAW yet.
* See https://issuetracker.google.com/u/3/issues/482079661 for more information.
*
* @note
* The {@linkcode Photo} has to be `dispose()`'d after it
* is no longer used, as otherwise the JS Runtime might not
* immediately delete it, possibly exhausting system resources.
*
* @example
* ```ts
* const photo = await photoOutput.capturePhoto(
* { flashMode: 'on' },
* {}
* )
* // ...
* photo.dispose()
* ```
*/
capturePhoto(
settings: CapturePhotoSettings,
callbacks: CapturePhotoCallbacks,
): Promise<Photo>
/**
* Captures a Photo and writes it to a temporary file
* using the given {@linkcode CapturePhotoSettings}.
* @example
* ```ts
* const photoFile = await photoOutput.capturePhotoToFile(
* { flashMode: 'on' },
* {}
* )
* ```
*/
capturePhotoToFile(
settings: CapturePhotoSettings,
callbacks: CapturePhotoCallbacks,
): Promise<PhotoFile>
/**
* Asynchronously prepares the {@linkcode CameraPhotoOutput}
* with the given {@linkcode settings} array to improve capture
* responsiveness for subsequent {@linkcode capturePhoto | capturePhoto(...)}
* calls when called with any of the same {@linkcode CapturePhotoSettings}
* that have been prepared via this method.
*
* @discussion
* It is recommended to always call this with a few common
* settings you expect to be used for {@linkcode capturePhoto | capturePhoto(...)}
* later on.
*
* It is perfectly fine to not call {@linkcode prepareSettings | prepareSettings(...)}
* when using Photo capture, but {@linkcode capturePhoto | capturePhoto(...)} may
* allocate buffers that cause higher latency on initial calls when aiming for quality.
*
* On Android, this method is no-op.
*
* @example
* ```ts
* const photoOutput = usePhotoOutput({})
*
* useEffect(() => {
* photoOutput.prepareSettings([
* { flashMode: 'off', enableDistortionCorrection: true },
* { flashMode: 'on', enableDistortionCorrection: false },
* ])
* }, [])
* ```
*/
prepareSettings(settings: CapturePhotoSettings[]): Promise<void>
}