跳到正文
DEV Community· FrameSprite·· 2 小時前AI 評分40

微型 BMP 圖示看起來傾斜?檢查 RGB24 列填充

Tiny BMP Icons Look Slanted? Check RGB24 Row Padding

AI 導讀

RGB24 未壓縮 BMP 圖示出現斜色時,應按四字節對齊計算每列 stride,不能只用 width × 3。讀取像素資料時,須依標頭中的偏移量定位,讀取可見像素後跳過列填充,並把截斷資料視為錯誤。Python 3.12.10 測試了寬度為 1、2、3、4 像素的 BMP,確認填充量依次為 1、2、3、0 字節。

正文

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.

Calculate the storage row first

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 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.

Respect the file's pixel-data offset

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 offers a maintained parser reference. Consult its accepted modes and checks instead of extending this small profile into an unbounded decoder.

Retain truncation as a real error

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 is useful when choosing a maintained decoder rather than maintaining format parsing in a game importer.

What was executed

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 confirmed four round trips and the padding sequence 1, 2, 3, 0. The input and recorded layouts 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.

Check the next artifact boundary

If the file is actually a PNG with damaged chunks, use the PNG CRC diagnosis. If a texture upload has its own pitch, follow the streaming-texture row-pitch guide. If two formats render the same pixels but have different file hashes, use the decoded-pixel identity check.

Editorial ownership

Prepared by the 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 with the relevant input, tool version and observed result.

Original guide and downloadable materials

來源:DEV Community · dev.to