px普贤教程PuXian
普贤教程 › 生态包

二维码实战

registry/qrcode 是纯 PuXian 实现的二维码:编码、解码、SVG、PBM、终端 ASCII 全都有,四级纠错、版本 1–10、自动选版本与最优掩码。它有个硬条件:必须编译跑,解释轨一张要 58 秒。

安装

bash
pxpkg add qrcode@0.2.0 && pxpkg install
px
import qrcode

十行生成一个二维码

px
import qrcode

def main():
    var r = qrcode_encode("https://px.dzty.club", "M")
    if r.is_err():
        print("失败:" + str(r.err()))
        return
    var version = r.ok()[0]
    var mask = r.ok()[1]
    var matrix = r.ok()[2]

    print("版本=" + str(version) + " 掩码=" + str(mask) + " 边长=" + str(qrcode_matrix_size(matrix)))
    print("深色模块=" + str(qrcode_count_black(matrix)))

    var svg = qrcode_svg(matrix, 4, 4)      # scale=4px/模块,静区 4 模块
    write_file("qr.svg", svg)

实测输出:

text
版本=2 掩码=7 边长=25
深色模块=328

接口

函数说明
qrcode_encode(s, ec)自动选版本 + 最优掩码 → Ok([version, mask, matrix])
qrcode_encode_at(s, ec, v, mask)固定版本/掩码(-1 表示自动),用于对拍
qrcode_decode(matrix)解码,纠错能力内会自动修正错码 → Ok(str)
qrcode_svg(matrix, scale, margin)矢量图字符串,可直接内联进 HTML
qrcode_ascii(matrix)终端渲染,██/空格,含 4 模块静区
qrcode_pbm(matrix, quiet)PBM 位图(P1,纯文本)
qrcode_version(matrix)由矩阵边长反推版本
qrcode_matrix_size(matrix) / qrcode_module_at / qrcode_count_black尺寸、取模块、统计深色模块

纠错级 ec 取 "L" / "M" / "Q" / "H":L 约容 7% 污损,H 约 30%。同样内容用 H 会让版本变大(模块更多、图更密)。

往返验证:编出来还能解回去

px
var m = qrcode_encode("https://px.dzty.club", "M").ok()[2]
print(qrcode_decode(m).ok())
# https://px.dzty.club

var cn = qrcode_encode("中文内容测试:普贤二维码 0.2.0", "H").ok()
print(cn[0])                        # 5   ← 中文按 UTF-8 字节走 byte 模式,版本涨到 5
print(qrcode_decode(cn[2]).ok())    # 中文内容测试:普贤二维码 0.2.0

三种输出形态怎么选

形态体积(上面那个链接)适用
qrcode_svg18,687 字节网页、打印、任意缩放不虚
qrcode_pbm纯文本位图要位图但不想引 PNG 编码器
qrcode_ascii34 行 × 每行 50 字符终端里手扫、日志里留证据

本站的这种用法最省事:直接把 SVG 塞进 data:image/svg+xml;base64,…,前端 <img src> 就能显示,不用落文件。

性能:必须编译跑

阶段解释轨 px run编译轨 px build
编码一个 v2 二维码57,850 ms33 ms
解码—(等不起)2 ms
生成 SVG—19 ms
这不是「慢一点」,是差 1700 倍同在解释轨跑一套完整流程,30 秒工具上限直接被超时杀掉。二维码属于「矩阵级计算 + 大量字符串拼装」,解释轨的每次变量访问都要查符号表,量级一大就崩。任何在请求里生成二维码的接口,必须走 px build 或 Ma 的 mode:"fast"。

在 Web 接口里签发(Ma px_routes)

px
import qrcode

def main():
    var text = env("QUERY_STRING")            # 实际项目请自己解析 query
    var r = qrcode_encode("https://px.dzty.club" + text, "M")
    if r.is_err():
        print("Status: 400 Bad Request")
        print("Content-Type: text/plain; charset=utf-8")
        print("")
        print(str(r.err()))
        return
    var svg = qrcode_svg(r.ok()[2], 6, 4)
    print("Status: 200 OK")
    print("Content-Type: image/svg+xml; charset=utf-8")
    print("Cache-Control: public, max-age=3600")
    print("")
    print(svg)
先编译再上线用 Ma 的 --px-probe qr.px 只编译不执行,确认产物能跑(0.22.0 起有这条命令)。别让 57 秒的解释轨进生产。

坑

1. 解释轨超时是「杀进程组」,请求直接 504/500

Ma 的 timeout_ms 到点会杀掉脚本进程组。二维码这种重计算脚本,解释轨永远跑不完。

2. 中文会推高版本

一个汉字 3 字节(UTF-8),走 byte 模式。14 个汉字 = 42 字节,配 H 级已经到版本 5。内容越长,模块越密,打印/手机扫的成功率越低——长链接先短化,再生成。

3. 静区(margin)不能省

扫描器靠静区定位。SVG 的 margin 默认 4 模块,别为了「好看」裁成 0;贴在深色底上时,还要给码加白底,否则扫不出。

4. qrcode_decode 不是 OCR

它解的是矩阵([[bool…]]),不是图片。拍张照片喂进去不行——要先生成矩阵或从图里自己采样出矩阵。纠错能修「错码字」,修不了「拍歪了」。

和 barcode 包的分工

二维码是二维码,装得下 URL 和中文;registry/barcode 是一维码(EAN-13 / EAN-8 / Code128 等),只装数字或短串,适合商品条码。两者都纯函数、都建议编译跑。