Logo
Section 1 / 4

读取和写入二维码

学习如何生成和读取不同类型的二维码。

导入

读取和写入二维码

学习如何生成和读取不同类型的二维码。

以下是一个快速示例,展示如何生成包含 Educative 网站链接的二维码:

1import qrcode 2data = 'https://educative.io' 3img = qrcode.make(data) 4print(type(img)) 5img.save('output/qrcode.png')

第1行: 首先,我们导入 qrcode 库。

第2行: 然后,我们定义要编码到二维码中的 data。在此例中,我们使用 Educative 网站的 URL。该数据可以是任意字符字符串,不一定是 URL。

第3行: 通过使用 qrcode.make() 函数,我们基于刚刚定义的 data 生成一个二维码。输出是一个 PIL 图像,因此我们可以对结果图像应用 PIL 库中的所有图像操作。

第4行: 我们验证上述函数的输出类型确实是图像,这里使用了 print(type()) 语句。

第5行: 最后,我们调用 PIL 图像的 save() 方法,将二维码图像保存为 PNG 文件。

qrcode 库还允许我们通过多种参数创建二维码,从而对生成的二维码实现更精细的控制。

以下是使用多种参数的进阶示例:

1import qrcode 2qr = qrcode.QRCode( 3 version = 2, 4 error_correction = qrcode.constants.ERROR_CORRECT_H, 5 box_size = 10, 6 border = 2, 7) 8 9data = 'https://educative.io' 10qr.add_data(data) 11qr.make(fit = True) 12 13img = qr.make_image(fill_color = "black", back_color = "white") 14img.save('output/qrcode.png')

第2–7行: 首先,我们创建 qrcode.QRCode() 类的一个实例。该构造函数允许我们设置若干参数。

第3行: 我们将二维码的 version 设置为 2。如前所述,二维码的版本号范围为 1 到 40。

这些版本号决定了生成二维码的大小。版本 1 的二维码最小,而版本 40 的最大。

第4行: 接下来的参数是 error_correction,用于设置错误纠正级别。

如前所述,共有四种错误纠正级别。我们需要使用 qrcode 库中预定义的常量来设置这些级别:

  • qrcode.constants.ERROR_CORRECT_L:可纠正最多 7% 的错误。
  • qrcode.constants.ERROR_CORRECT_M:可纠正最多 15% 的错误。
  • qrcode.constants.ERROR_CORRECT_Q:可纠正最多 25% 的错误。
  • qrcode.constants.ERROR_CORRECT_H:可纠正最多 30% 的错误。

默认的错误纠正级别是 M,但本例中我们将其设为 H。

第5行: 然后我们设置 box_size 参数。该参数决定生成二维码中每个像素的大小。本例中我们设为 10。

第6行: 最后我们设置 border 参数。该参数决定二维码周围的边框大小。根据二维码的官方规范,最小值应为 4,但本例中我们设为 2 作为示例。若未设置此参数,默认值为 4。

第9–10行: 创建名为 qr 的 QRCode 类实例后,我们可以为其添加数据。数据与之前相同——Educative 网站的 URL。我们通过 add_data() 方法添加该数据。

第11行: 通过调用 qr 对象的 make() 方法,我们指示其生成二维码数组。此处我们将 fit 参数设为 True,表示生成能容纳所有数据的最小尺寸二维码。

如果版本已设定为某个值(如本例),则该值将作为下限。若所需数据超出当前版本容量,则系统会自动选择更高版本,因为 fit 参数为 True。

第13行: 最后,我们使用 make_image() 方法生成图像。在此过程中,还可以设置像素颜色和背景颜色。像素颜色通过 fill_color 设为黑色,背景颜色通过 back_color 设为白色。

这两个参数均可接受颜色名称字符串或 RGB 颜色元组。

接下来,我们尝试一个变体:

1import qrcode 2 3qr = qrcode.QRCode( 4 version = 10, 5 error_correction = qrcode.constants.ERROR_CORRECT_L, 6 box_size = 5, 7 border = 3 8) 9 10data = 'https://educative.io' 11qr.add_data(data) 12qr.make(fit = True) 13 14img = qr.make_image(fill_color = "red", back_color = "black") 15img.save('output/qrcode.png')

以下参数已更改:

  • version 被设为 10。
  • error_correction 级别被设为 L。
  • box_size 被设为 5。
  • border 被设为 3。

请注意与前一示例的区别。

