certflow.handlers.scan_handler module

合格证扫描件处理器

负责扫描件的底层绘制和文件生成: - 图片绘制 (PIL) - 背景图片处理 - 文字渲染 - JPG/PDF 导出 - 布局计算 - 文件命名

class certflow.handlers.scan_handler.ScanImageHandler[源代码]

基类:object

扫描件图片处理器(底层绘制)

RENDER_DPI = 300
PX_PER_MM = 11.811023622047244
FONT_SCALE = 3.125
MM_TO_PX = 11.811023622047244
mm_to_px(mm)[源代码]

毫米转像素

参数:

mm (float) -- 毫米值

返回:

像素值

返回类型:

int

classmethod load_background_rgb(background_path)[源代码]

加载背景图并归一化到干净 sRGB(修复俄英文背景在 Linux/IDE 偏色)。

问题根因(实测 ru_en_bg.png):该 PNG 像素为 RGB 模式,却内嵌了约 557KB 的 CMYK 打印机 profile**(``Japan Color 2001 Coated``, device class=prtr, space=CMYK)——profile 与像素模式**不匹配。支持色彩管理的 看图器(Linux/IDE 预览)会试图按该 CMYK profile 解读 RGB 像素 → 顶栏/印章 偏色;不做色彩管理的看图器则正常。全中文/中英文背景无 ICC,故不受影响。

解法: - profile 的色彩空间与图像 mode **匹配**(如 RGB profile 配 RGB 图)→ 用

ImageCms 正常转换到 sRGB;

  • profile 与 mode 不匹配**(本例 CMYK profile 配 RGB 图,无法转换)→ 判定为错误标签,**剥离 profile,直接使用 RGB 像素值;

  • 无 ICC → 仅确保 mode == RGB。

最终一律**清除 ``icc_profile``**,使生成结果在任意看图器下渲染一致(消除 用户所述「Linux 环境 / IDE 打开导致偏色」的不确定性)。

参数:

background_path (str) -- 背景图片路径。

返回:

无 ICC profile 的 sRGB Image.Image

返回类型:

Image

create_canvas(width_mm, height_mm, background_path=None)[源代码]

创建画布

参数:
  • width_mm (float) -- 宽度(毫米)

  • height_mm (float) -- 高度(毫米)

  • background_path (str | None) -- 背景图片路径(可选)

返回:

PIL Image 对象

返回类型:

Image

draw_text(img, text, x_mm, y_mm, font_size=9, color='black')[源代码]

在画布上绘制文字(单段,不自动换行;框内换行请用 draw_field)。

参数:
  • img (Image) -- PIL Image 对象

  • text (str) -- 文字内容

  • x_mm (float) -- X 坐标(毫米)

  • y_mm (float) -- Y 坐标(毫米)

  • font_size (int) -- 字号(像素)

  • color (str) -- 颜色

返回:

直接在 img 上绘制,无返回值

返回类型:

None

draw_field(img, value, x_mm, y_mm, font_size=9, width_mm=None, height_mm=None, align='left', v_align='top', color='black')[源代码]

绘制字段:按框宽自动换行、超框高自动缩小字号、按对齐绘制。

解决阶段5扫描件两类渲染缺陷(BUG-006): - 长字符串(如产品型号 BESDZY-320)按框宽折行,不再溢出整行; - 字号按基准 font_size 给出,不再被放大 2 倍; - 内容超高时自动缩小字号以适配框高; - 支持水平(align)/垂直(v_align)对齐,使用坐标配置中的 width/height。

参数:
  • img (Image) -- PIL Image 对象

  • value (str) -- 字段文字内容

  • x_mm (float) -- 字段框左上角坐标(毫米)

  • y_mm (float) -- 字段框左上角坐标(毫米)

  • font_size (int) -- 基准字号(像素)

  • width_mm (float | None) -- 字段框宽/高(毫米);提供后启用换行与缩放

  • height_mm (float | None) -- 字段框宽/高(毫米);提供后启用换行与缩放

  • align (str) -- 水平对齐 left/center/right

  • v_align (str) -- 垂直对齐 top/center/bottom

  • color (str) -- 文字颜色

