Skip to content

Fix #498, part of #505: EPS image sources read in turn, restore undoes dictionary changes (PLRM) - #540

Merged
bflatastic merged 2 commits into
mainfrom
fix/eps-sources-restore
Oct 8, 2026
Merged

bflatastic merged 2 commits into
mainfrom
fix/eps-sources-restore

Conversation

@bflatastic

Copy link
Copy Markdown
Member

Redoes PR #507's two EPS import fixes using the PostScript Language Reference (3rd ed.) only. It's stacked on #535; review after it, or only the last two commits. Fixes #498. Part of #505.

Fix #498: an image's several data sources are read in turn

  • The reference has the image and colorimage operators read multiple data sources in turn, the same amount from each (§4.10 "Images", chapter 8).
  • The reader drained each source on its own. When the sources are procedures that read one file a row at a time, the first plane took every component's rows, and the image came out in sheared horizontal bands. That matches [Bug] Rendering glitch / horizontal artifacts when opening EPS vector map files #498.
  • Fix: one reader, read_sources, handles single sources, procedure filters and masked images too.
  • Tests in tests_images.rs:
    • procedures that read one file, in the dictionary form and the colorimage operand form;
    • separate string sources;
    • rows padded to a whole byte at 1, 2, 4, 12 and 16 bits with an odd width;
    • Flate PNG predictors.
  • Mutation check: with the old sequential reading, the procedures test fails.

Part of #505: restore puts dictionaries back as they were at the save (§3.7.3)

  • While a save is open, def, store, put, undef and dictionary copy keep the old value of each entry they change in a journal, counted against the memory budget.
  • restore undoes those changes, newest first. Restoring a save that is no longer valid raises invalidrestore.
  • cachestatus now reports a device's cache sizes instead of zeros.
  • Test: a program that counts its open saves in a dictionary under a depth limit reads to its end only when restore puts the count back. It fails without the journal, and also fails with a zero cachestatus.
  • Error Text Effect Vector (File Format EPS) #505's reporter sent no file, so this covers what the reference defines, not their specific EPS.

Dropped: #507's rule that stripped a *N suffix from font names. No public spec or user file backs it.

Comments cite PLRM sections. The import fuzz vocabulary covers several sources reading one file, sources of uneven lengths, and save/restore around dictionary changes. ROADMAP updated.

Checks

🤖 Generated with Claude Code

An image can take one data source per colour component
(MultipleDataSources, or `colorimage` with multi true). The PostScript
Language Reference (3rd ed., §4.10 "Images" and `image`/`colorimage` in
chapter 8) has the operator read the sources in turn, the same amount
from each. The reader drained each source on its own instead: when the
sources are procedures reading one file a row at a time, the first plane
took the rows of every component and the image came out in sheared
horizontal bands, as in #498.

- Data sources are read in turn by one reader, `read_sources`: a procedure
  once a round, a file or string a row a round, until each plane is full or
  its source ends. Single sources, procedure filters and masked images use
  it too; a string source resumes where it left off.
- Tests (`tests_images.rs`, programs written from the reference):
  procedures reading one file in the dictionary and `colorimage` operand
  forms (fails without the fix), separate string sources, rows padded to a
  byte at 1, 2, 4, 12 and 16 bits with an odd width (one and several
  sources), Flate PNG predictors with every row filter at an odd width.
  The import fuzz vocabulary has several sources reading one file and
  sources of uneven lengths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PostScript Language Reference (3rd ed., §3.7.3 "Save and Restore")
has `restore` reset composite objects in local VM to their values at the
`save`. The reader only restored the graphics state, so dictionary
entries changed between `save` and `restore` stayed changed: a program
that counts its open saves in a dictionary and refuses to go past a depth
stopped after that many saves in sequence, and the file fell back to its
preview. EPS files with many images, each drawn between `save` and
`restore`, are a likely case of #505; its reporter hasn't sent a file, so
this is part of it.

- While a `save` is open, `def`, `store`, `put`, `undef` and dictionary
  `copy` keep each entry's old value in a journal (counted against the
  memory budget); `restore` undoes it, newest change first, down to its
  save. A save restored already, itself or through an outer one, is no
  longer valid (`invalidrestore`, §3.7.3).
- `cachestatus` reports a device's cache sizes (chapter 8) instead of
  zeros: its last value, the most bytes one cached glyph may take, is what
  programs divide by.
- Tests (programs written from the reference): 100 saves counted in a
  dictionary under a depth limit, each dictionary change undone, saves
  restored twice, `cachestatus`'s glyph limit. Mutation-checked: without
  the journal or with a zero `cachestatus` the test fails. The import fuzz
  vocabulary has saves and restores around dictionary changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bflatastic
bflatastic changed the base branch from pr/eps-spec-only-tests to main October 8, 2026 16:44
@bflatastic
bflatastic force-pushed the fix/eps-sources-restore branch from aaf497c to b43b15a Compare October 8, 2026 16:44
@bflatastic
bflatastic merged commit 8c4c665 into main Oct 8, 2026
@bflatastic

Copy link
Copy Markdown
Member Author

Full cargo xtask ci passed on the integrated stack; merging.

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.

[Bug] Rendering glitch / horizontal artifacts when opening EPS vector map files

1 participant