任意の画像をダウンロードして、それに文字を入れて、SNSでシェアできる機能を作りたいと思い、その為の画像の方法を調べてみました。
参考にしたページ
ファイルをダウンロードする
Flutterでデバイスにファイルを保存するを参考にしました。
ローカルにファイルを生成し、そこに書き込みます。
ファイル名だけだとエラーになるので、getApplicationDocumentsDirectory()
を使い、画像を保存できるディレクトリ名を取得して、それと合わせて絶対パスで指定します。
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の簡単な使い方メモを参考しました。
複数画像をダウンロードして加工する方法が記載されていたのですが、今回は1つだけ加工できればいいので、ループしている部分を書き換えました。
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型を表示する方法があまりなく結果こうなりました。
final data = await image.toByteData(format: ui.ImageByteFormat.png);
bytes = data.buffer.asUint8List();
Widget内
Image(image: MemoryImage(bytes))
ソース全文
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内
Image(image: MemoryImage(bytes))
おまけ
一通り実装してから、【Flutter】Widgetを画像化→SNSシェア機能を実装するというページを見つけました・・・。
Widgetで文字列入りの画像を作るほうが作りやすいのでこちらを参考にすることにしました。