Move toImage() impl from RepaintRenderBoundary to OffsetLayer (#17060)
https://github.com/flutter/flutter/issues/16859
This commit is contained in:
parent
f0c4bc30c6
commit
a5a33325ef
@ -2,8 +2,9 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:collection';
|
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 'dart:ui' show Offset;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
@ -515,6 +516,41 @@ class OffsetLayer extends ContainerLayer {
|
|||||||
super.debugFillProperties(properties);
|
super.debugFillProperties(properties);
|
||||||
properties.add(new DiagnosticsProperty<Offset>('offset', offset));
|
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.
|
/// A composite layer that clips its children using a rectangle.
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
import 'dart:async';
|
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/animation.dart';
|
||||||
import 'package:flutter/foundation.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
|
/// will give you a 1:1 mapping between logical pixels and the output pixels
|
||||||
/// in the image.
|
/// 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:
|
/// See also:
|
||||||
///
|
///
|
||||||
|
/// * [OffsetLayer.toImage] for a similar API at the layer level.
|
||||||
/// * [dart:ui.Scene.toImage] for more information about the image returned.
|
/// * [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);
|
assert(!debugNeedsPaint);
|
||||||
final ui.SceneBuilder builder = new ui.SceneBuilder();
|
return layer.toImage(size, pixelRatio: pixelRatio);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user