Skip to main content
The Image component renders images from various sources including files, network URLs, and data URIs.

Basic Usage

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

export default function ImageExample() {
  const image = useImage(require("./photo.jpg"));
  
  if (!image) {
    return null; // Loading
  }
  
  return (
    <Canvas style={{ flex: 1 }}>
      <Image
        image={image}
        x={0}
        y={0}
        width={300}
        height={300}
        fit="cover"
      />
    </Canvas>
  );
}

Loading Images

useImage Hook

Load images from various sources:
import { useImage } from "@shopify/react-native-skia";

// From require
const localImage = useImage(require("./image.png"));

// From URL
const remoteImage = useImage("https://example.com/image.jpg");

// From file path
const fileImage = useImage("file:///path/to/image.png");

// From data URI
const dataImage = useImage("data:image/png;base64,iVBORw0KG...");

Imperative Loading

import { Skia } from "@shopify/react-native-skia";
import { useEffect, useState } from "react";

export default function LoadImage() {
  const [image, setImage] = useState(null);
  
  useEffect(() => {
    const loadImage = async () => {
      const response = await fetch("https://example.com/image.jpg");
      const data = await response.arrayBuffer();
      const img = Skia.Image.MakeImageFromEncoded(
        new Uint8Array(data)
      );
      setImage(img);
    };
    loadImage();
  }, []);
  
  return image;
}

Image Component Props

image
SkImage
required
The image object to render
x
number
required
X-coordinate of the image position
y
number
required
Y-coordinate of the image position
width
number
required
Width to render the image
height
number
required
Height to render the image
fit
Fit
default:"'contain'"
How the image should fit within the specified dimensions:
  • contain: Scale to fit inside while maintaining aspect ratio
  • cover: Scale to fill while maintaining aspect ratio
  • fill: Stretch to fill dimensions
  • fitHeight: Fit to height, may overflow width
  • fitWidth: Fit to width, may overflow height
  • scaleDown: Like contain but never scale up
  • none: No scaling
sampling
SamplingOptions
Sampling/filtering options for image scaling:
  • { filter: FilterMode.Linear } - Linear filtering (default)
  • { filter: FilterMode.Nearest } - Nearest neighbor (pixelated)
  • { B: number, C: number } - Cubic resampling (Mitchell-Netravali)

Fit Modes

Contain

Fits image inside bounds while preserving aspect ratio:
<Image
  image={image}
  x={0}
  y={0}
  width={300}
  height={300}
  fit="contain"
/>

Cover

Fills bounds while preserving aspect ratio (may crop):
<Image
  image={image}
  x={0}
  y={0}
  width={300}
  height={300}
  fit="cover"
/>

Fill

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

Image Sampling

Linear Filtering (Default)

Smooth scaling:
<Image
  image={image}
  fit="cover"
  sampling={{ filter: FilterMode.Linear }}
/>

Nearest Neighbor

Pixelated look (good for pixel art):
<Image
  image={image}
  fit="cover"
  sampling={{ filter: FilterMode.Nearest }}
/>

Cubic Resampling

High quality scaling:
import { MitchellCubicSampling } from "@shopify/react-native-skia";

<Image
  image={image}
  fit="cover"
  sampling={MitchellCubicSampling} // { B: 1/3, C: 1/3 }
/>

Image Shaders

Use images as patterns:
import { Canvas, Rect, ImageShader, useImage } from "@shopify/react-native-skia";

export default function ImagePattern() {
  const pattern = useImage(require("./pattern.png"));
  
  if (!pattern) return null;
  
  return (
    <Canvas style={{ flex: 1 }}>
      <Rect x={0} y={0} width={400} height={400}>
        <ImageShader
          image={pattern}
          tx="repeat"
          ty="repeat"
          fit="none"
        />
      </Rect>
    </Canvas>
  );
}

Image Effects

Blur

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

const image = useImage(require("./photo.jpg"));

<Canvas style={{ flex: 1 }}>
  <Image image={image} x={0} y={0} width={300} height={300} fit="cover">
    <Blur blur={10} />
  </Image>
</Canvas>

Color Tint

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

const image = useImage(require("./photo.jpg"));

<Canvas style={{ flex: 1 }}>
  <Image image={image} x={0} y={0} width={300} height={300} fit="cover">
    <ColorMatrix
      matrix={[
        1, 0, 0, 0, 0,
        0, 0.8, 0, 0, 0,
        0, 0, 0.8, 0, 0,
        0, 0, 0, 1, 0,
      ]}
    />
  </Image>
