Flutter Web RenderRepaintBoundary toimage does not render widgets with images - flutter

RepaintBoundary(
key: snapshotContainer,
child: Image.network('https://picsum.photos/250?image=9'),
);
and
final RenderRepaintBoundary boundary =
snapshotContainer.currentContext!
.findRenderObject()! as RenderRepaintBoundary;
final ui.Image image =
await boundary.toImage(pixelRatio: 2);
final ByteData? byteData = await image.toByteData(
format: ui.ImageByteFormat.png);
final Uint8List pngBytes =
byteData!.buffer.asUint8List();
produces an empty image. is there a way how to render widgets with images inside via Flutter Web CanvasKit?

You need to run flutter in production run mode to see this working. We have been facing the same issue and it seems if you run it using this command
flutter run -d chrome --web-renderer canvaskit --release --dart-define=BROWSER_IMAGE_DECODING_ENABLED=false
it should render your images.
Word of caution is that the BROWSER_IMAGE_DECODING_ENABLED=false is a workaround for an active issue in flutter

What worked for me is to use svg instead of png images, e.g.
import 'package:flutter_svg/svg.dart';
SvgPicture.asset(AppImages.mapPin, height: 20)
This works for Web without any other command line arguments or any other changes.

Related

Flutter: How to generate screenshots in arbitrary resolutions?

In Flutter, how do you get a screenshot for an arbitrary screen resolution? I.e. for a screen resolution that's different from the resolution the app is running in?
Is there a way to tell the Flutter engine to paint a single frame into a buffer with a specific resolution?
What I'm trying to accomplish is to generate the screenshots for the various app stores from within the app, but without scaling and cropping screenshots that were taken for different devices/resolutions.
How would you tackle that requirement?
Any advise is welcome,
Thank you!
if you are talking about taking a screenshot of a particular widget and saving it
the you have to use renderrepaint boundry with key .
dependencies - path provider
Image gallery saver ..
takeScreenshot(BuildContext context,GlobalKey _key,String slug) async {
RenderRepaintBoundary boundary = _key.currentContext.findRenderObject();
ui.Image image = await boundary.toImage(pixelRatio: 3.0);
final snackBar = SnackBar(content: Text("Image saved to gallery"));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
final directory = (await getApplicationDocumentsDirectory()).path;
ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
final result = await ImageGallerySaver.saveImage(
byteData.buffer.asUint8List(),
name: "name.jpg");
}

How do I take a screenshot for a PlatformView Widget in Flutter Mobile Application?

Here is the code I use to do a screenshot.
First, I placed the widget inside RepaintBoundary.
RepaintBoundary(
key: widgetKey,
child: childWidget,
),
Then somewhere else in the code, we initiate a screenshot with the following code.
/// Note: Delay added to the actual code ensuring widget finish rendering.
final RenderRepaintBoundary boundary =
widgetKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
final image = await boundary.toImage(pixelRatio: pixelRatio);
final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
The above code works for any widget except PlatformView widgets, which return an empty picture.
I've read the issues on Github #25306 and #83856.
They are closed, but the problem persists.
I've added a 2 seconds delay, but it still doesn't work.
Can someone help? Thanks

how to embed widgets to images and save it to the device

I have an image with a container on it. I want to be able to edit the TextField inside the container and save the image as an image to the device.
My current setup is a stack where I have the image and a container on top of each other. How can I save that as an image?
Note that I don't want to save the whole screen, just the image and whatever on it.
Future<File> createWave(BuildContext context, GlobalKey screen) async {
RenderRepaintBoundary boundary = screen.currentContext.findRenderObject();
ui.Image image = await boundary.toImage();
ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
Uint8List pngBytes = byteData.buffer.asUint8List();
final directory = (await getApplicationDocumentsDirectory()).path;
File imgFile = File('$directory/screenshot.png');
await imgFile.writeAsBytes(pngBytes);
return imgFile;
}
Thankfully since flutter uses skia to render it's graphics, we are able to take screenshots of widgets and there is already a really good article that does somethings similar. Basically you wrap your widget in a RepaintBoundary and assign it a key then use the key to call the RenderObject.toImage method. Here is another simple example to do this. It's amazing how simple it is :D

Black screen occurs while taking screenshot in flutter

I'm using a native surface view in a flutter When I take a screenshot using a repaint boundary widget. black screen issue occurs.
My code :
RenderRepaintBoundary boundary =_globalKey.currentContext.findRenderObject();
ui.Image image = await boundary.toImage(pixelRatio: 3.0);
ByteData byteData =
await image.toByteData(format: ui.ImageByteFormat.png);
Please guide me for solution

how specify Window for tests?

I need the screen in the test to look the same as on the physical device(or simulator). How can I do it? In my case device id Iphone SE.
I wrote a test that saves a screenshot to disk:
testWidgets('test', (WidgetTester tester) async {
final AutomatedTestWidgetsFlutterBinding binding = tester.binding;
binding.renderView.configuration = TestViewConfiguration(size: Size(640, 1136));
var widget = Scaffold(
appBar: AppBar(title: Text('title'),),
body: Column(children: <Widget>[
RaisedButton(
child: Text('button'),
onPressed: () {},)
],),
);
var key = new GlobalKey();
await tester.pumpWidget(
MaterialApp(home: RepaintBoundary(key: key, child: widget),),
);
await tester.pumpAndSettle();
await tester.runAsync(() async {
RenderRepaintBoundary boundary = key.currentContext.findRenderObject();
var image = await boundary.toImage();
var byteData = await image.toByteData(format: ImageByteFormat.png);
var pngBytes = byteData.buffer.asUint8List();
await File('screen.png').writeAsBytes(pngBytes);
});
});
if use ViewConfiguration with devicePixelRatio instead TestViewConfiguration, devicePixelRatio ignoring
MediaQuery too don work, if wrap MaterialApp
appbar and button less then on simulator
screen from test:
but expected(widgets scale):
You get the blocks instead of text because Flutter uses a specific test font (Ahem) that has all characters just blocks.
This makes it easier to render them equally on Linux (CI) and other platforms. I don't know if there are other reasons.
I also wasn't able to make images work in golden tests.
https://github.com/flutter/engine/pull/6913 was a recently merged fix to allow loading custom fonts in tests.
You can use flutter run --use-test-fonts to make Flutter use the Ahem font when you run the app on a real device so you can visualize how the test will look.
Related issues
https://github.com/flutter/flutter/issues/24405
https://github.com/flutter/flutter/issues/17910#issuecomment-445184463
I don't know if font's loaded this way work in golden tests though (they might still not work similar to images)
If you want to specify different screen sizes see (not tested myself) How to test Flutter widgets on different screen sizes?
Not sure if this suggestion is still of any value. I found it quite limited and the above suggestion probably works better) In Flutter Widget testing, how to make media.orientation to portrait?