Skip to content

Commit ee873a2

Browse files
committed
chore: cherry-pick to 2.0.0
1 parent e42c576 commit ee873a2

File tree

12 files changed

+135
-72
lines changed

12 files changed

+135
-72
lines changed

.vscode/launch.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
"name": "Flutter",
99
"request": "launch",
1010
"type": "dart",
11-
"program": "example/lib/main.dart"
11+
"program": "example/lib/main.dart",
12+
"args": [
13+
"--web-renderer canvaskit --dart-define=BROWSER_IMAGE_DECODING_ENABLED=false --release"
14+
]
1215
}
1316
]
1417
}

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## [2.0.0] - 13/05/2023
2+
* Migrate to `FlutterView` from `ui.window` @Mayb3Nots
3+
## [1.3.0] - 27/12/2022
4+
* Fix disposing widgets after capturing in widgetToUiImage function @Lan-tb
15
## [1.2.3] - 15/07/2021
26
* Support Inheriting Theme for Invisible Widget
37

example/android/app/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
2626
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
2727

2828
android {
29-
compileSdkVersion 30
29+
compileSdkVersion 31
3030

3131
sourceSets {
3232
main.java.srcDirs += 'src/main/kotlin'
@@ -36,7 +36,7 @@ android {
3636
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
3737
applicationId "com.screenshot.example"
3838
minSdkVersion 17
39-
targetSdkVersion 30
39+
targetSdkVersion 31
4040
versionCode flutterVersionCode.toInteger()
4141
versionName flutterVersionName
4242
}

example/android/app/src/main/AndroidManifest.xml

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<activity
77
android:name=".MainActivity"
88
android:launchMode="singleTop"
9+
android:exported="true"
910
android:theme="@style/LaunchTheme"
1011
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
1112
android:hardwareAccelerated="true"

example/android/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
buildscript {
2-
ext.kotlin_version = '1.3.50'
2+
ext.kotlin_version = '1.6.0'
33
repositories {
44
google()
55
jcenter()
@@ -26,6 +26,6 @@ subprojects {
2626
project.evaluationDependsOn(':app')
2727
}
2828

29-
task clean(type: Delete) {
29+
tasks.register("clean", Delete) {
3030
delete rootProject.buildDir
3131
}

example/lib/main.dart

+21-9
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ class MyApp extends StatelessWidget {
1515
title: 'Flutter Demo',
1616
theme: ThemeData(
1717
textTheme: TextTheme(
18-
headline6: TextStyle(
18+
titleLarge: TextStyle(
1919
color: Colors.yellow,
20-
fontSize: 50,
20+
// fontSize: 50,
2121
)),
2222
// This is the theme of your application.
2323
//
@@ -73,7 +73,14 @@ class _MyHomePageState extends State<MyHomePage> {
7373
border: Border.all(color: Colors.blueAccent, width: 5.0),
7474
color: Colors.amberAccent,
7575
),
76-
child: Text("This widget will be captured as an image")),
76+
child: Stack(
77+
children: [
78+
Image.asset(
79+
'assets/images/flutter.png',
80+
),
81+
Text("This widget will be captured as an image"),
82+
],
83+
)),
7784
),
7885
SizedBox(
7986
height: 25,
@@ -103,9 +110,16 @@ class _MyHomePageState extends State<MyHomePage> {
103110
border: Border.all(color: Colors.blueAccent, width: 5.0),
104111
color: Colors.redAccent,
105112
),
106-
child: Text(
107-
"This is an invisible widget",
108-
style: Theme.of(context).textTheme.headline6,
113+
child: Stack(
114+
children: [
115+
Image.asset(
116+
'assets/images/flutter.png',
117+
),
118+
Text(
119+
"This is an invisible widget",
120+
style: Theme.of(context).textTheme.titleLarge,
121+
),
122+
],
109123
));
110124
screenshotController
111125
.captureFromWidget(
@@ -138,9 +152,7 @@ class _MyHomePageState extends State<MyHomePage> {
138152
appBar: AppBar(
139153
title: Text("Captured widget screenshot"),
140154
),
141-
body: Center(
142-
child: Image.memory(capturedImage),
143-
),
155+
body: Center(child: Image.memory(capturedImage)),
144156
),
145157
);
146158
}

example/pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ dependencies:
1818
sdk: flutter
1919
screenshot:
2020
path: ../
21-
cupertino_icons: ^0.1.2
21+
# cupertino_icons: ^0.1.2
2222
# image_gallery_saver: ^1.1.0
2323

2424
dev_dependencies:

example/test/widget_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import 'package:flutter/material.dart';
99
import 'package:flutter_test/flutter_test.dart';
1010

11-
import 'package:example/main.dart';
11+
import '../lib/main.dart';
1212

1313
void main() {
1414
testWidgets('Counter increments smoke test', (WidgetTester tester) async {

example/windows/flutter/generated_plugins.cmake

+8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
list(APPEND FLUTTER_PLUGIN_LIST
66
)
77

8+
list(APPEND FLUTTER_FFI_PLUGIN_LIST
9+
)
10+
811
set(PLUGIN_BUNDLED_LIBRARIES)
912

1013
foreach(plugin ${FLUTTER_PLUGIN_LIST})
@@ -13,3 +16,8 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
1316
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
1417
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
1518
endforeach(plugin)
19+
20+
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
21+
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
22+
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
23+
endforeach(ffi_plugin)

lib/screenshot.dart

+29-12
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'src/platform_specific/file_manager/file_manager.dart';
1414
class Screenshot<T> extends StatefulWidget {
1515
final Widget? child;
1616
final ScreenshotController controller;
17+
1718
const Screenshot({
1819
Key? key,
1920
required this.child,
@@ -33,6 +34,7 @@ class Screenshot<T> extends StatefulWidget {
3334
///
3435
class ScreenshotController {
3536
late GlobalKey _containerKey;
37+
3638
ScreenshotController() {
3739
_containerKey = GlobalKey();
3840
}
@@ -50,6 +52,8 @@ class ScreenshotController {
5052
);
5153
ByteData? byteData =
5254
await image?.toByteData(format: ui.ImageByteFormat.png);
55+
image?.dispose();
56+
5357
Uint8List? pngBytes = byteData?.buffer.asUint8List();
5458

5559
return pngBytes;
@@ -75,9 +79,10 @@ class ScreenshotController {
7579
return fileManager.saveFile(content!, directory, name: fileName);
7680
}
7781

78-
Future<ui.Image?> captureAsUiImage(
79-
{double? pixelRatio: 1,
80-
Duration delay: const Duration(milliseconds: 20)}) {
82+
Future<ui.Image?> captureAsUiImage({
83+
double? pixelRatio = 1,
84+
Duration delay = const Duration(milliseconds: 20),
85+
}) {
8186
//Delay is required. See Issue https://github.com/flutter/flutter/issues/22308
8287
return new Future.delayed(delay, () async {
8388
try {
@@ -110,7 +115,7 @@ class ScreenshotController {
110115
///
111116
Future<Uint8List> captureFromWidget(
112117
Widget widget, {
113-
Duration delay: const Duration(seconds: 1),
118+
Duration delay = const Duration(seconds: 1),
114119
double? pixelRatio,
115120
BuildContext? context,
116121
Size? targetSize,
@@ -122,13 +127,15 @@ class ScreenshotController {
122127
targetSize: targetSize);
123128
final ByteData? byteData =
124129
await image.toByteData(format: ui.ImageByteFormat.png);
130+
image.dispose();
125131

126132
return byteData!.buffer.asUint8List();
127133
}
128134

135+
/// If you are building a desktop/web application that supports multiple view. Consider passing the [context] so that flutter know which view to capture.
129136
static Future<ui.Image> widgetToUiImage(
130137
Widget widget, {
131-
Duration delay: const Duration(seconds: 1),
138+
Duration delay = const Duration(seconds: 1),
132139
double? pixelRatio,
133140
BuildContext? context,
134141
Size? targetSize,
@@ -159,16 +166,20 @@ class ScreenshotController {
159166

160167
final RenderRepaintBoundary repaintBoundary = RenderRepaintBoundary();
161168

162-
Size logicalSize = targetSize ??
163-
ui.window.physicalSize / ui.window.devicePixelRatio; // Adapted
164-
Size imageSize = targetSize ?? ui.window.physicalSize; // Adapted
169+
final platformDispatcher = WidgetsBinding.instance.platformDispatcher;
170+
final fallBackView = platformDispatcher.views.first;
171+
final view =
172+
context == null ? fallBackView : View.maybeOf(context) ?? fallBackView;
173+
Size logicalSize =
174+
targetSize ?? view.physicalSize / view.devicePixelRatio; // Adapted
175+
Size imageSize = targetSize ?? view.physicalSize; // Adapted
165176

166177
assert(logicalSize.aspectRatio.toStringAsPrecision(5) ==
167178
imageSize.aspectRatio
168179
.toStringAsPrecision(5)); // Adapted (toPrecision was not available)
169180

170181
final RenderView renderView = RenderView(
171-
window: ui.window,
182+
view: view,
172183
child: RenderPositionedBox(
173184
alignment: Alignment.center, child: repaintBoundary),
174185
configuration: ViewConfiguration(
@@ -226,7 +237,7 @@ class ScreenshotController {
226237
pixelRatio: pixelRatio ?? (imageSize.width / logicalSize.width));
227238

228239
///
229-
///This delay sholud increas with Widget tree Size
240+
///This delay should increase with Widget tree Size
230241
///
231242
232243
await Future.delayed(delay);
@@ -251,10 +262,16 @@ class ScreenshotController {
251262
retryCounter--;
252263

253264
///
254-
///retry untill capture is successfull
265+
/// retry until capture is successful
255266
///
256-
257267
} while (isDirty && retryCounter >= 0);
268+
try {
269+
/// Dispose All widgets
270+
// rootElement.visitChildren((Element element) {
271+
// rootElement.deactivateChild(element);
272+
// });
273+
buildOwner.finalizeTree();
274+
} catch (e) {}
258275

259276
return image; // Adapted to directly return the image and not the Uint8List
260277
}

0 commit comments

Comments
 (0)