</Canvas>

Rounded Corners

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

const image = useImage(require("./photo.jpg"));
const clipPath = rrect(rect(0, 0, 300, 300), 20, 20);

<Canvas style={{ flex: 1 }}>
  <Group clip={clipPath}>
    <Image image={image} x={0} y={0} width={300} height={300} fit="cover" />
  </Group>
</Canvas>

Image Methods

SkImage objects have useful methods:
const image = useImage(require("./photo.jpg"));

if (image) {
  // Get dimensions
  const width = image.width();
  const height = image.height();
  
  // Get image info
  const info = image.getImageInfo();
  console.log(info); // { width, height, colorType, alphaType }
  
  // Encode to format
  const pngData = image.encodeToBytes(ImageFormat.PNG);
  const jpegData = image.encodeToBytes(ImageFormat.JPEG, 90);
  
  // Encode to base64
  const base64 = image.encodeToBase64(ImageFormat.PNG);
  
  // Create shader from image
  const shader = image.makeShaderOptions(
    TileMode.Repeat,
    TileMode.Repeat,
    FilterMode.Linear,
    MipmapMode.None
  );
  
  // Read pixel data
  const pixels = image.readPixels();
}

Animated Images

For GIFs and animated WebP:
import { Canvas, Image, useAnimatedImage } from "@shopify/react-native-skia";
import { useEffect } from "react";

export default function AnimatedGif() {
  const image = useAnimatedImage(require("./animated.gif"));
  
  useEffect(() => {
    if (image) {
      const id = setInterval(() => {
        image.decodeNextFrame();
      }, 1000 / 30); // 30 fps
      
      return () => clearInterval(id);
    }
  }, [image]);
  
  if (!image) return null;
  
  return (
    <Canvas style={{ flex: 1 }}>
      <Image
        image={image.currentFrame}
        x={0}
        y={0}
        width={300}
        height={300}
        fit="contain"
      />
    </Canvas>
  );
}

SVG Images

Render SVG files:
import { Canvas, ImageSVG, useSVG } from "@shopify/react-native-skia";

export default function SVGExample() {
  const svg = useSVG(require("./image.svg"));
  
  if (!svg) return null;
  
  return (
    <Canvas style={{ flex: 1 }}>
      <ImageSVG
        svg={svg}
        x={0}
        y={0}
        width={300}
        height={300}
      />
    </Canvas>
  );
}

Image Formats

Supported Formats

  • PNG (with transparency)
  • JPEG
  • WebP (including animated)
  • GIF (including animated)
  • BMP
  • ICO

Encoding Formats

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

// Encode to PNG (lossless, supports transparency)
const pngBytes = image.encodeToBytes(ImageFormat.PNG, 100);

// Encode to JPEG (lossy, smaller files, no transparency)
const jpegBytes = image.encodeToBytes(ImageFormat.JPEG, 90);

// Encode to WebP (modern format, good compression)
const webpBytes = image.encodeToBytes(ImageFormat.WEBP, 90);

Performance Tips

  • Preload images with useImage hook
  • Use appropriate image formats (JPEG for photos, PNG for graphics)
  • Choose correct sampling mode (nearest for pixel art, linear for photos)
  • Resize images before loading when possible
  • Cache image objects with useMemo
  • Use WebP format for best compression
  • Avoid loading very large images

Common Patterns

Circular Image

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

const image = useImage(require("./avatar.jpg"));
const clipPath = Skia.Path.Make();
clipPath.addCircle(75, 75, 75);

<Canvas style={{ width: 150, height: 150 }}>
  <Group clip={clipPath}>
    <Image image={image} x={0} y={0} width={150} height={150} fit="cover" />
  </Group>
</Canvas>
import { useSharedValue } from "react-native-reanimated";
import { Canvas, Image, useImage } from "@shopify/react-native-skia";

const images = [
  useImage(require("./img1.jpg")),
  useImage(require("./img2.jpg")),
  useImage(require("./img3.jpg")),
];

const offset = useSharedValue(0);

<Canvas style={{ flex: 1 }}>
  {images.map((img, i) => (
    <Image
      key={i}
      image={img}
      x={() => i * 300 + offset.value}
      y={0}
      width={300}
      height={400}
      fit="cover"
    />
  ))}
</Canvas>

Build docs developers (and LLMs) love