Flutterで画像をダウンロード、加工して表示する方法

任意の画像をダウンロードして、それに文字を入れて、SNSでシェアできる機能を作りたいと思い、その為の画像の方法を調べてみました。

##参考にしたページ
* [Flutterでデバイスにファイルを保存する](https://qiita.com/0maru/items/04513537d707527ea3aa)
* [FlutterのCanvasの簡単な使い方メモ](https://zenn.dev/razokulover/scraps/88f78a93c9678c)

##ファイルをダウンロードする
[Flutterでデバイスにファイルを保存する](https://qiita.com/0maru/items/04513537d707527ea3aa)を参考にしました。
ローカルにファイルを生成し、そこに書き込みます。
ファイル名だけだとエラーになるので、```getApplicationDocumentsDirectory()```を使い、画像を保存できるディレクトリ名を取得して、それと合わせて絶対パスで指定します。

```dart
Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path;
String imgPath = appDocPath + '/ファイル名';
final http.Response res = await http
	.get(Uri.parse('ダウンロードする画像のURL'));
final file = File(imgPath);
await file.create();
await file.writeAsBytes(res.bodyBytes);
```

##文字を入れる
[FlutterのCanvasの簡単な使い方メモ](https://zenn.dev/razokulover/scraps/88f78a93c9678c)を参考しました。
複数画像をダウンロードして加工する方法が記載されていたのですが、今回は1つだけ加工できればいいので、ループしている部分を書き換えました。

```dart
import 'dart:ui' as ui

final recoder = ui.PictureRecorder();
final canvas = Canvas(recoder);
final paint = Paint()..isAntiAlias = true;
final imgList = File(imgPath).readAsBytesSync();
var img = await decodeImageFromList(imgList);

final src = Rect.fromLTWH(0, 0, 300, 300);
const dst = Rect.fromLTWH(0, 0, 300, 300);
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();
image = await picture.toImage(100, 200);
```

##画面に表示する
Image型を、Uint8List型に変換しそれをWidgetで表示します。
Image型を表示する方法があまりなく結果こうなりました。

```dart
final data = await image.toByteData(format: ui.ImageByteFormat.png);
bytes = data.buffer.asUint8List();
```

Widget内

```dart
Image(image: MemoryImage(bytes))
```

##ソース全文

```dart
import 'dart:ui' as ui

Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path;
String imgPath = appDocPath + '/ファイル名';
final http.Response res = await http
	.get(Uri.parse('ダウンロードする画像のURL'));
final file = File(imgPath);
await file.create();
await file.writeAsBytes(res.bodyBytes);

final recoder = ui.PictureRecorder();
final canvas = Canvas(recoder);
final paint = Paint()..isAntiAlias = true;
final imgList = File(imgPath).readAsBytesSync();
var img = await decodeImageFromList(imgList);

final src = Rect.fromLTWH(0, 0, 300, 300);
const dst = Rect.fromLTWH(0, 0, 300, 300);
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();
image = await picture.toImage(100, 200);

final data = await image.toByteData(format: ui.ImageByteFormat.png);
bytes = data.buffer.asUint8List();
```

Widget内

```dart
Image(image: MemoryImage(bytes))
```

## おまけ
一通り実装してから、[【Flutter】Widgetを画像化→SNSシェア機能を実装する](https://zenn.dev/gold_panzee54/articles/210516-flutter-widget-to-image-share)というページを見つけました・・・。
Widgetで文字列入りの画像を作るほうが作りやすいのでこちらを参考にすることにしました。