Android 颤振-如何使用DrawImage方法在画布上绘制图像

Android 颤振-如何使用DrawImage方法在画布上绘制图像,android,canvas,dart,flutter,Android,Canvas,Dart,Flutter,我正试图在画布中绘制一个图像文件,以便在Flutter中构建我的小部件 我照做了,但没有成功。哦,他们会说: 要获取图像对象,请使用instantiateImageCodec 我确实尝试过使用instantialeimagecodec方法,但我只得到了一个Codec实例,而不是一个 使用canvas.drawImage 以下是我的代码的snnipet: Future<ui.Codec> _loadImage(AssetBundleImageKey key) async { fin

我正试图在画布中绘制一个图像文件,以便在Flutter中构建我的小部件

我照做了,但没有成功。哦,他们会说:

要获取图像对象,请使用instantiateImageCodec

我确实尝试过使用
instantialeimagecodec
方法,但我只得到了一个
Codec
实例,而不是一个

使用
canvas.drawImage

以下是我的代码的snnipet:

Future<ui.Codec> _loadImage(AssetBundleImageKey key) async {
  final ByteData data = await key.bundle.load(key.name);
   if (data == null)
  throw 'Unable to read data';
   return await ui.instantiateImageCodec(data.buffer.asUint8List());
}

final Paint paint = new Paint()
  ..color = Colors.yellow
  ..strokeWidth = 2.0
  ..strokeCap = StrokeCap.butt
  ..style = PaintingStyle.stroke;

var sunImage = new ExactAssetImage("res/images/grid_icon.png");

sunImage.obtainKey(new ImageConfiguration()).then((AssetBundleImageKey key){
  _loadImage(key).then((ui.Codec codec){
    print("frameCount: ${codec.frameCount.toString()}");
    codec.getNextFrame().then((info){
      print("image: ${info.image.toString()}");
      print("duration: ${info.duration.toString()}");
      canvas.drawImage(info.image, size.center(Offset.zero), paint);
    });
  });
});
Future\u加载映像(AssetBundleImageKey)异步{
final ByteData data=wait key.bundle.load(key.name);
如果(数据==null)
抛出“无法读取数据”;
return wait ui.instantialeimagecodec(data.buffer.asUint8List());
}
最终油漆=新油漆()
…颜色=颜色。黄色
..冲程宽度=2.0
..strokeCap=strokeCap.butt
..风格=绘画风格.笔划;
var sunImage=new ExactAssetImages(“res/images/grid_icon.png”);
sunImage.ActainKey(新的ImageConfiguration())。然后((AssetBundleImageKey){
_loadImage(键)。然后((ui.Codec-Codec){
打印(“帧数:${codec.frameCount.toString()}”);
codec.getNextFrame().then((信息){
打印(“图像:${info.image.toString()}”);
打印(“持续时间:${info.duration.toString()}”);
画布.drawImage(信息图像、大小、中心(偏移量为零)、绘制);
});
});
});

ui.Codec有一个方法
getNextFrame()
,该方法返回一个
未来
(你可能应该有关于多少帧的逻辑,但如果你知道它总是一张普通图片,你可以跳过它。)有一个
图像
属性,这就是你需要的图像

编辑:看看你在帖子中的代码,不清楚你在哪里做什么。这都是在
CustomPainter.paint
方法中定义的吗?如果是这样,您肯定会遇到问题,因为您只能在
paint
调用期间使用
canvas
;您不应该在函数之外保留对它的任何引用(这将包括任何异步调用)

我建议您使用FutureBuilder,以便在添加图像后仅在画布上绘制

看起来是这样的:

Future<Image> _loadImage(AssetBundleImageKey key) async {
  final ByteData data = await key.bundle.load(key.name);
  if (data == null)
    throw 'Unable to read data';
  var codec = await ui.instantiateImageCodec(data.buffer.asUint8List());
  // add additional checking for number of frames etc here
  var frame = await codec.getNextFrame();
  return frame.image;
}

new FutureBuilder<Image>(
  future: loadImage(....), // a Future<String> or null
  builder: (BuildContext context, AsyncSnapshot<Image> snapshot) {
    switch (snapshot.connectionState) {
      case ConnectionState.waiting: return new Text('Image loading...');
      default:
        if (snapshot.hasError)
          return new Text('Error: ${snapshot.error}');
        else
          // ImageCanvasDrawer would be a (most likely) statless widget
          // that actually makes the CustomPaint etc
          return new ImageCanvasDrawer(image: snapshot.data)
    }
  },
)
Future\u加载映像(AssetBundleImageKey)异步{
final ByteData data=wait key.bundle.load(key.name);
如果(数据==null)
抛出“无法读取数据”;
var codec=wait ui.instantialeimagecodec(data.buffer.asUint8List());
//在此处添加额外的帧数检查等
var frame=await codec.getNextFrame();
返回帧。图像;
}
新未来建设者(
future:loadImage(..)//a future或null
生成器:(BuildContext上下文,异步快照){
交换机(快照.连接状态){
case ConnectionState.waiting:返回新文本('图像加载…');
违约:
if(snapshot.hasError)
返回新文本('Error:${snapshot.Error}');
其他的
//ImageCanvasDrawer将是一个(很可能)无支架的小部件
//这实际上是定制的绘画等等
返回新的ImageCanvasDrawer(图像:snapshot.data)
}
},
)
类ImagePainter扩展了CustomPainter{
列表图像=新列表();
画师(
{键,
@需要这个。noOfSlice,
@需要这个。图像,
@需要这个轮换,
this.boxfit=boxfit.contain})
:
//:path=新路径()
//..添加椭圆(新矩形从圆形开始)(
//中心:新偏移(75.0,75.0),
//半径:40.0,
//     )),
tickPaint=新油漆(){
tickPaint.strokeWidth=2.5;
}
最后的国际努夫斯利;
最终油漆;
最终BoxFit-BoxFit;
ui.ImageByteFormat img;
ui.Rect Rect,inputSubrect,outputSubrect;
尺寸图像尺寸;
合适的尺寸;
双半径,
旋转=0.0,
_x,,
_y,,
_角度,
_拉迪恩,
_基准长度,
_我的天哪,
_因其原因,
_imageOffset=0.0,
_imageSizeConst=0.0;
@凌驾
虚空绘制(ui.Canvas画布,ui.Size){
打印(“图像数据::$images”);
半径=尺寸。宽度/2;
_角度=360/(noOfSlice*2.0);
_半径=(_角度*pi)/180;
_基长=2*半径*sin(_半径);
_内圆半径=(_基长/2)*tan(_半径);
if(noOfSlice==4){
_imageOffset=30.0;
_imageSizeConst=30.0;
_x=8.60;
_y=4.10;
}else if(noOfSlice==6){
_imageOffset=20.0;
_x=10.60;
_y=5.60;
}else if(noOfSlice==8){
_imageOffset=40.0;
_imageSizeConst=30.0;
_x=12.90;
_y=6.60;
}
//打印(“圆形radisu::$_incircleRadius”);
canvas.save();
canvas.translate(size.width/2,size.height/2);
canvas.rotate(-rotation);
int incr=0;
rect=ui.Offset((size.width/x)、size.width/y)和新大小(0.0,0.0);
imageSize=新尺寸(尺寸.宽度*1.5,尺寸.宽度*1.5);
尺寸=applyBoxFit(
boxfit,
图像大小,
新尺寸(尺寸宽度/2*.50+_英寸半径*.8,
尺寸/宽度/2*.50+_英寸*.8));
inputSubrect=
对齐。中心。刻字(尺寸。来源、偏移量。零点和图像尺寸);
outputSubrect=对齐。居中。刻字(大小。目的地,rect);
if(images.length==noOfSlice&&images.isNotEmpty)

对于(var i=1;i此简单实用方法返回给定图像资产路径的
未来

import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as UI;

import 'package:flutter/services.dart';

Future<UI.Image> loadUiImage(String imageAssetPath) async {
  final ByteData data = await rootBundle.load(imageAssetPath);
  final Completer<UI.Image> completer = Completer();
  UI.decodeImageFromList(Uint8List.view(data.buffer), (UI.Image img) {
    return completer.complete(img);
  });
  return completer.future;
}
导入'dart:async';
导入“dart:键入的_数据”;
将“dart:ui”导入为ui;
导入“包:flifter/services.dart”;
Future loadUiImage(字符串imageAssetPath)异步{
最终ByteData数据=等待rootBundle.load(imageAssetPath);
最终完成者完成者=完成者();
UI.decodeMageFromList(Uint8List.view(data.buffer),(UI.Image img){
返回完成符。完成(img);
});
返回completer.future;
}

谢谢你回答我的问题!我确实更新了我的代码
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as UI;

import 'package:flutter/services.dart';

Future<UI.Image> loadUiImage(String imageAssetPath) async {
  final ByteData data = await rootBundle.load(imageAssetPath);
  final Completer<UI.Image> completer = Completer();
  UI.decodeImageFromList(Uint8List.view(data.buffer), (UI.Image img) {
    return completer.complete(img);
  });
  return completer.future;
}