Set *DefaultBRColorMode: None in the vendor PPD so every job sends <</UseCIEColor false>>: Brother's Normal/Vivid modes enable the printer's own CIE conversion, which washed the colours out. Add six APPrinterPreset entries mapping print-color-mode and print-quality from driverless (AirPrint/IPP) clients onto the Brother device options; they use the notation CUPS generates itself (Apple metadata as 'key value' pairs, PPD options as '*Name Value'), because key=value strings are silently discarded. print-quality is 3/4/5. Add the PRINTER_OPTIONS env var: whitespace-separated key=value pairs applied as queue defaults on every start via lpadmin -o, validated against the queue's PPD, with warnings instead of a failed startup. Document all of it in the README. The VividNoCIE candidate was dropped after test prints showed no difference from None. Archive the OpenSpec change and sync the printserver/cups spec with the two new requirements.
This commit is contained in:
1 parent
75b68fe438
commit
30670de93b
9 files changed
+319
-33
No files matched your search
@@ -85,11 +85,26 @@ podman run -d --name printserver \
|
|||||||
| `PRINTER_NAME` | `HL4150CDN` | CUPS queue name. Also used as the name advertised via AirPrint/DNS-SD. |
|
| `PRINTER_NAME` | `HL4150CDN` | CUPS queue name. Also used as the name advertised via AirPrint/DNS-SD. |
|
||||||
| `PRINTER_DESCRIPTION` | *(empty)* | CUPS printer description (`lpadmin -D`), shown in the CUPS web UI. |
|
| `PRINTER_DESCRIPTION` | *(empty)* | CUPS printer description (`lpadmin -D`), shown in the CUPS web UI. |
|
||||||
| `PPD_FILE` | `/usr/share/cups/model/BR4150_2.PPD` | PPD used for the queue. |
|
| `PPD_FILE` | `/usr/share/cups/model/BR4150_2.PPD` | PPD used for the queue. |
|
||||||
|
| `PRINTER_OPTIONS` | *(empty)* | Space-separated PPD option assignments (`key=value`) applied as queue defaults on every start, e.g. `BRColorMode=Vivid TonerSaveMode=False`. Discover the names with `lpoptions -p <queue> -l`. |
|
||||||
| `CERT_EXTRA_NAMES` | *(empty)* | Comma-separated extra DNS names and/or IP addresses to put into the generated `_ipps` certificate. |
|
| `CERT_EXTRA_NAMES` | *(empty)* | Comma-separated extra DNS names and/or IP addresses to put into the generated `_ipps` certificate. |
|
||||||
| `CERT_DAYS` | `3650` | Validity of the generated certificate, in days. |
|
| `CERT_DAYS` | `3650` | Validity of the generated certificate, in days. |
|
||||||
|
|
||||||
No queue is created when neither `PRINTER_IP` nor `PRINTER_URI` is set.
|
No queue is created when neither `PRINTER_IP` nor `PRINTER_URI` is set.
|
||||||
|
|
||||||
|
`PRINTER_OPTIONS` sets queue defaults that survive the recreation of the queue,
|
||||||
|
because they are re-applied on every start:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
podman run -d --name printserver \
|
||||||
|
--network host \
|
||||||
|
-e PRINTER_IP=192.168.100.7 \
|
||||||
|
-e PRINTER_OPTIONS="BRMediaType=Plain BRColorMode=Vivid TonerSaveMode=False" \
|
||||||
|
printserver:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
Entries that the PPD does not know are logged as a warning and ignored; the
|
||||||
|
remaining ones are applied and the container starts normally.
|
||||||
|
|
||||||
### Choosing the connection
|
### Choosing the connection
|
||||||
|
|
||||||
The HL-4150CDN accepts PostScript directly, so the default is raw AppSocket.
|
The HL-4150CDN accepts PostScript directly, so the default is raw AppSocket.
|
||||||
@@ -187,7 +202,7 @@ The BR-Script3 PPD exposes the HL-4150CDN's hardware options. Common ones:
|
|||||||
| Paper source | `InputSlot` | `AutoSelect`, `Tray1`, `Tray2`, `MPTray` |
|
| Paper source | `InputSlot` | `AutoSelect`, `Tray1`, `Tray2`, `MPTray` |
|
||||||
| Two-sided printing | `Duplex` | `None`, `DuplexNoTumble` (long edge), `DuplexTumble` (short edge) |
|
| Two-sided printing | `Duplex` | `None`, `DuplexNoTumble` (long edge), `DuplexTumble` (short edge) |
|
||||||
| Colour / mono | `BRPrintQuality` | `Auto`, `Color`, `Black` |
|
| Colour / mono | `BRPrintQuality` | `Auto`, `Color`, `Black` |
|
||||||
| Colour mode | `BRColorMode` | `Normal`, `Vivid`, `None` |
|
| Colour mode | `BRColorMode` | `Normal`, `Vivid`, `None` (default) |
|
||||||
| Media type | `BRMediaType` | `Plain`, `Thin`, `Thick`, `Recycled`, `Glossy`, `Label`, envelopes, … |
|
| Media type | `BRMediaType` | `Plain`, `Thin`, `Thick`, `Recycled`, `Glossy`, `Label`, envelopes, … |
|
||||||
| Print quality | `CAPT` | `Fine` (600×600), `SuperFine` (2400 dpi class) |
|
| Print quality | `CAPT` | `Fine` (600×600), `SuperFine` (2400 dpi class) |
|
||||||
| Toner save | `TonerSaveMode` | `True`, `False` |
|
| Toner save | `TonerSaveMode` | `True`, `False` |
|
||||||
@@ -200,6 +215,57 @@ podman exec printserver lp -d HL4150CDN \
|
|||||||
-o Duplex=DuplexNoTumble -o BRPrintQuality=Color -o InputSlot=Tray1 report.pdf
|
-o Duplex=DuplexNoTumble -o BRPrintQuality=Color -o InputSlot=Tray1 report.pdf
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Why the macOS/iOS dialog shows fewer options
|
||||||
|
|
||||||
|
macOS and iOS print driverless (AirPrint / IPP Everywhere), so the dialog shows
|
||||||
|
only IPP-standard options: media size, duplex, pages per sheet, the
|
||||||
|
black-and-white/colour toggle and the quality slider. Brother-specific options
|
||||||
|
(`BRColorMode`, `BRMediaType`, `TonerSaveMode`, `CAPT`, …) have no IPP
|
||||||
|
equivalent and can never appear there. Set them server-side instead:
|
||||||
|
|
||||||
|
- as queue defaults at container start via `PRINTER_OPTIONS` (see
|
||||||
|
*Environment variables*),
|
||||||
|
- per job with `lp -o …`, or
|
||||||
|
- interactively in the CUPS web UI (`http://<host>:631/admin`, *Printing Options*).
|
||||||
|
|
||||||
|
The dialog's black-and-white/colour toggle maps to `print-color-mode` and the
|
||||||
|
quality slider to `print-quality`; the PPD presets documented below translate
|
||||||
|
both onto the Brother options, so they now really take effect:
|
||||||
|
|
||||||
|
| Dialog / IPP | PPD option it becomes |
|
||||||
|
| --- | --- |
|
||||||
|
| `print-color-mode=monochrome` | `BRPrintQuality=Black` |
|
||||||
|
| `print-color-mode=color` | `BRPrintQuality=Auto` |
|
||||||
|
| `print-quality=3` (draft) | `TonerSaveMode=True` |
|
||||||
|
| `print-quality=4` (normal) | defaults (`Fine`, toner save off) |
|
||||||
|
| `print-quality=5` (high) | `CAPT=SuperFine` (2400 dpi class) |
|
||||||
|
|
||||||
|
Client-specified values always win over the preset.
|
||||||
|
|
||||||
|
### Changes to the vendor PPD
|
||||||
|
|
||||||
|
`assets/Brother HL-4150CDN/ppd/BR4150_2.PPD` is Brother's original file plus
|
||||||
|
two additions, each marked with a `%` comment in the file:
|
||||||
|
|
||||||
|
- **`*DefaultBRColorMode: None` instead of `Normal`.** `Normal` and `Vivid` both
|
||||||
|
set `<</UseCIEColor true>>`; the printer's own CIE conversion washes the
|
||||||
|
colours out (see [Colours are printed pale / washed out](#colours-are-printed-pale--washed-out)).
|
||||||
|
- **Six `APPrinterPreset` entries** mapping `print-color-mode`
|
||||||
|
(color/monochrome) and `print-quality` (draft/normal/high) onto
|
||||||
|
`BRPrintQuality`, `CAPT` and `TonerSaveMode`. CUPS applies such presets for
|
||||||
|
driverless clients and always lets the client's own option values win. In
|
||||||
|
particular `print-color-mode=monochrome` becomes `BRPrintQuality=Black`, so
|
||||||
|
black-and-white printing works: the server cannot do the greyscale conversion
|
||||||
|
itself, because `pdftops` uses Poppler for Brother printers and Poppler
|
||||||
|
cannot produce greyscale (`WARNING: Grayscale/monochrome could be printed as
|
||||||
|
color with Poppler` in the CUPS log). The presets use the notation CUPS
|
||||||
|
generates itself — Apple metadata as `key value` pairs *without* `=`, PPD
|
||||||
|
options as `*Name Value` pairs on separate lines inside a multiline
|
||||||
|
`"…"` string. With `key=value` on a single line CUPS silently ignores the
|
||||||
|
whole preset (verified against libcups 2.4.2: `_ppdParseOptions()` splits on
|
||||||
|
whitespace, so `key=value` becomes the option *name* and the lookup fails).
|
||||||
|
Note that IPP `print-quality` is `3` (draft), `4` (normal), `5` (high).
|
||||||
|
|
||||||
## Client support
|
## Client support
|
||||||
|
|
||||||
| Platform | Path | Notes |
|
| Platform | Path | Notes |
|
||||||
@@ -384,6 +450,38 @@ still being rejected — fix that, or add the queue from the command line as
|
|||||||
above. macOS caches the failed attempt, so remove and re-add the printer after
|
above. macOS caches the failed attempt, so remove and re-add the printer after
|
||||||
changing anything on the server.
|
changing anything on the server.
|
||||||
|
|
||||||
|
### Colours are printed pale / washed out
|
||||||
|
|
||||||
|
Symptom: colour printouts look desaturated compared to the same PDF printed
|
||||||
|
directly from the Mac, or with Brother's own driver.
|
||||||
|
|
||||||
|
Cause: the PPD colour mode `Normal` (Brother's default) makes the printer's
|
||||||
|
PostScript interpreter apply its own CIE conversion (`<</UseCIEColor true>>`),
|
||||||
|
which washes colours out. `Vivid` sets `UseCIEColor` as well, so it does not
|
||||||
|
help either; `BRPrintQuality` (`BRColorAdapt`) and `TonerSaveMode` made no
|
||||||
|
visible difference in a side-by-side test. The container therefore ships the
|
||||||
|
PPD with `*DefaultBRColorMode: None` (`UseCIEColor` off), which produces
|
||||||
|
saturated output.
|
||||||
|
|
||||||
|
Check and, if needed, override the current default:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
podman exec printserver lpoptions -p <queue> -l | grep BRColorMode # expect *None
|
||||||
|
podman exec printserver lp -d <queue> -o BRColorMode=None test.pdf
|
||||||
|
```
|
||||||
|
|
||||||
|
If output is still pale with `BRColorMode=None`, check the printer's own menu
|
||||||
|
(Toner → Toner Save off) and make sure `BRMediaType` matches the media in the
|
||||||
|
tray.
|
||||||
|
|
||||||
|
Black-and-white is a related but separate path: `print-color-mode=monochrome`
|
||||||
|
from a driverless client is mapped by the PPD presets onto
|
||||||
|
`BRPrintQuality=Black` (the printer renders mono). It is deliberately *not* done
|
||||||
|
by the server — with its Poppler renderer, `pdftops` cannot convert to
|
||||||
|
greyscale. Forcing Ghostscript with `-o pdftops-renderer=gs` would, but that
|
||||||
|
path is not recommended for Brother printers (bugs in their PostScript
|
||||||
|
interpreters).
|
||||||
|
|
||||||
## CUPS 3 and the future of PPDs
|
## CUPS 3 and the future of PPDs
|
||||||
|
|
||||||
Adding the queue with a PPD makes `lpadmin` print:
|
Adding the queue with a PPD makes `lpadmin` print:
|
||||||
|
|||||||
@@ -374,9 +374,12 @@ restore
|
|||||||
*CloseUI: *BRPrintQuality
|
*CloseUI: *BRPrintQuality
|
||||||
|
|
||||||
*% Color Mode Information ===============
|
*% Color Mode Information ===============
|
||||||
|
*% Modified by this repo (see README, "Changes to the vendor PPD"):
|
||||||
|
*% - default switched from Normal to None: with UseCIEColor off the printer
|
||||||
|
*% skips its CIE conversion, which otherwise washes out the colours.
|
||||||
*OpenUI *BRColorMode/Colour Mode: PickOne
|
*OpenUI *BRColorMode/Colour Mode: PickOne
|
||||||
*OrderDependency: 131.0 AnySetup *BRColorMode
|
*OrderDependency: 131.0 AnySetup *BRColorMode
|
||||||
*DefaultBRColorMode: Normal
|
*DefaultBRColorMode: None
|
||||||
*BRColorMode Normal/Normal: "
|
*BRColorMode Normal/Normal: "
|
||||||
<</UseCIEColor true>>setpagedevice
|
<</UseCIEColor true>>setpagedevice
|
||||||
<</BRColorMode 0>>setpagedevice
|
<</BRColorMode 0>>setpagedevice
|
||||||
@@ -393,6 +396,48 @@ restore
|
|||||||
*End
|
*End
|
||||||
*CloseUI: *BRColorMode
|
*CloseUI: *BRColorMode
|
||||||
|
|
||||||
|
*% Added by this repo: presets mapping the IPP attributes of driverless
|
||||||
|
*% (AirPrint/IPP Everywhere) clients onto the device options below. CUPS applies
|
||||||
|
*% them automatically when a job carries print-color-mode / print-quality;
|
||||||
|
*% options the client states explicitly always take precedence. Format follows
|
||||||
|
*% the presets CUPS generates itself: Apple metadata as "key value" pairs
|
||||||
|
*% (no '='), PPD options as "*Name Value" pairs.
|
||||||
|
*APPrinterPreset ColorDraft/Colour, Draft: "
|
||||||
|
com.apple.print.preset.output-mode color
|
||||||
|
com.apple.print.preset.quality low
|
||||||
|
*TonerSaveMode True
|
||||||
|
"
|
||||||
|
*APPrinterPreset ColorNormal/Colour, Normal: "
|
||||||
|
com.apple.print.preset.output-mode color
|
||||||
|
com.apple.print.preset.quality normal
|
||||||
|
*TonerSaveMode False
|
||||||
|
"
|
||||||
|
*APPrinterPreset ColorHigh/Colour, High: "
|
||||||
|
com.apple.print.preset.output-mode color
|
||||||
|
com.apple.print.preset.quality high
|
||||||
|
*CAPT SuperFine
|
||||||
|
*TonerSaveMode False
|
||||||
|
"
|
||||||
|
*APPrinterPreset MonoDraft/B&W, Draft: "
|
||||||
|
com.apple.print.preset.output-mode monochrome
|
||||||
|
com.apple.print.preset.quality low
|
||||||
|
*BRPrintQuality Black
|
||||||
|
*TonerSaveMode True
|
||||||
|
"
|
||||||
|
*APPrinterPreset MonoNormal/B&W, Normal: "
|
||||||
|
com.apple.print.preset.output-mode monochrome
|
||||||
|
com.apple.print.preset.quality normal
|
||||||
|
*BRPrintQuality Black
|
||||||
|
*TonerSaveMode False
|
||||||
|
"
|
||||||
|
*APPrinterPreset MonoHigh/B&W, High: "
|
||||||
|
com.apple.print.preset.output-mode monochrome
|
||||||
|
com.apple.print.preset.quality high
|
||||||
|
*BRPrintQuality Black
|
||||||
|
*CAPT SuperFine
|
||||||
|
*TonerSaveMode False
|
||||||
|
"
|
||||||
|
|
||||||
*% Improve Gray Color Information ===============
|
*% Improve Gray Color Information ===============
|
||||||
*OpenUI *BRImprovedGray/Improve Grey Colour: PickOne
|
*OpenUI *BRImprovedGray/Improve Grey Colour: PickOne
|
||||||
*OrderDependency: 132.0 AnySetup *BRImprovedGray
|
*OrderDependency: 132.0 AnySetup *BRImprovedGray
|
||||||
|
|||||||
@@ -18,6 +18,9 @@
|
|||||||
# PRINTER_NAME CUPS queue name and advertised (DNS-SD) name.
|
# PRINTER_NAME CUPS queue name and advertised (DNS-SD) name.
|
||||||
# PRINTER_DESCRIPTION CUPS Description (lpadmin -D) shown in the web UI.
|
# PRINTER_DESCRIPTION CUPS Description (lpadmin -D) shown in the web UI.
|
||||||
# PPD_FILE PPD used for the queue.
|
# PPD_FILE PPD used for the queue.
|
||||||
|
# PRINTER_OPTIONS Space-separated PPD option assignments (key=value)
|
||||||
|
# applied as queue defaults on every start, e.g.
|
||||||
|
# "BRColorMode=Vivid TonerSaveMode=False".
|
||||||
# CERT_EXTRA_NAMES Comma-separated extra DNS names / IP addresses to put
|
# CERT_EXTRA_NAMES Comma-separated extra DNS names / IP addresses to put
|
||||||
# into the generated IPPS certificate (server SANs).
|
# into the generated IPPS certificate (server SANs).
|
||||||
# CERT_DAYS Validity of the generated certificate (default 3650).
|
# CERT_DAYS Validity of the generated certificate (default 3650).
|
||||||
@@ -29,6 +32,7 @@ PRINTER_URI="${PRINTER_URI:-}"
|
|||||||
PRINTER_PROTOCOL="${PRINTER_PROTOCOL:-socket}"
|
PRINTER_PROTOCOL="${PRINTER_PROTOCOL:-socket}"
|
||||||
PRINTER_DESCRIPTION="${PRINTER_DESCRIPTION:-}"
|
PRINTER_DESCRIPTION="${PRINTER_DESCRIPTION:-}"
|
||||||
PPD_FILE="${PPD_FILE:-/usr/share/cups/model/BR4150_2.PPD}"
|
PPD_FILE="${PPD_FILE:-/usr/share/cups/model/BR4150_2.PPD}"
|
||||||
|
PRINTER_OPTIONS="${PRINTER_OPTIONS:-}"
|
||||||
|
|
||||||
LOG_PREFIX="[entrypoint]"
|
LOG_PREFIX="[entrypoint]"
|
||||||
log() { echo "${LOG_PREFIX} $*"; }
|
log() { echo "${LOG_PREFIX} $*"; }
|
||||||
@@ -331,6 +335,50 @@ if lpstat -p "${PRINTER_NAME}" >/dev/null 2>&1; then
|
|||||||
log "queue ${PRINTER_NAME} is shared and set as default"
|
log "queue ${PRINTER_NAME} is shared and set as default"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Apply optional queue defaults from PRINTER_OPTIONS (see README). Runs on every
|
||||||
|
# start so the settings survive the (re)creation of the queue; an unusable entry
|
||||||
|
# only logs a warning instead of aborting the startup ("set -eu"). Names and
|
||||||
|
# values are checked against the queue's options first, because lpadmin would
|
||||||
|
# happily store unknown assignments as queue defaults.
|
||||||
|
apply_printer_options() {
|
||||||
|
[ -n "${PRINTER_OPTIONS}" ] || return 0
|
||||||
|
if ! lpstat -p "${PRINTER_NAME}" >/dev/null 2>&1; then
|
||||||
|
log "warning: queue ${PRINTER_NAME} does not exist; skipping PRINTER_OPTIONS"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
ppd_options="$(lpoptions -p "${PRINTER_NAME}" -l 2>/dev/null || true)"
|
||||||
|
for opt in ${PRINTER_OPTIONS}; do
|
||||||
|
case "${opt}" in
|
||||||
|
?*=*) ;;
|
||||||
|
*)
|
||||||
|
log "warning: ignoring malformed PRINTER_OPTIONS entry '${opt}' (expected key=value)"
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
name="${opt%%=*}"
|
||||||
|
value="${opt#*=}"
|
||||||
|
line="$(printf '%s\n' "${ppd_options}" | grep "^${name}/")" || {
|
||||||
|
log "warning: PPD has no option '${name}'; ignoring (names/values: 'lpoptions -p ${PRINTER_NAME} -l')"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
# Option lines look like "Name/Text: value1 value2 ..." ('*' = default).
|
||||||
|
values="$(printf '%s\n' "${line#*: }" | tr ' ' '\n' | sed 's/^\*//')"
|
||||||
|
if ! printf '%s\n' "${values}" | grep -qxF "${value}" \
|
||||||
|
&& ! { case "${value}" in Custom.*)
|
||||||
|
printf '%s\n' "${values}" | grep -q 'Custom\.'
|
||||||
|
;; *) false ;; esac; }; then
|
||||||
|
log "warning: PPD option '${name}' has no value '${value}'; ignoring"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if lpadmin -p "${PRINTER_NAME}" -o "${opt}" >/dev/null 2>&1; then
|
||||||
|
log "queue default ${opt} applied"
|
||||||
|
else
|
||||||
|
log "warning: lpadmin -o ${opt} failed; ignoring"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
apply_printer_options
|
||||||
|
|
||||||
# --- Verify CUPS is reachable on the network --------------------------------
|
# --- Verify CUPS is reachable on the network --------------------------------
|
||||||
# cupsd also runs with nothing but its domain socket, e.g. when it cannot bind
|
# cupsd also runs with nothing but its domain socket, e.g. when it cannot bind
|
||||||
# the privileged port 631 (rootless Podman with host networking). It then still
|
# the privileged port 631 (rootless Podman with host networking). It then still
|
||||||
|
|||||||
File renamed without changes.
+28
-7
@@ -85,6 +85,30 @@ geschickt hat – clientseitige Auswahl gewinnt also weiterhin
|
|||||||
(`ppd-mark.c`: „as long as the corresponding names are not already defined
|
(`ppd-mark.c`: „as long as the corresponding names are not already defined
|
||||||
in the IPP request").
|
in the IPP request").
|
||||||
|
|
||||||
|
**Preset-Notation (2026-10-20 empirisch geklärt).** Die Preset-Werte müssen so
|
||||||
|
geschrieben werden, wie CUPS sie selbst erzeugt (`ppd-cache.c`, Funktion
|
||||||
|
`cupsFilePrintf fp "*APPrinterPreset %s: \""`): eine mehrzeilige Zeichenkette,
|
||||||
|
in der Apple-Metadaten als `key value`-**Paare ohne `=`** und PPD-Optionen als
|
||||||
|
`*Name Value`-Paare stehen, jeweils durch Leerzeichen getrennt:
|
||||||
|
|
||||||
|
```
|
||||||
|
*APPrinterPreset MonoNormal/B&W, Normal: "
|
||||||
|
com.apple.print.preset.output-mode monochrome
|
||||||
|
com.apple.print.preset.quality normal
|
||||||
|
*BRPrintQuality Black
|
||||||
|
*TonerSaveMode False
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
`_ppdCacheCreateWithPPD()` parst den Wert mit `_ppdParseOptions()`, das an
|
||||||
|
Whitespace trennt – `key=value` in einer Zeile würde den *Namen*
|
||||||
|
`key=value` ergeben und der Lookup (`cupsGetOption("com.apple.print.preset.
|
||||||
|
quality", …)`) schlüge fehl. CUPS verwirft das Preset dann **stillschweigend**
|
||||||
|
(`num_presets[…]=0`), was im Test zunächst genau passierte. Verifiziert mit
|
||||||
|
einem libcups-2.4.2-Harness (`_ppd_cache_t` inspiziert) und im
|
||||||
|
`pstops`-Filterpfad. Zusätzlich: IPP-`print-quality` ist **3/4/5**
|
||||||
|
(Draft/Normal/High), nicht 2/5.
|
||||||
|
|
||||||
**2. PPD direkt im Repository ändern (nicht zur Build-Zeit patchen).**
|
**2. PPD direkt im Repository ändern (nicht zur Build-Zeit patchen).**
|
||||||
|
|
||||||
Die Asset-Datei `assets/Brother HL-4150CDN/ppd/BR4150_2.PPD` wird bereits
|
Die Asset-Datei `assets/Brother HL-4150CDN/ppd/BR4150_2.PPD` wird bereits
|
||||||
@@ -112,13 +136,12 @@ damit gilt es auch für eine persistente Queue. Fehler pro Token abfangen
|
|||||||
(`|| log warning`), da `set -eu` sonst den Start abbricht; unbekannte Namen
|
(`|| log warning`), da `set -eu` sonst den Start abbricht; unbekannte Namen
|
||||||
werden verworfen, ohne die übrigen zu blockieren.
|
werden verworfen, ohne die übrigen zu blockieren.
|
||||||
|
|
||||||
**5. Neue `BRColorMode`-Choice `VividNoCIE` nur unter Vorbehalt.**
|
**5. Neue `BRColorMode`-Choice `VividNoCIE` verworfen.**
|
||||||
|
|
||||||
`<</UseCIEColor false /BRColorMode 1>>` – Kombi, die es bisher nicht gibt
|
`<</UseCIEColor false /BRColorMode 1>>` – Kombi, die es bisher nicht gibt
|
||||||
(`None` lässt `/BRColorMode` unangetastet, `Vivid` erzwingt CIE). Wird als
|
(`None` lässt `/BRColorMode` unangetastet, `Vivid` erzwingt CIE). Als
|
||||||
Testdruck gegen `None` verglichen; nur übernommen, wenn der Ausdruck
|
Testdruck gegen `None` verglichen (2026-10-20): **nicht unterscheidbar**,
|
||||||
deutlich besser ist. Spezifikation hängt nicht davon ab (Default bleibt
|
daher nicht übernommen. `None` bleibt der einzige geänderte Default.
|
||||||
`None`, Überschreibung ist ohnehin möglich).
|
|
||||||
|
|
||||||
## Risks / Trade-offs
|
## Risks / Trade-offs
|
||||||
|
|
||||||
@@ -151,8 +174,6 @@ deutlich besser ist. Spezifikation hängt nicht davon ab (Default bleibt
|
|||||||
|
|
||||||
## Open Questions
|
## Open Questions
|
||||||
|
|
||||||
- Ob `VividNoCIE` mehr Sättigung liefert als `None` – wird im Tasks-Test
|
|
||||||
entschieden; ändert weder Spec (Default bleibt `None`) noch Aufbau.
|
|
||||||
- Ob macOS/iOS den Qualitätsregler als `print-quality` sendet – falls nicht,
|
- Ob macOS/iOS den Qualitätsregler als `print-quality` sendet – falls nicht,
|
||||||
bleiben die `print-quality`-Presets inert, `print-color-mode`-Presets
|
bleiben die `print-quality`-Presets inert, `print-color-mode`-Presets
|
||||||
wirken unabhängig davon (Server-seitig per `lp -o print-quality=…`
|
wirken unabhängig davon (Server-seitig per `lp -o print-quality=…`
|
||||||
+4
-4
@@ -41,16 +41,16 @@ Drucker-Queue):
|
|||||||
Start als Queue-Defaults gesetzt werden – damit überleben
|
Start als Queue-Defaults gesetzt werden – damit überleben
|
||||||
PPD-Optionen (z. B. `BRMediaType`, `TonerSaveMode`, `BRColorMode=Vivid`)
|
PPD-Optionen (z. B. `BRMediaType`, `TonerSaveMode`, `BRColorMode=Vivid`)
|
||||||
die Neuerzeugung der Queue.
|
die Neuerzeugung der Queue.
|
||||||
- **Optionale neue PPD-Choice `BRColorMode=VividNoCIE`**
|
|
||||||
(`<</UseCIEColor false /BRColorMode 1>>`) als Testkandidat für noch
|
|
||||||
gesättigtere Ausgabe als `None`; nur behalten, wenn der Testdruck
|
|
||||||
besser ist als `None`.
|
|
||||||
- **README**: neuer Abschnitt, warum der AirPrint-Dialog nur
|
- **README**: neuer Abschnitt, warum der AirPrint-Dialog nur
|
||||||
IPP-Standardoptionen zeigt und wie PPD-Optionen gesetzt werden (Env-Var,
|
IPP-Standardoptionen zeigt und wie PPD-Optionen gesetzt werden (Env-Var,
|
||||||
CUPS-Web-UI, `lp`); Troubleshooting „Farben sind blass" mit der
|
CUPS-Web-UI, `lp`); Troubleshooting „Farben sind blass" mit der
|
||||||
durchgeführten Testreihe; Dokumentation der funktionierenden
|
durchgeführten Testreihe; Dokumentation der funktionierenden
|
||||||
S/W-Abbildung.
|
S/W-Abbildung.
|
||||||
|
|
||||||
|
Verworfen: eine zusätzliche Choice `BRColorMode=VividNoCIE`
|
||||||
|
(`UseCIEColor false` + `/BRColorMode 1`) – die Testdrucke waren von `None`
|
||||||
|
nicht unterscheidbar, siehe `design.md`.
|
||||||
|
|
||||||
Kein Bestandteil: Änderungen am Containerfile (die PPD wird bereits
|
Kein Bestandteil: Änderungen am Containerfile (die PPD wird bereits
|
||||||
installiert), am Verbindungs-/Zertifikatsverhalten oder eine
|
installiert), am Verbindungs-/Zertifikatsverhalten oder eine
|
||||||
Server-seitige Erzwingung von Graustufen über `pdftops-renderer=gs`
|
Server-seitige Erzwingung von Graustufen über `pdftops-renderer=gs`
|
||||||
File renamed without changes.
+43
-20
@@ -2,29 +2,35 @@
|
|||||||
|
|
||||||
## 1. PPD: Farbmodus-Default, Presets und Dokumentation
|
## 1. PPD: Farbmodus-Default, Presets und Dokumentation
|
||||||
|
|
||||||
- [ ] 1.1 `assets/Brother HL-4150CDN/ppd/BR4150_2.PPD`: `*DefaultBRColorMode`
|
- [x] 1.1 `assets/Brother HL-4150CDN/ppd/BR4150_2.PPD`: `*DefaultBRColorMode`
|
||||||
von `Normal` auf `None` ändern, alle eigenen Ergänzungen mit
|
von `Normal` auf `None` ändern, alle eigenen Ergänzungen mit
|
||||||
`%`-Kommentar (Herkunft/Zweck) markieren.
|
`%`-Kommentar (Herkunft/Zweck) markieren.
|
||||||
Verifikation: `grep -n 'DefaultBRColorMode\|^% Modified' "assets/Brother HL-4150CDN/ppd/BR4150_2.PPD"`
|
Verifikation: `grep -n 'DefaultBRColorMode\|^% Modified' "assets/Brother HL-4150CDN/ppd/BR4150_2.PPD"`
|
||||||
zeigt `*DefaultBRColorMode: None` und den Kommentar.
|
zeigt `*DefaultBRColorMode: None` und den Kommentar.
|
||||||
- [ ] 1.2 PPD: sechs `APPrinterPreset`-Einträge ergänzen (Kombinationen
|
- [x] 1.2 PPD: sechs `APPrinterPreset`-Einträge ergänzen (Kombinationen
|
||||||
color/monochrome × low/normal/high gemäß Tabelle in `design.md`,
|
color/monochrome × low/normal/high gemäß Tabelle in `design.md`).
|
||||||
z. B. `*APPrinterPreset MonoNormal/Schwarz-Weiß Normal:
|
|
||||||
"*com.apple.print.preset.output-mode=monochrome
|
|
||||||
*com.apple.print.preset.quality=normal *BRPrintQuality=Black
|
|
||||||
*TonerSaveMode=False"`).
|
|
||||||
Verifikation: `grep -c '^\*APPrinterPreset' "assets/Brother HL-4150CDN/ppd/BR4150_2.PPD"`
|
Verifikation: `grep -c '^\*APPrinterPreset' "assets/Brother HL-4150CDN/ppd/BR4150_2.PPD"`
|
||||||
ergibt 6, und nach einem Build listet
|
ergibt 6, und nach einem Build listet
|
||||||
`lpoptions -p <queue> -l` weiterhin alle Optionen ohne
|
`lpoptions -p <queue> -l` weiterhin alle Optionen ohne
|
||||||
PPD-Warnung in `/var/log/cups/error_log`.
|
PPD-Warnung in `/var/log/cups/error_log`.
|
||||||
- [ ] 1.3 PPD: Choice `VividNoCIE` unter `BRColorMode` ergänzen
|
Ergebnis (2026-10-20): Zunächst als einzeilige `key=value`-Strings
|
||||||
|
geschrieben – CUPS verwarf alle sechs stillschweigend
|
||||||
|
(`_ppdParseOptions()` trennt an Whitespace, `key=value` wurde zum
|
||||||
|
*Namen*). Mit libcups-2.4.2-Harness (`_ppd_cache_t`-Inspektion) belegt
|
||||||
|
und auf das von CUPS selbst erzeugte Format umgestellt (mehrzeilig,
|
||||||
|
Apple-Metadaten als `key value`, PPD-Optionen als `*Name Value`).
|
||||||
|
Danach greifen alle sechs im `pstops`-Pfad (siehe 3.x).
|
||||||
|
- [x] 1.3 PPD: Choice `VividNoCIE` unter `BRColorMode` ergänzen
|
||||||
(`<</UseCIEColor false /BRColorMode 1>>setpagedevice`) und per
|
(`<</UseCIEColor false /BRColorMode 1>>setpagedevice`) und per
|
||||||
Testdruck gegen `None` vergleichen; nur behalten, wenn der Ausdruck
|
Testdruck gegen `None` vergleichen; nur behalten, wenn der Ausdruck
|
||||||
deutlich gesättigter ist.
|
deutlich gesättigter ist.
|
||||||
Verifikation: `lpoptions -p <queue> -l` zeigt die Choice, die
|
Verifikation: `lpoptions -p <queue> -l` zeigt die Choice, die
|
||||||
Entscheidung (behalten/entfernen) ist im README-Auswertungs-Abschnitt
|
Entscheidung (behalten/entfernen) ist im README-Auswertungs-Abschnitt
|
||||||
notiert.
|
notiert.
|
||||||
- [ ] 1.4 README: Abschnitt „Farben sind blass" (Ursache `UseCIEColor`,
|
Ergebnis (2026-10-20): Testdrucke `BRColorMode=VividNoCIE` (Job 5) und
|
||||||
|
`BRColorMode=None` (Job 6) sind **nicht unterscheidbar** → Choice
|
||||||
|
wieder entfernt (README/Tabelle bereinigt).
|
||||||
|
- [x] 1.4 README: Abschnitt „Farben sind blass" (Ursache `UseCIEColor`,
|
||||||
durchgeführte Testreihe mit `lp -o BRColorMode=…`,
|
durchgeführte Testreihe mit `lp -o BRColorMode=…`,
|
||||||
Ergebnis `None`), Abschnitt „Änderungen an der Hersteller-PPD"
|
Ergebnis `None`), Abschnitt „Änderungen an der Hersteller-PPD"
|
||||||
(welche Einträge ergänzt wurden und warum) und Abschnitt
|
(welche Einträge ergänzt wurden und warum) und Abschnitt
|
||||||
@@ -35,7 +41,7 @@
|
|||||||
|
|
||||||
## 2. entrypoint: `PRINTER_OPTIONS`
|
## 2. entrypoint: `PRINTER_OPTIONS`
|
||||||
|
|
||||||
- [ ] 2.1 `entrypoint.sh`: `PRINTER_OPTIONS` (Standard leer) nach der
|
- [x] 2.1 `entrypoint.sh`: `PRINTER_OPTIONS` (Standard leer) nach der
|
||||||
Queue-Erzeugung in Tokens `key=value` zerlegen und jedes per
|
Queue-Erzeugung in Tokens `key=value` zerlegen und jedes per
|
||||||
`lpadmin -o` setzen, an derselben Stelle wie
|
`lpadmin -o` setzen, an derselben Stelle wie
|
||||||
`printer-is-shared`/`-D`/`-d`, bei jedem Start.
|
`printer-is-shared`/`-D`/`-d`, bei jedem Start.
|
||||||
@@ -43,12 +49,12 @@
|
|||||||
`PRINTER_OPTIONS="BRColorMode=Vivid TonerSaveMode=False"` und
|
`PRINTER_OPTIONS="BRColorMode=Vivid TonerSaveMode=False"` und
|
||||||
`lpoptions -p <queue> -l` zeigt `Vivid` und `True` als Default
|
`lpoptions -p <queue> -l` zeigt `Vivid` und `True` als Default
|
||||||
(`*Vivid`, `*True`).
|
(`*Vivid`, `*True`).
|
||||||
- [ ] 2.2 Fehler pro Token abfangen, damit `set -eu` den Start nicht
|
- [x] 2.2 Fehler pro Token abfangen, damit `set -eu` den Start nicht
|
||||||
abbricht, und warnen.
|
abbricht, und warnen.
|
||||||
Verifikation: Start mit `PRINTER_OPTIONS="NoSuchOption=Foo"` erzeugt
|
Verifikation: Start mit `PRINTER_OPTIONS="NoSuchOption=Foo"` erzeugt
|
||||||
eine Warning-Zeile im Log, der Container erreicht
|
eine Warning-Zeile im Log, der Container erreicht
|
||||||
„ready: CUPS on 631/tcp" und `lpstat -r` meldet „scheduler is running".
|
„ready: CUPS on 631/tcp" und `lpstat -r` meldet „scheduler is running".
|
||||||
- [ ] 2.3 README: neue Zeile in der Env-Var-Tabelle plus Kurzbeispiel unter
|
- [x] 2.3 README: neue Zeile in der Env-Var-Tabelle plus Kurzbeispiel unter
|
||||||
„Environment variables" (inkl. Hinweis `lpoptions -p <queue> -l` zur
|
„Environment variables" (inkl. Hinweis `lpoptions -p <queue> -l` zur
|
||||||
Entdeckbarkeit der Namen).
|
Entdeckbarkeit der Namen).
|
||||||
Verifikation: das Beispiel aus der Tabelle in einen `podman run`-Befehl
|
Verifikation: das Beispiel aus der Tabelle in einen `podman run`-Befehl
|
||||||
@@ -56,21 +62,38 @@
|
|||||||
|
|
||||||
## 3. Integrationstests am laufenden System
|
## 3. Integrationstests am laufenden System
|
||||||
|
|
||||||
- [ ] 3.1 Image neu bauen und Container starten.
|
- [x] 3.1 Image neu bauen und Container starten.
|
||||||
Verifikation: `podman build -t printserver:latest .` endet ohne Fehler,
|
Verifikation: `podman build -t printserver:latest .` endet ohne Fehler,
|
||||||
das Log enthält „ready: CUPS on 631/tcp, mDNS on 5353/udp".
|
das Log enthält „ready: CUPS on 631/tcp, mDNS on 5353/udp".
|
||||||
- [ ] 3.2 S/W-Druck aus dem macOS-Dialog (derselbe Farbjob wie zuvor).
|
Ergebnis (2026-10-20, podman 6.1.4/macOS-VM): Build und Start ok; der
|
||||||
|
Container bindet 631 nur nach
|
||||||
|
`podman machine ssh -- sudo sysctl -w net.ipv4.ip_unprivileged_port_start=631`
|
||||||
|
(rootless VM) – danach „ready".
|
||||||
|
- [x] 3.2 S/W-Druck aus dem macOS-Dialog (derselbe Farbjob wie zuvor).
|
||||||
Verifikation: Ausdruck ist schwarz/weiß – vorher kam er farbig heraus.
|
Verifikation: Ausdruck ist schwarz/weiß – vorher kam er farbig heraus.
|
||||||
- [ ] 3.3 Farbdruck ohne weitere Optionen aus dem Dialog und per
|
Server-seitig verifiziert (2026-10-20): `print-color-mode=monochrome`
|
||||||
|
→ `<</BRProcessColor 1>>`. Sichtprüfung durch Nutzer (2026-10-20):
|
||||||
|
Testseite 2 ist schwarz/weiß. **Bestanden.**
|
||||||
|
- [x] 3.3 Farbdruck ohne weitere Optionen aus dem Dialog und per
|
||||||
`lp -d <queue> test.pdf`.
|
`lp -d <queue> test.pdf`.
|
||||||
Verifikation: Ausdruck ist so gesättigt wie der bisherige
|
Verifikation: Ausdruck ist so gesättigt wie der bisherige
|
||||||
`BRColorMode=None`-Testdruck; `lpoptions -p <queue> -l` zeigt `*None`
|
`BRColorMode=None`-Testdruck; `lpoptions -p <queue> -l` zeigt `*None`
|
||||||
als Farbmodus-Default.
|
als Farbmodus-Default.
|
||||||
- [ ] 3.4 Qualitätsstufen prüfen.
|
Verifiziert (2026-10-20): `lpoptions` zeigt `*None`, `pstops` emittiert
|
||||||
Verifikation: `lp -o print-quality=2 test.pdf` (draft, sichtbar
|
`<</UseCIEColor false>>` auch ohne Job-Optionen. Sichtprüfung durch
|
||||||
tonersparender) und `lp -o print-quality=5 test.pdf` (high, `CAPT`
|
Nutzer: Testseite 1 ist kräftig/gesättigt (nicht mehr blass).
|
||||||
SuperFine) erzeugen unterscheidbare Ausdrucke gegenüber
|
**Bestanden.**
|
||||||
`print-quality=3`.
|
- [x] 3.4 Qualitätsstufen prüfen.
|
||||||
|
Verifikation: `lp -o print-quality=3 test.pdf` (IPP draft, sichtbar
|
||||||
|
tonersparender: `true tonersave`) und `lp -o print-quality=5 test.pdf`
|
||||||
|
(IPP high, `CAPT SuperFine`, `<</BRApt 2 /HWResolution [600 600]>>`)
|
||||||
|
erzeugen unterscheidbare Ausdrucke gegenüber `print-quality=4`
|
||||||
|
(IPP normal). Hinweis: IPP-`print-quality` ist 3/4/5 – nicht 2/5.
|
||||||
|
Verifiziert (2026-10-20): serverseitig im `pstops`-Output (3 →
|
||||||
|
`true tonersave`, 5 → `BRApt 2`); Sichtprüfung durch Nutzer: Seite 3
|
||||||
|
(draft) blass/tonersparend, klar unterscheidbar von 1/4. Seite 1 = 4
|
||||||
|
erwartungsgemäß (SuperFine vs. Fine bei diesem Testmotiv optisch
|
||||||
|
gleich, serverseitig aber gesetzt). **Bestanden.**
|
||||||
|
|
||||||
## Workflow follow-up
|
## Workflow follow-up
|
||||||
|
|
||||||
@@ -54,6 +54,57 @@ The system SHALL translate the PPD's device options into PostScript
|
|||||||
- **WHEN** a job selects colour or mono
|
- **WHEN** a job selects colour or mono
|
||||||
- **THEN** the emitted PostScript sets the corresponding colour/mono device parameters
|
- **THEN** the emitted PostScript sets the corresponding colour/mono device parameters
|
||||||
|
|
||||||
|
#### Scenario: A driverless client selects black and white
|
||||||
|
- **WHEN** an AirPrint/IPP client sends `print-color-mode=monochrome`
|
||||||
|
- **THEN** the emitted PostScript sets the mono device parameters (`/BRProcessColor 1`) and the job prints in black and white, independent of the PDF renderer used by the server
|
||||||
|
|
||||||
|
#### Scenario: A driverless client selects colour
|
||||||
|
- **WHEN** an AirPrint/IPP client sends `print-color-mode=color`
|
||||||
|
- **THEN** the job prints in colour and the emitted PostScript disables toner saving
|
||||||
|
|
||||||
|
#### Scenario: A driverless client selects the print quality
|
||||||
|
- **WHEN** an AirPrint/IPP client sends `print-quality=draft`, `normal` or `high`
|
||||||
|
- **THEN** the emitted PostScript selects the mapped device settings: toner saving for draft, full toner for normal, and the `CAPT` high-resolution setting for high
|
||||||
|
|
||||||
|
### Requirement: Queue defaults are configurable at runtime
|
||||||
|
The container SHALL accept a `PRINTER_OPTIONS` environment variable holding
|
||||||
|
space-separated PPD option assignments (`key=value`) and apply each assignment
|
||||||
|
as a queue default on every start, so PPD-specific device options survive the
|
||||||
|
recreation of the queue.
|
||||||
|
|
||||||
|
#### Scenario: Options are applied on start
|
||||||
|
- **WHEN** the container is started with `PRINTER_OPTIONS="BRColorMode=Vivid TonerSaveMode=False"`
|
||||||
|
- **THEN** after startup the queue defaults include `BRColorMode=Vivid` and `TonerSaveMode=False`
|
||||||
|
|
||||||
|
#### Scenario: Defaults apply to driverless clients
|
||||||
|
- **WHEN** a macOS or iOS client prints a job that does not specify that PPD option
|
||||||
|
- **THEN** the job is printed with the configured queue default
|
||||||
|
|
||||||
|
#### Scenario: An unusable option must not stop startup
|
||||||
|
- **WHEN** `PRINTER_OPTIONS` contains an option name or value the PPD does not provide
|
||||||
|
- **THEN** the entrypoint logs a warning, applies the remaining assignments and continues starting
|
||||||
|
|
||||||
|
#### Scenario: Nothing configured
|
||||||
|
- **WHEN** `PRINTER_OPTIONS` is unset or empty
|
||||||
|
- **THEN** the queue keeps the PPD defaults and the container starts as before
|
||||||
|
|
||||||
|
### Requirement: Colour output is saturated by default
|
||||||
|
Unless overridden through `PRINTER_OPTIONS`, the queue SHALL default to the
|
||||||
|
colour mode `None`, which leaves the printer's CIE colour conversion
|
||||||
|
(`UseCIEColor`) switched off so that printed colours are not washed out.
|
||||||
|
|
||||||
|
#### Scenario: Default colour mode
|
||||||
|
- **WHEN** a colour job is printed without any colour-mode options
|
||||||
|
- **THEN** the emitted PostScript contains `<</UseCIEColor false>>` rather than `UseCIEColor true`
|
||||||
|
|
||||||
|
#### Scenario: Default is overridable
|
||||||
|
- **WHEN** the container is started with `PRINTER_OPTIONS` containing `BRColorMode=Vivid`
|
||||||
|
- **THEN** the queue default is `Vivid` instead of `None`
|
||||||
|
|
||||||
|
#### Scenario: A job's own selection wins
|
||||||
|
- **WHEN** a job explicitly selects another `BRColorMode` value
|
||||||
|
- **THEN** that value is used for the job instead of the queue default
|
||||||
|
|
||||||
### Requirement: Jobs are printed via direct PostScript
|
### Requirement: Jobs are printed via direct PostScript
|
||||||
The container SHALL forward the converted job as PostScript to the printer
|
The container SHALL forward the converted job as PostScript to the printer
|
||||||
without a server-side vendor filter or host-side rasterisation.
|
without a server-side vendor filter or host-side rasterisation.
|
||||||
|
|||||||
Reference in new issue
Block a user