Files
juergen 30670de93b
ci/woodpecker/push/build Pipeline was successful
fix pale colours and map driverless print options
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.
2026-10-20 08:28:08 +02:00

181 lines
8.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Design
## Context
Motivation und Messergebnisse stehen in `proposal.md`; hier nur die
technischen Randbedingungen, die den Ansatz bestimmen:
- **Jobkette** für einen AirPrint-Job: macOS/iOS → IPP (PDF) → `pdftopdf` →
`pdftops` → `pstops` (PPD-Optionen, JCL/PJL) → `socket://9100:9100` →
Drucker.
- **`pdftops` (cups-filters 1.28)** läuft mit Default-Renderer
`CUPS_PDFTOPS_RENDERER` = `hybrid`; `hybrid` wechselt für
**Brother** ausdrücklich auf **Poppler**, um Bugs im PS-Interpreter des
Druckers zu umgehen (`filter/pdftops.c`, „Switching to Poppler's pdftops
instead of Ghostscript for Brother …"). Poppler kann keine Graustufen
erzeugen – es wird nur `WARNING: Grayscale/monochrome could be printed as
color with Poppler` geloggt. Deshalb ist ein serverseitiger
Grauzwang über `pdftops-renderer=gs` zwar technisch möglich, aber
ausgeschlossen (siehe Decisions).
- **CUPS-Optionsspalte**: `cupsMarkOptions()` (`cups/ppd-mark.c`) bildet
`print-color-mode` und `print-quality` ausschließlich über
*Presets* ab, die `_ppdCacheCreateWithPPD()` (`cups/ppd-cache.c`) aus
`APPrinterPreset`-Attributen der PPD – oder als Fallback aus einem
bekannten Grau-Optionsschlüssel (`ColorModel=Gray`, `BRMonoColor=Mono`,
`HPColorMode=grayscale`, …) – aufbaut. Die BR-Script3-PPD enthält
keines davon (Brother nutzt `BRPrintQuality=Black`), daher wird
`print-color-mode=monochrome` heute stillschweigend verworfen.
PPD-spezifische Optionen wie `BRColorMode`/`BRMediaType`/`TonerSaveMode`
sind darüber hinaus keine IPP-Attribute und erscheinen im
driverless AirPrint-Dialog grundsätzlich nicht.
- Die Queue wird bei jedem Containerstart neu erzeugt (kein Persistenz-Volume
vorausgesetzt), Queue-Defaults müssen deshalb bei jedem Start erneut
gesetzt werden – so wie bereits `printer-is-shared` und `-D`.
## Goals / Non-Goals
**Goals:**
- Gesättigte Farbausgabe als Zustand (Default `BRColorMode=None`).
- S/W und Qualitätsstufe von macOS/iOS wirken geräteitig, ohne von der
PDF-Renderer-Wahl abzuhängen.
- PPD-Optionen, die der Dialog nicht zeigen kann, dauerhaft über die
Umgebung konfigurierierbar machen (`PRINTER_OPTIONS`).
- Nichts am Containerfile, an Discovery/Zertifikat oder am Windows-Weg ändern.
**Non-Goals:**
- Brother-spezifische Optionen (Vivid, Medientyp, Toner Save) im
AirPrint-Dialog sichtbar machen – mangels IPP-Äquivalent nicht darstellbar;
stattdessen serverseitige Defaults + Doku.
- Serverseitige Graustufen-Konvertierung (Poppler-Pfad) oder Wechsel des
Renderers.
- Änderung an der Drucker- oder Panel-Konfiguration selbst.
## Decisions
**1. Abbildung über `APPrinterPreset` in der PPD (statt `ColorModel`-Option,
Renderer-Wechsel oder entrypoint-Logik).**
Sechs Presets – Kombination aus `com.apple.print.preset.output-mode`
(`color`/`monochrome`) und `com.apple.print.preset.quality`
(`low`/`normal`/`high`) – deren PPD-Optionen CUPS bei passendem
Job-Attribut automatisch mitmarkiert:
| Preset (mode/quality) | PPD-Optionen |
| --- | --- |
| color / low | `TonerSaveMode=True` |
| color / normal | `TonerSaveMode=False` |
| color / high | `CAPT=SuperFine TonerSaveMode=False` |
| monochrome / low | `BRPrintQuality=Black TonerSaveMode=True` |
| monochrome / normal | `BRPrintQuality=Black TonerSaveMode=False` |
| monochrome / high | `BRPrintQuality=Black CAPT=SuperFine TonerSaveMode=False` |
*Alternativen verworfen:* (a) `ColorModel`-Option mit Choice `Gray` anlegen –
löst zwar ebenfalls das Mono-Preset, verändert aber zusätzlich die
Werbung/Defaults von `print-color-mode` und die `cupsColorSpace`-Semantik in
`pstops`/Raster-Pfaden; (b) `pdftops-renderer=gs` als Queue-Default –
bringt den Grauzwang zurück, riskiert aber genau die PS-Interpreter-Bugs,
wegen derer `hybrid` bei Brother Poppler wählt; (c) Grauzwang im
`entrypoint` per `lpadmin -o` – unmöglich, da die Konvertierung im Filter
passiert und Poppler sie nicht kann.
CUPS vergibt Preset-Optionen nur, wenn der Client den Namen nicht selbst
geschickt hat – clientseitige Auswahl gewinnt also weiterhin
(`ppd-mark.c`: „as long as the corresponding names are not already defined
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).**
Die Asset-Datei `assets/Brother HL-4150CDN/ppd/BR4150_2.PPD` wird bereits
gecommitted und vom Containerfile unverändert nach `/usr/share/cups/model`
kopiert. Die Änderungen (`*DefaultBRColorMode: None`, Presets, ggf. neue
Choice) werden als PPD-konforme Einträge mit `%`-Kommentar ergänzt, die
Herkunft des Files bleibt dokumentiert. *Alternative verworfen:*
`sed`-Patch im Containerfile – zweite Quellwahrheit, schwerer zu reviewen,
und `COPY` + `RUN`-Logik müsste ohnehin getestet werden.
**3. Farbmodus-Default in der PPD statt als Entry-Point-Sonderfall.**
`*DefaultBRColorMode: None` wirkt für jede aus dieser PPD erzeugte Queue,
auch für manuell angelegte, ohne dass `entrypoint.sh` etwas davon wissen
muss. `PRINTER_OPTIONS` bleibt damit generisch (Default leer) und dient nur
der Konfiguration, nicht dem Fix.
**4. `PRINTER_OPTIONS`-Parsing und Anwendung.**
Leerzeichengetrennte `key=value`-Tokens (Brother-Choice-Werte enthalten
keine Leerzeichen; getrennt wird auch an Zeilenumbrüchen). Jedes Token wird
einzeln als `lpadmin -o` gesetzt, direkt an der Stelle, an der heute
`printer-is-shared`, `-D` und `-d` gesetzt werden, und **bei jedem Start** –
damit gilt es auch für eine persistente Queue. Fehler pro Token abfangen
(`|| log warning`), da `set -eu` sonst den Start abbricht; unbekannte Namen
werden verworfen, ohne die übrigen zu blockieren.
**5. Neue `BRColorMode`-Choice `VividNoCIE` verworfen.**
`<</UseCIEColor false /BRColorMode 1>>` – Kombi, die es bisher nicht gibt
(`None` lässt `/BRColorMode` unangetastet, `Vivid` erzwingt CIE). Als
Testdruck gegen `None` verglichen (2026-10-20): **nicht unterscheidbar**,
daher nicht übernommen. `None` bleibt der einzige geänderte Default.
## Risks / Trade-offs
- [PPD weicht dauerhaft vom Brother-Original ab] → Änderungen mit
`%`-Kommentar markieren, der README-Abschnitt „Änderungen an der PPD"
nennt Grund und Stelle; Upstream-Vergleich bleibt durch die
unveränderte Herkunft im Header möglich.
- [`print-quality=draft` druckt sichtbar weniger Toner („blass")] →
bewusst die Semantik des Reglers; dokumentiert, per Job und über
`PRINTER_OPTIONS` überschreibbar.
- [Mono wird jetzt geräteitig gerendert (`/BRProcessColor 1`), nicht mehr
gar nicht] → Grau-Wiedergabe des Druckers ist die einzige realistische
Route mit Poppler-Renderer; Akzeptanztest im Tasks.
- [`PRINTER_OPTIONS` wird bei falscher Schreibweise ignoriert] → Warning im
Log, `lpoptions -p <queue> -l` als Referenz in der Doku genannt.
- [Persistentes Volume: Defaults könnten aus altem Stand zurückkommen] →
Neu-Setzen bei jedem Start überschreibt sie deterministisch.
- [MacOS-Caches bei Drucker-Änderungen] → keine Client-Änderung nötig;
Server-Attribute bleiben gleich, nur Job-Verarbeitung ändert sich.
## Migration Plan
1. Image neu bauen (`podman build`), Container neu starten (Queue wird
ohnehin neu erzeugt bzw. Defaults überschrieben).
2. Akzeptanztest: S/W-Druck aus dem macOS-Dialog, Farbdruck-Vergleich mit
und ohne `PRINTER_OPTIONS`.
3. Rollback: Image auf den vorherigen Commit bauen; Einträge in der PPD
sind mit demselben Revert rückgängig zu machen, `PRINTER_OPTIONS` bei
Bedarf leer lassen.
## Open Questions
- Ob macOS/iOS den Qualitätsregler als `print-quality` sendet – falls nicht,
bleiben die `print-quality`-Presets inert, `print-color-mode`-Presets
wirken unabhängig davon (Server-seitig per `lp -o print-quality=…`
testbar).