The web supports the standard
Image widget to display images.
However, because web browsers are built to run untrusted code safely,
there are certain limitations in what you can do with images compared
to mobile and desktop platforms. This page explains these limitations
and offers ways to work around them.
This section summarizes the technologies available across Flutter and the web, on which the solutions below are based on.
Images in Flutter
Flutter offers the
Image widget as well as the low-level
dart:ui/Image class for rendering images.
Image widget has enough functionality for most use-cases.
dart:ui/Image class can be used in
advanced situations where fine-grained control of the image is needed.
Images on the web
The web offers several methods for displaying images. Below are some of the common ones:
- The built-in
drawImagemethod on the
- Custom image codec that renders to a WebGL canvas.
Each option has its own benefits and drawbacks. For example, the built-in
elements fit nicely among other HTML elements, and they automatically take
advantage of browser caching, and built-in image optimization and memory
management. They allow you to safely display images from arbitrary sources
(more on than in the CORS section below).
drawImage is great when the image
must fit within other content rendered using the
<canvas> element. You also
gain control over image sizing and, when the CORS policy allows it, read the
pixels of the image back for further processing. Finally, WebGL gives you the
highest degree of control over the image. Not only can you read the pixels and
apply custom image algorithms, but you can also use GLSL for
Cross-Origin Resource Sharing (CORS)
CORS is a mechanism that browsers use to control how one site accesses the
resources of another site. It is designed such that, by default, one web-site
is not allowed to make HTTP requests to another site using XHR or
fetch. This prevents scripts on another site from acting on behalf
of the user and from gaining access to another site’s resources without
<canvas>, the browser automatically
blocks access to pixels when it knows that an image is coming from another site
and the CORS policy disallows access to data.
WebGL requires access to the image data in order to be able to render the image. Therefore, images to be rendered using WebGL must only come from servers that have a CORS policy configured to work with the domain that serves your application.
Flutter renderers on the web
Flutter offers a choice of two renderers on the web:
HTML: this renderer uses a combination of HTML, CSS, Canvas 2D, and SVG
to render UI. It uses the
<img>element to render images.
- CanvasKit: this renderer uses WebGL to render UI, and therefore requires access to the pixels of the image.
Because the HTML renderer uses the
<img> element it can display images from
arbitrary sources. However, this places the following limitations on what you
can do with them:
- Limited support for
- No support for
- No access to frame data in animated images (
frameCountis always 1,
repetitionCountis always 0).
- No support for
- Limited support for shader effects that can be applied to images.
- No control over image memory (
Image.disposehas no effect). The memory is managed by the browser behind-the-scenes.
The CanvasKit renderer implements Flutter’s image API fully. However, it requires access to image pixels to do so, and is therefore subject to the CORS policy.
In-memory, asset, and same-origin network images
If the app has the bytes of the encoded image in memory, provided as an
asset, or stored on the same server that serves the application
(also known as same-origin), no extra effort is necessary.
The image can be displayed using
in both HTML and CanvasKit modes.
The HTML renderer can load cross-origin images without extra configuration.
CanvasKit requires that the app gets the bytes of the encoded image. There are several ways to do this, discussed below.
Host your images in a CORS-enabled CDN.
Typically, content delivery networks (CDN) can be configured to customize what
domains are allowed to access your content. For example, Firebase site hosting
allows specifying a custom
Access-Control-Allow-Origin header in the
Lack control over the image server? Use a CORS proxy.
If the image server cannot be configured to allow CORS requests from your application, you may still be able to load images by proxying the requests through another server. This will require that the intermediate server has sufficient access to load the images.
This method can be used in situations when the original image server serves images publicly, but is not configured with the correct CORS headers.
Use in a platform view.
Flutter supports embedding HTML inside the app using
Use it to create an
<img> element to render the image from another domain.
However, do keep in mind that this comes with the limitations explained in the
section “Flutter renderers on the web” above.
As of today, using too many HTML elements with the CanvasKit renderer may
hurt performance. If images interleave non-image content Flutter needs to
create extra WebGL contexts between the
<img> elements. If your application
needs to display a lot of images on the same screen all at once, consider using
the HTML renderer instead of CanvasKit.