captureFromWidget returns black image in screenshot library - flutter

I'm trying to capture QrImage using screenshot package specifically .captureFromWidget method, I'm not building the widget QrImage, because I don't want to show it just print it out using the sumni_printer package.
I tried to show the QR before printing when it was an image, and it showed flawsly as it is.
here's the code:
Future<Uint8List> getQRBytes(String data) async {
QrImage qr = QrImage(
data: data,
size: 100,
);
ScreenshotController screenshotController = ScreenshotController();
Screenshot(
controller: screenshotController,
child: qr,
);
Uint8List bytes = await screenshotController.captureFromWidget(qr);
return bytes;
}
and the results when printed in sumni printer:
this is how I import the Uint8List when printing:
Uint8List qr = await getQRBytes(data);
await SunmiPrinter.printImage(qr);
here's how it looks in the app

It turns out it's the sunmi_printer package...
there's a new package, sunmi_printer_plus
it solved my issue and it's an amazing package

Related

Flutter: Async Await Function Not Waiting

I am doing some image processing and building in my app using the Image package. In this case, I am building a LinearProgressIndicator widget that is then converted into an image file, that is then merged into a larger image later on. However, the functions to build and take the image of the progress indicator widget isn't being waited on and the following error is observed
FileSystemException: Cannot open file, path = '/Users//Library/Developer/CoreSimulator/Devices//data/Containers/Data/Application//Library/Caches/bar.png' (OS Error: No such file or directory, errno = 2)
However, the progress indicator file is being created (I can see the cache), and then if I rerunning the image processing it works just fine (because now the file is there). However, I need it work on the first time. Here is what I have for image processing
import 'package:image/image.dart' as ui;
Future<File> instagramChalShare(BuildContext context, double progress) async {
//this is where it does not appear the progressBarPathFunct is being waited on
final testFile = await progressBarPathFunct(context, progress);
ui.Image tester = ui.decodeImage(testFile.readAsBytesSync());
//image is then resized
ui.Image progressResized = ui.Image(600, 90);
ui.drawImage(progressResized, tester);
//now progress bar is merged into larger image
final mergedImage = ui.Image(width, height);
ui.copyInto(mergedImage, progressResized, blend: true);
List<int> imageFile = ui.encodePng(mergedImage);
final imageFilePath = await File('${(await getTemporaryDirectory()).path}/temp.png').create();
print('picture finished $imageFilePath');
return imageFilePath.writeAsBytes(imageFile);
}
Here is the function to build the LinearProgressIndictor, convert it to an image, and create a file where the image is held.
Future<File> progressBarPathFunct(BuildContext context, double progress) async {
final progressFile = File('${(await getTemporaryDirectory()).path}/bar.png');
var indicator = LinearPercentIndicator(
percent: progress > 1.0 ? 1.0 : progress,
width: context.size.width,
lineHeight: 13,
),
barRadius: Radius.circular(20),
);
screenshotController.captureFromWidget(
InheritedTheme.captureAll(context, Material(child: indicator)),
).then((capturedProgress) async {
await progressFile.create(recursive: true);
await progressFile.writeAsBytes(capturedProgress);
});
print('progress bar path from functions ${progressFile.path}');
return progressFile;
}
This function is working, but it seems the top one creating the merged Image file is not waiting for this function to finish before attempting to complete.
Edit
I am following the example from the screenshot package to generate an image of a widget that is not on the screen.

Get a PNG file from a Flutter Widget without drawing to the screen

