[Bug/High] Stage 2 quality picker offers qualities invalid for selected media type #214

Closed
opened 2026-09-17 22:07:22 +01:00 by gronod · 0 comments
Owner

Summary

The Stage 2 quality selector lists every quality token advertised by lpoptions -l, regardless of the selected media type. Both the Epson (InkjetPrinter2, e.g. XP-55) and Canon (Pro9500 II) drivers restrict which quality values are valid per media — selecting an invalid combination makes the driver reject the job.

Example (Epson XP-55): media 0 (plain) allows {301 Fast Economy, 302 Economy, 303 Normal, 304 Fine}; media 15 (Premium Semigloss) allows {305 Quality, 307 Best Quality, 308 Draft} — the picker currently shows all 7 for every media.

Root Cause Analysis

  • Stage2View.qualityGroup renders workflow.print.printerCaps.qualities unfiltered (Sources/ICCery/Stage2View.swift ~L416-420).
  • CupsService.capabilities(from:listings,ppd:) populates qualities from the global lpoptions -l listing of the detected quality key (EPIJ_Qual / CNIJPrintQuality) — no media relationship (Packages/ICCeryCore/Sources/ICCeryCore/Print/CupsService.swift ~L157-170).
  • PrinterCapabilities has no media→quality field (PrinterModels.swift).
  • Checked-and-dismissed: standard PPD *UIConstraints/*Constraints (absent in both PPDs); APPrinterPreset blocks (recommended defaults only, not validity); IPP print-quality-supported/media-col-database (global lists only, no per-media matrix).

Driver truth found:

  • Epson: *EPIJUIConstraint: <cond>|<forbidden choice> in <EPIJDriverBasePath>/Machine/<EPIJMachineBundleName>/Contents/Resources/PDEData.dat — forbids *EPIJ_Qual <q> when LHS terms hold (*EPIJ_Medi <m> plus EPIJ_PSrc/EPIJ_FdSo/EPIJ_Ink_). Evaluating non-media terms against lpoptions *-defaults reproduces the driver sets exactly.
  • Canon: *CNIJNameTblPath + *CNIJTableID PPD keys → cnb_<TableID>0.tbl binary — 20-byte LE records {0x30, 1, u32 0, u16 3, u16 flag, u32 mediaID(|0x10000=borderless), u16 0, u16 quality} enumerating allowed CNIJPrintQuality values per CNIJMediaType.

Proposed Fix

  • PrinterCapabilities gains qualityIDsByMediaType: [String: Set<String>] + qualities(forMediaType:) (order-preserving, never-empty fallback).
  • New MediaQualityConstraints resolver (ICCeryCore, pure): PPD *UIConstraints → Epson PDEData.dat → Canon tbl; first non-empty source wins; fail-open to unfiltered.
  • PrintSessionViewModel: availableQualities computed; selectedMediaType.didSet clamps selectedQuality (default-if-allowed else first); seeding + panel apply-back + makeRequest honour the map.
  • Stage2View.qualityGroup iterates availableQualities.

Acceptance Criteria

  • Epson XP-55: plain paper shows exactly {Fast Economy, Economy, Normal, Fine}; Premium Semigloss shows {Draft, Quality, Best Quality}.
  • Canon Pro9500 II: photo media hide Fast/Normal(Fast); plain paper hides Fine.
  • Switching media with an invalid quality selected re-selects a valid one automatically.
  • Drivers with no constraint data show the full quality list (no regression).
  • xcodebuild test -scheme ICCery -destination 'platform=macOS' green.

References

  • #201 M12 native spool (Stage 2 overrides always win — unchanged).
  • docs/issue-printer-quality-ignored.md
## Summary The Stage 2 quality selector lists every quality token advertised by `lpoptions -l`, regardless of the selected media type. Both the Epson (InkjetPrinter2, e.g. XP-55) and Canon (Pro9500 II) drivers restrict which quality values are valid per media — selecting an invalid combination makes the driver reject the job. Example (Epson XP-55): media 0 (plain) allows {301 Fast Economy, 302 Economy, 303 Normal, 304 Fine}; media 15 (Premium Semigloss) allows {305 Quality, 307 Best Quality, 308 Draft} — the picker currently shows all 7 for every media. ## Root Cause Analysis - `Stage2View.qualityGroup` renders `workflow.print.printerCaps.qualities` unfiltered (`Sources/ICCery/Stage2View.swift` ~L416-420). - `CupsService.capabilities(from:listings,ppd:)` populates `qualities` from the global `lpoptions -l` listing of the detected quality key (`EPIJ_Qual` / `CNIJPrintQuality`) — no media relationship (`Packages/ICCeryCore/Sources/ICCeryCore/Print/CupsService.swift` ~L157-170). - `PrinterCapabilities` has no media→quality field (`PrinterModels.swift`). - Checked-and-dismissed: standard PPD `*UIConstraints`/`*Constraints` (absent in both PPDs); `APPrinterPreset` blocks (recommended defaults only, not validity); IPP `print-quality-supported`/`media-col-database` (global lists only, no per-media matrix). Driver truth found: - Epson: `*EPIJUIConstraint: <cond>|<forbidden choice>` in `<EPIJDriverBasePath>/Machine/<EPIJMachineBundleName>/Contents/Resources/PDEData.dat` — forbids `*EPIJ_Qual <q>` when LHS terms hold (`*EPIJ_Medi <m>` plus `EPIJ_PSrc`/`EPIJ_FdSo`/`EPIJ_Ink_`). Evaluating non-media terms against lpoptions `*`-defaults reproduces the driver sets exactly. - Canon: `*CNIJNameTblPath` + `*CNIJTableID` PPD keys → `cnb_<TableID>0.tbl` binary — 20-byte LE records `{0x30, 1, u32 0, u16 3, u16 flag, u32 mediaID(|0x10000=borderless), u16 0, u16 quality}` enumerating allowed `CNIJPrintQuality` values per `CNIJMediaType`. ## Proposed Fix - `PrinterCapabilities` gains `qualityIDsByMediaType: [String: Set<String>]` + `qualities(forMediaType:)` (order-preserving, never-empty fallback). - New `MediaQualityConstraints` resolver (ICCeryCore, pure): PPD `*UIConstraints` → Epson `PDEData.dat` → Canon tbl; first non-empty source wins; fail-open to unfiltered. - `PrintSessionViewModel`: `availableQualities` computed; `selectedMediaType.didSet` clamps `selectedQuality` (default-if-allowed else first); seeding + panel apply-back + `makeRequest` honour the map. - `Stage2View.qualityGroup` iterates `availableQualities`. ## Acceptance Criteria - [x] Epson XP-55: plain paper shows exactly {Fast Economy, Economy, Normal, Fine}; Premium Semigloss shows {Draft, Quality, Best Quality}. - [x] Canon Pro9500 II: photo media hide Fast/Normal(Fast); plain paper hides Fine. - [x] Switching media with an invalid quality selected re-selects a valid one automatically. - [x] Drivers with no constraint data show the full quality list (no regression). - [x] `xcodebuild test -scheme ICCery -destination 'platform=macOS'` green. ## References - #201 M12 native spool (Stage 2 overrides always win — unchanged). - docs/issue-printer-quality-ignored.md
gronod added the Kind/Bug
Priority
High
2
Project/ICCery-v2Bug/Backend
labels 2026-09-17 22:07:22 +01:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: gronod/iccery-v2-mac#214