Print via Brother BR-Script3 PostScript instead of the vendor driver

The HL-4150CDN emulates PostScript 3, so CUPS converts client documents to PostScript and forwards them to socket://<ip>:9100. The official BR-Script3 PPD turns device options (tray, duplex, colour, media type, toner save, ...) into setpagedevice instructions. This drops the i386 multiarch runtime and the broken Brother vendor filter chain, and removes the unused Brother Linux packages from the repo.
This commit is contained in:
juergen committed 2026-10-18 16:54:33 +02:00
1 parent 6f3162849b
commit 30c685e085
22 files changed
+1070 -273

No files matched your search

@@ -2,61 +2,104 @@
## Context
See proposal.md for motivation - we need to create a Podman container that runs a CUPS print server for Brother HL-4150CDN. The repo contains the Brother driver packages in `assets/Brother HL-4150CDN/`:
- `lpr-driver/hl4150cdnlpr-1.1.1-5.i386.deb`
- `cupswrapper/hl4150cdncupswrapper-1.1.1-5.i386.deb`
- `installer/linux-brprinter-installer-2.2.6-0.gz` (reference only; we will NOT run it in the build - it is interactive and downloads from the network)
See proposal.md. We need a Podman container that runs CUPS for the Brother
HL-4150CDN network printer and shares it over IPP/AirPrint.
Key observations:
- Brother drivers are i386 binaries (32-bit ELF). Container needs 32-bit runtime libraries.
- CUPS wrapper + LPR packages provide PPD, filters, and helper binaries.
- AirPrint requires CUPS + Avahi/mDNS (DNS-SD).
- Brother's cups wrapper installs files to /usr/local/Brother/ and may need symlinks into CUPS directories.
Facts established while exploring the device at `192.168.100.7`:
- The printer is a Brother HL-4150CDN (`Ver.1.22`) with PCL6 and **BR-Script3
(PostScript 3)** emulation — `@PJL INFO CONFIG` lists `POSTSCRIPT`.
- Open services: `:9100` (raw/AppSocket), `:515` (LPR/LPD), `:631` (IPP/IPPS)
and `:80` (Brother web UI). It has one paper cassette plus the MP tray.
- A raw PostScript job sent to `:9100` is interpreted by the printer, and a full
CUPS job with `Duplex=DuplexNoTumble BRPrintQuality=Color` printed correctly
(duplex, colour).
An earlier iteration used Brother's Linux packages. That vendor CUPS chain is
broken in `debian:bookworm-slim`: `filterhl4150cdn` needs `file` (and `a2ps` as
a fallback), which are absent, so the filter exits 1 and emits zero bytes. That
chain also rasterises locally (Ghostscript → `ppmraw` → `brhl4150cdnfilter`) and
stores per-queue options in a single global file (`brhl4150cdnrc`), which is
heavy and racy. The packages have since been removed from the repository.
Crucially, the Brother **vendor** PPD (`brhl4150cdn.ppd`) cannot be used for
direct PostScript because its option values are blank (`" "`); all
option handling lives in the vendor filter. Brother's **BR-Script3 PPD**, in
contrast, encodes every option as PostScript `setpagedevice`.
## Goals / Non-Goals
**Goals:**
- Create a Containerfile that builds a working image for Podman
- Install and configure Brother HL-4150CDN drivers
- Share printer via IPP with AirPrint discovery
- Expose ports 631 (CUPS/IPP) and 5353/udp (mDNS)
- Make it easy to run with podman
- Build a working CUPS image for Podman with no 32-bit dependencies.
- Drive the printer with its native PostScript (BR-Script3) interpreter.
- Preserve the hardware options the user cares about: paper tray, duplex and
colour/mono (plus the other options the PPD exposes).
- Share the queue over IPP and advertise it via AirPrint.
- Keep the printer address/name runtime-configurable.
**Non-Goals:**
- Managing multiple printers
- Custom SSL/TLS configuration for CUPS (use defaults or documented)
- Persistent CUPS spool/state beyond basic setup
- Managing multiple printers.
- Sharing via SMB/Samba (Windows uses a client-side Brother driver).
- Persisting CUPS spool/state beyond the container lifecycle.
- TLS for the CUPS web interface.
## Decisions
### Base image
- Use Debian/Ubuntu (or similar) as base to handle .deb packages and 32-bit libs easily. Alternatively Alpine, but Alpine needs musl + 32-bit support can be more complex for prebuilt i386 ELF binaries from Brother. Debian stable is practical.
### Base image and packages
Use `debian:bookworm-slim` with `cups`, `cups-client`, `cups-filters`,
`avahi-daemon`, `avahi-utils`, `libnss-mdns`, `dbus`, `ghostscript` and
`poppler-utils`. No `dpkg --add-architecture i386` and no Brother `.deb`
packages: the job is converted to PostScript in CUPS and interpreted by the
printer, so no vendor binary is needed.
### Driver installation
- Use the local `.deb` packages from `assets/Brother HL-4150CDN/` (copied into the build context) and install with `dpkg -i --force-all`. No network download at build time for the driver itself.
- Do not run the Brother installer script (`linux-brprinter-installer-2.2.6-0.gz`) in the build - it is interactive and downloads packages from download.brother.com.
- Also need to install brcupsconfpt1 helper if needed - comes with cups wrapper.
- Run the cups wrapper install logic as per Brother installer (or manually create symlinks).
_Alternative considered:_ keep Brother's Linux CUPS wrapper + LPR filter. It
provides the same options but requires 32-bit libraries, Ghostscript
rasterisation and the missing `file`/`a2ps` tools, and it writes options to a
single global config file. Rejected.
### CUPS + Avahi + DBus
- Install cups, avahi-daemon, dbus. Run dbus and avahi-daemon; start cupsd.
- Configure CUPS to allow remote access/sharing. For containerized setup, typically need to listen on all interfaces and configure sharing.
### Print path: direct PostScript via the BR-Script3 PPD
Install Brother's official BR-Script3 PPD as
`/usr/share/cups/model/BR4150_2.PPD` (committed at
`assets/Brother HL-4150CDN/ppd/BR4150_2.PPD`, extracted from the vendor Windows
driver) and create the queue with it. CUPS's `pstops` filter reads the PPD and
injects the selected option code (e.g. `/BRFeeder`, `/Duplex`,
`/BRProcessColor`, `/MediaType`) into the job; the PPD's `*JCLBegin`,
`*JCLToPSInterpreter` and `*JCLEnd` entries wrap it in PJL. The result is
forwarded unchanged to the printer.
### Printer configuration
- Add printer via lpadmin using the Brother PPD. Point to network URI (e.g., ipp://PRINTER_IP/ipp or socket://PRINTER_IP:9100 - depends on printer; HL-4150CDN is network printer).
- Enable printer sharing and default options.
A stock PostScript PPD (like CUPS's own `generic.ppd`) has no `*cupsFilter`
either, and CUPS accepts such PPDs — the printer's native format is
`application/vnd.cups-postscript`.
### Device URI
Use raw AppSocket as the default: `socket://<ip>:9100`. `lpd://<ip>/binary_p1`
and `ipp://…` remain available through `PRINTER_PROTOCOL`/`PRINTER_URI`.
### Client support
- macOS / iOS / iPadOS: AirPrint → CUPS. The queue advertises `image/urf`,
`image/pwg-raster`, `application/pdf` and `application/postscript`, with
`urf-supported = V1.4,CP1,W8,PQ4,SRGB24,RS600,DM1,FN3`, `sides-supported`
(one-sided/two-sided long/short edge) and `color-supported = true`.
- Linux: IPP / IPP Everywhere, or plain IPP with PDF/PostScript.
- Windows: client-side Brother BR-Script3 Windows driver, pointed at the
printer directly or at the shared queue.
### Runtime configuration
- The printer endpoint and advertised name are supplied through environment variables rather than baked into the image, so the same image can be pointed at any HL-4150CDN:
- `PRINTER_IP` + `PRINTER_PROTOCOL` (lpd/socket/ipp) derive the device URI.
- `PRINTER_URI` overrides the derived URI for full control.
- `PRINTER_NAME` sets the CUPS queue name and the DNS-SD/AirPrint advertised name.
- `PRINTER_DESCRIPTION` sets the CUPS Description (Info) shown in the web UI.
- The entrypoint builds the URI and runs lpadmin at startup, then shares the queue.
The printer endpoint and advertised name come from environment variables
(`PRINTER_IP`, `PRINTER_PROTOCOL`, `PRINTER_URI`, `PRINTER_NAME`,
`PRINTER_DESCRIPTION`, `PPD_FILE`) rather than being baked into the image. The
entrypoint derives the URI and runs `lpadmin` on startup, then shares the queue.
## Risks / Trade-offs
- [Risk] Brother binaries are 32-bit only → require multiarch libs (libc6:i386, etc.). Increases image size slightly.
- [Risk] Using .deb packages assumes glibc-based base. If we choose different base, need to ensure compatibility.
- [Risk] Avahi in container needs --net=host or proper mDNS setup. AirPrint discovery typically works better with host network mode; document this.
- [Risk] CUPS state (printers.conf, etc.) should be persisted if we want config to survive restarts - may need volumes.
- [Risk] The AirPrint path (URF → PDF → PostScript) relies on cups-filters'
`rastertopdf`; it was not exercised with a real URF job during exploration.
macOS/iOS printing should be verified end to end.
- [Risk] Colour handling now relies on the printer's PostScript RIP rather than
Brother's host-side colour tables; output may differ slightly from the vendor
raster driver.
- [Risk] The committed PPD is a Windows PPD and contains no CUPS-specific keys.
CUPS accepts it as a PostScript PPD (verified for this CUPS version), but this
should be re-checked on CUPS upgrades.
- [Risk] Avahi needs host networking (or equivalent) to advertise mDNS.
- [Risk] CUPS state is not persisted; the queue is recreated on every start.