You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter:如何使用drawImage方法在Canvas上绘制图片

How to get a ui.Image from ImageCodec for canvas.drawImage in Flutter

Hey there! I totally get the confusion here—you’ve followed the docs to grab an ImageCodec, but now you need that final ui.Image instance to actually draw on your Canvas. Let’s break this down step by step to get you sorted.

The missing piece: Extracting ui.Image from the Codec

The instantiateImageCodec method gives you a Codec, which acts as a decoder for your image data. To get the usable ui.Image you need for drawing, you have to pull the first (or desired) frame from this codec using getNextFrame(). This method returns a FrameInfo object, which holds the actual ui.Image inside it.

Modified code for your _loadImage method

Here’s how to adjust your existing function to return a Future<ui.Image> instead of a Codec:

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

Future<ui.Image> _loadImage(AssetBundleImageKey key) async {
  // Fetch the raw image data from the asset bundle
  final ByteData data = await key.bundle.load(key.name);
  // Create the codec from the image data
  final ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List());
  // Extract the first frame from the codec
  final ui.FrameInfo frameInfo = await codec.getNextFrame();
  // Return the ready-to-use ui.Image
  return frameInfo.image;
}

Using the ui.Image in a CustomPainter

Once you have your ui.Image, you can integrate it into a CustomPainter to draw on the Canvas. Here’s a complete example that handles the async load and drawing:

class MyCustomPainter extends CustomPainter {
  final ui.Image? image;

  MyCustomPainter(this.image);

  @override
  void paint(Canvas canvas, Size size) {
    if (image == null) return;

    // Draw the image at the top-left corner with original size
    canvas.drawImage(image!, Offset.zero, Paint());

    // Optional: Scale the image to fit the entire canvas
    final scaledImage = ui.Image.resize(
      image!, 
      width: size.width.toInt(), 
      height: size.height.toInt()
    );
    canvas.drawImage(scaledImage, Offset.zero, Paint());
  }

  @override
  bool shouldRepaint(covariant MyCustomPainter oldDelegate) {
    return oldDelegate.image != image;
  }
}

// In your widget tree:
FutureBuilder<ui.Image>(
  future: _loadImage(AssetBundleImageKey(
    bundle: rootBundle,
    name: 'assets/your_image.png', // Replace with your asset path
    scale: 1.0,
  )),
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      return CustomPaint(
        painter: MyCustomPainter(snapshot.data),
        size: Size.infinite,
      );
    } else {
      return const Center(child: CircularProgressIndicator());
    }
  },
)

Quick tips to avoid headaches

  • Dispose the image: When your widget is disposed, call image?.dispose() to free up memory—this prevents leaks, especially if you’re loading multiple images.
  • Animated images: If you’re working with a GIF or other animated asset, you can loop through frames by calling codec.getNextFrame() repeatedly. For static images, just the first frame is enough.
  • Asset setup: Double-check that your image is listed in the assets section of your pubspec.yaml—otherwise the asset bundle won’t be able to find it.

内容的提问来源于stack exchange,提问作者Anderson Andrade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:56:37