Skip to main content
Images are essential for creating rich visual experiences. React Native Skia provides powerful tools for loading, displaying, and manipulating images from various sources.

Loading Images

useImage Hook

The useImage hook is the primary way to load images. It returns an SkImage instance or null while loading.
import { useImage } from "@shopify/react-native-skia";

// From JavaScript bundle
const image1 = useImage(require("./assets/oslo.jpg"));

// From network
const image2 = useImage("https://picsum.photos/200/300");

// From native bundle (Android/iOS)
const image3 = useImage("Logo");

Error Handling

The hook provides an optional error handler:
const image = useImage(
  require("./assets/photo.jpg"),
  (error) => {
    console.error("Failed to load image:", error);
  }
);

MakeImageFromEncoded

Create images from encoded data:
import { Skia } from "@shopify/react-native-skia";

// From base64 string
const data = Skia.Data.fromBase64(
  "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=="
);
const image = Skia.Image.MakeImageFromEncoded(data);

MakeImage

Create images from raw pixel data:
import { Skia, AlphaType, ColorType } from "@shopify/react-native-skia";

// Create a 256x256 image with custom pixels
const pixels = new Uint8Array(256 * 256 * 4);
pixels.fill(255);

let i = 0;
for (let x = 0; x < 256; x++) {
  for (let y = 0; y < 256; y++) {
    pixels[i++] = (x * y) % 255; // Red
    pixels[i++] = x % 255;        // Green
    pixels[i++] = y % 255;        // Blue
    pixels[i++] = 255;            // Alpha
  }
}

const data = Skia.Data.fromBytes(pixels);
const image = Skia.Image.MakeImage(
  {
    width: 256,
    height: 256,
    alphaType: AlphaType.Opaque,
    colorType: ColorType.RGBA_8888,
  },
  data,
  256 * 4 // bytes per row
);

Image Component

The Image component displays images on the canvas.

Props

NameTypeDescription
imageSkImageThe image instance to display
xnumberLeft position of the destination
ynumberTop position of the destination
widthnumberWidth of the destination
heightnumberHeight of the destination
fitFitHow the image fits in the rectangle (default: contain)
samplingSamplingSampling method for quality control

Basic Example

import { Canvas, Image, useImage } from "@shopify/react-native-skia";

const ImageDemo = () => {
  const image = useImage(require("./assets/oslo.jpg"));
  
  if (!image) {
    return null; // Still loading
  }
  
  return (
    <Canvas style={{ flex: 1 }}>
      <Image 
        image={image} 
        fit="contain" 
        x={0} 
        y={0} 
        width={256} 
        height={256} 
      />
    </Canvas>
  );
};

Fit Modes

Control how images fit within their bounds:

contain

Fits the entire image within the bounds, maintaining aspect ratio:
<Image image={image} fit="contain" x={0} y={0} width={256} height={256} />

cover

Covers the entire bounds, may crop the image:
<Image image={image} fit="cover" x={0} y={0} width={256} height={256} />

fill

Stretches the image to fill the bounds:
<Image image={image} fit="fill" x={0} y={0} width={256} height={256} />

fitWidth

Scales to match width, maintains aspect ratio:
<Image image={image} fit="fitWidth" x={0} y={0} width={256} height={256} />

fitHeight

Scales to match height, maintains aspect ratio:
<Image image={image} fit="fitHeight" x={0} y={0} width={256} height={256} />

scaleDown

Like contain, but never scales up:
<Image image={image} fit="scaleDown" x={0} y={0} width={256} height={256} />

none

No fitting applied, uses image’s natural size:
<Image image={image} fit="none" x={0} y={0} width={256} height={256} />

Sampling Options

Control image quality and performance:

Cubic Sampling (Best Quality)

Use cubic sampling for high-quality rendering:
import { Canvas, Image, useImage, CubicSampling } from "@shopify/react-native-skia";

const HighQuality = () => {
  const image = useImage(require("./assets/photo.jpg"));
  
  return (
    <Canvas style={{ flex: 1 }}>
      <Image
        image={image}
        fit="contain"
        x={0}
        y={0}
        width={256}
        height={256}
        sampling={CubicSampling}
      />
    </Canvas>
  );
};

Custom Cubic Sampling

import { Canvas, Image, useImage } from "@shopify/react-native-skia";

const CustomCubic = () => {
  const image = useImage(require("./assets/photo.jpg"));
  
  return (
    <Canvas style={{ flex: 1 }}>
      <Image
        image={image}
        fit="contain"
        x={0}
        y={0}
        width={256}
        height={256}
        sampling={{ B: 0, C: 0.5 }}
      />
    </Canvas>
  );
};

