Fix RLE4 absolute mode decoding for odd pixel counts#9710
Open
nyxst4ck wants to merge 2 commits into
Open
Conversation
In an RLE4 absolute run, the count byte gives a number of 4-bit pixels packed two per byte and padded up to a whole byte. The decoder divided the count by two with floor division, so an odd count read one byte too few: the final pixel was dropped and the file pointer was left misaligned, desyncing the rest of the stream and typically raising "not enough image data". Read ceil(count / 2) bytes instead, and emit exactly `count` pixels so the trailing padding nibble of an odd run is discarded.
Member
|
For the record, a specification reference for this is https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/73b57f24-6d78-4eeb-9c06-8f892d88f1ab |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes proposed in this pull request
Tests/test_file_bmp.py::test_rle4_absolute_odd).Bug
In a BMP
BI_RLE4absolute run, the count byte specifies a number of 4-bit pixels. Those pixels are packed two per byte and the run is padded up to a whole byte (and then to a 16-bit word boundary). When the count is odd, the run still occupiesceil(count / 2)bytes — the last nibble is padding.The decoder computed the number of bytes to read with floor division:
For an odd count (e.g. 3 pixels) this reads one byte too few (
3 // 2 == 1). As a result:In practice the desync causes the decode to terminate early and raise
ValueError: not enough image data.Root cause and fix
src/PIL/BmpImagePlugin.py, absolute-mode branch ofBmpRleDecoder.decode:(byte[0] + 1) // 2reads the correct (ceil) number of bytes, and the2 * i + 1 < byte[0]guard emits exactlybyte[0]pixels so the padding nibble of an odd run is discarded rather than turned into an extra pixel.Reproduction (red → green)
The new test builds a minimal 3×1 RLE4 BMP whose single row is one absolute run of 3 pixels (palette indices 1, 2, 3).
mainit fails:ValueError: not enough image data.[1, 2, 3].The existing
test_rle4(which usesTests/images/bmp/g/pal4rle.bmp) and the rest ofTests/test_file_bmp.pycontinue to pass (33 passed). Even-count absolute runs are unaffected.ruffandblackare clean on the changed files.