Skip to content

Instantly share code, notes, and snippets.

@PlugFox
Last active April 25, 2024 13:17
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save PlugFox/b2445fc249f566ad6499f520e2f6808c to your computer and use it in GitHub Desktop.
Save PlugFox/b2445fc249f566ad6499f520e2f6808c to your computer and use it in GitHub Desktop.
Flutter get screenshot from canvas layer
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:gallery_saver/gallery_saver.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'screenshot.dart';
void main() => runApp(const App());
class App extends StatelessWidget {
const App({super.key});
Future<void> saveScreenshot(ByteData data) async {
File? file;
try {
final dir = await getTemporaryDirectory();
file = File(join(dir.path, 'screenshot_${DateTime.now().millisecondsSinceEpoch.toRadixString(36)}.png'));
await file.writeAsBytes(data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes));
await GallerySaver.saveImage(file.path);
} finally {
await file?.delete();
}
}
@override
Widget build(BuildContext context) => ScreenshotScope(
child: MaterialApp(
title: 'Material App',
home: Scaffold(
appBar: AppBar(
title: const Text('App Bar'),
),
body: SafeArea(
child: Center(
child: SingleChildScrollView(
child: ScreenshotScope(
child: Builder(
builder: (context) => ElevatedButton(
onPressed: () => ScreenshotScope.takeScreenshot(context).then<void>(saveScreenshot),
child: Text('Hello World\n' * 100),
),
),
),
),
),
),
),
),
);
}
/// How to take a screenshot of widgets
import 'dart:typed_data' as td;
import 'dart:ui' as ui;
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
class ScreenshotScope extends StatelessWidget {
const ScreenshotScope({required this.child, super.key});
final Widget child;
static Future<td.ByteData> takeScreenshot(
BuildContext context, {
double pixelRatio = 1.0,
}) async {
RenderRepaintBoundary? boundary;
context.visitAncestorElements((element) {
if (element.widget is ScreenshotScope) return false;
final renderObject = element.renderObject;
if (renderObject is RenderRepaintBoundary) boundary = renderObject;
return true;
});
if (boundary == null) throw UnsupportedError('No ScreenshotScope found');
final image = await boundary!.toImage(pixelRatio: pixelRatio);
final bytes = await image.toByteData(format: ui.ImageByteFormat.png);
if (bytes is! td.ByteData) throw UnsupportedError('Error converting image to bytes');
return bytes;
}
@override
Widget build(BuildContext context) => RepaintBoundary(child: child);
}
@PlugFox
Copy link
Author

PlugFox commented Jan 16, 2022

Просто обернуть виджет в ScreenshotScope.

Получение скриншота из контекста:

final screenshot = await ScreenshotScope.takeScreenshot(context);

Ну и сохранить на диск png, например:

final dir = await getTemporaryDirectory();
final file = File(join(dir.path, 'screenshot_${DateTime.now().toIso8601String()}.png'));
await file.writeAsBytes(
  screenshot.buffer.asUint8List(screenshot.offsetInBytes, screenshot.lengthInBytes),
);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment