All Articles

画面をキャプチャして、画像ファイルとしてギャラリーに保存する方法

目次

方法

手順

  1. Widgetへアクセスできるようにするために、GlobalKeyを生成しておく。
  2. 画像ファイル化したい範囲のウィジェットをRepaintBoundaryでラップする。
  3. RepaintBoundaryのkeyに、手順1で生成したGlobalKeyを割り当てる。
  4. どこかのイベント内にWidgetを画像ファイル化する処理を入れる。
  5. ギャラリーに保存する処理を入れる

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 == 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 ");
  }

Published Nov 14, 2020

Flutterでスマホアプリ開発しています