A Photo

Understanding the Photo type

A Photo is a RAW- or processed in-memory buffer, captured by a CameraPhotoOutput.

See "The Photo Output" for more information about capturing Photos.

Displaying a Photo

A Photo holds an in-memory buffer of its pixels, and can be converted to an Image (from react-native-nitro-image) entirely in-memory by using toImageAsync():

const photo = ...
const image = await photo.toImageAsync()

The image can then be displayed in a <NitroImage /> view:

import { NitroImage } from 'react-native-nitro-image'

function App() {
  const image = ...
  return (
    <NitroImage
      style={{ flex: 1 }}
      image={image}
    />
  )
}

Saving to a File

To save a Photo to an image file, use saveToTemporaryFileAsync(...) or saveToFileAsync(...):

const photo = ...
const path = await photo.saveToTemporaryFileAsync()

Saving to the Camera Roll

After a Photo has been saved to a file, you can save it to the user's Camera Roll using a library like @react-native-camera-roll/camera-roll or expo-media-library.

Container Formats

Photos can be captured in different container formats (see PhotoContainerFormat), which adjusts the capture pipeline's processing steps accordingly - for example, 'dcm' is a RAW format and applies almost no processing in a capture pipeline, whereas 'jpeg' or 'heic' are processed formats and apply color-grading, compression, multi-capture-fusion, HDR, and other processing steps in the capture pipeline.

You can inspect a Photo's PhotoContainerFormat via the containerFormat property:

console.log(photo.containerFormat) // 'jpeg'

Accessing a Photo's Pixel Buffer

Some Photos allow accessing their pixel buffer directly in-memory, without decoding. On iOS, this is often only available on RAW photos (containerFormat == 'dcm'), while on Android this is available on all Photos.

if (photo.hasPixelBuffer) {
  const pixelBuffer = photo.getPixelBuffer()
  const rgba = new Uint8Array(pixelBuffer)
  // process pixels
}

A Photo's Pixel Buffer does not contain any container metadata (JPEG/HEIC headers), or EXIF flags - it's purely pixels.

Accessing the Pixel Buffer via NitroImage

Since a Photo can be converted to an Image (from react-native-nitro-image), it is also a common pattern to access pixels via the react-native-nitro-image APIs;

const photo = ...
const image = await photo.toImageAsync()
const pixelBuffer = await image.toRawPixelData()

Note

It is worth noting that converting to an Image performs an encoding pass, and reading the Pixel Buffer requires a decoding pass.

Accessing a Photo's Pixel Buffer directly does not require any encoding/decoding passes.

Accessing a Photo's Encoded Image Data

The Photo also provides access to its Encoded Image Data - which is what would be written to a File if it was saved - including container metadata and EXIF flags.

You can get the Encoded Image Data via getFileDataAsync(), for example to write this to a network stream entirely in-memory;

const photo = ...
const encodedData = await photo.getFileDataAsync()
// Upload to backend:
await fetch('https://my-backend.com/upload', {
  method: 'POST',
  headers: { 'Content-Type': 'image/jpeg' },
  body: Buffer.from(encodedData)
})

Skia Images

A Photo can also be imported into @shopify/react-native-skia using the Encoded Image Data APIs, which allows you to apply shaders or custom drawing/rendering commands to it:

const photo = ...
const encodedData = await photo.getFileDataAsync()
// Convert Photo to SkImage:
const bytes = new Uint8Array(buffer)
const data = Skia.Data.fromBytes(bytes)
const image = Skia.Image.MakeImageFromEncoded(data)
// Render SkImage in SkCanvas now