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
The image object to render
X-coordinate of the image position
Y-coordinate of the image position
Width to render the image
Height to render the image
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/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>
);
}
- PNG (with transparency)
- JPEG
- WebP (including animated)
- GIF (including animated)
- BMP
- ICO
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);
- 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>
Image Carousel
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>