A fork of https://github.com/crosspoint-reader/crosspoint-reader
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: Deduplicated BMP header writing in Xtc (#1439)

## Summary

**What is the goal of this PR?**

Replaced manual 1-bit BMP header logic in `Xtc::generateCoverBmp()` and
`Xtc::generateThumbBmp()` with calls to the existing `createBmpHeader()`
utility. Added a `BmpRowOrder` enum and param to support the top-down
row order of XTC cover images.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**PARTIALLY**_

authored by

Zach Nelson and committed by
GitHub
5ba85290 104f391a

+21 -95
+6 -6
lib/GfxRenderer/BitmapHelpers.cpp
··· 108 108 return (gray >= adjustedThreshold) ? 1 : 0; 109 109 } 110 110 111 - void createBmpHeader(BmpHeader* bmpHeader, int width, int height) { 111 + void createBmpHeader(BmpHeader* bmpHeader, int width, int height, BmpRowOrder rowOrder) { 112 112 if (!bmpHeader) return; 113 113 114 114 // Zero out the memory to ensure no garbage data if called on uninitialized stack memory ··· 126 126 127 127 bmpHeader->infoHeader.biSize = sizeof(bmpHeader->infoHeader); 128 128 bmpHeader->infoHeader.biWidth = width; 129 - bmpHeader->infoHeader.biHeight = height; 129 + bmpHeader->infoHeader.biHeight = (rowOrder == BmpRowOrder::TopDown) ? -height : height; 130 130 bmpHeader->infoHeader.biPlanes = 1; 131 131 bmpHeader->infoHeader.biBitCount = 1; 132 132 bmpHeader->infoHeader.biCompression = 0; 133 133 bmpHeader->infoHeader.biSizeImage = imageSize; 134 - bmpHeader->infoHeader.biXPelsPerMeter = 0; 135 - bmpHeader->infoHeader.biYPelsPerMeter = 0; 136 - bmpHeader->infoHeader.biClrUsed = 0; 137 - bmpHeader->infoHeader.biClrImportant = 0; 134 + bmpHeader->infoHeader.biXPelsPerMeter = 2835; // 72 DPI 135 + bmpHeader->infoHeader.biYPelsPerMeter = 2835; // 72 DPI 136 + bmpHeader->infoHeader.biClrUsed = 2; 137 + bmpHeader->infoHeader.biClrImportant = 2; 138 138 139 139 // Color 0 (black) 140 140 bmpHeader->colors[0].rgbBlue = 0;
+3 -1
lib/GfxRenderer/BitmapHelpers.h
··· 11 11 uint8_t quantize1bit(int gray, int x, int y); 12 12 int adjustPixel(int gray); 13 13 14 + enum class BmpRowOrder { BottomUp, TopDown }; 15 + 14 16 // Populates a 1-bit BMP header in the provided memory. 15 - void createBmpHeader(BmpHeader* bmpHeader, int width, int height); 17 + void createBmpHeader(BmpHeader* bmpHeader, int width, int height, BmpRowOrder rowOrder); 16 18 17 19 // 1-bit Atkinson dithering - better quality than noise dithering for thumbnails 18 20 // Error distribution pattern (same as 2-bit but quantizes to 2 levels):
+11 -87
lib/Xtc/Xtc.cpp
··· 7 7 8 8 #include "Xtc.h" 9 9 10 + #include <Bitmap.h> 10 11 #include <HalStorage.h> 11 12 #include <Logging.h> 12 13 ··· 172 173 return false; 173 174 } 174 175 175 - // Write BMP header 176 - // BMP file header (14 bytes) 177 - const uint32_t rowSize = ((pageInfo.width + 31) / 32) * 4; // Row size aligned to 4 bytes 178 - const uint32_t imageSize = rowSize * pageInfo.height; 179 - const uint32_t fileSize = 14 + 40 + 8 + imageSize; // Header + DIB + palette + data 180 - 181 - // File header 182 - coverBmp.write('B'); 183 - coverBmp.write('M'); 184 - coverBmp.write(reinterpret_cast<const uint8_t*>(&fileSize), 4); 185 - uint32_t reserved = 0; 186 - coverBmp.write(reinterpret_cast<const uint8_t*>(&reserved), 4); 187 - uint32_t dataOffset = 14 + 40 + 8; // 1-bit palette has 2 colors (8 bytes) 188 - coverBmp.write(reinterpret_cast<const uint8_t*>(&dataOffset), 4); 189 - 190 - // DIB header (BITMAPINFOHEADER - 40 bytes) 191 - uint32_t dibHeaderSize = 40; 192 - coverBmp.write(reinterpret_cast<const uint8_t*>(&dibHeaderSize), 4); 193 - int32_t width = pageInfo.width; 194 - coverBmp.write(reinterpret_cast<const uint8_t*>(&width), 4); 195 - int32_t height = -static_cast<int32_t>(pageInfo.height); // Negative for top-down 196 - coverBmp.write(reinterpret_cast<const uint8_t*>(&height), 4); 197 - uint16_t planes = 1; 198 - coverBmp.write(reinterpret_cast<const uint8_t*>(&planes), 2); 199 - uint16_t bitsPerPixel = 1; // 1-bit monochrome 200 - coverBmp.write(reinterpret_cast<const uint8_t*>(&bitsPerPixel), 2); 201 - uint32_t compression = 0; // BI_RGB (no compression) 202 - coverBmp.write(reinterpret_cast<const uint8_t*>(&compression), 4); 203 - coverBmp.write(reinterpret_cast<const uint8_t*>(&imageSize), 4); 204 - int32_t ppmX = 2835; // 72 DPI 205 - coverBmp.write(reinterpret_cast<const uint8_t*>(&ppmX), 4); 206 - int32_t ppmY = 2835; 207 - coverBmp.write(reinterpret_cast<const uint8_t*>(&ppmY), 4); 208 - uint32_t colorsUsed = 2; 209 - coverBmp.write(reinterpret_cast<const uint8_t*>(&colorsUsed), 4); 210 - uint32_t colorsImportant = 2; 211 - coverBmp.write(reinterpret_cast<const uint8_t*>(&colorsImportant), 4); 176 + // Write 1-bit BMP header (top-down row order) 177 + BmpHeader bmpHeader; 178 + createBmpHeader(&bmpHeader, pageInfo.width, pageInfo.height, BmpRowOrder::TopDown); 179 + coverBmp.write(reinterpret_cast<const uint8_t*>(&bmpHeader), sizeof(bmpHeader)); 212 180 213 - // Color palette (2 colors for 1-bit) 214 - // XTC 1-bit polarity: 0 = black, 1 = white (standard BMP palette order) 215 - // Color 0: Black (text/foreground in XTC) 216 - uint8_t black[4] = {0x00, 0x00, 0x00, 0x00}; 217 - coverBmp.write(black, 4); 218 - // Color 1: White (background in XTC) 219 - uint8_t white[4] = {0xFF, 0xFF, 0xFF, 0x00}; 220 - coverBmp.write(white, 4); 181 + const uint32_t rowSize = ((pageInfo.width + 31) / 32) * 4; 221 182 222 183 // Write bitmap data 223 184 // BMP requires 4-byte row alignment ··· 400 361 return false; 401 362 } 402 363 403 - // Write 1-bit BMP header for fast home screen rendering 404 - const uint32_t rowSize = (thumbWidth + 31) / 32 * 4; // 1 bit per pixel, aligned to 4 bytes 405 - const uint32_t imageSize = rowSize * thumbHeight; 406 - const uint32_t fileSize = 14 + 40 + 8 + imageSize; // 8 bytes for 2-color palette 407 - 408 - // File header 409 - thumbBmp.write('B'); 410 - thumbBmp.write('M'); 411 - thumbBmp.write(reinterpret_cast<const uint8_t*>(&fileSize), 4); 412 - uint32_t reserved = 0; 413 - thumbBmp.write(reinterpret_cast<const uint8_t*>(&reserved), 4); 414 - uint32_t dataOffset = 14 + 40 + 8; // 1-bit palette has 2 colors (8 bytes) 415 - thumbBmp.write(reinterpret_cast<const uint8_t*>(&dataOffset), 4); 364 + // Write 1-bit BMP header (top-down row order) 365 + BmpHeader bmpHeader; 366 + createBmpHeader(&bmpHeader, thumbWidth, thumbHeight, BmpRowOrder::TopDown); 367 + thumbBmp.write(reinterpret_cast<const uint8_t*>(&bmpHeader), sizeof(bmpHeader)); 416 368 417 - // DIB header 418 - uint32_t dibHeaderSize = 40; 419 - thumbBmp.write(reinterpret_cast<const uint8_t*>(&dibHeaderSize), 4); 420 - int32_t widthVal = thumbWidth; 421 - thumbBmp.write(reinterpret_cast<const uint8_t*>(&widthVal), 4); 422 - int32_t heightVal = -static_cast<int32_t>(thumbHeight); // Negative for top-down 423 - thumbBmp.write(reinterpret_cast<const uint8_t*>(&heightVal), 4); 424 - uint16_t planes = 1; 425 - thumbBmp.write(reinterpret_cast<const uint8_t*>(&planes), 2); 426 - uint16_t bitsPerPixel = 1; // 1-bit for black and white 427 - thumbBmp.write(reinterpret_cast<const uint8_t*>(&bitsPerPixel), 2); 428 - uint32_t compression = 0; 429 - thumbBmp.write(reinterpret_cast<const uint8_t*>(&compression), 4); 430 - thumbBmp.write(reinterpret_cast<const uint8_t*>(&imageSize), 4); 431 - int32_t ppmX = 2835; 432 - thumbBmp.write(reinterpret_cast<const uint8_t*>(&ppmX), 4); 433 - int32_t ppmY = 2835; 434 - thumbBmp.write(reinterpret_cast<const uint8_t*>(&ppmY), 4); 435 - uint32_t colorsUsed = 2; 436 - thumbBmp.write(reinterpret_cast<const uint8_t*>(&colorsUsed), 4); 437 - uint32_t colorsImportant = 2; 438 - thumbBmp.write(reinterpret_cast<const uint8_t*>(&colorsImportant), 4); 439 - 440 - // Color palette (2 colors for 1-bit: black and white) 441 - uint8_t palette[8] = { 442 - 0x00, 0x00, 0x00, 0x00, // Color 0: Black 443 - 0xFF, 0xFF, 0xFF, 0x00 // Color 1: White 444 - }; 445 - thumbBmp.write(palette, 8); 369 + const uint32_t rowSize = (thumbWidth + 31) / 32 * 4; 446 370 447 371 // Allocate row buffer for 1-bit output 448 372 uint8_t* rowBuffer = static_cast<uint8_t*>(malloc(rowSize));
+1 -1
src/util/ScreenshotUtil.cpp
··· 62 62 63 63 BmpHeader header; 64 64 65 - createBmpHeader(&header, phyWidth, phyHeight); 65 + createBmpHeader(&header, phyWidth, phyHeight, BmpRowOrder::BottomUp); 66 66 67 67 bool write_error = false; 68 68 if (file.write(reinterpret_cast<uint8_t*>(&header), sizeof(header)) != sizeof(header)) {