This tutorial explains some different ways to get the width and height of an image.
If you want to get the dimensions of an image programmatically in Flutter, it can be done in several ways. You can read the examples below. This tutorial only explains how to get the dimensions of the original image, not how to get the rendered size. You can read our tutorial about how to get the size of a widget in Flutter if what you need to get is the rendered size.
For this tutorial, we create a simple class ImageDetail
that stores the width and height values of an image.
class ImageDetail {
final int width;
final int height;
final Uint8List? bytes;
ImageDetail({required this.width, required this.height, this.bytes});
}
Below are different ways to get the dimensions of an image.
Using ImageStreamListener
This method is suitable if you want to display the image using Image
widget. The source of the image can be from network, file, asset, or memory. First of all, you need to create the Image
widget. The example below uses a network URL as the source. However, the steps for other sources are very similar.
final Image image = Image.network(
'https://www.woolha.com/media/2020/05/flutter-colorfilter-merge-identity.jpg',
);
The Image
widget has image
property which returns an ImageProvider
. Then, use the resolve
method of the ImageProvider
class to create an ImageStream
. Finally, you can add an ImageStreamListener
listener.
The constructor of ImageStreamListener
has a required positional argument whose type is a function. You have to pass a function which accepts ImageInfo
as the first argument and a boolean as the second argument. The ImageInfo
contains the actual data of the image. The second argument indicates whether the listener is being invoked during the call to addListener
. For getting the image size, you only need to use the first argument.
The listener is invoked when the image information becomes available. Inside the listener, you can get the value of ImageInfo
that's passed as the argument. It has a property named ui.Image
, which has the width
and height
properties of the image.
Completer<ImageDetail> completer = Completer<ImageDetail>();
image.image
.resolve(const ImageConfiguration())
.addListener(ImageStreamListener((ImageInfo imageInfo, bool _) {
final dimensions = ImageDetail(
width: imageInfo.image.width,
height: imageInfo.image.height,
);
completer.complete(dimensions);
}));
The example above uses a Completer
which will complete inside the listener after the image information has been available. Therefore, we can use the FutureBuilder
widget by using the Completer
's Future
.
return FutureBuilder(
future: completer.future,
builder: (BuildContext context, AsyncSnapshot<ImageDetail> snapshot) {
if (!snapshot.hasData) {
return Container();
}
return Column(
children: [
image,
Text('${snapshot.data?.width} x ${snapshot.data?.height}')
],
);
},
);
Using ImageDescriptor
Another way to get the size of an image is by using ImageDescriptor
. It doesn't require you to create a widget, so it's suitable if you don't want to render the image. First, you need to get the bytes of the image as Unit8List
type. Below is the example if the image is from a network URL. The code below requires the http
package added to the dependencies
in pubspec.yaml
file. Then, add import 'package:http/http.dart' as http;
at the top of the file.
final response = await http.get(Uri.parse(imageUrl));
final bytes = response.bodyBytes; // returns Unit8List
If the source is the application's asset, it's also necessary to get the bytes as shown in the example below.
final byteData = await rootBundle.load(assetPath);
final bytes = byteData.buffer.asUint8List();
To create the ImageDescriptor
, you need to have the ImmutableBuffer
value, which can be obtained using ImmutableBuffer.fromUint8List
. Then, convert the buffer to ImageDescriptor
by using ImageDescriptor.encoded
method. The ImageDescriptor
has the width
and height
properties of the image. After getting the necessary values, don't forget to dispose the descriptor and the buffer.
final buffer = await ImmutableBuffer.fromUint8List(bytes);
final descriptor = await ImageDescriptor.encoded(buffer);
final dimensions = ImageDetail(
width: descriptor.width,
height: descriptor.height,
bytes: bytes,
);
descriptor.dispose();
buffer.dispose();
Using ImageDimensions
Another way is by decoding the image bytes to ui.Image
. Assuming you already have the bytes in Unit8List
, you need to decode the image to ui.Image
by using decodeImageFromList
method. Then, you can get the width
and height
values.
final response = await http.get(Uri.parse(imageUrl));
final bytes = response.bodyBytes;
final decodedImage = await decodeImageFromList(bytes);
return ImageDetail(
width: decodedImage.width,
height: decodedImage.height,
bytes: bytes,
);
Full Code
import 'dart:async';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Woolha.com Flutter Tutorial',
home: MyPage(),
);
}
}
class MyPage extends StatelessWidget {
const MyPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Woolha.com Flutter Tutorial'),
backgroundColor: Colors.teal,
),
body: SingleChildScrollView(
child: Column(
children: const [
GetImageDimensionsUsingWidgetListener(),
GetImageDimensionsUsingImageDescriptor(),
GetImageDimensionsUsingImageDecoder(),
GetAssetImageDimensions(),
],
),
),
);
}
}
class ImageDetail {
final int width;
final int height;
final Uint8List? bytes;
ImageDetail({required this.width, required this.height, this.bytes});
}
class GetImageDimensionsUsingWidgetListener extends StatelessWidget {
const GetImageDimensionsUsingWidgetListener({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final Image image = Image.network(
'https://www.woolha.com/media/2020/05/flutter-colorfilter-merge-identity.jpg',
);
Completer<ImageDetail> completer = Completer<ImageDetail>();
image.image
.resolve(const ImageConfiguration())
.addListener(ImageStreamListener((ImageInfo imageInfo, bool _) {
final dimensions = ImageDetail(
width: imageInfo.image.width,
height: imageInfo.image.height,
);
completer.complete(dimensions);
}));
return FutureBuilder(
future: completer.future,
builder: (BuildContext context, AsyncSnapshot<ImageDetail> snapshot) {
if (!snapshot.hasData) {
return Container();
}
return Column(
children: [
image,
Text('${snapshot.data?.width} x ${snapshot.data?.height}')
],
);
},
);
}
}
class GetImageDimensionsUsingImageDescriptor extends StatelessWidget {
const GetImageDimensionsUsingImageDescriptor({Key? key}) : super(key: key);
Future<ImageDetail> _getImageDimensions(String imageUrl) async {
final response = await http.get(Uri.parse(imageUrl));
final bytes = response.bodyBytes;
final buffer = await ImmutableBuffer.fromUint8List(bytes);
final descriptor = await ImageDescriptor.encoded(buffer);
final dimensions = ImageDetail(
width: descriptor.width,
height: descriptor.height,
bytes: bytes,
);
descriptor.dispose();
buffer.dispose();
return dimensions;
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _getImageDimensions('https://www.woolha.com/media/2020/05/flutter-colorfilter-merge-identity.jpg'),
builder: (BuildContext context, AsyncSnapshot<ImageDetail> snapshot) {
if (!snapshot.hasData) {
return Container();
}
return Column(
children: [
Image.memory((snapshot.data?.bytes)!),
Text('${snapshot.data?.width} x ${snapshot.data?.height}')
],
);
},
);
}
}
class GetImageDimensionsUsingImageDecoder extends StatelessWidget {
const GetImageDimensionsUsingImageDecoder({Key? key}) : super(key: key);
Future<ImageDetail> _getImageDimensions(String imageUrl) async {
final response = await http.get(Uri.parse(imageUrl));
final bytes = response.bodyBytes;
final decodedImage = await decodeImageFromList(bytes);
return ImageDetail(
width: decodedImage.width,
height: decodedImage.height,
bytes: bytes,
);
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _getImageDimensions('https://www.woolha.com/media/2020/05/flutter-colorfilter-merge-identity.jpg'),
builder: (BuildContext context, AsyncSnapshot<ImageDetail> snapshot) {
if (!snapshot.hasData) {
return Container();
}
return Column(
children: [
Image.memory((snapshot.data?.bytes)!),
Text('${snapshot.data?.width} x ${snapshot.data?.height}')
],
);
},
);
}
}
class GetAssetImageDimensions extends StatelessWidget {
const GetAssetImageDimensions({Key? key}) : super(key: key);
Future<ImageDetail> _getImageDimensions(String assetPath) async {
final byteData = await rootBundle.load(assetPath);
final bytes = byteData.buffer.asUint8List();
final decodedImage = await decodeImageFromList(bytes);
return ImageDetail(
width: decodedImage.width,
height: decodedImage.height,
bytes: bytes,
);
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _getImageDimensions('assets/images/flutter.png'),
builder: (BuildContext context, AsyncSnapshot<ImageDetail> snapshot) {
if (!snapshot.hasData) {
return Container();
}
return Column(
children: [
Image.memory((snapshot.data?.bytes)!),
Text('${snapshot.data?.width} x ${snapshot.data?.height}')
],
);
},
);
}
}
Summary
There are several ways to get the dimensions of an image in Flutter. First, you can create an Image
widget and add ImageStreamListener
, which will be invoked when the image information becomes available. You can also get the ImageDescriptor
from the bytes or decode the bytes to ui.Image
to get the width and height values.
You can also read about: