画面をキャプチャして、画像ファイルとしてギャラリーに保存する方法
目次
方法
- 標準クラスのRepaintBoundaryを使用する
- image_gallery_saverライブラリを使用する
手順
- Widgetへアクセスできるようにするために、GlobalKeyを生成しておく。
- 画像ファイル化したい範囲のウィジェットをRepaintBoundaryでラップする。
- RepaintBoundaryのkeyに、手順1で生成したGlobalKeyを割り当てる。
- どこかのイベント内にWidgetを画像ファイル化する処理を入れる。
- ギャラリーに保存する処理を入れる
Widgetへアクセスできるようにするために、GlobalKeyを生成しておく。
class _BodyState extends State<Body> {
File _image;
Uint8List _image64;
final picker = ImagePicker();
GlobalKey _globalKey = GlobalKey(); // 1. GlobalKey生成
画像ファイル化したい範囲のウィジェットをRepaintBoundaryでラップする。とRepaintBoundaryのkeyに、手順1で生成したGlobalKeyを割り当てる。
RepaintBoundary(
key: _globalKey, ←3
child: Stack(
children: [
Positioned(
child: Image.asset(
"assets/images/edit/simple_heart6.png",
height: getProportionateScreenHeight(300),
width: getProportionateScreenWidth(300),
fit: BoxFit.cover,
),
),
Positioned(
どこかのイベント内にWidgetを画像ファイル化する処理を入れる。
import 'dart:convert';
import 'dart:typed_data';
import 'dart:ui' as ui;
// ボタンが押された時
void _exportToImage() async {
// 現在描画されているWidgetを取得する
RenderRepaintBoundary boundary =
_globalKey.currentContext.findRenderObject();
// 取得したWidgetからイメージファイルをキャプチャする
ui.Image image = await boundary.toImage(
pixelRatio: 3.0,
);
// 以下はお好みで
// PNG形式化
ByteData byteData = await image.toByteData(
format: ui.ImageByteFormat.png,
);
// バイトデータ化
final _pngBytes = byteData.buffer.asUint8List();
setState(() {
_image64 = _pngBytes;
});
}
- 作成した画像ファイルを表示する処理は以下
- _image64の形式は、
Uint8List _image64;である必要がある
- _image64の形式は、
_image64 == null
? Text("data")
: new Image.memory(
_image64,
height: getProportionateScreenHeight(200),
width: getProportionateScreenWidth(200),
),
ギャラリーに保存する処理を入れる
- pubspec.yamlファイルに以下を追加
image_gallery_saver: ^1.6.4
- 以下のように使う
import 'package:image_gallery_saver/image_gallery_saver.dart';
// ボタンが押された時
void _exportToImage() async {
// 現在描画されているWidgetを取得する
RenderRepaintBoundary boundary =
_globalKey.currentContext.findRenderObject();
// 取得したWidgetからイメージファイルをキャプチャする
ui.Image image = await boundary.toImage(
pixelRatio: 3.0,
);
// 以下はお好みで
// PNG形式化
ByteData byteData = await image.toByteData(
format: ui.ImageByteFormat.png,
);
// バイトデータ化
final _pngBytes = byteData.buffer.asUint8List();
// BASE64形式化
final _base64 = base64Encode(_pngBytes);
print(_base64);
// ここから
final result = await ImageGallerySaver.saveImage(_pngBytes);
// print(result);
// ここまで追加
setState(() {
_image64 = _pngBytes;
});
}
エラー
flutter: Another exception was thrown: NoSuchMethodError: The method 'findRenderObject' was called on null.
-
参考
-
これは、コンテキストがまだ状態に関連付けられていないために発生します。
-
対応策
- レイアウトが完了した後に呼び出す。
GlobalKey _globalKey = GlobalKey(); // 1. GlobalKey生成
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
super.initState();
}
_afterLayout(_) {
_getSizes();
_getPositions();
}
_getSizes() {
final RenderBox renderBoxRed = _globalKey.currentContext.findRenderObject();
final sizeRed = renderBoxRed.size;
print("SIZE of Red: $sizeRed");
}
_getPositions() {
final RenderBox renderBoxRed = _globalKey.currentContext.findRenderObject();
final positionRed = renderBoxRed.localToGlobal(Offset.zero);
print("POSITION of Red: $positionRed ");
}