flutter capture the widget to image and then create PDF file to printer

Viewed 11723

My flutter app captures the widget to image and then creates PDF file to printer, but it shows ridiculous result as below picture.

Let me know if you have any better method to print Chinese character and qr image to a receipt (bluetooth printer with paper width 75mm)

Here with the widget:

RepaintBoundary(
      key: _renderObjectKey,
      child: ListView(
        children: <Widget>[
          Form(
            key: tableNumberFormKey,
            child:
            ListTile(
              title: TextFormField(
                initialValue: "",
                style: TextStyle(fontSize: 48.0),
                textAlign: TextAlign.center,
                maxLength: 4,
                keyboardType: TextInputType.phone,
                onSaved: (val) => inputTableNumber = val.toString(),
                validator: (val) => val.isEmpty ? '' : null,
                decoration: new InputDecoration(
                  labelText: "輸入檯號",
                  hintText: "例如:12",
                ),
              ),
            ),
          ),
          FlatButton(
            textColor: Colors.blueAccent,
            child: Text(
              "列印 QR CODE",
              style: TextStyle(fontWeight: FontWeight.w500, fontSize: 20.0),
            ),
            color: Colors.transparent,
            onPressed: () {
              _showQRandPrint();
              SystemChannels.textInput.invokeMethod('TextInput.hide');
            },
          ),
          inputTableNumber == ""
              ? ListTile(title: Text(''),)
              : Center(
            child: QrImage(
              data: qrString,
              size: 300.0,
              version: 10,
              backgroundColor: Colors.white,
            ),
          ),

        ],
      ),
    );

Here with the function to create image and pdf to printer.

void _showQRandPrint() {
    final FormState form = tableNumberFormKey.currentState;

    if (form.validate()) {
      form.save();

      _getWidgetImage().then((img) {
        final pdf = new PDFDocument();
        final page = new PDFPage(pdf, pageFormat: PDFPageFormat(75.0, 100.0));
        final g = page.getGraphics();
        final font = new PDFFont(pdf);

        PDFImage image = new PDFImage(
            pdf,
            image: img,
            width: 75,
            height: 100);
        g.drawImage(image, 0.0, 0.0);

        Printing.printPdf(document: pdf);
      });

    }
    else {
      setState(() {
        inputTableNumber = "";
      });
    }
  }

  Future<Uint8List> _getWidgetImage() async {
    try {
      RenderRepaintBoundary boundary =
      _renderObjectKey.currentContext.findRenderObject();
      ui.Image image = await boundary.toImage(pixelRatio: 3.0);
      ByteData byteData =
      await image.toByteData(format: ui.ImageByteFormat.png);
      var pngBytes = byteData.buffer.asUint8List();
      var bs64 = base64Encode(pngBytes);
      debugPrint(bs64.length.toString());
      return pngBytes;
    } catch (exception) {}
  }

result picture preview:

enter image description here

The widget on the screen is:

enter image description here

2 Answers

Few errors:

  • PDFPageFormat(75.0, 100.0) is in pdf native dimensions. If you want milimeters, do:

    PDFPageFormat(75.0 * PDFPageFormat.MM, 100.0 * PDFPageFormat.MM)
    
  • When you declare an image, you have to pass the pixel size

  • And the image cannot be png, but rawRgba data:

    // var img = await image.toByteData(format: ui.ImageByteFormat.rawRgba);
    PDFImage image = new PDFImage(
            pdf,
            image: img.buffer.asUint8List(),
            width: img.width,
            height: img.height);
    
  • the pdf coordinate system has 0,0 at the bottom left corner of the page and still in pdf units so you have to use:

    g.drawImage(image, 100.0 * PDFPageFormat.MM, 0.0, 75.0* PDFPageFormat.MM);
    

    the third parameter set the width. the height is calculated to keep the aspect ratio.

    maybe you will have to adapt this to center the image, but there is an example on the library page.

Found an easiest solution. Just use aspectRatio to adjust image size, not in declaration of PdfImage. Once you have the Uint8List file, do this:

final image = PdfImage.file(
  pdf.document,
  bytes: list, //Uint8List
);

And then, on the pdf document itself use:

pw.AspectRatio(
              aspectRatio: 3/2,
              child: pw.Image(image)
            )

Thats all.

Related