Skip to content

fix(psd): fix indexed transparency#5177

Merged
lgritz merged 5 commits into
AcademySoftwareFoundation:mainfrom
ssh4net:fix/psd-indexed-transparency
May 28, 2026
Merged

fix(psd): fix indexed transparency#5177
lgritz merged 5 commits into
AcademySoftwareFoundation:mainfrom
ssh4net:fix/psd-indexed-transparency

Conversation

@ssh4net
Copy link
Copy Markdown
Contributor

@ssh4net ssh4net commented Apr 30, 2026

Description

Fixes indexed-color PSD transparency handling when the transparent palette index
is 0.

Before this change, the PSD reader used m_transparency_index both as the
palette index value and as the signal that a transparency-index resource was
present. That made index 0 ambiguous: it is a valid transparent palette index,
but it evaluated as false when deciding whether to add an alpha channel.

As a result, an indexed PSD with transparency index 0 could expose a
3-channel output spec, then later indexed_to_rgb() would treat
m_transparency_index >= 0 as meaning transparency exists and write 4 bytes per
pixel. That could write a 4-channel row into a caller buffer sized for
3 channels.

The fix separates those two pieces of state:

  • m_has_transparency_index records whether the transparency resource exists.
  • m_transparency_index stores only the numeric palette index.
  • Index 0 now correctly adds an alpha channel.
  • Transparency indexes outside the valid palette range 0..255 are rejected.
  • indexed_to_rgb() now checks source and destination spans before writing.

Tests

Added regression coverage to testsuite/psd-colormodes.

The test now generates indexed PSD variants from the existing
pattern2-8-indexed.psd fixture with transparency indexes:

  • 0: valid, should report/read as 4-channel PSD.
  • 255: valid, should report/read as 4-channel PSD.
  • 256: invalid, should be rejected.

Validated locally with:

python3 -m py_compile testsuite/psd-colormodes/run.py \
    testsuite/psd-colormodes/src/make-indexed-transparency-psds.py

ninja -C build-psd oiiotool iconvert idiff

Also ran the generated PSD cases and a manual full psd-colormodes test; final
out.txt matched the updated reference

Checklist:

  • I have read the guidelines on contributions and code review procedures.
  • I have read the Policy on AI Coding Assistants
    and if I used AI coding assistants, I have an Assisted-by: Codex GPT5.5xHigh
    line in the pull request description above.
  • I have updated the documentation if my PR adds features or changes
    behavior.
  • I am sure that this PR's changes are tested in the testsuite.
  • I have run and passed the testsuite in CI before submitting the
    PR, by pushing the changes to my fork and seeing that the automated CI
    passed there. (Exceptions: If most tests pass and you can't figure out why
    the remaining ones fail, it's ok to submit the PR and ask for help. Or if
    any failures seem entirely unrelated to your change; sometimes things break
    on the GitHub runners.)
  • My code follows the prevailing code style of this project and I
    fixed any problems reported by the clang-format CI test.
  • If I added or modified a public C++ API call, I have also amended the
    corresponding Python bindings. If altering ImageBufAlgo functions, I also
    exposed the new functionality as oiiotool options.

ssh4net and others added 4 commits July 23, 2025 19:13
avcodec_close (AVCodecContext *avctx) removing in ffmpeg 7.2 and was deprecated for couple years

Signed-off-by: Vlad (Kuzmin) Erium <libalias@gmail.com>
@ssh4net ssh4net force-pushed the fix/psd-indexed-transparency branch from 0eb7507 to 937633d Compare May 1, 2026 05:06
@lgritz
Copy link
Copy Markdown
Collaborator

lgritz commented May 1, 2026

There is some widespread outage of Ubuntu package related machines and it's causing a lot of our CI to fail, unrelated to the contents of any of our PRs or CI runs. It's across the board. We may no be able to trust failing CI results until tomorrow. Don't expend any effort fixing, give it a while to clear up.

@lgritz lgritz added bug Crash or wrong behavior of an existing feature. file formats Image file formats, ImageInput, ImageOutput labels May 22, 2026
@lgritz
Copy link
Copy Markdown
Collaborator

lgritz commented May 27, 2026

@ssh4net This is still failing one test -- psd-colormodes. Only on the "Linux ARM latest releases gcc14" variant, and curiously not on the nearly identical setup using clang.

The failure is a hash. Maybe there is a LSB difference somewhere, only on ARM and only with gcc?

Can you investigate? If there's no obvious culprit, maybe the test should be changed to not output the hash and do a pixel comparison with threshold? Or maybe if you inspect the results visibly and it looks fine, just commit a second reference output to the ref directory that will match for the other hash being reported?

@ssh4net
Copy link
Copy Markdown
Contributor Author

ssh4net commented May 28, 2026

@lgritz Yes, will check.

Signed-off-by: Vlad (Kuzmin) Erium <libalias@gmail.com>
@ssh4net ssh4net force-pushed the fix/psd-indexed-transparency branch from 937633d to 74c8ac1 Compare May 28, 2026 04:05
@ssh4net
Copy link
Copy Markdown
Contributor Author

ssh4net commented May 28, 2026

Root cause: for transparent indexed pixels we synthesize RGBA = 0,0,0,0, then PSD composite alpha cleanup calls removeBackground(). With white background and alpha 0, it computes a negative RGB value and casts that float back to uint8_t. That conversion is implementation-dependent, so x86 and ARM can hash different pixels.

@lgritz lgritz changed the title Fix/psd indexed transparency fix(psd): fix indexed transparency May 28, 2026
Copy link
Copy Markdown
Collaborator

@lgritz lgritz left a comment

Choose a reason for hiding this comment

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

LGTM

@lgritz lgritz merged commit 6b7fe61 into AcademySoftwareFoundation:main May 28, 2026
28 checks passed
lgritz pushed a commit to lgritz/OpenImageIO that referenced this pull request May 29, 2026
Fixes indexed-color PSD transparency handling when the transparent
palette index is `0`.

Before this change, the PSD reader used `m_transparency_index` both as the
palette index value and as the signal that a transparency-index resource was
present. That made index `0` ambiguous: it is a valid transparent palette index,
but it evaluated as false when deciding whether to add an alpha channel.

As a result, an indexed PSD with transparency index `0` could expose a
3-channel output spec, then later `indexed_to_rgb()` would treat
`m_transparency_index >= 0` as meaning transparency exists and write 4
bytes per pixel. That could write a 4-channel row into a caller buffer sized for
3 channels.

The fix separates those two pieces of state:

- `m_has_transparency_index` records whether the transparency resource exists.
- `m_transparency_index` stores only the numeric palette index.
- Index `0` now correctly adds an alpha channel.
- Transparency indexes outside the valid palette range `0..255` are rejected.
- `indexed_to_rgb()` now checks source and destination spans before writing.

### Tests

Added regression coverage to `testsuite/psd-colormodes`.

The test now generates indexed PSD variants from the existing
`pattern2-8-indexed.psd` fixture with transparency indexes:

- `0`: valid, should report/read as 4-channel PSD.
- `255`: valid, should report/read as 4-channel PSD.
- `256`: invalid, should be rejected.

Validated locally with:

```bash
python3 -m py_compile testsuite/psd-colormodes/run.py \
    testsuite/psd-colormodes/src/make-indexed-transparency-psds.py

ninja -C build-psd oiiotool iconvert idiff
```

Also ran the generated PSD cases and a manual full psd-colormodes test;
final out.txt matched the updated reference

Assisted-by: Codex GPT5.5xHigh

---------

Signed-off-by: Vlad (Kuzmin) Erium <libalias@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Crash or wrong behavior of an existing feature. file formats Image file formats, ImageInput, ImageOutput

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants