Flutterでウィジェットを作成するために、キャンバスに画像ファイルを描画しようとしています。
私は canvas documentation に従いましたが、成功しませんでした。 O Image docs 、次のように言います:
Imageオブジェクトを取得するには、instantiateImageCodecを使用します。
私はinstantiateImageCodec
メソッドを使用しようとしましたが、 Image ではなくCodec
インスタンスを取得するだけです
どのようにcanvas.drawImage
を使用してキャンバスに描画するui.Imageのインスタンスを取得する正しい方法は
これが私のコードのスニペットです:
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);
});
});
});
ui.CodecにはgetNextFrame()
メソッドがあり、Future<FrameInfo>
(おそらくフレーム数に関するロジックがあるはずですが、それが常に通常の画像であることがわかっている場合は、スキップできます。) FrameInfo
にはimage
プロパティがあり、必要な画像です。
編集:あなたが投稿にあるコードを見ると、どこで何をしているのか明確ではありません。それはすべてCustomPainter.Paint
方法?その場合、canvas
呼び出しの期間中のみPaint
を使用できるため、間違いなく問題が発生します。関数の外部への参照は保持しないでください(非同期呼び出しが含まれます)。
画像を追加した後でのみキャンバスに描画できるように、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<UI.Image>
を返します。
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;
}
class ImagePainter extends CustomPainter {
List<ui.Image> images = new List<ui.Image>();
ImagePainter(
{Key key,
@required this.noOfSlice,
@required this.images,
@required this.rotation,
this.boxfit = BoxFit.contain})
:
// : path = new Path()
// ..addOval(new Rect.fromCircle(
// center: new Offset(75.0, 75.0),
// radius: 40.0,
// )),
tickPaint = new Paint() {
tickPaint.strokeWidth = 2.5;
}
final int noOfSlice;
final tickPaint;
final BoxFit boxfit;
ui.ImageByteFormat img;
ui.Rect rect, inputSubrect, outputSubrect;
Size imageSize;
FittedSizes sizes;
double radius,
rotation = 0.0,
_x,
_y,
_angle,
_radiun,
_baseLength,
_imageCircleradius,
_incircleRadius,
_imageOffset = 0.0,
_imageSizeConst = 0.0;
@override
void Paint(ui.Canvas canvas, ui.Size size) {
print("image data:: $images");
radius = size.width / 2;
_angle = 360 / (noOfSlice * 2.0);
_radiun = (_angle * pi) / 180;
_baseLength = 2 * radius * sin(_radiun);
_incircleRadius = (_baseLength / 2) * tan(_radiun);
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;
}
//print("circle 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) & new Size(0.0, 0.0);
imageSize = new Size(size.width * 1.5, size.width * 1.5);
sizes = applyBoxFit(
boxfit,
imageSize,
new Size(size.width / 2 * .50 + _incircleRadius * .8,
size.width / 2 * .50 + _incircleRadius * .8));
inputSubrect =
Alignment.center.inscribe(sizes.source, Offset.zero & imageSize);
outputSubrect = Alignment.center.inscribe(sizes.destination, rect);
if (images.length == noOfSlice && images.isNotEmpty)
for (var i = 1; i <= noOfSlice * 2; ++i) {
if (i % 2 != 0) {
canvas.drawLine(
new Offset(0.0, 0.0),
new Offset(0.0, size.width / 2 - 4.2),
tickPaint,
);
} else {
canvas.save();
canvas.translate(-0.0, -((size.width) / 2.2));
ui.Image image = images[incr];
if (image != null) {
canvas.drawImageRect(
image, inputSubrect, outputSubrect, new Paint());
}
canvas.restore();
incr++;
}
canvas.rotate(2 * pi / (noOfSlice * 2.0));
}
canvas.restore();
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
}