import type { Image } from 'react-native-nitro-image'
import type { HybridObject } from 'react-native-nitro-modules'
import type { CameraOrientation } from '../common-types/CameraOrientation'
import type { PhotoContainerFormat } from '../common-types/PhotoContainerFormat'
import type {
CameraPhotoOutput,
CapturePhotoSettings,
} from '../outputs/CameraPhotoOutput.nitro'
import type { CameraCalibrationData } from './CameraCalibrationData.nitro'
import type { Depth } from './Depth.nitro'
/**
* Represents a captured {@linkcode Photo} in-memory.
*
* {@linkcode Photo | Photos} can be captured with
* a {@linkcode CameraPhotoOutput}, and can be saved
* to a file using {@linkcode Photo.saveToTemporaryFileAsync | saveToTemporaryFileAsync()}.
*
* To display the photo to the user, use
* {@linkcode Photo.toImageAsync | toImageAsync()}, then
* display that using `react-native-nitro-image`'s
* `` component.
*
* @note
* As with all in-memory objects holding large native memory
* such as Photos, Frames, Images or more, make sure to
* {@linkcode Photo.dispose | dispose()} the Photo once you
* are no longer using it, as otherwise the JS Runtime might
* not immediately delete it, possibly exhausting system resources.
*
* @example
* Display the Photo to the user using `react-native-nitro-image`:
* ```tsx
* const photoOutput = ...
* const [image, setImage] = useState()
*
* const takePhoto = async () => {
* const photo = await photoOutput.capturePhoto({}, {})
* const img = await photo.toImageAsync()
* setImage(img)
* photo.dispose()
* }
*
* return
* ```
* @example
* Save the photo to a temporary file:
* ```ts
* const photoOutput = ...
*
* const takePhoto = async () => {
* const photo = await photoOutput.capturePhoto({}, {})
* const image = await photo.toImageAsync()
* photo.dispose()
* }
* ```
* @example
* Convert the Photo to a Skia Image:
* ```ts
* const photoOutput = ...
* const photo = await photoOutput.capturePhoto({}, {})
* const encodedData = await photo.getFileDataAsync()
* const bytes = new Uint8Array(encodedData)
* const data = Skia.Data.fromBytes(bytes)
* const skiaImage = Skia.Image.MakeImageFromEncoded(data)
* photo.dispose()
* ```
*/
export interface Photo
extends HybridObject<{ ios: 'swift'; android: 'kotlin' }> {
/**
* Gets whether this {@linkcode Photo} is mirrored alongside the
* vertical axis.
*/
readonly isMirrored: boolean
/**
* Gets the {@linkcode CameraOrientation} this {@linkcode Photo} was
* captured in.
*
* {@linkcode CameraOrientation} will be applied lazily via EXIF
* flags, or when converting the {@linkcode Photo} to an
* {@linkcode Image}.
*/
readonly orientation: CameraOrientation
/**
* Represents the timestamp this {@linkcode Photo} was
* captured at, using the system's host clock, in seconds.
*/
readonly timestamp: number
/**
* Gets whether this {@linkcode Photo} is a RAW photo (i.e.
* no processing has been applied), or a processed photo (e.g.
* JPEG).
* @see {@linkcode containerFormat}
*/
readonly isRawPhoto: boolean
/**
* Get the width of this {@linkcode Photo}, in pixels.
*/
readonly width: number
/**
* Get the height of this {@linkcode Photo}, in pixels.
*/
readonly height: number
/**
* Get the {@linkcode PhotoContainerFormat} of
* this {@linkcode Photo}.
*/
readonly containerFormat: PhotoContainerFormat
// TODO: Expose EXIF Metadata
// readonly exifMetadata: AnyMap
/**
* Get whether this {@linkcode Photo} has
* a native pixel buffer attached to it,
* which allows reading its pixels from JS.
* @see {@linkcode getPixelBuffer | getPixelBuffer()}
*/
readonly hasPixelBuffer: boolean
/**
* Get the {@linkcode Photo}'s native pixel
* buffer. This allows readonly access
* to the individual pixels.
*
* This does not contain any EXIF data.
* @throws If {@linkcode hasPixelBuffer} is false.
*/
getPixelBuffer(): ArrayBuffer
/**
* Get the associated {@linkcode Depth} data
* for this {@linkcode Photo} if it has one.
* @see {@linkcode CapturePhotoSettings.enableDepthData}
*/
readonly depth?: Depth
/**
* Get the associated {@linkcode CameraCalibrationData}
* for this {@linkcode Photo} if calibration data delivery
* was enabled.
*
* @see {@linkcode CapturePhotoSettings.enableCameraCalibrationDataDelivery}
* @platform iOS
*/
readonly calibrationData?: CameraCalibrationData
/**
* Asynchronously saves this {@linkcode Photo} to
* a file at the given {@linkcode path}, using this
* {@linkcode containerFormat}.
*
* @param path The path to save the Image to.
* Must contain a full path name including filename
* and extension. All parent directories must exist,
* but the file itself must not exist.
* This must be a filesystem path, not a `file://` URL.
*/
saveToFileAsync(path: string): Promise
/**
* Asynchronously saves this {@linkcode Photo} to
* a temporary file using this {@linkcode containerFormat},
* and returns the path it was saved at.
*
* The returned value is a filesystem path, not a `file://` URL.
*/
saveToTemporaryFileAsync(): Promise
/**
* Gets the raw file data of the {@linkcode Photo} after
* processing and including EXIF flags.
*/
getFileData(): ArrayBuffer
/**
* Asynchronously gets the raw file data of
* the {@linkcode Photo} after processing
* and including EXIF flags.
*/
getFileDataAsync(): Promise
/**
* Converts this {@linkcode Photo} to an {@linkcode Image},
* possibly applying {@linkcode orientation} and {@linkcode isMirrored}
* settings.
* @throws If the {@linkcode Photo} is a raw photo (see {@linkcode isRawPhoto})
* @throws If the {@linkcode Photo}'s Image data cannot be accessed
*/
toImage(): Image
/**
* Asynchronously converts this {@linkcode Photo} to an {@linkcode Image},
* possibly applying {@linkcode orientation} and {@linkcode isMirrored}
* settings.
* @throws If the {@linkcode Photo} is a raw photo (see {@linkcode isRawPhoto})
* @throws If the {@linkcode Photo}'s Image data cannot be accessed
*/
toImageAsync(): Promise
}