Skip to content

Preserve alpha channel when saving RGBA images as BMP - #10512

Open
anishpentyala wants to merge 3 commits into
python-pillow:mainfrom
anishpentyala:bmp-rgba-alpha
Open

anishpentyala wants to merge 3 commits into
python-pillow:mainfrom
anishpentyala:bmp-rgba-alpha

Conversation

@anishpentyala

@anishpentyala anishpentyala commented Nov 15, 2026 •

Copy link
Copy Markdown

When saving an RGBA image as BMP, Pillow writes a 40-byte BITMAPINFOHEADER with BI_RGB compression. The alpha bytes are present in the pixel data, but the header gives readers no way to know the 4th byte is alpha rather than padding - Pillow's own reader therefore reloads such files in mode RGB (BGRX), and the alpha channel is unrecoverable from a Pillow round trip. (Per the BMP spec, the 4th component in a BI_RGB RGBQUAD is reserved, not
alpha; Pillow's reader deliberately does not assume alpha there - see the comment referencing #1293.)

Pillow's BMP reader already honors an explicit alpha channel when a file declares one via a BITMAPV4/V5HEADER or BI_BITFIELDS masks (see also the read-side USE_RAW_ALPHA work in #8602). This PR makes the writer declare what it writes: standalone BMP saves of RGBA images now use a 108-byte BITMAPV4HEADER with BI_BITFIELDS compression and RGBA channel masks (R=0x00FF0000, G=0x0000FF00, B=0x000000FF, A=0xFF000000), so the alpha channel survives a save/reload round trip and is discoverable by any V4-aware reader.

Changes proposed in this pull request:

  • Write BITMAPV4HEADER + BI_BITFIELDS + channel masks for RGBA BMP saves
  • Keep the plain 40-byte BITMAPINFOHEADER for all other modes and for DIB output (DIB data is embedded in formats like ICO whose readers may expect the classic header)
  • Tests: RGBA round trip (pixel-exact incl. alpha), V4 header/masks assertion, RGB header unchanged, DIB header unchanged
  • Release note in docs/releasenotes/13.1.0.rst

Compatibility tradeoff (explicit): this changes the default on-disk header for RGBA BMP saves. V4 headers date to the Windows 95/NT4 era and are widely supported, but a minimal decoder that only understands 40-byte headers could reject such files; I have not tested third-party decoders exhaustively. Would an opt-in encoder option be preferable to changing the default?

Updated release notes for version 13.1.0 to include changes regarding BMP saving and zlib dependency.
Added tests for RGBA handling in BMP format.
Updated BMP header handling to support RGBA images with BITMAPV4HEADER and added channel masks.
@radarhere

Copy link
Copy Markdown
Member

Hi. Judging from your profile, you have used AI to create this PR. If this feature would be helpful to you personally in some way, please let us know. However, if this was created purely because AI had an idea, I would rather prioritize other work that we know would help people.

@anishpentyala

Copy link
Copy Markdown
Author

Hi, I convert images to BMP for a custom ESP32 display interface to avoid JPEG or PNG decoding, and my reader supports V4 headers. Preserving alpha would be useful in that workflow when working with transparent images. Thank you for taking a look!

@radarhere radarhere added the 🤖-assisted AI-assisted label Nov 15, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🤖-assisted AI-assisted

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants