Flutter - Display Image From File

This tutorial shows you how to load image from a local file in Flutter using Image.File and FileImage.

Sometimes an application needs to be able to display images from files. In Flutter, displaying an image can be done by using Image widget. Flutter provides a named constructor File.Image which can be used if the image source is from a file. Alternatively, you can also use FileImage. The usage examples can be found in this tutorial.

Handle Permission

To access a file in storage, the app needs to have the permission to read storage. Otherwise the user will get a permission error unless the file is located in the app's directory. The easiest way to handle permission is by using a 3rd party package such as permission_handler. First, add the package in the dependencies section of pubspec.yaml

  permission_handler: ^5.1.0+2

After running flutter pub get (or click on 'Packages get' in Android Studio), the package can be used by adding this import statement.

  import 'package:permission_handler/permission_handler.dart';

Below is a code sample to handle storage permission.

  initState() {
    super.initState();

    () async {
      _permissionStatus = await Permission.storage.status;

      if (_permissionStatus != PermissionStatus.granted) {
        PermissionStatus permissionStatus= await Permission.storage.request();
        setState(() {
          _permissionStatus = permissionStatus;
        });
      }
    } ();
  }

Using Image.File

Below is the named constructeor Image.File.

  Image.file(
    File file, {
    Key? key,
    double scale = 1.0,
    this.frameBuilder,
    this.errorBuilder,
    this.semanticLabel,
    this.excludeFromSemantics = false,
    this.width,
    this.height,
    this.color,
    this.colorBlendMode,
    this.fit,
    this.alignment = Alignment.center,
    this.repeat = ImageRepeat.noRepeat,
    this.centerSlice,
    this.matchTextDirection = false,
    this.gaplessPlayback = false,
    this.isAntiAlias = false,
    this.filterQuality = FilterQuality.low,
    int? cacheWidth,
    int? cacheHeight,
  })

