I'm using flutter with the pdf plugin to generate a PDF document where I need to display a grid of images. The images are stored in a List<File>.
Here's what I've tried. Keep in mind that all these widgets are from the pdf package and not from material.
GridView(
crossAxisCount: 5,
childAspectRatio: 1,
children: door.images.map((image) {
return Container(
child: Image(MemoryImage(?????), fit: BoxFit.cover),
);
}).toList(),
),
Note: door.images is the List<File>
How do I convert the File image (from the List<File>) to the Uint8List bytes needed for the MemoryImage widgets?
Convert your File to imagebytes.
final List<int> _imageBytes = await image.readAsBytes();
And then convert the imagebytes to your Uint8List.
final String _uint8List = base64Encode(_imageBytes);
Related
I am creating my first PDF document in Flutter using the pdf package.
Here you have a partial screenshot from the pdf part that I need to change:
You may see 6 rows, each of them has a time and a string.
Here you have the code for that screenshot:
static Widget buildTablaDiario(List<dynamic> listaDiarioActual){
return ListView.builder(
itemCount: listaDiarioActual.length,
itemBuilder: (pw.Context context, index){
DiarioModelo diario = listaDiarioActual[index];
DateTime tempDateI =
new DateFormat("yyyy-MM-dd hh:mm:ss")
.parse(diario.fecha_diario);
String date1 = DateFormat("dd-MM-yyyy HH:mm")
.format(tempDateI);
String hora = DateFormat("HH:mm")
.format(tempDateI);
return Row(
children: [
pw.Text("${hora}"),
pw.SizedBox(width: 10),
pw.Text(diario.descripcion,overflow: TextOverflow.clip)
]
);
}
);
}
I would like to set a right margin in order to avoid the text lines to end at the right edge from the document.
I know it's late, but in case anyone is still looking for an answer...
inside pw.Page or pw.MultiPage there is a margin attribute where you can add paddings
pdf.addPage(
pw.MultiPage(
pageFormat: PdfPageFormat.a4,
**margin: const pw.EdgeInsets.only(top: 100),**
orientation: pw.PageOrientation.portrait,...
Another approach is the following:
Before pdf.save() run the following to add your custom margins
for (int i = 1; i < pdf.document.pdfPageList.pages.length; i++) {
pdf.document.pdfPageList.pages
.elementAt(i)
.pageFormat
.copyWith(marginLeft: 50, marginTop: 100, marginRight: 50, marginBottom: 50);
}
We can work on images in Flutter using import 'package:image/image.dart' as ToolsImage; package to scale them with ToolsImage.copyResize() and manipulate individual pixels with ToolsImage.Image.getPixel(x,y)
To display image from memory bytes (ByteData/Uint8List/List<int>) we can use MemoryImage:
Container(child: Image(image: MemoryImage(image.data.buffer.asUint8List())))
I'm getting an exception:
Exception: Invalid image data
whichever List I use. What's wrong?
Remember to add HEADER to image bytes after format conversions!
ByteData imageByteData = await rootBundle.load('res/images/basic/dizzy-face.png');
List<int> values = imageByteData.buffer.asUint8List();
ToolsImage.Image? photo = ToolsImage.decodeImage(values);
photo = ToolsImage.copyResize(photo!, height: 32, width: 32);
removes header information (pixel-by-pixel manipulation removes header info).
Use:
List<int>? imageWithHeader = ToolsImage.encodeNamedImage(TEST_IMAGE, ".bmp");
and then:
Container(child: Image(image: MemoryImage(Uint8List.fromList(imageWithHeader))))
Last line enables us to convert package:image/image.dart to package:flutter/src/widgets/image.dart (UI Image Widget)
For example on the given image 1 and 2 as a network image in the grid view and others are captured locally.
use gridview.count
GridView.count(
children:[
//widget1() to display NetworkImage
//Widget2() for other NewtorkImage(),
//widget3 to display image captured from imagepicker.
//widget4
])
You can make a list of all images you have and then you can conditionally render the images on the screen. See below example:
List<String> imgUrls = [];
GridView.builder(ctx,index){
gridDelegate:SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 10,
crossAxisSpacing: 4.0,
mainAxisSpacing: 4.0
),
//check if the url is valid
if(isValid) {
NetworkImage(url:imgUrls[index]);
}else if(isValidPath){
//check if the user has uploaded photo to local and path is valid
Image.asset(imgUrls[index]);
}else{
//show error widget
SizedBox();
}
}
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
I am using https://pub.dev/packages/multi_image_picker in my project so that the user can select multiple images.
Following is my code to upload multiple images to Firebase Storage
StorageReference _storageReference = FirebaseStorage.instance
.ref();
await Future.wait(userSelectImages.map((Asset asset) async {
ByteData byteData = await asset.getByteData(quality: 50);
List<int> imageData = byteData.buffer.asUint8List();
StorageUploadTask _uploadTask =
_storageReference.child("$HEALTH_LOG/${asset.name}").putData(imageData);
final StreamSubscription<StorageTaskEvent> _streamSubscription =
_uploadTask.events.listen((event) {
double percent = event != null
? event.snapshot.bytesTransferred /
event.snapshot.totalByteCount
: 0;
});
uploadUrls
.add(await (await _uploadTask.onComplete).ref.getDownloadURL());
await _streamSubscription.cancel();
But I get a crash saying Too many open files and GL_OUT_OF_MEMORY
The code works fine when I select one or two images, but if select 7 to 8 images I get the crash
Edit 2
Alright after debugging more I got to know the real issue. There is no error or bug in the way I am uploading an image to firebase storage. The main issue is to display those user-selected images.
Suppose the user picks multiple images. Now I want to preview those images before the user can upload them to firebase. So I am displaying those images in GridView.Builder which causes the out of memory issue. I have found a bug on Flutter repo regarding this https://github.com/flutter/flutter/issues/21571
So my code for displaying images in GridView is as follows
return GridView.builder(
shrinkWrap: true,
physics: const ScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, childAspectRatio: 1),
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8),
child: AssetThumb(
asset: patientHealthLogsBloc.resultAssetValue[index],
width: MediaQuery.of(context).size.width ~/ 3,
height: 100,
quality: 30,
),
);
},
itemCount: patientHealthLogsBloc?.resultAssetValue?.length ?? 0,
);
If I comment on the above code of displaying previews then images are uploaded properly but displaying those images causes out of memory error. I even tested on the iPad which causes the same issue.
So the real root cause of the issue was that the widget was wrapped in a stream builder which caused it to keep rebuilding it again and again even if data did not changed