Unverified Commit a5a33325 authored by Todd Volkert's avatar Todd Volkert Committed by GitHub

Move toImage() impl from RepaintRenderBoundary to OffsetLayer (#17060)

https://github.com/flutter/flutter/issues/16859
parent f0c4bc30
......@@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:collection';
import 'dart:ui' as ui show ImageFilter, Picture, SceneBuilder;
import 'dart:ui' as ui show Image, ImageFilter, Picture, Scene, SceneBuilder;
import 'dart:ui' show Offset;
import 'package:flutter/foundation.dart';
......@@ -515,6 +516,41 @@ class OffsetLayer extends ContainerLayer {
super.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<Offset>('offset', offset));
}
/// Capture an image of the current state of this layer and its children.
///
/// The returned [ui.Image] has uncompressed raw RGBA bytes, in the
/// dimensions [logicalSize] multiplied by the [pixelRatio].
///
/// The [pixelRatio] describes the scale between the logical pixels and the
/// size of the output image. It is independent of the
/// [window.devicePixelRatio] for the device, so specifying 1.0 (the default)
/// will give you a 1:1 mapping between logical pixels and the output pixels
/// in the image.
///
/// See also:
///
/// * [RenderRepaintBoundary.toImage] for a similar API at the render object level.
/// * [dart:ui.Scene.toImage] for more information about the image returned.
Future<ui.Image> toImage(Size logicalSize, {double pixelRatio: 1.0}) async {
assert(pixelRatio != null);
final ui.SceneBuilder builder = new ui.SceneBuilder();
final Matrix4 transform = new Matrix4.diagonal3Values(pixelRatio, pixelRatio, 1.0);
transform.translate(-offset.dx, -offset.dy, 0.0);
builder.pushTransform(transform.storage);
addToScene(builder, Offset.zero);
final ui.Scene scene = builder.build();
try {
// Size is rounded up to the next pixel to make sure we don't clip off
// anything.
return await scene.toImage(
(pixelRatio * logicalSize.width).ceil(),
(pixelRatio * logicalSize.height).ceil(),
);
} finally {
scene.dispose();
}
}
}
/// A composite layer that clips its children using a rectangle.
......
......@@ -4,7 +4,7 @@
import 'dart:async';
import 'dart:ui' as ui show ImageFilter, Gradient, SceneBuilder, Scene, Image;
import 'dart:ui' as ui show ImageFilter, Gradient, Image;
import 'package:flutter/animation.dart';
import 'package:flutter/foundation.dart';
......@@ -2470,27 +2470,52 @@ class RenderRepaintBoundary extends RenderProxyBox {
/// will give you a 1:1 mapping between logical pixels and the output pixels
/// in the image.
///
/// ## Sample code
///
/// The following is an example of how to go from a `GlobalKey` on a
/// `RepaintBoundary` to a PNG:
///
/// ```dart
/// class PngHome extends StatefulWidget {
/// PngHome({Key key}) : super(key: key);
///
/// @override
/// _PngHomeState createState() => new _PngHomeState();
/// }
///
/// class _PngHomeState extends State<PngHome> {
/// GlobalKey globalKey = new GlobalKey();
///
/// Future<void> _capturePng() async {
/// RenderRepaintBoundary boundary = globalKey.currentContext.findRenderObject();
/// ui.Image image = await boundary.toImage();
/// ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
/// Uint8List pngBytes = byteData.buffer.asUint8List();
/// print(pngBytes);
/// }
///
/// @override
/// Widget build(BuildContext context) {
/// return RepaintBoundary(
/// key: globalKey,
/// child: Center(
/// child: FlatButton(
/// child: Text('Hello World', textDirection: TextDirection.ltr),
/// onPressed: _capturePng,
/// ),
/// ),
/// );
/// }
/// }
/// ```
///
/// See also:
///
/// * [OffsetLayer.toImage] for a similar API at the layer level.
/// * [dart:ui.Scene.toImage] for more information about the image returned.
Future<ui.Image> toImage({double pixelRatio: 1.0}) async {
Future<ui.Image> toImage({double pixelRatio: 1.0}) {
assert(!debugNeedsPaint);
final ui.SceneBuilder builder = new ui.SceneBuilder();
final Matrix4 transform = new Matrix4.diagonal3Values(pixelRatio, pixelRatio, 1.0);
transform.translate(-layer.offset.dx, -layer.offset.dy, 0.0);
builder.pushTransform(transform.storage);
layer.addToScene(builder, Offset.zero);
final ui.Scene scene = builder.build();
try {
// Size is rounded up to the next pixel to make sure we don't clip off
// anything.
return await scene.toImage(
(pixelRatio * size.width).ceil(),
(pixelRatio * size.height).ceil(),
);
} finally {
scene.dispose();
}
return layer.toImage(size, pixelRatio: pixelRatio);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment