Last active
November 9, 2020 13:27
-
-
Save kangabru/23770a466e9366f21ea8d12d22b6f12e to your computer and use it in GitHub Desktop.
Allows you extract an image of specific widgets within your app. Includes the ability to ignore certain widgets and to crop the final image.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:typed_data'; | |
import 'dart:ui' as ui; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter/rendering.dart'; | |
// Note: [ui.Image] represents the lower level image data while [Image] represents a renderable image. | |
/// Provides the ability to take screenshots of specific widgets. | |
mixin Screenshot<T extends StatefulWidget> on State<T> { | |
static GlobalKey _key = new GlobalKey(); | |
/// Wrap this around widget you wish to screenshot. | |
Widget screenshotThis(Widget child) => RepaintBoundary(key: _key, child: child); | |
/// Returns the screenshot of the widgets wrapped with [screenshotThis]. | |
/// Applies an optional background and crop to the final image. | |
Future<ScreenshotData> takeScreenshot({Color background, Rect crop}) async { | |
var imageDataRaw = await _getScreenshotData(); | |
var imageData = await _updateImage(imageDataRaw, background, crop); | |
return _convertDataToImage(imageData); | |
} | |
/// Returns the raw image of the widgets to screenshot. | |
Future<ui.Image> _getScreenshotData() async { | |
RenderRepaintBoundary boundary = _key.currentContext.findRenderObject(); | |
return boundary.toImage(); | |
} | |
/// Converts the raw image into a renderable form. | |
Future<ScreenshotData> _convertDataToImage(ui.Image imageData) async { | |
var byteData = await imageData.toByteData(format: ui.ImageByteFormat.png); | |
var pngBytes = byteData.buffer.asUint8List(); | |
var image = Image.memory(pngBytes); | |
return ScreenshotData(image, pngBytes); | |
} | |
/// Processes an image with an optional background color and crop | |
Future<ui.Image> _updateImage(ui.Image image, [Color background, Rect crop]) { | |
var pictureRecorder = new ui.PictureRecorder(); | |
Canvas canvas = new Canvas(pictureRecorder); | |
canvas.drawPaint(Paint()..color = background ?? Colors.transparent); | |
// No crop provided so render the full image | |
if (crop == null) { | |
int width = image.width, height = image.height; | |
canvas.drawImage(image, Offset.zero, Paint()); | |
return pictureRecorder.endRecording().toImage(width, height); | |
} | |
// Crop the image by extracting the crop rect and moving to the top left | |
final width = crop.width, height = crop.height; | |
var dest = Rect.fromLTWH(0, 0, width, height); | |
canvas.drawImageRect(image, crop, dest, Paint()); | |
return pictureRecorder.endRecording().toImage(width.floor(), height.floor()); | |
} | |
} | |
/// Contains a renderable Image and the raw image bytes. | |
class ScreenshotData { | |
final Image image; | |
final Uint8List pngBytes; | |
ScreenshotData(this.image, this.pngBytes); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment