# Tiny BMP Icons Look Slanted? Check RGB24 Row Padding

> Source: <https://dev.to/framesprite-team/tiny-bmp-icons-look-slanted-check-rgb24-row-padding-1809>
> Published: 2026-10-22 20:58:55+00:00

Disclosure: This article was generated with AI for the FrameSprite team, which has a commercial interest in FrameSprite. It received a separate AI editorial review against the cited sources. Executed synthetic fixtures are identified with their runtime and limits; no other editor, engine, production or performance test is implied.

Advance through a 24-bit uncompressed BMP by its padded row stride, not simply width × 3. A width that does not naturally align to four bytes leaves padding at the end of each row. Treating that padding as pixels shifts every later row and can produce slanted colors in tiny game icons.

**Key takeaway:** Odd widths are useful parser tests. A four-pixel-wide RGB24 sample can hide a missing-padding bug.

For the restricted RGB24 BMP profile used here:

```
row_bytes = width * 3
stride = ((row_bytes + 3) // 4) * 4
padding = stride - row_bytes
```

The [BITMAPINFOHEADER documentation](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader) explains DIB dimensions and stride. This guide is about uncompressed RGB24 data, not every BMP compression or bit-depth variant.

| Width | Visible row bytes | Stored stride | Padding bytes | 
|---|---|---|---|
| 1 | 3 | 4 | 1 | 
| 2 | 6 | 8 | 2 | 
| 3 | 9 | 12 | 3 | 
| 4 | 12 | 12 | 0 | 

The values come from authored two-row fixtures. The fourth row is a useful control: a broken parser may appear correct at width four while failing the other widths.

Locate the pixel array through the header's offset rather than assuming the image always begins at a hard-coded position. The authored files use a 54-byte header arrangement, but that is a fixture choice. Other BMP variants can include extra structures.

Within each stored row, read only width × 3 visible bytes. For this profile, convert the stored BGR triplets into your chosen canonical RGB representation, then skip the padding before the next row. Handle row orientation separately; adding padding does not decide which stored row is the top of the image.

The [Pillow BMP implementation](https://github.com/python-pillow/Pillow/blob/main/src/PIL/BmpImagePlugin.py) offers a maintained parser reference. Consult its accepted modes and checks instead of extending this small profile into an unbounded decoder.

Before iterating rows, verify that the pixel-data range fits inside the file. Do not let a permissive slice silently shorten the last row. Reject a height, offset or stride that exceeds your declared size and memory limits before allocating an output image.

Pillow's [format-support documentation](https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html) is useful when choosing a maintained decoder rather than maintaining format parsing in a game importer.

Python 3.12.10 constructed original 1-, 2-, 3- and 4-pixel-wide RGB24 BMPs and decoded both rows back into their original pixels. Five assertions in the [checker](https://www.framesprite.com/guides/bmp-sprite-rgb24-row-padding-fixture-check.py) confirmed four round trips and the padding sequence 1, 2, 3, 0. The [input](https://www.framesprite.com/guides/bmp-sprite-rgb24-row-padding-fixture-input.json) and [recorded layouts](https://www.framesprite.com/guides/bmp-sprite-rgb24-row-padding-fixture-results.json) preserve the dimensions.

No engine or external image application was executed. The checker is an educational restricted-format exercise, not a hardened general BMP decoder.

If the file is actually a PNG with damaged chunks, use the [PNG CRC diagnosis](https://www.framesprite.com/guides/sprite-png-chunk-crc-corruption-diagnosis). If a texture upload has its own pitch, follow the [streaming-texture row-pitch guide](https://www.framesprite.com/guides/sdl3-streaming-texture-frame-row-pitch). If two formats render the same pixels but have different file hashes, use the [decoded-pixel identity check](https://www.framesprite.com/guides/sprite-png-file-hash-versus-decoded-pixel-identity).

Prepared by the [workflow team](https://www.framesprite.com/about#workflow-team), which has a commercial relationship with this site. This guide was drafted with AI assistance; independent editorial review is recorded separately. [Report a technical correction](https://www.framesprite.com/contact) with the relevant input, tool version and observed result.
