flutterimagedart

Flutter image generation in background


Is it possible to generate (and save as an image) interface or individual flutter widgets without displaying the program, in the background / console utility? For windows/Linux.

While this is a working variant, the program is still displayed:

import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:io';
import 'package:intl/intl.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  const test = Text(
    'Hello, World!',
    style: TextStyle(fontSize: 24.0),
  );

  final boundaryKey = GlobalKey();
  final RepaintBoundary repaintBoundary = RepaintBoundary(
    key: boundaryKey,
    child: test,
  );

  WidgetsBinding.instance.addPostFrameCallback((_) async {
    DateTime now = DateTime.now();
    var formatter = DateFormat('hh.mm.ss');
    String formattedDate = formatter.format(now);
    print(formattedDate);

    final RenderRepaintBoundary boundary =
        boundaryKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
    final image = await boundary.toImage(pixelRatio: 3.0);
    final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
    final pngBytes = byteData!.buffer.asUint8List();

    final file = File('results/$formattedDate.png');
    await file.writeAsBytes(pngBytes);

    print('Image saved to: ${file.path}');
  });

  runApp(MaterialApp(home: repaintBoundary));
}


Solution

  • Thanks to spauldhaliwal

    Here is how I did it:

    import 'dart:io';
    import 'dart:typed_data';
    import 'package:flutter/material.dart';
    import 'package:flutter_test/flutter_test.dart';
    import 'package:screenshot/screenshot.dart';
    
    void main() async {
      TestWidgetsFlutterBinding.ensureInitialized();
    
      final ScreenshotController screenshotController = ScreenshotController();
    
      void saveCapturedWidget(Uint8List capturedImage) {
        final file = File('results/my_image.jpg');
        file.writeAsBytesSync(capturedImage);
        print('Image saved to: ${file.path}');
      }
    
      const double widgetWidth = 200.0;
      const double widgetHeight = 200.0;
    
      Widget invisibleWidget = Container(
        width: widgetWidth,
        height: widgetHeight,
        color: Colors.blue,
        child: const Center(
          child: Text(
            'Invisible Widget',
            style: TextStyle(color: Colors.white, fontSize: 20),
          ),
        ),
      );
    
      final capturedImage = await screenshotController.captureFromWidget(
        invisibleWidget,
        targetSize: const Size(widgetWidth, widgetHeight),
        pixelRatio: 1.0,
      );
    
      saveCapturedWidget(capturedImage);
    
      print('Image generation completed. Exiting...');
      exit(0);
    }