Skip to content

Fix UnrollPlanarWordsPremul() skipping only 1 plane instead of Extra planes#585

Merged
mm2 merged 1 commit into
mm2:masterfrom
94xhn:fix-unroll-planar-words-premul-extra
Jul 19, 2026
Merged

Fix UnrollPlanarWordsPremul() skipping only 1 plane instead of Extra planes#585
mm2 merged 1 commit into
mm2:masterfrom
94xhn:fix-unroll-planar-words-premul-extra

Conversation

@94xhn

@94xhn 94xhn commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

UnrollPlanarWordsPremul() in src/cmspack.c computes ExtraFirst but never reads T_EXTRA(info->InputFormat). When ExtraFirst is set it advances accum by a single Stride, regardless of how many extra (non-color) planes are actually declared. For formats with Extra > 1 this shifts every subsequent color-channel read one plane early and leaves the last color channel unread, corrupting the unrolled pixel.

The chunky sibling UnrollAnyWordsPremul() had the identical bug and was already fixed by adding an Extra local and multiplying it into the pre-skip offset (accum += Extra * sizeof(cmsUInt16Number)). This PR applies the equivalent fix to the planar function:

cmsUInt32Number Extra = T_EXTRA(info -> InputFormat);
...
if (ExtraFirst) {
    accum += Extra * Stride;
}

Reproduced with a formatter-dispatch harness for COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|PLANAR_SH(1)|EXTRA_SH(2)|PREMUL_SH(1)|DOSWAP_SH(1) (2 extra planes ahead of 4 color planes): before the fix wIn came out as {0x5555,0x4444,0x3333,0x2222} instead of the correct {0x6666,0x5555,0x4444,0x3333}, with the K channel never read at all. After the fix, a 5-case regression suite covering Extra=1/2/3 with both ExtraFirst settings (including the pre-existing, most common Extra=1 case, and the already-correct !ExtraFirst path) all pass with no behavior change to previously-correct cases.

…planes

UnrollPlanarWordsPremul() in src/cmspack.c advances accum by a single
Stride when ExtraFirst is set, regardless of how many extra (non-color)
planes are declared via T_EXTRA(). For formats with Extra > 1 (e.g. two
extra planes ahead of the color planes), this shifts every subsequent
color-channel read one plane early and leaves the last color channel
unread, corrupting the unrolled pixel.

The chunky sibling UnrollAnyWordsPremul() had the identical bug, fixed
in a prior merge by adding an Extra local (T_EXTRA(info->InputFormat))
and multiplying it into the pre-skip offset. This applies the same fix
to the planar function: add the missing Extra local and change the
ExtraFirst pre-skip from `accum += Stride` to `accum += Extra * Stride`.

Verified with a formatter-dispatch harness exercising
COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|PLANAR_SH(1)|
EXTRA_SH(2)|PREMUL_SH(1)|DOSWAP_SH(1): before the fix, wIn came out as
{0x5555,0x4444,0x3333,0x2222} instead of the correct
{0x6666,0x5555,0x4444,0x3333}, with the K channel never read. After
the fix all 5 regression cases (Extra=1/2/3, both ExtraFirst settings)
pass with no change to previously-correct behavior.
@mm2
mm2 merged commit cf69bf9 into mm2:master Jul 19, 2026
17 checks passed
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