Skip to content

PDF stage 4.4: PDF function evaluator + colour spaces#562

Open
andiwand wants to merge 1 commit into
pdf-stage-4.3-clippingfrom
pdf-stage-4.4-functions-color
Open

PDF stage 4.4: PDF function evaluator + colour spaces#562
andiwand wants to merge 1 commit into
pdf-stage-4.3-clippingfrom
pdf-stage-4.4-functions-color

Conversation

@andiwand

Copy link
Copy Markdown
Member

Stage 4.4: the PDF function evaluator and colour-space resolution — a shared prerequisite for faithful colour (and, later, shadings). Stacked on #561 (4.3).

4.4a — function evaluator (pdf_function, ISO 32000-1 7.10)

  • type 2 exponential interpolation, type 3 stitching, type 0 sampled (multilinear interpolation over an m-dimensional grid, big-endian sample reader), type 4 PostScript calculator (a stack machine: arithmetic, comparison, boolean, stack ops and if/ifelse).
  • Inputs clip to /Domain, outputs to /Range. Pure and unit-testable via a small resolve/load-stream context.

4.4b — colour spaces (pdf_color, 8.6)

  • Resolve /ColorSpace resources and the cs/CS/sc/scn/SC/SCN operators (previously only the device operators were modelled). Convert to sRGB at emit time: ICCBased (by /Alternate or component count), Cal*/Lab (Lab → XYZ → sRGB), Indexed (palette lookup), Separation/DeviceN (tint transform via 4.4a). Overprint ignored.
  • The resource-aware colour operators are handled in pdf_page_extractor (which has the Resources); the device operators stay in GraphicsState::execute and now clear any active non-device space. The active space rides on GraphicsState::Color, so q/Q scope it.

Tests

Each function type against worked vectors (incl. domain clipping, ifelse); each colour space → expected RGB (Lab extremes, an Indexed palette, a Separation tint); end-to-end cs/scn resolution through the extractor. Full suite green.

🤖 Generated with Claude Code

Shared prerequisite for proper colour (and, later, shadings): evaluate
PDF functions and resolve non-device colour spaces to RGB at emit time.

4.4a — function evaluator (`pdf_function`, ISO 32000-1 7.10):
- type 2 (exponential interpolation), type 3 (stitching), type 0
  (sampled, multilinear interpolation over an m-dimensional grid), and
  type 4 (a PostScript calculator stack machine: arithmetic, comparison,
  boolean, stack and `if`/`ifelse` control). Inputs clip to `/Domain`,
  outputs to `/Range`. Pure and unit-tested in isolation via a small
  resolve/load-stream context.

4.4b — colour spaces (`pdf_color`, 8.6):
- resolve `/ColorSpace` resources and the `cs`/`CS`/`sc`/`scn`/`SC`/`SCN`
  operators (previously only the device operators were modelled). Convert
  to sRGB at emit time: ICCBased (by `/Alternate` or component count),
  Cal*/Lab (Lab → XYZ → sRGB), Indexed (palette lookup),
  Separation/DeviceN (tint transform via 4.4a). Overprint ignored.
- The colour operators that need the resources are handled in
  `pdf_page_extractor` (which has them); the device operators stay in
  `GraphicsState::execute` and now clear any active non-device space. The
  active space rides on `GraphicsState::Color`, so `q`/`Q` scope it.

Tests: each function type against worked vectors (incl. domain clipping,
ifelse); each colour space → expected RGB (incl. Lab extremes, an Indexed
palette, a Separation tint); and end-to-end `cs`/`scn` resolution through
the extractor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7Lp7cZPX84gvGmaGA6bHq

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 19ef43757f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +162 to +164
default:
return std::vector<double>(
static_cast<std::size_t>(std::max(components, 1)), 0.0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve black when aliasing DeviceCMYK resources

When a /ColorSpace resource aliases /DeviceCMYK (for example /CS1 /DeviceCMYK) and content selects it with /CS1 cs, this path initializes the color via ColorSpaceDef::initial_components(), which returns four zero components. to_rgb({0,0,0,0}) is white, while the direct /DeviceCMYK cs branch in set_color_space explicitly initializes {0,0,0,1} as black, so the same color space renders differently whenever a path is painted after selecting the resource alias before an scn value is supplied.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant