Skip to content

feat: import common BMP formats with lossiness reporting - #4

Merged
kbuffardi merged 6 commits into
masterfrom
feature/common-bmp-import
Sep 30, 2026
Merged

kbuffardi merged 6 commits into
masterfrom
feature/common-bmp-import

Conversation

@kbuffardi

Copy link
Copy Markdown
Owner

Summary

  • replace native-struct BMP parsing with checked little-endian decoding and atomic failure behavior
  • import CORE/INFO/V2/V3/V4/V5 BMPs across indexed, RGB, bitfield, RLE4, and RLE8 encodings
  • add Bitmap::isLossy() with the confirmed alpha, color-precision, and color-metadata semantics
  • preserve stored RGB values when alpha is discarded and keep 24-bpp BI_RGB save output
  • document supported inputs, lossiness behavior, safety limits, and unsupported formats

Supported input

  • BITMAPCOREHEADER: 1/4/8/24-bpp uncompressed
  • BI_RGB: 1/4/8/16/24/32-bpp
  • BI_BITFIELDS: 16/32-bpp, including declared alpha masks
  • BI_RLE4 and BI_RLE8: encoded/absolute runs, EOL, EOB, delta, and alignment
  • bottom-up images plus top-down uncompressed/bitfield images

Embedded JPEG/PNG, CMYK, later OS/2-specific variants, and color-profile transforms remain explicitly unsupported and are documented in the README.

Lossiness contract

isLossy() is true when import discards color information or precision:

  • a declared alpha channel contains at least one non-opaque sample
  • an RGB bitfield component wider than 8 bits is quantized
  • meaningful V4/V5 color metadata is retained only as numeric RGB values without applying its transform

Palette/RLE expansion, lower-depth RGB expansion, row orientation, padding removal, opaque alpha, and BGRX reserved bytes remain lossless. Spatial dimensions are never resampled.

Safety

  • validate signatures, known DIB layouts, dimensions, planes, compression/depth pairs, offsets, palette regions, masks, strides, profile ranges, and decoded-size arithmetic
  • reject out-of-bounds RLE runs/deltas and truncated command streams
  • decode into temporary state and commit only after full success
  • cap input files at 512 MiB and decoded images at 100 million pixels
  • add no decoder dependencies

Verification

  • ./test_runner.sh
  • g++ -std=c++11 -Wall -Wextra -pedantic -c bitmap.cpp -o /tmp/bitmap.o
  • g++ -std=c++11 -Wall -Wextra -pedantic -fsanitize=address,undefined -fno-omit-frame-pointer bitmap.cpp tests/bitmap_tests.cpp -o /tmp/bitmap-tests-sanitized
  • /tmp/bitmap-tests-sanitized
  • g++ -std=c++11 -Wall -Wextra -pedantic example.cpp bitmap.cpp -o /tmp/bitmap-example (only the pre-existing untracked example emits signed/unsigned loop warnings)
  • git diff --check master...HEAD

Closes #1

@kbuffardi
kbuffardi merged commit 5f9e588 into master Sep 30, 2026
1 check passed
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.

Support multiple bit depths

1 participant