返回:

直接在 img 上绘制,无返回值

返回类型:

None

save_jpg(img, file_path, quality=95)[源代码]

保存为 JPG 文件

参数:
  • img (Image) -- PIL Image 对象

  • file_path (str) -- 文件路径

  • quality (int) -- 质量 (1-100)

返回:

文件路径

返回类型:

str

save_pdf(img, file_path)[源代码]

保存为 PDF 文件

参数:
  • img (Image) -- PIL Image 对象

  • file_path (str) -- 文件路径

返回:

文件路径

返回类型:

str

class certflow.handlers.scan_handler.ScanLayoutHandler(rows=1, cols=1)[源代码]

基类:object

扫描件布局处理器(负责位置计算)

参数:
calculate_canvas_size(cert_width_mm, cert_height_mm)[源代码]

计算画布尺寸

参数:
  • cert_width_mm (float) -- 单张合格证宽度(毫米)

  • cert_height_mm (float) -- 单张合格证高度(毫米)

返回:

(width_px, height_px) 像素尺寸

返回类型:

tuple[int, int]

calculate_canvas_size_mm(cert_width_mm, cert_height_mm)[源代码]

计算画布尺寸(毫米)

参数:
  • cert_width_mm (float) -- 单张合格证宽度(毫米)

  • cert_height_mm (float) -- 单张合格证高度(毫米)

返回:

(width_mm, height_mm) 毫米尺寸

返回类型:

tuple[float, float]

get_position(index, cert_width_mm, cert_height_mm)[源代码]

获取指定索引的位置

参数:
  • index (int) -- 合格证索引(0-based)

  • cert_width_mm (float) -- 单张宽度(毫米)

  • cert_height_mm (float) -- 单张高度(毫米)

返回:

(x_offset_mm, y_offset_mm, row, col)

返回类型:

tuple[float, float, int, int]

is_multi_page()[源代码]

是否为多张拼接模式

参数:

返回:

当 rows*cols > 1(多张拼接)时为 True

返回类型:

bool

get_total_pages(total_certs)[源代码]

计算总页数

参数:

total_certs (int) -- 总合格证数量

返回:

总页数

返回类型:

int

effective_grid(n)[源代码]

返回实际占用网格 (used_rows, used_cols),用于最后一页(非满)裁剪画布。

满页(n == per_page)时返回完整 (rows, cols),行为不变;非满页时 去除多余空白单元格:

  • 仅当所有单元落在**单行**(used_rows == 1)时,按实际列数横向裁剪, 彻底消除尾部空白;

  • 否则(上方已有满行,仅末行不满)保留整列宽,仅裁剪纵向空行。

这样最后一页不会生成整块 180×200 的空白合格证,画布尺寸贴合实际内容。

参数:

n (int) -- 本页实际单元(单台编号)数量。

返回:

(used_rows, used_cols) 实际参与排版的行列数。

返回类型:

tuple[int, int]

class certflow.handlers.scan_handler.ScanExportHandler(output_dir, output_format='JPG')[源代码]

基类:object

扫描件导出处理器(负责文件命名和组织)

参数:
  • output_dir (str)

  • output_format (str)

ensure_output_dir()[源代码]

确保输出目录存在

参数:

返回:

递归创建 output_dir,已存在则跳过

返回类型:

None

generate_filename_single(certificate_no)[源代码]

生成单张模式文件名

参数:

certificate_no (str) -- 合格证编号

返回:

完整文件路径

返回类型:

str

generate_filename_multi(page_num, total_pages)[源代码]

生成多张拼接模式文件名

参数:
  • page_num (int) -- 当前页码

  • total_pages (int) -- 总页数

返回:

完整文件路径

返回类型:

str

generate_filename(base_name, page_num=1, total_pages=1)[源代码]

生成文件名(兼容接口)

参数:
  • base_name (str) -- 基础名称

  • page_num (int) -- 页码

  • total_pages (int) -- 总页数

返回:

完整文件路径

返回类型:

str