【问题标题】:Printing generated QR codes on a PDF file在 PDF 文件上打印生成的二维码
【发布时间】:2020-01-31 15:30:02
【问题描述】:

我正在创建一个使用 QR 码的 ReactJS 应用程序,我希望能够一次打印带有一批代码的 PDF 文档。我目前使用react-qr-svg 来生成代码和@react-pdf/renderer 来创建文档。问题是我无法在文档上显示这些二维码。

首先我尝试使用来自 @react-pdf/renderer 的 Image 标签,如下所示:

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

Whick 当然没用,之后我尝试将 SVG 转换为数据缓冲区,但没有任何结果。

有什么直接的解决方案吗?我应该为这个项目使用其他库吗?

【问题讨论】:

  • 嘿,Eddy,运气好吗?

标签: javascript reactjs svg qr-code react-pdf


【解决方案1】:

我使用qrcode.react@react-pdf/renderer。 您需要做的第一件事是将您的 QR 画布转换为 base64

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

然后,将 base64 字符串 (qrCodeDataUri) 作为属性传递给您的 PDF 组件,位于@react-pdf/renderer 图像标签的源代码中:

<Image source={ {uri: props.yourBase64Image} } />

【讨论】:

  • 更好的解决方案! (如果我们可以直接从 qrccode 组件到 base64 数据而不必写入 DOM,那感觉会更干净一些——但这仍然很棒!)
【解决方案2】:

直接来自文档:https://www.npmjs.com/package/react-qr-svg

你不需要把它放在图片标签中。

我的假设是这个库输出&lt;svg&gt; ... &lt;/svg&gt;(即直接输出的有效HTML标签)

你可以直接输出标签/元素吗?

  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"
            />
          );
      }
  } 

更新

如果我理解正确,我们不能简单地在页面上输出&lt;svg&gt;...&lt;/svg&gt;,因为库@react-pdf/renderer 不适用于svg 标签。所以我建议我们将 svg 序列化为 base-64 字符串,将其分配给图像标签的 src,然后它应该可以工作。

我把一个没有库的简化演示放在一起:https://codepen.io/Alexander9111/pen/QWweYXO

HTML(简体):

<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);

现在,如果我们想在 React 中这样做,我假设我们可以这样做:

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 }/>
          );
      }
  } 

或者我们或许可以使用诸如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>
            ) 
      }
  } 

更新 - 我让它在 CodePen 上的 React 中工作:https://codepen.io/Alexander9111/pen/GRJKQQK

HTML:&lt;div id="root"&gt;&lt;/div&gt;

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

反应 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')
);

【讨论】:

  • 这是不可能的,因为它不会在 PDF 文件上呈现 SVG。控制台打印“未捕获的错误:传递给 PDF 渲染器的 rect 类型的无效元素”。我知道 svg 和 rect 不是 react-pdf 原语,不会在文档上打印,我在问是否有人可以指出正确的方向来实现这一目标。
  • 啊,好吧,现在我明白你的意思了。应该有一种方法可以将 svg 序列化为字符串。让我试着把一个演示放在一起。我假设这一切都必须是客户端?
  • Eddy 我的回答好运吗?
  • 我让它在 CodePen 上的 React 中工作:codepen.io/Alexander9111/pen/GRJKQQK - 查看我的更新答案
  • 抱歉,我无法测试到现在。它仍然不起作用,因为 serializeToString 将函数作为参数而不是对象。我正在尝试找到解决方法。
【解决方案3】:

我的解决方案没有将初始 svg 写入 DOM,而是将 react 组件转换为静态标记。然后我解析该标记以在 @react-pdf/renderer 支持的 Svg 组件中使用其属性。

import React from 'react';
import { Text, View, Svg, Path } from '@react-pdf/renderer';
import { renderToStaticMarkup } from 'react-dom/server';
import ReactHtmlParser from 'react-html-parser';
import QRCode from 'qrcode.react';

const PdfWithQrCode = () => {
    const qrCodeComponent = (
        <QRCode
            value={ssf_id}
            renderAs="svg"
            size={80}
        />
    );

    const qrCodeComponentStaticMarkup = renderToStaticMarkup(qrCodeComponent);

    const parsedQrCodeSvg = parseQrCodeMarkup(qrCodeComponentStaticMarkup);
    if (! parsedQrCodeSvg) {
        return null;
    }

    return (
        <View>
            <Svg
                style={{ width: 50, height: 50 }}
                viewBox="0 0 29 29"
            >
                {parsedQrCodeSvg.props.children.filter(c => c.type === 'path').map((child, index) => (
                    <Path
                        key={index}
                        d={child.props.d}
                        fill={child.props.fill}
                    />
                ))}
            </Svg>
        </View>
    );
}

const parseQrCodeMarkup = (markup) => {
    let parsedQrCodeSvg = null;

    ReactHtmlParser(markup).forEach(el => {
        const { type } = el;
        if (type === 'svg') {
            parsedQrCodeSvg = el;
        }
    });

    return parsedQrCodeSvg;
};

export default PdfWithQrCode;

【讨论】:

    猜你喜欢
    • 2023-03-06
    • 1970-01-01
    • 1970-01-01
    • 2017-09-17
    • 1970-01-01
    • 1970-01-01
    • 2016-12-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多