The basic usage only requires you to pass an argument which is an instance of File. In addition, you are not allowed to pass null value for scale and repeat arguments (just keep the default value if you don't want to set it).

Below is a basic example that only passes the file argument. No size constraints applied to the widget and the actual size of the used image (the width) is bigger than the available space.

  Image.file(
    File('/storage/emulated/0/Download/test.jpg'),
  )

Output:

Flutter - ImageFile

As you can see from the output, the default behavior is the image is scaled down so that it can fit in the available space. The next examples in this tutorial show you how to customize how the image should be rendered.

Set Width and Height

You can set the width and the height of the loaded image by passing width and height named arguments respectively.

The below example sets both width and height values to 100.

  Image.file(
    File('/storage/emulated/0/Download/test.jpg'),
    width: 100,
    height: 100,
  )

Output:

Flutter - ImageFile - Width & Height

Set Fit

If you set the image to be a specified size, sometimes the image may not fit in the available space. In that case, you may need to set how the image should be inscribed to the space. To do so, pass a BoxFit enum value as fit argument. We have a post about FittedBox which shows the differences between the BoxFit enum values.

The below example uses BoxFit.fill, which fills the target box by distorting the source's aspect ratio.

  Image.file(
    File('/storage/emulated/0/Download/test.jpg'),
    width: 100,
    height: 100,
    fit: BoxFit.fill,
  )

Output:

Flutter - ImageFile - Fit - BoxFit.fill

Set Alignment

To set how the image should be aligned in the space, pass a named argument alignment. You can use Alignment value or create a custom alignment using the constructor of Alignment.

The code below sets the alignment to topCenter.

  Image.file(
    File('/storage/emulated/0/Download/test.jpg'),
    width: 100,
    height: 100,
    alignment: Alignment.topCenter,
  )

Output:

Flutte - ImageFile - Alignment - topCenter

Set Repeat Mode

If the image doesn't fill all the available space, you can make it repeated by passing repeat argument. The value is an enum of ImageRepeat whose possible values are:

  • repeat: Repeat the image in both the x and y directions until the box is filled.
  • repeatX: Repeat the image in the x direction until the box is filled horizontally.
  • repeatY: Repeat the image in the y direction until the box is filled vertically.
  • noRepeat: Leave uncovered portions of the box transparent.

If you don't pass the argument, the default value is ImageRepeat.noRepeat. The code below uses ImageRepeat.repeat. Since the box is already filled horizontally, it only repeats in the y direction.

  Image.file(
    File('/storage/emulated/0/Download/test.jpg'),
    width: 100,
    height: 100,
    repeat: ImageRepeat.repeat,
  )

Output:

Flutte - ImageFile - repeat

Blend Image With Color

You can set a color to be blended with each pixel by passing color argument. How to blend the color with the image can be set by passing colorBlendMode argument. The BlendMode mode enum has so many values you can choose.

The example below blends the image with red color using saturation mode.

  Image.file(
    File('/storage/emulated/0/Download/test.jpg'),
    width: 100,
    height: 100,
    color: Colors.red,
    colorBlendMode: BlendMode.saturation
  )

Output:

Flutte - ImageFile - Color Blend - red - saturation

Set Scale

The scale argument is used to set how many image pixels for every one logical pixel. It applies to both width and height. For example, if the scale is 2, there are 4 image pixels per one logical pixel. Thus, if you create an Image.File with a scale of 4, the rendered width and height will be half as big as having a scale value of 2. That's because a logical pixel contains more image pixels.

Below is an example which sets the scale argument to 4.

  Image.file(
    File('/storage/emulated/0/Download/test.jpg'),
    scale: 4,
  )

Output:

Flutte - ImageFile - Scale - 4

Using Error Builder

An error may occur while trying to load an image from a file, for example if the file doesn't exist or if the app doesn't have the storage permission. You can handle it by displaying another widget. It can be done by passing a function as errorBuilder. The function returns a Widget and has the following parameters:

  • BuildContext context: The build context.
  • Object error: The error object.
  • StackTrace stackTrace: The stack trace.

The code below shows a Container widget with 'Error load image' text inside if the image cannot be loaded successfully.

  Image.file(
    File('/storage/emulated/0/Download/test.jpg'),
    errorBuilder: (
      BuildContext context,
      Object error,
      StackTrace stackTrace,
    ) {
      return Container(
        color: Colors.grey,
        width: 100,
        height: 100,
        child: const Center(
          child: const Text('Error load image', textAlign: TextAlign.center),
        ),
      )
    },
  )

Output:

Flutte - ImageFile - errorBuilder

Using Frame Builder

You can pass a function as frameBuilder to customize how the image should be rendered. The function which must return a Widget has the following parameters:

  • BuildContext context: The build context.
  • Widget child: The default image.
  • int frame: The current frame number. It will be null before the first image is ready. If the image only has one frame, the value can't be greater than 0. For multi-frame images (such as GIFs), the value will be increased by one for every frame.
  • bool wasSynchronouslyLoaded: whether the image was available synchronously and available to be painted immediately. For multi-frame images (such as images), the value for all frames will be true after the first image available.

Below is an example that adds a border around the image.

  Image.file(
    File('/storage/emulated/0/Download/test.jpg'),
    width: 100,
    height: 100,
    frameBuilder: (
      BuildContext context,
      Widget child,
      int frame,
      bool wasSynchronouslyLoaded,
    ) {
      return Container(
        decoration: BoxDecoration(
          border: Border.all(color: Colors.red, width: 5),
        ),
        child: child,
      );
    },
  )

Output:

Flutte - ImageFile - frameBuilder

Image.File Parameters

  • File file *: The file to be loaded as an image.
  • Key key: The widget's key, used to control how a widget is replaced with another widget.
  • double scale: A linear scale factor for drawing this image at its intended size, applies to both width and height. Defaults to 1.0.
  • ImageFrameBuilder frameBuilder: A builder function responsible for creating the widget that represents this image..
  • ImageErrorWidgetBuilder errorBuilder: A builder function that is called if an error occurs during image loading.
  • String semanticLabel: A Semantic description of the image.
  • bool excludeFromSemantics: Whether to exclude this image from semantics. Defaults to false.
  • double width: If non-null, require the image to have this width.
  • double height: If non-null, require the image to have this height.
  • Color color: If non-null, this color is blended with each image pixel using colorBlendMode.
  • BlendMode colorBlendMode: How to combine color with the image.
  • BoxFit fit: How to inscribe the image into the space allocated during layout.
  • AlignmentGeometry alignment: How to align the image within its bounds. Defaults to Alignment.center.
  • ImageRepeat repeat: How to paint any portions of the layout bounds not covered by the image. Defaults to ImageRepeat.noRepeat.
  • Rect centerSlice: The center slice for a nine-patch image.
  • bool matchTextDirection: Whether to paint the image in the direction of the TextDirection. Defaults to false.
  • bool gaplessPlayback: Whether to continue showing the old image (if true) or briefly show nothing (if alse) when the image provider changes. Defaults to false.
  • bool isAntiAlias: Whether to paint the image with anti-aliasing. Defaults to false.
  • FilterQuality filterQuality: Used to set the FilterQuality of the image. Defaults to FilterQuality.low.
  • int cacheWidth: The width size at which the image must be decoded.
  • int cacheHeight: The height size at which the image must be decoded.

*: required

Using FileImage

FileImage is a class that extends ImageProvider. It's not a widget, so you can't use it directly. You can pass it as the ImageProvider of an Image widget. Below is the constructor of FileImage.

  const FileImage(this.file, { this.scale = 1.0 })

It's required to pass the file argument whose type is File. There is an optional named argument scale whose default value is 1.0. The scale argument has the same usage as the one on Image.File. Below is a usage example of FileImage which also passes the optional scale argument.

  Image(
    image: FileImage(
      File('/storage/emulated/0/Download/test.jpg'),
      scale: 4
    ),
  )

Output:

Flutte - ImageFile - Scale - 4

FileImage Parameters

  • File file *: The file to be loaded as an image.
  • double scale: A linear scale factor for drawing this image at its intended size, applies to both width and height. Defaults to 1.0.

*: required

Full Code

  import 'dart:io';
  
  import 'package:flutter/material.dart';
  import 'package:flutter/widgets.dart';
  import 'package:permission_handler/permission_handler.dart';
  
  void main() => runApp(MyApp());
  
  class MyApp extends StatelessWidget {
  
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        title: 'Woolha.com Flutter Tutorial',
        home: Scaffold(
          appBar: AppBar(
            title: const Text('Woolha.com | ImageFile Example'),
            backgroundColor: Colors.teal,
          ),
          body: FileImageExample(),
        ),
      );
    }
  }
  
  class FileImageExample extends StatefulWidget {
  
    @override
    _FileImageExampleState createState() => _FileImageExampleState();
  }
  
  class _FileImageExampleState extends State<FileImageExample> {
  
    PermissionStatus _permissionStatus;
  
    initState() {
      super.initState();
  
      () async {
        _permissionStatus = await Permission.storage.status;
  
        if (_permissionStatus != PermissionStatus.granted) {
          PermissionStatus permissionStatus= await Permission.storage.request();
          setState(() {
            _permissionStatus = permissionStatus;
          });
        }
      } ();
    }
  
    @override
    Widget build(BuildContext context) {
      if (_permissionStatus != PermissionStatus.granted) {
        return Text('Not granted');
      }
  
      return Image.file(
        File('/storage/emulated/0/Download/test.jpg'),
        width: 100,
        height: 100,
        fit: BoxFit.fill,
        repeat: ImageRepeat.repeat,
        alignment: Alignment.topCenter,
        color: Colors.red,
        colorBlendMode: BlendMode.saturation,
  //      scale: 4,
        errorBuilder: (
          BuildContext context,
          Object error,
          StackTrace stackTrace,
        ) {
          print(error);
          print(stackTrace);
          return Container(
            color: Colors.grey,
            width: 100,
            height: 100,
            child: const Center(
              child: const Text('Error load image', textAlign: TextAlign.center),
            ),
          );
        },
        frameBuilder: (
          BuildContext context,
          Widget child,
          int frame,
          bool wasSynchronouslyLoaded,
        ) {
          return Container(
            decoration: BoxDecoration(
              border: Border.all(color: Colors.red, width: 5),
            ),
            child: child,
          );
        },
      );
  //    return Image(
  //      image: FileImage(
  //        File('/storage/emulated/0/Download/test.jpg'),
  //        scale: 4
  //      ),
  //    );
    }
  }

Summary

That's how to load image from file in Flutter. You can use Image.File or FileImage. You can also read our tutorial about: