Skip to content

Commit 6226561

Browse files
committed
feat: 补充 CUPS 驱动包、HP foo2zjs 固件和中西文字体
参考 tzishue/cloud-printer 镜像补充驱动覆盖面: 驱动包:printer-driver-splix(三星/施乐)、printer-driver-postscript-hp、 printer-driver-hpijs、foomatic-db-engine、cups-browsed 固件:新增 install-foo2zjs-firmware.sh 脚本,构建期从公共镜像源下载并 编译 HP LaserJet 1000/1005/1018/P1005/P1006/P1505 固件(arm2hpdl 转换), entrypoint.sh 扩展为启动时对所有 HP host-based 型号加载固件 字体:fonts-wqy-zenhei/microhei、fonts-noto-cjk、fonts-arphic-uming/ukai、 fonts-droid-fallback、fonts-dejavu-core、fonts-liberation2、fonts-urw-base35、 gsfonts,确保 CUPS filter 链光栅化时正确渲染未嵌入字体的中英文内容
1 parent afaf259 commit 6226561

3 files changed

Lines changed: 228 additions & 33 deletions

File tree

cups/Dockerfile

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ ARG TARGETARCH
1515
ARG TARGETVARIANT
1616

1717
LABEL maintainer="涵曦 <im.hanxi@gmail.com>"
18-
LABEL description="Debian-based CUPS server (compiled from OpenPrinting/cups source) with Epson L380 official driver + Brother driverless/laser support preinstalled"
18+
LABEL description="Debian-based CUPS server (compiled from OpenPrinting/cups source) with wide printer driver coverage: Epson, HP, Canon, Brother, Samsung/Xerox, Konica Minolta, Sharp, and more"
1919