Filter and Mipmap Modes

import { Canvas, Image, useImage, FilterMode, MipmapMode } from "@shopify/react-native-skia";

const FilterExample = () => {
  const image = useImage(require("./assets/photo.jpg"));
  
  return (
    <Canvas style={{ flex: 1 }}>
      {/* Nearest filter - fastest, lowest quality */}
      <Image
        image={image}
        x={0}
        y={0}
        width={128}
        height={128}
        sampling={{ filter: FilterMode.Nearest, mipmap: MipmapMode.None }}
      />
      
      {/* Linear filter - better quality */}
      <Image
        image={image}
        x={128}
        y={0}
        width={128}
        height={128}
        sampling={{ filter: FilterMode.Linear, mipmap: MipmapMode.Linear }}
      />
    </Canvas>
  );
};

Image Instance Methods

Once loaded, SkImage instances provide useful methods:

Dimensions

const width = image.width();
const height = image.height();
const info = image.getImageInfo();

Encoding

Export images to various formats:
// As bytes (PNG by default)
const bytes = image.encodeToBytes();

// As JPEG with quality
const jpegBytes = image.encodeToBytes(ImageFormat.JPEG, 90);

// As base64 string
const base64 = image.encodeToBase64();
const jpegBase64 = image.encodeToBase64(ImageFormat.JPEG, 80);

Reading Pixels

// Read all pixels
const pixels = image.readPixels();

// Read a region
const regionPixels = image.readPixels(10, 10, {
  width: 100,
  height: 100,
  alphaType: AlphaType.Premul,
  colorType: ColorType.RGBA_8888,
});

Creating Shaders

import { TileMode } from "@shopify/react-native-skia";

// With filter options
const shader = image.makeShaderOptions(
  TileMode.Repeat,
  TileMode.Repeat,
  FilterMode.Linear,
  MipmapMode.None
);

// With cubic sampling
const cubicShader = image.makeShaderCubic(
  TileMode.Clamp,
  TileMode.Clamp,
  0,
  0.5
);

Advanced Techniques

Image Clipping

import { Canvas, Image, useImage, Circle } from "@shopify/react-native-skia";

const ClippedImage = () => {
  const image = useImage(require("./assets/photo.jpg"));
  
  return (
    <Canvas style={{ flex: 1 }}>
      <Circle cx={128} cy={128} r={100}>
        <Image image={image} fit="cover" x={0} y={0} width={256} height={256} />
      </Circle>
    </Canvas>
  );
};

Image Transformations

import { Canvas, Group, Image, useImage } from "@shopify/react-native-skia";

const TransformedImage = () => {
  const image = useImage(require("./assets/photo.jpg"));
  
  return (
    <Canvas style={{ flex: 1 }}>
      <Group transform={[{ rotate: Math.PI / 4 }]}>
        <Image image={image} x={0} y={0} width={256} height={256} />
      </Group>
    </Canvas>
  );
};

Image with Effects

import { Canvas, Image, useImage, Blur, ColorMatrix } from "@shopify/react-native-skia";

const ImageWithEffects = () => {
  const image = useImage(require("./assets/photo.jpg"));
  
  return (
    <Canvas style={{ flex: 1 }}>
      <Image image={image} x={0} y={0} width={256} height={256}>
        <Blur blur={5} />
        <ColorMatrix
          matrix={[
            0.95, 0, 0, 0, 0.05,
            0.65, 0, 0, 0, 0.15,
            0.15, 0, 0, 0, 0.5,
            0, 0, 0, 1, 0,
          ]}
        />
      </Image>
    </Canvas>
  );
};

Performance Tips

  • Cache loaded images with useImage
  • Use appropriate sampling modes for your use case
  • Consider image dimensions - smaller is faster
  • Preload images when possible
  • Use fitWidth or fitHeight when appropriate
  • Optimize image formats (WebP, JPEG) before bundling

Common Patterns

Conditional Rendering

const ImageDemo = () => {
  const image = useImage(require("./assets/photo.jpg"));
  
  return (
    <Canvas style={{ flex: 1 }}>
      {image && (
        <Image image={image} x={0} y={0} width={256} height={256} />
      )}
    </Canvas>
  );
};

Multiple Images

const Gallery = () => {
  const image1 = useImage(require("./assets/photo1.jpg"));
  const image2 = useImage(require("./assets/photo2.jpg"));
  
  return (
    <Canvas style={{ flex: 1 }}>
      {image1 && <Image image={image1} x={0} y={0} width={128} height={128} />}
      {image2 && <Image image={image2} x={128} y={0} width={128} height={128} />}
    </Canvas>
  );
};

See Also

Build docs developers (and LLMs) love