使用 Python3 创建带有 SVG 边框模板的二维码
Posted
技术标签:
【中文标题】使用 Python3 创建带有 SVG 边框模板的二维码【英文标题】:Create QR codes with a SVG border template using Python3 【发布时间】:2019-11-15 21:49:51 【问题描述】:我正在使用 Python 二维码库生成 SVG 二维码:
factory = qrcode.image.svg.SvgImage
img = qr.make_image(fill_color="black", back_color="white", image_factory=factory)
我有一个单独的 SVG 图像 (border.svg)。如何将 QR 码对象 (img) 集成到边框 svg 中以生成一个组合 svg 文件?我发现很多 svg 库可以转换为 png/eps,但没有一个能够简单地整合两个图像。
奖励:必须缩放边框(或 QR 图像)以适合,因为根据 QR 码的数据大小,QR svg 的尺寸会有所不同。
【问题讨论】:
border.svg 是什么样的,是二维码周围需要复制的图案,还是二维码空白处的边框正方形? 它是一个带有空白点的正方形。 【参考方案1】:我为 python SVG 模块做了一些探索,但我没有想出任何让问题变得更简单的方法。
SVG 实际上只是 XML。因此,您可以编辑 SVG 的 XML 并更改 SVG。 Python 确实有很好的内置对 XML 的支持(实际上是 *ML)。
基本思想是获取边界并获取其大小。然后,我们使用大小缩放 qr 代码以适合边界内。然后我们将 qr 添加到边界 SVG-XML 并保存到新文件中。
from lxml import etree
# Create XML objects
boarder = etree.parse('boarder.svg')
qr = etree.parse('qr.svg') # ET.parse('qr.svg').getroot()
# Get size of boarder
Bhight = int(boarder.xpath('//*[local-name()="svg"]/@width')[0])
Bwidth = int(boarder.xpath('//*[local-name()="svg"]/@height')[0])
# Make sure that it is a square
assert(Bhight == Bwidth)
# resize qr code for boarder.
qrBack = qr.xpath('//*[local-name()="svg"]//*[local-name()="g"]//*[local-name()="rect"]')[0]
# Also needs to be a square
assert(qrBack.attrib['height'] == qrBack.attrib['width'])
# Calc offset code from boarder
qrWidth = int(qrBack.attrib['width'])
offset = (Bwidth - qrWidth) / 2
# Add offset attribute
qr.xpath('//*[local-name()="svg"]//*[local-name()="g"]')[0].attrib['transform'] = 'translate(0,0)'.format(offset)
# get qr code
QRC = qr.xpath('//*[local-name()="svg"]//*[local-name()="g"]')[0]
# Take Boarder as xml root
root = boarder.getroot()
# Add QRC to root
root.append(QRC)
# Write new svg to file
with open( 'boarder+qr.svg', 'w' ) as f:
f.write( etree.tostring( root, pretty_print=True, xml_declaration=True, encoding='UTF-8', standalone="yes").decode() )
创建文件boarder+qr.svg
。
供参考:
寄宿生.svg
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg8"
version="1.1"
>
<defs
id="defs2" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1">
<path
id="rect1379"
d="m 0,0 h 110 v 110 H 0 Z 0"
style="
stroke:#FFFFFF;
stroke-width:0.89999998;
stroke-linecap:round;
stroke-linejoin:round;
stroke-miterlimit:4;
stroke-dasharray:none;
stroke-dashoffset:0;
stroke-opacity:1"
/>
</g>
</svg>
qr.svg
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg">
<desc>Zint Generated Symbol
</desc>
<g id="barcode" fill="#000000">
<rect x="0" y="0" fill="#FFFFFF" />
<rect x="12.00" y="12.00" />
<rect x="36.00" y="12.00" />
<rect x="54.00" y="12.00" />
<rect x="60.00" y="12.00" />
<rect x="66.00" y="12.00" />
<rect x="12.00" y="15.00" />
<rect x="30.00" y="15.00" />
<rect x="36.00" y="15.00" />
<rect x="45.00" y="15.00" />
<rect x="51.00" y="15.00" />
<rect x="60.00" y="15.00" />
<rect x="66.00" y="15.00" />
<rect x="84.00" y="15.00" />
<rect x="12.00" y="18.00" />
<rect x="18.00" y="18.00" />
<rect x="30.00" y="18.00" />
<rect x="39.00" y="18.00" />
<rect x="51.00" y="18.00" />
<rect x="57.00" y="18.00" />
<rect x="66.00" y="18.00" />
<rect x="72.00" y="18.00" />
<rect x="84.00" y="18.00" />
<rect x="12.00" y="21.00" />
<rect x="18.00" y="21.00" />
<rect x="30.00" y="21.00" />
<rect x="45.00" y="21.00" />
<rect x="57.00" y="21.00" />
<rect x="66.00" y="21.00" />
<rect x="72.00" y="21.00" />
<rect x="84.00" y="21.00" />
<rect x="12.00" y="24.00" />
<rect x="18.00" y="24.00" />
<rect x="30.00" y="24.00" />
<rect x="36.00" y="24.00" />
<rect x="45.00" y="24.00" />
<rect x="66.00" y="24.00" />
<rect x="72.00" y="24.00" />
<rect x="84.00" y="24.00" />
<rect x="12.00" y="27.00" />
<rect x="30.00" y="27.00" />
<rect x="36.00" y="27.00" />
<rect x="48.00" y="27.00" />
<rect x="60.00" y="27.00" />
<rect x="66.00" y="27.00" />
<rect x="84.00" y="27.00" />
<rect x="12.00" y="30.00" />
<rect x="36.00" y="30.00" />
<rect x="42.00" y="30.00" />
<rect x="48.00" y="30.00" />
<rect x="54.00" y="30.00" />
<rect x="60.00" y="30.00" />
<rect x="66.00" y="30.00" />
<rect x="36.00" y="33.00" />
<rect x="57.00" y="33.00" />
<rect x="12.00" y="36.00" />
<rect x="27.00" y="36.00" />
<rect x="36.00" y="36.00" />
<rect x="45.00" y="36.00" />
<rect x="60.00" y="36.00" />
<rect x="81.00" y="36.00" />
<rect x="12.00" y="39.00" />
<rect x="18.00" y="39.00" />
<rect x="24.00" y="39.00" />
<rect x="33.00" y="39.00" />
<rect x="48.00" y="39.00" />
<rect x="54.00" y="39.00" />
<rect x="66.00" y="39.00" />
<rect x="75.00" y="39.00" />
<rect x="81.00" y="39.00" />
<rect x="15.00" y="42.00" />
<rect x="21.00" y="42.00" />
<rect x="30.00" y="42.00" />
<rect x="36.00" y="42.00" />
<rect x="48.00" y="42.00" />
<rect x="57.00" y="42.00" />
<rect x="72.00" y="42.00" />
<rect x="84.00" y="42.00" />
<rect x="18.00" y="45.00" />
<rect x="33.00" y="45.00" />
<rect x="42.00" y="45.00" />
<rect x="57.00" y="45.00" />
<rect x="69.00" y="45.00" />
<rect x="75.00" y="45.00" />
<rect x="15.00" y="48.00" />
<rect x="24.00" y="48.00" />
<rect x="39.00" y="48.00" />
<rect x="48.00" y="48.00" />
<rect x="57.00" y="48.00" />
<rect x="66.00" y="48.00" />
<rect x="84.00" y="48.00" />
<rect x="21.00" y="51.00" />
<rect x="39.00" y="51.00" />
<rect x="57.00" y="51.00" />
<rect x="66.00" y="51.00" />
<rect x="81.00" y="51.00" />
<rect x="12.00" y="54.00" />
<rect x="30.00" y="54.00" />
<rect x="39.00" y="54.00" />
<rect x="69.00" y="54.00" />
<rect x="84.00" y="54.00" />
<rect x="18.00" y="57.00" />
<rect x="24.00" y="57.00" />
<rect x="33.00" y="57.00" />
<rect x="39.00" y="57.00" />
<rect x="45.00" y="57.00" />
<rect x="54.00" y="57.00" />
<rect x="69.00" y="57.00" />
<rect x="12.00" y="60.00" />
<rect x="21.00" y="60.00" />
<rect x="30.00" y="60.00" />
<rect x="39.00" y="60.00" />
<rect x="60.00" y="60.00" />
<rect x="81.00" y="60.00" />
<rect x="36.00" y="63.00" />
<rect x="60.00" y="63.00" />
<rect x="72.00" y="63.00" />
<rect x="78.00" y="63.00" />
<rect x="84.00" y="63.00" />
<rect x="12.00" y="66.00" />
<rect x="45.00" y="66.00" />
<rect x="54.00" y="66.00" />
<rect x="60.00" y="66.00" />
<rect x="66.00" y="66.00" />
<rect x="72.00" y="66.00" />
<rect x="84.00" y="66.00" />
<rect x="12.00" y="69.00" />
<rect x="30.00" y="69.00" />
<rect x="36.00" y="69.00" />
<rect x="54.00" y="69.00" />
<rect x="60.00" y="69.00" />
<rect x="72.00" y="69.00" />
<rect x="84.00" y="69.00" />
<rect x="12.00" y="72.00" />
<rect x="18.00" y="72.00" />
<rect x="30.00" y="72.00" />
<rect x="45.00" y="72.00" />
<rect x="54.00" y="72.00" />
<rect x="81.00" y="72.00" />
<rect x="12.00" y="75.00" />
<rect x="18.00" y="75.00" />
<rect x="30.00" y="75.00" />
<rect x="42.00" y="75.00" />
<rect x="54.00" y="75.00" />
<rect x="60.00" y="75.00" />
<rect x="72.00" y="75.00" />
<rect x="12.00" y="78.00" />
<rect x="18.00" y="78.00" />
<rect x="30.00" y="78.00" />
<rect x="36.00" y="78.00" />
<rect x="51.00" y="78.00" />
<rect x="57.00" y="78.00" />
<rect x="72.00" y="78.00" />
<rect x="81.00" y="78.00" />
<rect x="12.00" y="81.00" />
<rect x="30.00" y="81.00" />
<rect x="36.00" y="81.00" />
<rect x="54.00" y="81.00" />
<rect x="69.00" y="81.00" />
<rect x="12.00" y="84.00" />
<rect x="36.00" y="84.00" />
<rect x="51.00" y="84.00" />
<rect x="60.00" y="84.00" />
<rect x="75.00" y="84.00" />
<rect x="84.00" y="84.00" />
</g>
</svg>
您可能需要更改一些内容,以便正确定位源 SVG,但这应该会给您一个很好的起点。
寄宿生+qr.svg
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" id="svg8" version="1.1" >
<defs id="defs2"/>
<metadata id="metadata5">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<g id="layer1">
<path id="rect1379" d="m 0,0 h 110 v 110 H 0 Z 0" style=" stroke:#FFFFFF; stroke-width:0.89999998; stroke-linecap:round; stroke-linejoin:round; stroke-miterlimit:4; stroke-dasharray:none; stroke-dashoffset:0; stroke-opacity:1"/>
</g>
<svg:g id="barcode" fill="#000000" transform="translate(5.0,5.0)">
<svg:rect x="0" y="0" fill="#FFFFFF"/>
<svg:rect x="12.00" y="12.00" />
<svg:rect x="36.00" y="12.00" />
<svg:rect x="54.00" y="12.00" />
<svg:rect x="60.00" y="12.00" />
<svg:rect x="66.00" y="12.00" />
<svg:rect x="12.00" y="15.00" />
<svg:rect x="30.00" y="15.00" />
<svg:rect x="36.00" y="15.00" />
<svg:rect x="45.00" y="15.00" />
<svg:rect x="51.00" y="15.00" />
<svg:rect x="60.00" y="15.00" />
<svg:rect x="66.00" y="15.00" />
<svg:rect x="84.00" y="15.00" />
<svg:rect x="12.00" y="18.00" />
<svg:rect x="18.00" y="18.00" />
<svg:rect x="30.00" y="18.00" />
<svg:rect x="39.00" y="18.00" />
<svg:rect x="51.00" y="18.00" />
<svg:rect x="57.00" y="18.00" />
<svg:rect x="66.00" y="18.00" />
<svg:rect x="72.00" y="18.00" />
<svg:rect x="84.00" y="18.00" />
<svg:rect x="12.00" y="21.00" />
<svg:rect x="18.00" y="21.00" />
<svg:rect x="30.00" y="21.00" />
<svg:rect x="45.00" y="21.00" />
<svg:rect x="57.00" y="21.00" />
<svg:rect x="66.00" y="21.00" />
<svg:rect x="72.00" y="21.00" />
<svg:rect x="84.00" y="21.00" />
<svg:rect x="12.00" y="24.00" />
<svg:rect x="18.00" y="24.00" />
<svg:rect x="30.00" y="24.00" />
<svg:rect x="36.00" y="24.00" />
<svg:rect x="45.00" y="24.00" />
<svg:rect x="66.00" y="24.00" />
<svg:rect x="72.00" y="24.00" />
<svg:rect x="84.00" y="24.00" />
<svg:rect x="12.00" y="27.00" />
<svg:rect x="30.00" y="27.00" />
<svg:rect x="36.00" y="27.00" />
<svg:rect x="48.00" y="27.00" />
<svg:rect x="60.00" y="27.00" />
<svg:rect x="66.00" y="27.00" />
<svg:rect x="84.00" y="27.00" />
<svg:rect x="12.00" y="30.00" />
<svg:rect x="36.00" y="30.00" />
<svg:rect x="42.00" y="30.00" />
<svg:rect x="48.00" y="30.00" />
<svg:rect x="54.00" y="30.00" />
<svg:rect x="60.00" y="30.00" />
<svg:rect x="66.00" y="30.00" />
<svg:rect x="36.00" y="33.00" />
<svg:rect x="57.00" y="33.00" />
<svg:rect x="12.00" y="36.00" />
<svg:rect x="27.00" y="36.00" />
<svg:rect x="36.00" y="36.00" />
<svg:rect x="45.00" y="36.00" />
<svg:rect x="60.00" y="36.00" />
<svg:rect x="81.00" y="36.00" />
<svg:rect x="12.00" y="39.00" />
<svg:rect x="18.00" y="39.00" />
<svg:rect x="24.00" y="39.00" />
<svg:rect x="33.00" y="39.00" />
<svg:rect x="48.00" y="39.00" />
<svg:rect x="54.00" y="39.00" />
<svg:rect x="66.00" y="39.00" />
<svg:rect x="75.00" y="39.00" />
<svg:rect x="81.00" y="39.00" />
<svg:rect x="15.00" y="42.00" />
<svg:rect x="21.00" y="42.00" />
<svg:rect x="30.00" y="42.00" />
<svg:rect x="36.00" y="42.00" />
<svg:rect x="48.00" y="42.00" />
<svg:rect x="57.00" y="42.00" />
<svg:rect x="72.00" y="42.00" />
<svg:rect x="84.00" y="42.00" />
<svg:rect x="18.00" y="45.00" />
<svg:rect x="33.00" y="45.00" />
<svg:rect x="42.00" y="45.00" />
<svg:rect x="57.00" y="45.00" />
<svg:rect x="69.00" y="45.00" />
<svg:rect x="75.00" y="45.00" />
<svg:rect x="15.00" y="48.00" />
<svg:rect x="24.00" y="48.00" />
<svg:rect x="39.00" y="48.00" />
<svg:rect x="48.00" y="48.00" />
<svg:rect x="57.00" y="48.00" />
<svg:rect x="66.00" y="48.00" />
<svg:rect x="84.00" y="48.00" />
<svg:rect x="21.00" y="51.00" />
<svg:rect x="39.00" y="51.00" />
<svg:rect x="57.00" y="51.00" />
<svg:rect x="66.00" y="51.00" />
<svg:rect x="81.00" y="51.00" />
<svg:rect x="12.00" y="54.00" />
<svg:rect x="30.00" y="54.00" />
<svg:rect x="39.00" y="54.00" />
<svg:rect x="69.00" y="54.00" />
<svg:rect x="84.00" y="54.00" />
<svg:rect x="18.00" y="57.00" />
<svg:rect x="24.00" y="57.00" />
<svg:rect x="33.00" y="57.00" />
<svg:rect x="39.00" y="57.00" />
<svg:rect x="45.00" y="57.00" />
<svg:rect x="54.00" y="57.00" />
<svg:rect x="69.00" y="57.00" />
<svg:rect x="12.00" y="60.00" />
<svg:rect x="21.00" y="60.00" />
<svg:rect x="30.00" y="60.00" />
<svg:rect x="39.00" y="60.00" />
<svg:rect x="60.00" y="60.00" />
<svg:rect x="81.00" y="60.00" />
<svg:rect x="36.00" y="63.00" />
<svg:rect x="60.00" y="63.00" />
<svg:rect x="72.00" y="63.00" />
<svg:rect x="78.00" y="63.00" />
<svg:rect x="84.00" y="63.00" />
<svg:rect x="12.00" y="66.00" />
<svg:rect x="45.00" y="66.00" />
<svg:rect x="54.00" y="66.00" />
<svg:rect x="60.00" y="66.00" />
<svg:rect x="66.00" y="66.00" />
<svg:rect x="72.00" y="66.00" />
<svg:rect x="84.00" y="66.00" />
<svg:rect x="12.00" y="69.00" />
<svg:rect x="30.00" y="69.00" />
<svg:rect x="36.00" y="69.00" />
<svg:rect x="54.00" y="69.00" />
<svg:rect x="60.00" y="69.00" />
<svg:rect x="72.00" y="69.00" />
<svg:rect x="84.00" y="69.00" />
<svg:rect x="12.00" y="72.00" />
<svg:rect x="18.00" y="72.00" />
<svg:rect x="30.00" y="72.00" />
<svg:rect x="45.00" y="72.00" />
<svg:rect x="54.00" y="72.00" />
<svg:rect x="81.00" y="72.00" />
<svg:rect x="12.00" y="75.00" />
<svg:rect x="18.00" y="75.00" />
<svg:rect x="30.00" y="75.00" />
<svg:rect x="42.00" y="75.00" />
<svg:rect x="54.00" y="75.00" />
<svg:rect x="60.00" y="75.00" />
<svg:rect x="72.00" y="75.00" />
<svg:rect x="12.00" y="78.00" />
<svg:rect x="18.00" y="78.00" />
<svg:rect x="30.00" y="78.00" />
<svg:rect x="36.00" y="78.00" />
<svg:rect x="51.00" y="78.00" />
<svg:rect x="57.00" y="78.00" />
<svg:rect x="72.00" y="78.00" />
<svg:rect x="81.00" y="78.00" />
<svg:rect x="12.00" y="81.00" />
<svg:rect x="30.00" y="81.00" />
<svg:rect x="36.00" y="81.00" />
<svg:rect x="54.00" y="81.00" />
<svg:rect x="69.00" y="81.00" />
<svg:rect x="12.00" y="84.00" />
<svg:rect x="36.00" y="84.00" />
<svg:rect x="51.00" y="84.00" />
<svg:rect x="60.00" y="84.00" />
<svg:rect x="75.00" y="84.00" />
<svg:rect x="84.00" y="84.00" />
</svg:g>
</svg>
【讨论】:
以上是关于使用 Python3 创建带有 SVG 边框模板的二维码的主要内容,如果未能解决你的问题,请参考以下文章