Back to Expo

Image

docs/pages/versions/v55.0.0/sdk/image.mdx

latest8.4 KB
Original Source

import APISection from '/components/plugins/APISection'; import { APIInstallSection } from '/components/plugins/InstallSection'; import { ConfigPluginExample, ConfigPluginProperties, ConfigReactNative, } from '/ui/components/ConfigSection'; import { YesIcon, NoIcon } from '/ui/components/DocIcons'; import { Terminal } from '~/ui/components/Snippet';

expo-image is a cross-platform React component that loads and renders images.

Main features:

  • Designed for speed
  • Support for many image formats (including animated ones)
  • Disk and memory caching
  • Supports BlurHash and ThumbHash - compact representations of a placeholder for an image
  • Transitioning between images when the source changes (no more flickering!)
  • Implements the CSS object-fit and object-position properties (see contentFit and contentPosition props)
  • Uses performant SDWebImage and Glide under the hood

Supported image formats

FormatAndroidiOSWeb
WebP<YesIcon /><YesIcon /><YesIcon />
PNG / APNG<YesIcon /><YesIcon /><YesIcon />
AVIF<YesIcon /><YesIcon /><YesIcon />
HEIC<YesIcon /><YesIcon /><NoIcon /> not adopted yet
JPEG<YesIcon /><YesIcon /><YesIcon />
GIF<YesIcon /><YesIcon /><YesIcon />
SVG<YesIcon /><YesIcon /><YesIcon />
ICO<YesIcon /><YesIcon /><YesIcon />
ICNS<NoIcon /><YesIcon /><NoIcon />
PSD (composite preview)<NoIcon /><YesIcon /><NoIcon />

Installation

<APIInstallSection />

Configuration in app config

You can configure build-time settings for expo-image using its config plugin. Add the plugin to the plugins array in your app.json or app.config.js and rebuild the native project.

<ConfigPluginExample>
json
{
  "expo": {
    "plugins": [
      [
        "expo-image",
        {
          "disableLibdav1d": true
        }
      ]
    ]
  }
}
</ConfigPluginExample>

<ConfigPluginProperties properties={[ { name: 'disableLibdav1d', platform: 'ios', description: 'When true, skips adding the bundled libavif/libdav1d Pod. Use this when another dependency (such as FFmpegKit) already links libdav1d. Disabling the Pod removes AVIF image support on iOS unless another decoder is available.', default: 'false', }, ]} />

<ConfigReactNative> If you are not using Continuous Native Generation ([CNG](/workflow/continuous-native-generation/)) or you're using native **ios** project manually, then set the shell environment variable `EXPO_IMAGE_DISABLE_LIBDAV1D=1` before running `pod install` to achieve the same effect. Alternatively, you can add `ENV['EXPO_IMAGE_DISABLE_LIBDAV1D'] ||= '0'` to the top of your `Podfile`. </ConfigReactNative>

Usage

jsx
import { Image } from 'expo-image';
import { StyleSheet, View } from 'react-native';

const blurhash =
  '|rF?hV%2WCj[ayj[a|j[az_NaeWBj@ayfRayfQfQM{M|azj[azf6fQfQfQIpWXofj[ayj[j[fQayWCoeoeaya}j[ayfQa{oLj?j[WVj[ayayj[fQoff7azayj[ayj[j[ayofayayayj[fQj[ayayj[ayfjj[j[ayjuayj[';

export default function App() {
  return (
    <View style={styles.container}>
      <Image
        style={styles.image}
        source="https://picsum.photos/seed/696/3000/2000"
        placeholder={{ blurhash }}
        contentFit="cover"
        transition={1000}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  image: {
    flex: 1,
    width: '100%',
    backgroundColor: '#0553',
  },
});

API

js
import { Image } from 'expo-image';
<APISection packageName="expo-image" apiName="Image" />

Generating a blurhash on a server

Images can significantly improve the visual experience, however, they can also slow down app/page loading times due to their large file sizes. To overcome this, you can create placeholder images using blurhash algorithm that provides an immersive experience while deferring the loading of the actual picture until later.

This guide demonstrates how to create a blurhash of an uploaded image on the backend using JavaScript and Express.js. The same techniques and principles apply to other languages and server technologies.

Start by installing a few dependencies: multer for handling multipart requests, sharp for converting files to a data buffer, and the official blurhash JavaScript package.

<Terminal cmd={['$ npm install multer sharp blurhash']} />

Next, import all required functions from installed packages and initialize multer:

js
// Multer is a middleware for handling `multipart/form-data`.
const multer = require('multer');
// Sharp allows you to receive a data buffer from the uploaded image.
const sharp = require('sharp');
// Import the encode function from the blurhash package.
const { encode } = require('blurhash');

// Initialize `multer`.
const upload = multer();

Assuming the app is a variable that holds a reference to the Express server, an endpoint can be created that accepts an image and returns a JSON response containing the generated blurhash.

js
app.post('/blurhash', upload.single('image'), async (req, res) => {
  const { file } = req;
  // If the file is not available we're returning with error.
  if (file === null) {
    res.status(400).json({ message: 'Image is missing' });
    return;
  }

  // Users can specify number of components in each axes.
  const componentX = req.body.componentX ?? 4;
  const componentY = req.body.componentY ?? 3;

  // We're converting provided image to a byte buffer.
  // Sharp currently supports multiple common formats like JPEG, PNG, WebP, GIF, and AVIF.
  const { data, info } = await sharp(file.buffer).ensureAlpha().raw().toBuffer({
    resolveWithObject: true,
  });

  const blurhash = encode(
    new Uint8ClampedArray(data),
    info.width,
    info.height,
    componentX,
    componentY
  );
  res.json({ blurhash });
});

Additionally, the request can include two parameters: componentX and componentY, are passed through the algorithm. These values can be calculated or hard-coded on the server or specified by the user. However, they must be within the range of 1 to 9 and have an aspect ratio similar to the uploaded image. A value of 9 will give the best results but may take longer to generate the hash.

The process of generating a blurhash can be accomplished in various languages and server technologies, similar to the one using JavaScript. The key step is to locate an encoder for your chosen language, which can often be found in the woltapp/blurhash repository. Once you have the encoder, you will need to obtain a representation of the image. Some libraries use a default image class (for example, the Swift implementation uses UIImage). In other cases, you will have to provide raw byte data. Make sure to check the encoder's documentation to confirm the expected data format.

When working with raw byte data, ensure that the alpha layer is present (each pixel is represented by red, green, blue, and alpha values). Failing to do so will lead to errors such as "width and height must match the pixels array".