PSD: layers with a "real user supplied layer mask" (channel -3) stored as Raw fail to load ("unsupported compression")
I maintainer di solito rispondono entro 2 giorni
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 72/100
Direzione di ricerca
Start with src/psd.imageio/psdinput.cpp, especially PSDInput::load_layer_channel() and its handling of channel ID -3 and declared channel lengths. Use the attached repro_raw.psd and repro_rle.psd files with oiiotool --info to compare behavior. Done means the Raw file opens without misreading the next channel, while existing mask handling continues to work.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Environment
- OpenImageIO 3.1.7.0 (as bundled with Blender 5.0 / 5.1 / 5.2.2), macOS
- Also reproduced with the PyPI wheels 3.1.7.0, 3.1.19.0 and 3.2.2.0 (Linux)
Description
A PSD fails to open when all of the following are true:
- A layer has both a layer mask (channel ID -2) and a "real user supplied
layer mask" (channel ID -3). - The -3 channel is stored uncompressed (compression = 0).
- The -3 mask rectangle differs in size from the layer's bounds.
- At least one more layer follows it.
The file is valid per the PSD spec (all channel lengths in the layer records
are correct). Photoshop itself writes this structure, e.g. for a shape layer
(vector mask) that also has a pixel layer mask.
Steps to reproduce
oiiotool repro_raw.psd --info
Expected
The file opens, like repro_rle.psd.
Actual
[Layer Channel] unsupported compression 65535
failed to open "repro_raw.psd": failed load_layers
With real Photoshop files, the reported compression value varies from file to
file (e.g. 41616).
Attachments
repro_psd.zip contains two minimal files generated with Python
(64×64, RGB, 8-bit, 2 layers, no metadata):
repro_raw.psd: the -3 channel is Raw → failsrepro_rle.psd: identical, except the -3 channel is RLE → loads
Layout of "Layer 1" in repro_raw.psd:
| rectangle (t, l, b, r) | size | declared channel length | |
|---|---|---|---|
| layer bounds | 8, 8, 40, 40 | 32×32 | 1026 per color/alpha channel |
| -2 (layer mask) | 12, 12, 28, 36 | 24×16 | 386 = 2 + 384 |
| -3 (real user mask) | 16, 20, 48, 30 | 10×32 | 322 = 2 + 320 |
Analysis
In PSDInput::load_layer_channel() (v3.1.7.0 L1624-1653; same logic in
main around L1780 / L1814), only ChannelID_LayerMask (-2) uses its own
rectangle (mask_data). Channel -3 falls back to the layer bounds. The real
user mask rectangle exists in the layer mask data, but it is skipped
(// skip "real" fields).
For Compression_Raw, the declared channel length is then overwritten with
row_length * height, and the stream skips that many bytes:
For the attached file, the reader skips 32 × 32 = 1024 bytes instead of 320,
which overshoots by 704 bytes. It then reads two bytes of unrelated pixel data
(0xFFFF) as the compression of the next channel.
RLE works in 3.1.x because the skip there is based on the declared
data_length. With 3.2.2.0, the RLE case also fails when the -3 height
differs from the layer height
(RLE row lengths (...) exceed available data). In that case, the row-count
table is read with the wrong number of rows, and the new check from #5591
rejects it. This does not happen with the attached RLE file, because its -3
height equals the layer height.
I also confirmed that a variant whose -3 rectangle equals the layer bounds
loads fine with Raw. This is the same class of bug that #1714 fixed for
channel -2.
Possible fix (untested)
Masks are never exposed as image channels, so -3 could be skipped using the
declared length:
+ // The real user mask (-3) has its own rectangle (the "real" fields of the
+ // layer mask data), which is not parsed. Its pixels are never exposed,
+ // so skip it using the length declared in the layer record.
+ if (channel_info.channel_id == ChannelID_UserMask)
+ return ioseek(start_pos + channel_info.data_length);
Alternatives:
- Parse the real user mask rectangle and use it for -3.
- In general, never let the Raw path override the declared
data_length.
- Lingua principale
- C++
- Stelle
- 2.4k
- Fork
- 718
- Merge medio
- 2g 18h
- PR unite (30g)
- 85
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di AcademySoftwareFoundation/OpenImageIO
-
bug: get_image_info returns true after copying an uninitialised buffer into the caller's output when every UDIM tile is unreadableForse già presa @lgritz l’ha presa 1 giorno fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
AcademySoftwareFoundation/OpenImageIO#5662 · 1 commento · 1 assegnatario ·
I maintainer di solito rispondono entro 2 giorni
-
bug: copy() writes destination channels the source does not have, taking the values from past the source's pixelForse già presa @lgritz l’ha presa 1 giorno fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 35/100
AcademySoftwareFoundation/OpenImageIO#5661 · 1 commento · 1 assegnatario ·
I maintainer di solito rispondono entro 2 giorni
-
bug: a malformed filename throws std::regex_error out of ImageCache, and catching it deadlocks the file cacheForse già presa @lgritz l’ha presa 1 giorno fa. Aperta
AcademySoftwareFoundation/OpenImageIO#5660 · 1 assegnatario ·
I maintainer di solito rispondono entro 2 giorni
-
bug: deep paste wraps into the next scanline instead of clipping, and ignores chbeginForse già presa @lgritz l’ha presa 1 giorno fa. Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 45/100
AcademySoftwareFoundation/OpenImageIO#5649 · 1 commento · 1 assegnatario ·
I maintainer di solito rispondono entro 2 giorni
-
bug: make_kernel("binomial", ...) indexes its tap arrays past their allocation for even or fractional extentsForse già presa @lgritz l’ha presa 3 giorni fa. Aperta
Difficoltà 3/5 Mezza giornata Idoneità per principianti 62/100
AcademySoftwareFoundation/OpenImageIO#5648 ·
I maintainer di solito rispondono entro 2 giorni
Tutte le issue di AcademySoftwareFoundation/OpenImageIO
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
xiaoyifang/goldendict-ng#3148 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 91/100
triton-inference-server/server#9069 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
I maintainer di solito rispondono entro 4 giorni
-
documentation
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100