2020
ENV DEBIAN_FRONTEND=noninteractive
2121
ENV TZ=Asia/Shanghai
@@ -69,6 +69,16 @@ RUN apt-get update && \
6969
printer-driver-cups-pdf \
7070
printer-driver-escpr \
7171
printer-driver-foo2zjs \
72+
# ── 三星/施乐 SPL 激光机(CLP-300、SCX-4200、ML-2010 等) ──
73+
# printer-driver-all 作为依赖已拉入,这里显式声明确保可见性和 armhf 兼容性。
74+
printer-driver-splix \
75+
# ── HP PostScript PPD + HP 喷墨驱动 ──
76+
printer-driver-postscript-hp \
77+
printer-driver-hpijs \
78+
# ── Foomatic PPD 生成引擎(支持动态生成 Foomatic 数据库中打印机的 PPD) ──
79+
foomatic-db-engine \
80+
# ── CUPS 远程打印机发现(cups-filters 在新版 Debian 不再自动拉入此包) ──
81+
cups-browsed \
7282
# ── Brother 兼容驱动 ──
7383
# Brother 官方未把任何 Linux 驱动上传 Debian 主仓库,用户常见的 Brother 打印机
7484
# (含新款 DCP-T425W、HL-Lxxxx 等)在 CUPS 里出现 "IPP Everywhere (color)" 选项
@@ -88,7 +98,23 @@ RUN apt-get update && \
8898
hpijs-ppds \
8999
hp-ppd \
90100
hplip \
91-
avahi-daemon && \
101+
avahi-daemon \
102+
# ── 字体:CUPS filter 链(cups-filters → Ghostscript → 光栅化)处理 ──
103+
# 未嵌入字体的 PDF 时需要系统字体;PostScript 打印机需要 URW base 35。
104+
# CJK 中文字体
105+
fonts-wqy-zenhei \
106+
fonts-wqy-microhei \
107+
fonts-noto-cjk \
108+
fonts-arphic-uming \
109+
fonts-arphic-ukai \
110+
fonts-droid-fallback \
111+
# 西文基础字体
112+
fonts-dejavu-core \
113+
fonts-liberation2 \
114+
fonts-urw-base35 \
115+
gsfonts \
116+
fontconfig && \
117+
fc-cache -f && \
92118
apt-get clean && rm -rf /var/lib/apt/lists/*
93119

94120
# ────────────────────────────────────────────────────────────────────
@@ -118,6 +144,16 @@ RUN /tmp/build-scripts/install-escpr2.sh
118144
# 详见 scripts/install-canon-capt.sh
119145
RUN /tmp/build-scripts/install-canon-capt.sh
120146

147+
# ────────────────────────────────────────────────────────────────────
148+
# foo2zjs / foo2xqx 固件:HP host-based 激光打印机系列。
149+
# ────────────────────────────────────────────────────────────────────
150+
# 覆盖 HP LaserJet 1000/1005/1018(foo2zjs)和 P1005/P1006/P1505(foo2xqx)。
151+
# HP 1020 的固件由 install-hp-laserjet1020.sh 单独处理。
152+
# 构建期从公共镜像站下载固件源并用 arm2hpdl 编译转换(需要 gcc,
153+
# 因此必须在 cleanup-build.sh 之前执行)。全架构通用。
154+
# 详见 scripts/install-foo2zjs-firmware.sh
155+
RUN /tmp/build-scripts/install-foo2zjs-firmware.sh
156+
121157
# ────────────────────────────────────────────────────────────────────
122158
# 清理编译工具链。
123159
# ────────────────────────────────────────────────────────────────────

cups/entrypoint.sh

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -52,45 +52,36 @@ if [ -d /etc/cups/ppd ]; then
5252
fi
5353

5454
# ── HP host-based 打印机固件上传(issue #48 真正的修复点) ────────────
55-
# HP LaserJet 1020 / 1018 / 1005 / P100x / P1505 等"GDI / host-based"机型
56-
# 每次上电都要先由主机把固件写入 /dev/usb/lpN 才能进入工作状态。物理机上
55+
# HP LaserJet 1020 / 1018 / 1005 / 1000 / P100x / P1505 等"GDI / host-based"
56+
# 机型每次上电都要先由主机把固件写入 /dev/usb/lpN 才能进入工作状态。物理机上
5757
# 由 foo2zjs 安装的 udev 规则(/usr/lib/udev/rules.d/85-hplj10xx.rules)
5858
# 根据 USB 产品字串匹配后 RUN+="hpljNNNN",触发同包提供的
5959
# /usr/lib/udev/hpljNNNN 脚本——脚本内部走 CUPS USB backend 把
6060
# /lib/firmware/hp/sihpNNNN.dl 上传到打印机。
6161
#
6262
# 容器内没有 udev daemon、kernel uevent 也不会自动传进来,原生 udev 规则
63-
# 不会触发,issue #48 用户反馈的"换 A4 PPD 之后还是打不出来 + 手动
64-
# `cat sihp1020.dl > /dev/usb/lp0` 后才能打印"就是这一步缺失。
63+
# 不会触发。这里复用 foo2zjs 上游同一个脚本——手动给它喂上 SUBSYSTEM 环境
64+
# 变量让防御性检查通过。CUPS backend 自己通过 libusb 枚举设备 ID 里带对应
65+
# 型号字串的打印机并上传固件。
6566
#
66-
# 这里复用 foo2zjs 上游同一个脚本——不重新发明扫 sysfs 的轮子——只是手动
67-
# 给它喂上 udev 本来会注入的 SUBSYSTEM 环境变量,让脚本里 `[ "$SUBSYSTEM"
68-
# != "usb" ] && exit` 的防御性检查通过,进入 CUPS USB backend 加载分支。
69-
# CUPS backend 自己会通过 libusb 枚举设备 ID 里带 "HP...LaserJet...1020"
70-
# 字串的打印机,把 /lib/firmware/hp/sihp1020.dl 写进去;上传完成后打印机
71-
# 切到 ready 态、产品字串不再含我们关心的型号,无副作用可重复调用。
67+
# 后台跑:上游脚本里有 `sleep 3`(避开 udev 探测竞态),同步调用会拖慢
68+
# cupsd 启动。后台跑既不阻塞 cupsd,也不影响 USB backend。
7269
#
73-
# 后台跑:上游脚本里有两个 `sleep 3`(避开 udev 探测竞态),共 6s;同步
74-
# 调用会拖慢 cupsd 启动。后台跑既不阻塞 cupsd,也不影响 USB backend——
75-
# 上传期间 cupsd 即使被请求打印也会排队,固件就绪后第一份打印就能成功。
76-
#
77-
# 不做定时轮询:CUPS USB backend 不区分"固件已加载/未加载",重复上传可能
78-
# 干扰正在打印的设备。打印机断电重连后通常 Docker 设备映射也需要重做
79-
# (--device=/dev/usb/lp0 是构建期固定的),届时用户重启容器即可重新触发。
80-
HPLJ_LOADER=/usr/lib/udev/hplj1020
81-
HPLJ_LOG=/var/log/cups/hplj1020-firmware.log
82-
if [ -x "$HPLJ_LOADER" ]; then
83-
mkdir -p /var/log/cups
84-
echo "[entrypoint] dispatching $HPLJ_LOADER in background (issue #48); detailed log: $HPLJ_LOG"
85-
# 子 shell 隔离环境变量与 set -x 跟踪输出,避免污染主流程。
86-
# 脚本里 log() 函数在无 tty 时默认走 logger → syslog,容器内无 syslog
87-
# 守护会丢日志;这里把 stderr/stdout 一起重定向到固定文件,配合上一行
88-
# echo 提示用户去哪里看,方便 issue #48 类问题的复诊。
89-
(
90-
set +x
91-
SUBSYSTEM=usb "$HPLJ_LOADER" >>"$HPLJ_LOG" 2>&1 || true
92-
) &
93-
fi
70+
# 覆盖型号:hplj1000/1005/1018/1020(foo2zjs)+ hpljP1005/P1006/P1505(foo2xqx)。
71+
# 仅对固件文件存在且 udev 脚本可执行的型号调用。
72+
HPLJ_LOADERS="hplj1000 hplj1005 hplj1018 hplj1020 hpljP1005 hpljP1006 hpljP1505"
73+
HPLJ_FW_LOG=/var/log/cups/hp-firmware.log
74+
mkdir -p /var/log/cups
75+
for loader_name in $HPLJ_LOADERS; do
76+
loader_path="/usr/lib/udev/${loader_name}"
77+
if [ -x "$loader_path" ]; then
78+
echo "[entrypoint] dispatching ${loader_name} in background; log: ${HPLJ_FW_LOG}"
79+
(
80+
set +x
81+
SUBSYSTEM=usb "$loader_path" >>"$HPLJ_FW_LOG" 2>&1 || true
82+
) &
83+
fi
84+
done
9485

9586
# ── 后台拉起 avahi-daemon 与 ipp-usb:用于 driverless / IPP Everywhere 发现 ──
9687
# 其中 ipp-usb 负责把 USB 直连的 IPP Everywhere 打印机(如 Brother DCP-T425W)
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
#!/usr/bin/env bash
2+
# foo2zjs / foo2xqx 系列 HP host-based 打印机固件安装脚本。
3+
#
4+
# 覆盖型号(均为"GDI / host-based"打印机,每次上电需主机上传固件):
5+
# foo2zjs: HP LaserJet 1000, 1005, 1018
6+
# foo2xqx: HP LaserJet P1005, P1006/P1008, P1505
7+
#
8+
# 注意:HP LaserJet 1020 的固件由 install-hp-laserjet1020.sh 独立处理(从
9+
# GitHub Releases 下载 sihp1020.dl + 派生 A4-default PPD),本脚本跳过。
10+
#
11+
# 固件来源:从公共镜像站下载 .tar.gz(含 .img 原始固件),用 arm2hpdl 工具
12+
# 转换为 CUPS 可用的 .dl 格式。arm2hpdl 是 foo2zjs 项目的单文件 C 工具,
13+
# 构建期从 GitHub 克隆编译。
14+
#
15+
# 安装路径:/lib/firmware/hp/(Debian foo2zjs 包所有 udev 脚本 hpljXXXX 的
16+
# FWDIR 硬编码路径;merged-usr 下与 /usr/lib/firmware/hp/ 等价)。
17+
#
18+
# 本脚本必须在 cleanup-build.sh 之前运行——编译 arm2hpdl 需要 gcc。
19+
20+
set -eo pipefail
21+
22+
# ────────────────────────────────────────────────────────────────────
23+
# 配置
24+
# ────────────────────────────────────────────────────────────────────
25+
FW_INSTALL_DIR="/lib/firmware/hp"
26+
27+
# 公共固件下载源(按优先级排列,首个成功即停止)
28+
FIRMWARE_SOURCES=(
29+
"https://www.quirinux.org/printers"
30+
"https://mirrors.edge.kernel.org/pub/software/drivers/foo2zjs/firmware"
31+
"http://foo2zjs.rkkda.com/firmware"
32+
)
33+
34+
# foo2zjs 系列固件(ZjStream 协议)
35+
FOO2ZJS_MODELS=(sihp1000 sihp1005 sihp1018)
36+
37+
# foo2xqx 系列固件(XQX 协议)
38+
FOO2XQX_MODELS=(sihpP1005 sihpP1006 sihpP1505)
39+
40+
# ────────────────────────────────────────────────────────────────────
41+
# 编译 arm2hpdl 转换工具
42+
# ────────────────────────────────────────────────────────────────────
43+
echo "[foo2zjs-firmware] compiling arm2hpdl converter..."
44+
45+
ARM2HPDL=""
46+
TMPDIR_BUILD="$(mktemp -d /tmp/foo2zjs-build.XXXXXX)"
47+
trap 'rm -rf "${TMPDIR_BUILD}"' EXIT
48+
49+
wget -q "https://raw.githubusercontent.com/koenkooi/foo2zjs/master/arm2hpdl.c" \
50+
-O "${TMPDIR_BUILD}/arm2hpdl.c"
51+
gcc -o "${TMPDIR_BUILD}/arm2hpdl" "${TMPDIR_BUILD}/arm2hpdl.c"
52+
ARM2HPDL="${TMPDIR_BUILD}/arm2hpdl"
53+
echo "[foo2zjs-firmware] arm2hpdl compiled: ${ARM2HPDL}"
54+
55+
mkdir -p "${FW_INSTALL_DIR}"
56+
57+
# ────────────────────────────────────────────────────────────────────
58+
# 通用下载 & 转换函数
59+
# ────────────────────────────────────────────────────────────────────
60+
download_and_convert() {
61+
local fw_name="$1"
62+
local target_path="${FW_INSTALL_DIR}/${fw_name}.dl"
63+
64+
# 跳过已存在的固件(sihp1020 由 install-hp-laserjet1020.sh 安装)
65+
if [ -s "${target_path}" ]; then
66+
echo "[foo2zjs-firmware] ${fw_name}.dl already exists, skipping"
67+
return 0
68+
fi
69+
70+
local tarball="${TMPDIR_BUILD}/${fw_name}.tar.gz"
71+
local downloaded=false
72+
73+
for src in "${FIRMWARE_SOURCES[@]}"; do
74+
if wget -q --no-check-certificate "${src}/${fw_name}.tar.gz" -O "${tarball}" 2>/dev/null; then
75+
downloaded=true
76+
break
77+
fi
78+
done
79+
80+
if ! $downloaded || [ ! -s "${tarball}" ]; then
81+
echo "[foo2zjs-firmware] WARNING: ${fw_name}.tar.gz download failed from all sources"
82+
return 1
83+
fi
84+
85+
# 解压并转换
86+
tar xzf "${tarball}" -C "${TMPDIR_BUILD}" 2>/dev/null
87+
88+
if [ -f "${TMPDIR_BUILD}/${fw_name}.img" ]; then
89+
"${ARM2HPDL}" "${TMPDIR_BUILD}/${fw_name}.img" > "${target_path}" 2>/dev/null
90+
rm -f "${TMPDIR_BUILD}/${fw_name}.img"
91+
elif [ -f "${TMPDIR_BUILD}/${fw_name}.dl" ]; then
92+
cp "${TMPDIR_BUILD}/${fw_name}.dl" "${target_path}"
93+
rm -f "${TMPDIR_BUILD}/${fw_name}.dl"
94+
else
95+
echo "[foo2zjs-firmware] WARNING: ${fw_name}.tar.gz contains neither .img nor .dl"
96+
rm -f "${tarball}"
97+
return 1
98+
fi
99+
100+
rm -f "${tarball}"
101+
102+
if [ -s "${target_path}" ]; then
103+
echo "[foo2zjs-firmware] installed ${fw_name}.dl ($(wc -c < "${target_path}") bytes)"
104+
return 0
105+
else
106+
echo "[foo2zjs-firmware] WARNING: ${fw_name}.dl is empty after conversion"
107+
rm -f "${target_path}"
108+
return 1
109+
fi
110+
}
111+
112+
# ────────────────────────────────────────────────────────────────────
113+
# 下载 foo2zjs 系列固件
114+
# ────────────────────────────────────────────────────────────────────
115+
echo "[foo2zjs-firmware] === foo2zjs firmware (ZjStream) ==="
116+
ZJS_OK=0
117+
ZJS_FAIL=0
118+
for fw in "${FOO2ZJS_MODELS[@]}"; do
119+
if download_and_convert "$fw"; then
120+
ZJS_OK=$((ZJS_OK + 1))
121+
else
122+
ZJS_FAIL=$((ZJS_FAIL + 1))
123+
fi
124+
done
125+
126+
# ────────────────────────────────────────────────────────────────────
127+
# 下载 foo2xqx 系列固件
128+
# ────────────────────────────────────────────────────────────────────
129+
echo "[foo2zjs-firmware] === foo2xqx firmware (XQX) ==="
130+
XQX_OK=0
131+
XQX_FAIL=0
132+
for fw in "${FOO2XQX_MODELS[@]}"; do
133+
if download_and_convert "$fw"; then
134+
XQX_OK=$((XQX_OK + 1))
135+
else
136+
XQX_FAIL=$((XQX_FAIL + 1))
137+
fi
138+
done
139+
140+
# ────────────────────────────────────────────────────────────────────
141+
# 兼容符号链接
142+
# ────────────────────────────────────────────────────────────────────
143+
# P1007 使用与 P1005 相同的固件;P1008 使用与 P1006 相同的固件
144+
if [ -f "${FW_INSTALL_DIR}/sihpP1005.dl" ] && [ ! -e "${FW_INSTALL_DIR}/sihpP1007.dl" ]; then
145+
ln -sf sihpP1005.dl "${FW_INSTALL_DIR}/sihpP1007.dl"
146+
echo "[foo2zjs-firmware] symlink: sihpP1007.dl → sihpP1005.dl"
147+
fi
148+
if [ -f "${FW_INSTALL_DIR}/sihpP1006.dl" ] && [ ! -e "${FW_INSTALL_DIR}/sihpP1008.dl" ]; then
149+
ln -sf sihpP1006.dl "${FW_INSTALL_DIR}/sihpP1008.dl"
150+
echo "[foo2zjs-firmware] symlink: sihpP1008.dl → sihpP1006.dl"
151+
fi
152+
153+
# ────────────────────────────────────────────────────────────────────
154+
# 权限修正 & 汇总
155+
# ────────────────────────────────────────────────────────────────────
156+
chmod 644 "${FW_INSTALL_DIR}"/sihp*.dl 2>/dev/null || true
157+
158+
TOTAL_OK=$((ZJS_OK + XQX_OK))
159+
TOTAL_FAIL=$((ZJS_FAIL + XQX_FAIL))
160+
161+
echo "[foo2zjs-firmware] === summary ==="
162+
echo "[foo2zjs-firmware] installed: ${TOTAL_OK}, failed: ${TOTAL_FAIL}"
163+
ls -la "${FW_INSTALL_DIR}"/sihp*.dl 2>/dev/null || true
164+
165+
if [ "${TOTAL_OK}" -eq 0 ]; then
166+
echo "[foo2zjs-firmware] FATAL: no firmware files were installed"
167+
exit 1
168+
fi

0 commit comments

Comments
 (0)