Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support arbitrary masks for uncompressed RGB DDS images #7589

Merged
merged 5 commits into from
Dec 31, 2023

Conversation

radarhere
Copy link
Member

Resolves #7517

When DDS images contain uncompressed RGB data, they have red, green, blue (and possibly alpha) masks to filter the bits of each pixel into the final value for the channel.

Currently, Pillow only supports masks giving 8 bits per channel.

# Texture contains uncompressed RGB data
masks = {mask: ["R", "G", "B", "A"][i] for i, mask in enumerate(masks)}
rawmode = ""
if pfflags & DDPF_ALPHAPIXELS:
rawmode += masks[0xFF000000]
else:
self._mode = "RGB"
rawmode += masks[0xFF0000] + masks[0xFF00] + masks[0xFF]

The linked issue has found an image with masks that use 5 bits per channel. So this PR adds support for arbitrary masks by adding a dedicated Python decoder.

src/PIL/DdsImagePlugin.py Outdated Show resolved Hide resolved
Co-authored-by: Aarni Koskela <[email protected]>

data = bytearray()
bytecount = bitcount // 8
while len(data) < self.state.xsize * self.state.ysize * len(masks):
Copy link
Contributor

Choose a reason for hiding this comment

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

Might be worth it to precalculate the total here to avoid that extra multiplication every loop (since we know the value can't possibly change):

Suggested change
while len(data) < self.state.xsize * self.state.ysize * len(masks):
total_size = self.state.xsize * self.state.ysize * len(masks)
while len(data) < total_size:

Copy link
Member Author

Choose a reason for hiding this comment

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

I personally think the current version is simpler to read, and expect the performance difference to be negligible.

The current version is also used in a few other places in Pillow - but at the same time, that's probably because I wrote them.

while len(data) < self.state.xsize * self.state.ysize * bands:

Comment on lines 261 to 262
value = self.fd.read(bytecount)
int_value = sum(value[i] << i * 8 for i in range(bytecount))
Copy link
Contributor

Choose a reason for hiding this comment

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

int.from_bytes?

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, I've pushed a commit.

@hugovk hugovk merged commit 119885a into python-pillow:main Dec 31, 2023
56 checks passed
@radarhere radarhere deleted the dds_rgb branch January 1, 2024 02:10
radarhere added a commit to radarhere/Pillow that referenced this pull request Jan 1, 2024
hugovk added a commit that referenced this pull request Jan 1, 2024
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.

PIL.UnidentifiedImageError: cannot identify image file (DDS file)
3 participants