在下一个示例中,我们可以看到,使用 qrcode 库,也可以在二维码中嵌入图像。

1import qrcode 2from qrcode.image.styledpil import StyledPilImage 3from qrcode.image.styles.colormasks import SolidFillColorMask 4 5qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_H) 6 7data = 'https://educative.io' 8qr.add_data(data) 9 10img = qr.make_image(image_factory=StyledPilImage, 11 color_mask=SolidFillColorMask(front_color = (73,81,245)), 12 embeded_image_path='resources/educative.png') 13img.save('output/qrcode.png')

第5行: 添加图像时,必须将错误纠正级别设为 H。如前所述,将图像嵌入二维码时,该图像会被视为二维码中的缺陷,因此需要使用最高级别的错误纠正方法进行修复。

第10行: 在使用 make_image() 方法创建图像时,首先将 image_factory 参数设为 StyledPilImage,以便支持图像嵌入。

第11行: 我们指定 color_mask 为 SolidFillColorMask,这允许为二维码的像素赋予颜色——本例中为 Educative 标志的颜色。

第12行: 最后,我们通过 embeded_image_path 参数添加 Educative 标志的 PNG 图像。

第13行: 二维码图像按常规方式保存。

使用 pyzbar 读取二维码

要读取二维码,我们可以使用之前安装并用于一维条形码的 pyzbar 库。

在下面的例子中,我们从资源目录中的图像读取一个二维码。

1from PIL import Image 2from pyzbar.pyzbar import decode, ZBarSymbol 3 4im1 = 'resources/QRcode.png' 5img = Image.open(im1).convert('RGB') 6 7decoded = decode(img, symbols=[ZBarSymbol.QRCODE]) 8 9print("decoded:", decoded) 10print("data:", decoded[0].data.decode())

第1–2行: 首先,我们导入所需的库。

第4–5行: 然后,我们使用 PIL 的 open() 方法打开包含二维码的图像,并将其转换为 RGB 模式,以确保图像包含完整的三个颜色通道。这一点很重要,因为 Pillow 可能会将图像以灰度模式(单通道)打开。

第7行: 接着,我们使用 pyzbar 库中的 decode() 函数,在加载的图像中查找二维码。

第8–9行: 最后,我们打印出完整的解码信息,特别是返回的数据内容。

因此,我们首先得到一个包含一个 Decoded 对象的列表,该对象包含多个字段:data、type、rect 和 polygon。可以看到,条形码类型为 QRCODE,数据为 https://educative.io。

第二个结果是 Decoded 对象中 data 字段的字符串形式,即 https://educative.io。

我们还可以尝试定位图像中实际的二维码位置。为此,我们可以像之前一样创建一个函数。

在下面的例子中,该函数名为 markImageQR()。其基本功能是加载图像,然后查找其中可能存在的所有二维码。

1from PIL import Image, ImageDraw 2from pyzbar.pyzbar import decode, ZBarSymbol 3 4def markImageQR(imgPath): 5 img = Image.open(imgPath).convert('RGB') 6 draw = ImageDraw.Draw(img) 7 for d in decode(img, symbols=[ZBarSymbol.QRCODE]): 8 draw.rectangle(((d.rect.left, d.rect.top), (d.rect.left + d.rect.width, d.rect.top + d.rect.height)), outline=(0, 0, 255), width=5) 9 draw.polygon(d.polygon, outline=(0, 255, 0), width=3) 10 draw.text((d.rect.left, d.rect.top + d.rect.height), d.data.decode(), (255, 0, 0)) 11 return img 12 13im1 = 'resources/QRcode.png' 14markImageQR(im1).save('output/qr1.png') 15 16im2 = 'resources/QRcodeEducative.png' 17markImageQR(im2).save('output/qr2.png')

第8行: 对于图像中找到的每个二维码,我们使用 rectangle() 方法绘制矩形,并利用 decode() 函数返回的 rect 数据。矩形为蓝色,边框宽度为 5。

第9行: 接着,我们使用 polygon() 方法绘制多边形,并使用 decode() 函数返回的 polygon 数据。该多边形为绿色,边框宽度为 3。

第10行: 二维码中的 data 也会以文本形式显示在矩形下方,使用 text() 方法。

第13–17行: 在此代码示例中,我们将 markImageQR() 函数应用于两个不同的二维码。

在两个图像输出中,我们都能看到绿色多边形位于蓝色矩形之上。原因是多边形与矩形重叠,即它们的位置基本一致。

附录

读取和写入数据矩阵码