Search code examples
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);
    }