#pragma once #include #include // ============================================================================ // BMP WRITING HELPERS // ============================================================================ // Write 16-bit value in little-endian format inline void write16(Print& out, const uint16_t value) { out.write(value & 0xFF); out.write((value >> 8) & 0xFF); } // Write 32-bit unsigned value in little-endian format inline void write32(Print& out, const uint32_t value) { out.write(value & 0xFF); out.write((value >> 8) & 0xFF); out.write((value >> 16) & 0xFF); out.write((value >> 24) & 0xFF); } // Write 32-bit signed value in little-endian format inline void write32Signed(Print& out, const int32_t value) { out.write(value & 0xFF); out.write((value >> 8) & 0xFF); out.write((value >> 16) & 0xFF); out.write((value >> 24) & 0xFF); } // Write BMP header with 2-bit color depth (4-level grayscale) static inline void writeBmpHeader2bit(Print& bmpOut, const int width, const int height) { // Calculate row padding (each row must be multiple of 4 bytes) const int bytesPerRow = (width * 2 + 31) / 32 * 4; // 2 bits per pixel, round up const int imageSize = bytesPerRow * height; const uint32_t fileSize = 70 + imageSize; // 14 (file header) + 40 (DIB header) + 16 (palette) + image // BMP File Header (14 bytes) bmpOut.write('B'); bmpOut.write('M'); write32(bmpOut, fileSize); // File size write32(bmpOut, 0); // Reserved write32(bmpOut, 70); // Offset to pixel data // DIB Header (BITMAPINFOHEADER - 40 bytes) write32(bmpOut, 40); write32Signed(bmpOut, width); write32Signed(bmpOut, -height); // Negative height = top-down bitmap write16(bmpOut, 1); // Color planes write16(bmpOut, 2); // Bits per pixel (2 bits) write32(bmpOut, 0); // BI_RGB (no compression) write32(bmpOut, imageSize); write32(bmpOut, 2835); // xPixelsPerMeter (72 DPI) write32(bmpOut, 2835); // yPixelsPerMeter (72 DPI) write32(bmpOut, 4); // colorsUsed write32(bmpOut, 4); // colorsImportant // Color Palette (4 colors x 4 bytes = 16 bytes) // Format: Blue, Green, Red, Reserved (BGRA) uint8_t palette[16] = { 0x00, 0x00, 0x00, 0x00, // Color 0: Black 0x55, 0x55, 0x55, 0x00, // Color 1: Dark gray (85) 0xAA, 0xAA, 0xAA, 0x00, // Color 2: Light gray (170) 0xFF, 0xFF, 0xFF, 0x00 // Color 3: White }; for (const uint8_t i : palette) { bmpOut.write(i); } }