Skip to content

fix(save): apply the annotation opacity inside the vector appearance stream - #538

Closed
philip-tam wants to merge 1 commit into
OpenAEC-Foundation:mainfrom
philip-tam:fix/vector-ap-annotation-opacity
Closed

philip-tam wants to merge 1 commit into
OpenAEC-Foundation:mainfrom
philip-tam:fix/vector-ap-annotation-opacity

Conversation

@philip-tam

@philip-tam philip-tam commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • A polygon / filled area with 40% opacity was saved with /CA 0.4 but an appearance stream (/AP /N) that drew the fill and border at full strength, with no transparency state in its resources. Viewers that show the stored appearance instead of regenerating it from /CA (e.g. a PDF editor like Acrobat) display it at 100% until the opacity is edited there, which makes the viewer rebuild the appearance (and then it shows 40%).
  • attachVectorAP now reads the annotation's /CA, adds a /GSo ExtGState (ca and CA) to the appearance resources and applies it first (/GSo gs). A separate fill alpha (/GSf, fill-only) is multiplied by it. This is the same structure the viewer itself writes after the opacity is edited.
  • Applies to every annotation type that goes through attachVectorAP, and only when /CA is below 1; nothing changes for opaque annotations.
  • Files saved earlier keep the opaque appearance until they are saved again.

Test plan

  • New tests: ap-opacity (plan: no opacity, 40%, fill alpha combined) and ap-opacity-opslaan (saves a filled area with /CA 0.4 with pdf-lib, reloads the bytes and checks /GSo gs first in the content and ca/CA 0.4 in the resources; opaque and /CA 1 unchanged; fill alpha multiplied)
  • The stored expectation for the dimension snapshot with /CA 0.8 gains the same /GSo state (only that case changes)
  • Full unit suite passes
  • Manually: a polygon at 40% saved by this build shows 40% immediately in Acrobat, without touching the opacity bar

…stream

A polygon/filled area with 40% opacity was saved with /CA 0.4 but an
appearance stream that drew the fill and border at full strength with no
transparency state. Viewers that show the stored appearance then display it
at 100% until the opacity is edited and the appearance regenerated.

attachVectorAP now reads the annotation /CA, adds an /GSo ExtGState (ca and
CA) to the appearance resources and applies it first; a separate fill alpha
(/GSf) is multiplied by it. The stored expectation of the dimension
snapshot test with /CA 0.8 gains the same state.
@DutchSailor

Copy link
Copy Markdown
Collaborator

Thank you for this, @philip-tam. The opacity problem it describes is already fixed on main by #512: zetDoorzichtigheidInAp applies the annotation opacity to every appearance stream after it is built (saver.js), including the vector appearance streams. With this PR on top, arrows and text box leaders would be dimmed twice (0.4 becomes 0.16), and the fill alpha would be multiplied by /CA, which breaks the save-and-reopen round trip. So we are closing it rather than merging. Your other PRs (#540, #542, #543 and #523) are included in release 2026.42.0 (#576).

@philip-tam

Copy link
Copy Markdown
Collaborator Author

Thank you for this, @philip-tam. The opacity problem it describes is already fixed on main by #512: zetDoorzichtigheidInAp applies the annotation opacity to every appearance stream after it is built (saver.js), including the vector appearance streams. With this PR on top, arrows and text box leaders would be dimmed twice (0.4 becomes 0.16), and the fill alpha would be multiplied by /CA, which breaks the save-and-reopen round trip. So we are closing it rather than merging. Your other PRs (#540, #542, #543 and #523) are included in release 2026.42.0 (#576).

Thanks for the explanation and for checking the interaction with the existing fix in #512. I understand why this PR should be closed to avoid applying the annotation opacity twice.

I also appreciate the confirmation that my other PRs are included in release 2026.42.0. Thanks for reviewing and integrating those contributions!

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.

2 participants