I have a game a bit like Wordle, and I want to add a share capability much like Wordle does. I have a flag on my game grid widget which allows me to render the normal displayed version, or a special version for sharing. I'd like to use the widget to get a PNG file (or PNG byte data). I'd prefer to not actually draw this to the screen, just render it to some framebuffer and convert to PNG, although rendering to the screen is okay if the alternative is not possible. Looking through the docs, its not obvious whether what I am trying to do is possible or even makes sense (it seems I probably have to get the widget instantiated as an element and then get a render object, which seems to imply having to put it in my layout and draw it to the display), but maybe I am missing something. Is there a way to do this?
You might want to look at flutter's screenshot package.
A simple package to capture widgets as Images. Now you can also capture the widgets that are not rendered on the screen!
1. Create Instance of Screenshot Controller
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
Uint8List _imageFile;
//Create an instance of ScreenshotController
ScreenshotController screenshotController = ScreenshotController();
#override
void initState() {
// TODO: implement initState
super.initState();
}
...
}
2. Wrap the widget that you want to capture inside Screenshot Widget. Assign the controller to screenshotController that you have created earlier
Screenshot(
controller: screenshotController,
child: Text("This text will be captured as image"),
),
3. Take the screenshot by calling capture method. This will return a Uint8List
screenshotController.capture().then((Uint8List image) {
//Capture Done
setState(() {
_imageFile = image;
});
}).catchError((onError) {
print(onError);
});
Extra: Saving images to Specific Location
final directory = (await getApplicationDocumentsDirectory ()).path; //from path_provide package
String fileName = DateTime.now().microsecondsSinceEpoch;
path = '$directory';
screenshotController.captureAndSave(
path //set path where screenshot will be saved
fileName:fileName
);
Refer this example
I was once working on an app in which I needed something similar. After searching for a while I found a package named 'screenshot'
This package lets you convert both visible or invisible widgets to an image.
Here is the sample code from their document
ScreenshotController screenshotController = ScreenshotController();
function createScreenshot(){
screenshotController
.captureFromWidget(Container(
padding: const EdgeInsets.all(30.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.blueAccent, width: 5.0),
color: Colors.redAccent,
),
child: Text("This is an invisible widget"),
),
).then((capturedImage) {
// Here you will get image object
});
}

Flutter convert ByteData to File

I'm using this template/package to draw in Flutter https://pub.dev/packages/scribble/example.
Now I want to convert the drawn image to a File. So that I can use it in my tflite model. To predict the image the runModelOnImage (tflite package) function requires a path to the image.
The used scribble package, provides the saveImage function to return the drawn image as byteData:
// saveImage
Future<void> _saveImage(BuildContext context) async {
final image = await notifier.renderImage();
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text("Your Image"),
content: Image.memory(image.buffer.asUint8List()),
),
);
}
How can I transform the byteData image to a File so I can use it in my model?
ByteData is an abstraction for:
A fixed-length, random-access sequence of bytes that also provides random and unaligned access to the fixed-width integers and floating point numbers represented by those bytes.
As Gunter mentioned in the comments, you can use File.writeAsBytes. It does require a bit of API work to get from ByteData to a List, however.
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
Future<void> writeToFile(ByteData data, String path) {
final buffer = data.buffer;
return new File(path).writeAsBytes(
buffer.asUint8List(data.offsetInBytes, data.lengthInBytes));
}
You can read more about this on here

CREATE INVOICE PDF using FLUTTER WEB

I need to create a path to temporarily store my pdf file before sharing it. but path_provider does not support web. please what other way can i use to share the pdf decuments.
knowing that I want to create an incoice.
here is the context with some code
Future getPdf(Uint8List screenShot) async {
pw.Document pdf = pw.Document();
final img = pw.MemoryImage(screenShot);
pdf.addPage(
pw.Page(
pageFormat: PdfPageFormat.a4,
build: (context) {
return pw.Expanded(
child: pw.Image(img),
);
},
),
);
// File pdfFile = File('Your path + File name');
// pdfFile.writeAsBytesSync(await pdf.save());
print(pdf);
}
in this specific case I would like to use an alternative to path_provider

Unable to load asset in Flutter

I'm sharing a picture that I've taken previously with the camera using image_picker. It works fine on the emulator but not on my device:
onPressed: () async {
ByteData image = await rootBundle.load(team.avatar.path);
...
},
This is the error with the path:
Unable to load asset:
/storage/emulated/0/Android/data/drodriguez.apps.Words/files/Pictures/scaled_2eccad3d-382e-462e-b124-b8fa06a2a32b791445736175256137.jpg
The image is being shown without errors so the path is 100% correct:
Image.file(
_orderedTeams[index].avatar,
fit: BoxFit.cover,
height: 92.0,
width: 92.0,
)
Do I need to add something else maybe on the pubspec.yml?
You can't use the rootBundle to access files on the phone. The rootBundle (as said in its docs) only works for files packaged with the application when was built (probably saved on assets, declared on pubspec, etc).
If you want to load an image from the phone, this maybe help.
ANSWER
This function can read a filePath and return a Uint8List (a byteArray):
Future<Uint8List> _readFileByte(String filePath) async {
Uri myUri = Uri.parse(filePath);
File audioFile = new File.fromUri(myUri);
Uint8List bytes;
await audioFile.readAsBytes().then((value) {
bytes = Uint8List.fromList(value);
print('reading of bytes is completed');
}).catchError((onError) {
print('Exception Error while reading audio from path:' +
onError.toString());
});
return bytes;
}
And, to get a ByteData just:
var path = 'Some path to an image';
var byteArray = _readFileByte(path);
ByteData data = ByteData.view(byteArray.buffer);
(The answer is based on this)