如何在 Flutter 中确定图像的宽度和高度?

How do I determine the width and height of an image in Flutter?

假设我在 pubspec.yaml 中声明了我的图像,如下所示:

  assets:
    - assets/kitten.jpg

我的 Flutter 代码是这样的:

void main() {
  runApp(
    new Center(
      child: new Image.asset('assets/kitten.jpg'),
    ),
  );
}

既然我有了 new Image.asset(),我该如何确定该图像的宽度和高度?例如,我只想打印出图像的宽度和高度。

(看起来 dart:ui's Image class 有宽度和高度,但不确定如何从小部件的图像转到 dart:ui 的图像。)

谢谢!

您可以resolve the ImageProvider to get an ImageStream, then use addListener在图像准备就绪时收到通知。

import 'dart:ui' as ui;
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(new MaterialApp(
    home: new MyHomePage(),
  ));
}

class MyHomePage extends StatelessWidget {

  Future<ui.Image> _getImage() {
    Completer<ui.Image> completer = new Completer<ui.Image>();
    new NetworkImage('https://i.stack.imgur.com/lkd0a.png')
      .resolve(new ImageConfiguration())
      .addListener((ImageInfo info, bool _) => completer.complete(info.image));
    return completer.future;
  }

  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Image Dimensions Example"),
      ),
      body: new Center(
        child: new FutureBuilder<ui.Image>(
          future: _getImage(),
          builder: (BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
            if (snapshot.hasData) {
              ui.Image image = snapshot.data;
              return new Text(
                '${image.width}x${image.height}',
                style: Theme.of(context).textTheme.display4);
            } else {
              return new Text('Loading...');
            }
          },
        ),
      ),
    );
  }
}

更新的解决方案:

有了新版本的flutter,旧的解决方案已经过时了。现在 addListener 需要 ImageStreamListener.

Widget build(BuildContext context) {
    Image image = new Image.network('https://i.stack.imgur.com/lkd0a.png');
    Completer<ui.Image> completer = new Completer<ui.Image>();
    image.image
      .resolve(new ImageConfiguration())
      .addListener(ImageStreamListener((ImageInfo info, bool _) { 
        completer.complete(info.image));
      })
    ...
    ...

原始版本:

如果您已经有一个 Image 小部件,您可以通过在其 ImageProvider 上调用 resolve 从中读取 ImageStream

import 'dart:ui' as ui;
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(new MaterialApp(
    home: new MyHomePage(),
  ));
}

class MyHomePage extends StatelessWidget {

  Widget build(BuildContext context) {
    Image image = new Image.network('https://i.stack.imgur.com/lkd0a.png');
    Completer<ui.Image> completer = new Completer<ui.Image>();
    image.image
      .resolve(new ImageConfiguration())
      .addListener((ImageInfo info, bool _) => completer.complete(info.image));
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Image Dimensions Example"),
      ),
      body: new ListView(
        children: [
          new FutureBuilder<ui.Image>(
            future: completer.future,
            builder: (BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
              if (snapshot.hasData) {
                return new Text(
                  '${snapshot.data.width}x${snapshot.data.height}',
                  style: Theme.of(context).textTheme.display3,
                );
              } else {
                return new Text('Loading...');
              }
            },
          ),
          image,
        ],
      ),
    );
  }
}

如果您只想在异步函数中获取图像的宽度和高度,那么其他答案似乎过于复杂。您可以直接使用 flutter lib 获取图像分辨率,如下所示:

import 'dart:io';

File image = new File('image.png'); // Or any other way to get a File instance.
var decodedImage = await decodeImageFromList(image.readAsBytesSync());
print(decodedImage.width);
print(decodedImage.height);

新版本的 flutter 旧解决方案不起作用示例:

  image.image
  .resolve(new ImageConfiguration())
  .addListener((ImageInfo info, bool _) => completer.complete(info.image));

工作版本以下:

_image.image
    .resolve(new ImageConfiguration())
    .addListener(new ImageStreamListener((ImageInfo image, bool _) {
  completer.complete(image.image);
}));

创建一个方法,例如:

Future<Size> _calculateImageDimension() {
  Completer<Size> completer = Completer();
  Image image = Image.network("https://i.stack.imgur.com/lkd0a.png");
  image.image.resolve(ImageConfiguration()).addListener(
    ImageStreamListener(
      (ImageInfo image, bool synchronousCall) {
        var myImage = image.image;
        Size size = Size(myImage.width.toDouble(), myImage.height.toDouble());
        completer.complete(size);
      },
    ),
  );
  return completer.future;
}

并像这样使用它:

_calculateImageDimension().then((size) => print("size = ${size}")); // 487.0,696.0

如果你不想使用 FutureBuilder 或 then,你也可以像这样使用 await:

别忘了导入图片。但是因为有两个图像类,像这样导入它并与ui.Image

一起使用
 import 'dart:ui' as ui

然后就可以按如下方式获取图片的尺寸了。

 final Image image = Image(image: AssetImage('assets/images/someimage.png'));
 Completer<ui.Image> completer = new Completer<ui.Image>();
    image.image
        .resolve(new ImageConfiguration())
        .addListener(new ImageStreamListener((ImageInfo image, bool _) {
      completer.complete(image.image);
    }));
 ui.Image info = await completer.future;
 int width = info.width;
 int height = info.height;

一种检查从资产加载的图像尺寸的简单方法。

var img = await rootBundle.load("Your image path");
var decodedImage = await decodeImageFromList(img.buffer.asUint8List());
int imgWidth = decodedImage.width;
int imgHeight = decodedImage.height;

这是一个方便的辅助函数,基于其他解决方案

辅助函数

Future<ImageInfo> getImageInfo(Image img) async {
  final c = new Completer<ImageInfo>();
  img.image
    .resolve(new ImageConfiguration())        
    .addListener(new ImageStreamListener((ImageInfo i, bool _) {
      c.complete(i);
    }));
  return c.future;    
}

用法

Image image = Image.network("https://example.com/pic.png");
ImageInfo info = await getImageInfo(image);

最简单的方法是使用 MediaQuery

            width: MediaQuery.of(context).size.width * 0.4,

获取资产图像大小的简单方法。

      Future<Size> _loadAssetImageSize(String asset) async{
         ByteData data = await rootBundle.load(asset);
         ui.Codec codec = await 
         ui.instantiateImageCodec(data.buffer.asUint8List());
         ui.FrameInfo fi = await codec.getNextFrame();
         return Size(fi.image.width.toDouble(), fi.image.height.toDouble());
  }

只需要解码图像边界的方法:

    final buffer = await ui.ImmutableBuffer.fromUint8List(bytes);
    final descriptor = await ui.ImageDescriptor.encoded(buffer);

    final imageWidth = descriptor.width;
    final imageHeight = descriptor.height;
    print("imageWidth: $imageWidth, imageHeight: $imageHeight");

    descriptor.dipose();
    buffer.dipose();