Open6

FlutterのCanvasの簡単な使い方メモ

YuheiNakasakaYuheiNakasaka

Javascriptのcanvasのように色々な画像や文字を一つのcanvasに描いて1枚の画像を生成できると便利。Flutterでも同じようなことが出来るので基本的な扱い方を調べてみる。

YuheiNakasakaYuheiNakasaka

なので基本的には下記のようなコードで書いていくことになる。

以下、全てのコード例はあくまで要点のみ書いているだけなのでそのままコピペして動くものではない。注意。

import 'dart:ui' as ui;

void main() async {
  final recoder = ui.PictureRecorder();
  final canvas = Canvas(recoder);
  final paint = Paint()..isAntiAlias = true;

  // ☆いろいろなdrawingの処理...

  final picture = await recoder.endRecording();
  final image = await picture.toImage(100, 100); // exportしたい画像サイズをwidth,heightで指定

  // imageをアップロードしたりダウンロードしたりする処理...
}
YuheiNakasakaYuheiNakasaka

☆いろいろなdrawing処理について。

文字を描画したい場合はTextSpanを作成し、TextPainterでCanvasに描画していく。日本語はもちろん絵文字も描画できる。

const span = TextSpan(
    style: TextStyle(
      color: Colors.white,
      fontSize: 24,
      fontWeight: FontWeight.bold,
    ),
    text: '好きなテキストを指定してくだされ😇',
);
final textPainter = TextPainter(
    text: span,
    textAlign: TextAlign.left,
    textDirection: TextDirection.ltr,
);
textPainter.layout();
textPainter.paint(canvas, const Offset(50, 50));
YuheiNakasakaYuheiNakasaka

ローカルの画像を描画したい場合はまずローカルの画像をui.Imageに変換するためにUiny8Listからui.decodeImageFromListでdecodeする。そしてその画像をdrawImageRectでCanvasに描画する。
下記の例の場合は画像が縦横300x300とすると、左上の(x,y)=(0,0)から横200縦200の部分を対象に切り出して、Canvasの左上の(x,y)=(0,0)から横100縦100に合うように描画するという命令になっている。JavascriptのCanvasに慣れてる人だと説明しなくてもわかると思う。

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

// 画像は縦横300x300とする
final rawData = await rootBundle.load("assets/images/sample.png");
final imgList = Uint8List.view(rawData.buffer);
ui.decodeImageFromList(imgList, (img) {
  final src = Rect.fromLTWH(0, 0, 200, 200); 
  const dst = Rect.fromLTWH(0, 0, 100, 100);
  canvas.drawImageRect(img, src, dst, paint);
});
YuheiNakasakaYuheiNakasaka

canvasに複数の文字や画像を描画する場合の例は下記。画像と文字が描画された100x200の画像が生成される。簡単。

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

final recoder = ui.PictureRecorder();
final canvas = Canvas(recoder);
final paint = Paint()..isAntiAlias = true;

final rawData = await rootBundle.load("assets/images/sample.png");
final imgList = Uint8List.view(rawData.buffer);
ui.decodeImageFromList(imgList, (img) {
  final src = Rect.fromLTWH(0, 0, 300, 300); 
  const dst = Rect.fromLTWH(0, 0, 100, 100);
  canvas.drawImageRect(img, src, dst, paint);

  const span = TextSpan(
      style: TextStyle(
        color: Colors.white,
        fontSize: 24,
        fontWeight: FontWeight.bold,
      ),
      text: '好きなテキストを指定してくだされ😇',
  );
  final textPainter = TextPainter(
      text: span,
      textAlign: TextAlign.left,
      textDirection: TextDirection.ltr,
  );
  textPainter.layout();
  textPainter.paint(canvas, const Offset(30, 120));

  final picture = await recoder.endRecording();
  final image = await picture.toImage(100, 200);
});