Umi-OCR HTTP 二维码接口实战:Base64 识别与文本生成图片的完整调用指南
本文基于 Umi-OCR 仓库中 docs/http/api_qrcode.md 的官方接口说明,系统讲解 Umi-OCR 二维码 HTTP 接口的两类能力:将 Base64 图片解析为二维码/条形码文本,以及从文本反向生成二维码图片。读完后,你可以直接在自己的项目(前端脚本、后端服务或自动化流水线)中集成离线二维码识别与生成能力,并从源码层面理解接口背后的 zxingcpp 解析链、图像预处理参数和错误码设计。
一、前置准备:启动 HTTP 服务
Umi-OCR 的二维码接口属于其 HTTP 接口体系的一部分。调用接口前需要满足以下条件:
- 开启 HTTP 服务:在 Umi-OCR 的全局设置页中勾选“高级”选项后,可以看到 HTTP 服务设置,默认处于开启状态。接口手册见 docs/http/README.md。
- 确认监听端口:默认端口为
1224,可从 UmiOCR-data/py_src/utils/pre_configs.py 中确认默认配置"server_port": 1224。若端口被占用,UmiOCR-data/py_src/server/web_server.py 中的服务逻辑会自动递增端口并记录实际端口,以启动日志中的Listening on http://...为准。 - 访问地址:本机调用使用
http://127.0.0.1:1224;如需被局域网访问,需将主机切换为“任何可用地址”。
从源码结构看,HTTP 服务基于 Bottle 框架构建,并在 UmiOCR-data/py_src/server/web_server.py 中为所有响应添加了 Access-Control-Allow-Origin: * 等跨域头,因此浏览器前端可以直接 fetch 调用;同时单次请求体上限被设置为 100 MB(BaseRequest.MEMFILE_MAX),大尺寸图片的 Base64 请求无需担心被截断。
官方手册还给出了三条运行注意事项(见 docs/http/README.md):
- 关闭 Umi-OCR 时若仍有未断开的 HTTP 连接,可能导致进程关闭不完全,需等待连接释放或强制结束进程;
- 后端组件对并发支持较差,尽量不要并发调用;
- 长时间、大批量、连续调用时小概率出现
ECONNREFUSED之类报错,重新发起请求即可。
二、接口总览:一个 URL,两种模式
二维码识别与二维码生成共用同一个 URL /api/qrcode(例:http://127.0.0.1:1224/api/qrcode),均为 POST 方法、JSON 字典参数。区分两种模式的关键在于请求体中携带的键:
- 请求体含
base64键 → 走图片识别二维码分支; - 请求体含
text键 → 走文本生成二维码图片分支。
这一路由分派逻辑可以直接在 UmiOCR-data/py_src/server/qrcode_server.py 中确认:
# 路由函数
def init(UmiWeb):
@UmiWeb.route("/api/qrcode", method="POST")
def _qrcode():
try:
data = request.json
except Exception as e:
return json.dumps({"code": 800, "data": f"请求无法解析为json。"})
if not data:
return json.dumps({"code": 801, "data": f"请求为空。"})
if "base64" in data:
return json.dumps(base2text(data))
elif "text" in data:
return json.dumps(text2base(data))
return json.dumps({"code": 802, "data": '指令中不存在 "base64" 或 "text"'})
由此得到一组“请求级”错误码,在任何分支之前就会返回:
| code | 含义 |
|---|---|
800 |
请求体无法解析为 JSON |
801 |
请求体为空 |
802 |
指令中既没有 "base64" 也没有 "text" |
以下分两节详细讲解两种模式的请求/响应格式与调用示例。
三、模式一:Base64 识别二维码(/api/qrcode)
传入图片的 Base64 编码字符串,返回图中所有二维码/条形码的文本、格式、位置和方向。一张图片中可能包含多个码,接口会逐一返回。
3.1 请求格式
方法:POST,参数为 JSON 字典:
- base64 :必填。待识别图像的 Base64 编码字符串,无需
data:image/png;base64,等前缀。 - options :可选。参数字典,支持以下图像预处理选项:
| 参数 | 取值范围 | 默认行为 | 说明 |
|---|---|---|---|
preprocessing.median_filter_size |
1~9 的奇数 | 不滤波 | 中值滤波器大小,用于去噪 |
preprocessing.sharpness_factor |
0.1~10.0 | 不调整 | 锐度增强因子 |
preprocessing.contrast_factor |
0.1~10.0 | 不调整 | 对比度增强因子:>1 增强,0~1 减弱,1 保持原样 |
preprocessing.grayscale |
true/false |
false |
是否转换为灰度图 |
preprocessing.threshold |
0~255 整数 | 不生效 | 二值化阈值,仅当 grayscale=true 时生效 |
参数示例:
{
"base64": "iVBORw0KGgoAAAAN……",
"options": {
"preprocessing.sharpness_factor": 1.0,
"preprocessing.contrast_factor": 1.0,
"preprocessing.grayscale": false,
"preprocessing.threshold": false
}
}
3.2 响应格式
返回 JSON,顶层结构与 OCR 结果非常相似:
| 字段 | 类型 | 描述 |
|---|---|---|
code |
int | 任务状态码。100 为成功,101 为图中无码(无文本),其余为失败 |
data |
list/string | 识别结果。成功时为列表;101 或失败时为错误原因字符串 |
time |
double | 识别耗时(秒) |
timestamp |
double | 任务开始时间戳(秒) |
code==100 时,data 为列表,记录图片中每个码的结果,每项包含:
| 参数名 | 类型 | 描述 |
|---|---|---|
text |
string | 码的文本内容 |
format |
string | 码的格式,如 "QRCode",可选值见下 |
box |
list | 文本框顺时针四个角的 xy 坐标:[左上,右上,右下,左下] |
orientation |
int | 码的方向,0 为正上 |
score |
int | 为与 OCR 格式兼容而设,永远为 1,无实际含义 |
支持的码格式 format 取值:
"Aztec"、"Codabar"、"Code128"、"Code39"、"Code93"、"DataBar"、"DataBarExpanded"、"DataMatrix"、"EAN13"、"EAN8"、"ITF"、"LinearCodes"、"MatrixCodes"、"MaxiCode"、"MicroQRCode"、"PDF417"、"QRCode"、"UPCA"、"UPCE"
识别成功的结果示例:
{
"code": 100,
"data": [ {
"orientation": 0,
"box": [[4,4],[25,4],[25,25],[4,25]],
"score": 1,
"format": "QRCode",
"text": "abc"
} ],
"time": 0,
"timestamp": 1711521012.625574
}
识别失败(含 code==101 无码、其他错误码)时,data 为字符串错误原因,例如:
{"code": 204, "data": "【Error】zxingcpp 二维码解析失败。\n[Error] zxingcpp read_barcodes failed。……"}
3.3 调用示例(JavaScript)
以下示例摘自官方文档,可直接用于浏览器或 Node 环境:
const url = "http://127.0.0.1:1224/api/qrcode";
const base64 = "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/...(此处为完整 Base64,原文见 docs/http/api_qrcode.md)";
const data = { "base64": base64 };
fetch(url, {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
if(data.code === 100) {
console.log("QRCode count:", data.data.length);
for (let d of data.data) {
console.log(" text: ", d.text);
console.log(" format: ", d.format);
console.log(" orientation: ", d.orientation);
console.log(" ====");
}
}
else {
console.log("Error! Code", data.code, " Msg: ", data.data);
}
})
.catch(error => console.error(error));
3.4 源码解析:识别链路与错误码
识别二维码的实际执行逻辑位于 UmiOCR-data/py_src/mission/mission_qrcode.py。HTTP 层 base2text 取出 base64 与 options 后,通过 MissionQRCode.addMissionWait(opt, [{"base64": base64}]) 提交任务并同步等待结果,核心处理在 msnTask 方法中,链路为:读图 → 预处理 → zxingcpp 解析 → 结果转字典,各环节都有独立错误码:
| code | 阶段 | 说明 |
|---|---|---|
901 |
依赖检查 | 无法导入二维码解析器 zxingcpp |
202 |
读图 | 图片读取失败(Base64 解码或 Image.open 失败) |
203 |
预处理 | 图像预处理失败 |
204 |
解析 | zxingcpp.read_barcodes 抛异常 |
205 |
结果转换 | 解析结果转字典失败 |
101 |
无码 | 图中未找到任何码,data 为 "QR code not found in the image." |
102 |
解码失败 | 检测到码但全部解码无效 |
几个值得注意的实现细节(均见 UmiOCR-data/py_src/mission/mission_qrcode.py):
- box 坐标顺序:
_zxingcpp2dict按top_left → top_right → bottom_right → bottom_left组装四个角,与文档“顺时针四角”的描述一致。 - 非文本内容的处理:当码的
content_type不是Text时(如 GS1、二进制内容),源码会先尝试按 UTF-8 解码bytes;解码失败则在文本前加[Base64]标记并以 Base64 字符串输出。也就是说text字段在极少数情况下可能是“type: Binary+ Base64”的混合内容,调用方需留意。 - 预处理参数与文档的对应关系:
_preprocessing方法(mission_qrcode.py)中,中值滤波使用 PIL 的MedianFilter(size=s)且要求奇数;锐度、对比度使用ImageEnhance;二值化逻辑为灰度值 > threshold → 255,否则 → 0,且仅在grayscale=true时执行——这解释了为什么文档强调threshold只在灰度模式下生效。 - score 恒为 1:源码中
d["score"] = 1有注释“置信度,兼容OCR格式,无意义”,与文档描述吻合。
四、模式二:从文本生成二维码图片(/api/qrcode)
传入文本,根据文本生成二维码图片,返回图片的 Base64 字符串(JPEG 编码)。URL 与识别接口一致,仅请求参数不同。
4.1 请求格式
方法:POST,参数为 JSON 字典:
- text :必填。要写入二维码的文本。
- options :可选。参数字典:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
format |
string | "QRCode" |
码格式,可选值同识别接口的 format 列表 |
w |
int | 0 |
生成图像宽度,0 表示自动设为最小宽度 |
h |
int | 0 |
生成图像高度,0 表示自动设为最小高度 |
quiet_zone |
int | -1 |
码四周空白边缘宽度,-1 表示自动调节 |
ec_level |
int | -1 |
纠错等级。-1:自动,1:7%,0:15%,3:25%,2:30%。仅对 Aztec、PDF417、QRCode 生效 |
参数示例:
{
"text": "要写入二维码的文本",
"options": {
"format": "QRCode",
"w": 0,
"h": 0,
"quiet_zone": -1,
"ec_level": -1
}
}
4.2 响应格式
| 字段 | 类型 | 描述 |
|---|---|---|
code |
int | 100 成功,其余为失败 |
data |
string | 成功时为图片的 Base64 字符串(JPEG 编码);失败时为错误信息字符串 |
4.3 调用示例(JavaScript)
const url = "http://127.0.0.1:1224/api/qrcode";
const data = {
"text": "test abc 123 !!!",
// "options": {
// "format": "QRCode",
// "w": 0,
// "h": 0,
// "quiet_zone": -1,
// "ec_level": -1,
// }
};
fetch(url, {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
if(data.code === 100) {
console.log("Image base64: \n", data.data);
}
else {
console.log("Error! Code", data.code, " Msg: ", data.data);
}
})
.catch(error => console.error(error));
拿到 Base64 后,前端可直接拼成 <img src="data:image/jpeg;base64,..."> 展示,后端则可解码写盘。
4.4 源码解析:生成链路
生成分支的服务端实现为 UmiOCR-data/py_src/server/qrcode_server.py 中的 text2base:它从 options 中取出 format(默认 QRCode)、w/h(默认 0)、quiet_zone(默认 -1)、ec_level(默认 -1),调用 MissionQRCode.createImage 得到 PIL 图像,再以 JPEG 格式写入 BytesIO 并 Base64 编码返回——这与文档“返回图片编码为 jpeg”的描述一致;异常时返回 {"code": 200, "data": "[Error] ..."}。
真正的编码动作在 UmiOCR-data/py_src/mission/mission_qrcode.py 的 createImage 中:
- 先通过
getattr(zxingcpp.BarcodeFormat, format, None)校验格式名是否合法,非法格式直接返回[Error] format {format} not in zxingcpp.BarcodeFormat!; - 调用
zxingcpp.write_barcode(bFormat, text, w, h, quiet_zone, ec_level)生成位图,再经Image.fromarray(bit, "L")转为灰度 PIL 图像; - 源码注释明确了纠错等级映射:
-1自动、1对应 L(7%)、0对应 M(15%)、3对应 Q(25%)、2对应 H(30%),且纠错等级仅用于Aztec、PDF417和QRCode——与文档表格一致。
五、错误码速查与常见问题
把请求级与分支级错误码汇总如下,方便排障:
| code | 所属分支 | 含义 |
|---|---|---|
800 |
路由层 | 请求无法解析为 JSON |
801 |
路由层 | 请求为空 |
802 |
路由层 | 指令中不存在 "base64" 或 "text" |
901 |
识别 | zxingcpp 解析器导入失败 |
100 |
识别/生成 | 成功 |
101 |
识别 | 图中无码 |
102 |
识别 | 码全部解码失败 |
200 |
生成 | 生成过程抛异常(data 为错误信息) |
202 |
识别 | 图片读取失败 |
203 |
识别 | 图像预处理失败 |
204 |
识别 | zxingcpp 解析异常 |
205 |
识别 | 结果转字典失败 |
实践建议:
- 先验连通性:浏览器访问
http://127.0.0.1:1224/应返回 Umi-OCR 的名称标识(见 web_server.py 的根路由),可用于确认服务已启动。 - 小图失败时加预处理:对模糊、有噪点的截图,可组合
median_filter_size(奇数)+contrast_factor(>1)+ 灰度/二值化重试,参数含义见 3.1 节表格。 - 避免并发:官方手册明确后端并发支持较差,批量业务请串行调用;偶发
ECONNREFUSED时重试即可。 - 注意
score字段:该字段仅用于格式兼容,不要将其当作置信度使用。
六、相关文档与延伸阅读
二维码接口并非孤立存在,Umi-OCR 的 HTTP 接口手册中还包含可组合使用的其他能力:
- HTTP接口手册总览:服务开启、局域网访问与注意事项;
- 图片OCR接口:Base64 图片文字识别,其响应格式(box/score/end)与二维码接口刻意保持兼容;
- 文档识别(PDF)流程:上传 → 轮询 → 下载 → 清理的完整任务流,配套 Python 示例 与 Web 示例;
- 命令行接口:
/argv接口等价于命令行传参,仅允许127.0.0.1调用,可参考 README_CLI.md 了解全部命令行参数; - CHANGE_LOG.md 记录了二维码功能演进:二维码解析库改用 zxingcpp、新增二维码识别页与生成功能、HTTP 二维码接口支持图像预处理参数等,可作为版本能力确认依据。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00