Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Printing generated QR codes on a PDF file

I'm creating a ReactJS app that uses QR codes and I want to be able to print a PDF document with a batch of codes at once. I'm currently using both react-qr-svg to generate the codes and @react-pdf/renderer to create the document. The problem is that I haven't been able to show these QR Codes on the document.

First I tried using the Image tag from @react-pdf/renderer like this:

<Image
  src={<QRCode
    level="Q"
    style={{width: 256, marginBottom: 50 }}
    value={'hello world'}
  />}
/>

Whick of course didn't work, after that I tried to convert the SVG to a Data Buffer and had no results.

Is there any straightforward solution for this? Should I use other libraries for this project?

like image 302
Eddy Aguirre Avatar asked Jan 31 '20 15:01

Eddy Aguirre


People also ask

Can I create a QR code for a PDF file?

Create your own PDF QR Code in 3 easy steps. Click 'Create QR Code' -> Choose 'PDF QR' type. Upload your PDF or paste the URL to the file. Customize the look and design of the QR Code as you like. Click on Next—and you're done!

Can I print out a QR code?

Once you have a QR code that links to a website or document, you can print it and place it on various sales and marketing materials, like social media posts, one-pagers, billboards, signage, and more.


2 Answers

I use qrcode.react with @react-pdf/renderer. First thing you need to do is to convert your QR canvas to base64

const qrCodeCanvas = document.querySelector('canvas');
const qrCodeDataUri = qrCodeCanvas.toDataURL('image/jpg', 0.3);

Then, pass base64 string (qrCodeDataUri) as a prop to your PDF component in source of @react-pdf/renderer image tag:

<Image source={ {uri: props.yourBase64Image} } />
like image 149
Maksym Koshyk Avatar answered Sep 23 '22 00:09

Maksym Koshyk


Directly from the docs: https://www.npmjs.com/package/react-qr-svg

You don’t need to put it in an image tag.

My assumption is this library outputs <svg> ... </svg> (I.e. valid HTML tags to output directly)

You can just output the tag/element out directly?

  import React from "react";
  import { QRCode } from "react-qr-svg";

  class Demo extends React.Component {
      render() {
          return (
            <QRCode
            bgColor="#FFFFFF"
            fgColor="#000000"
            level="Q"
            style={{ width: 256 }}
            value="some text"
            />
          );
      }
  } 

UPDATE

If I understand correctly, we cannot simply output <svg>...</svg> on the page as the library @react-pdf/renderer will not work with svg tags. So I propose we serialize the svg to a base-64 string, assigning that to the src of the image tag and then it should work.

I put a simplified demo together without libraries:https://codepen.io/Alexander9111/pen/QWweYXO

HTML (simplified):

<svg>    
    <ellipse class="ground" fill="##787f6a" cx="283.5" cy="487.5" rx="259" ry="80"/>
    <path class="kiwi" fill="#94d31b" d="M210.333,65.331C104.367,...,203.01z"/>
</svg>
<div id="target">
    <!-- place to put our img tag -->
</div>

JS:

const svg = document.querySelector("svg");
const serializer = new XMLSerializer();
const svgStr = serializer.serializeToString(svg);

const img = document.createElement("img")
img.src = 'data:image/svg+xml;base64,'+ window.btoa(svgStr);

const target = document.querySelector("#target");
target.appendChild(img);
svg.parentNode.removeChild(svg);

Now, if we want to do this in React, I assume we can do it something like this:

import React from "react";
import { QRCode } from "react-qr-svg";

  class Demo extends React.Component {
      render() {
        const svg = function {
          return (<QRCode
                  level="Q"
                  style={{width: 256, marginBottom: 50 }}
                  value={'hello world'}
              />);
        };
        const serializer = new XMLSerializer();
        const svgStr = serializer.serializeToString(svg);
        const img_src = 'data:image/svg+xml;base64,'+ window.btoa(svgStr);

          return (
            <img src={ img_src }/>
          );
      }
  } 

OR we could probably do it with lifecycle hooks such as componentDidMount()

import React from "react";
import { QRCode } from "react-qr-svg";

  class Demo extends React.Component {
    componentDidMount() {
        const div = this.refs.target;
        const svg = div.querySelector("svg");
        const serializer = new XMLSerializer();
        const svgStr = serializer.serializeToString(svg);
        const img = this.refs.img;
        img.src = 'data:image/svg+xml;base64,'+ window.btoa(svgStr);
        svg.parentNode.removeChild(svg);
      }

    render() {                
      return (<div ref="target">
                <QRCode
                level="Q"
                style={{width: 256, marginBottom: 50 }}
                value={'hello world'}
                />
              <img ref="img"/>
              </div>
            ) 
      }
  } 

UPDATE - I have it working in React on CodePen: https://codepen.io/Alexander9111/pen/GRJKQQK

HTML: <div id="root"></div>

CSS: svg{border: 2px solid black;} img{border: 2px solid blue;}

React JS:

class Demo extends React.Component {
  componentDidMount() {
    const div = this.refs.target;
    const svg = div.querySelector("svg");
    console.log(svg);
    const serializer = new XMLSerializer();
    const svgStr = serializer.serializeToString(svg);
    const img = this.refs.img;
    console.log(img);
    img.src = 'data:image/svg+xml;base64,'+ window.btoa(svgStr);
    svg.parentNode.removeChild(svg);
  }
  render() {                
      return (
        <div ref="target">
          <svg width="400" height="400">
            <circle r="100" cx="200" cy="200" fill="red" />
          </svg>
          <img ref="img"/>
        </div>
      ); 
    }
} 

ReactDOM.render(
  <Demo/>,
  document.getElementById('root')
);
like image 33
Alex L Avatar answered Sep 26 '22 00:09

Alex L