packed 2bpp output, 0 = black, 1 = dark gray, 2 = light gray, 3 = white
| 179 | |
| 180 | // packed 2bpp output, 0 = black, 1 = dark gray, 2 = light gray, 3 = white |
| 181 | BmpReaderError Bitmap::readNextRow(uint8_t* data, uint8_t* rowBuffer) const { |
| 182 | // Note: rowBuffer should be pre-allocated by the caller to size 'rowBytes' |
| 183 | if (file.read(rowBuffer, rowBytes) != rowBytes) return BmpReaderError::ShortReadRow; |
| 184 | |
| 185 | prevRowY += 1; |
| 186 | |
| 187 | uint8_t* outPtr = data; |
| 188 | uint8_t currentOutByte = 0; |
| 189 | int bitShift = 6; |
| 190 | int currentX = 0; |
| 191 | |
| 192 | // Helper lambda to pack 2bpp color into the output stream |
| 193 | auto packPixel = [&](const uint8_t lum) { |
| 194 | uint8_t color; |
| 195 | if (atkinsonDitherer) { |
| 196 | color = atkinsonDitherer->processPixel(adjustPixel(lum), currentX); |
| 197 | } else if (fsDitherer) { |
| 198 | color = fsDitherer->processPixel(adjustPixel(lum), currentX); |
| 199 | } else { |
| 200 | if (nativePalette) { |
| 201 | // Palette matches native gray levels: direct mapping (still apply brightness/contrast/gamma) |
| 202 | color = static_cast<uint8_t>(adjustPixel(lum) >> 6); |
| 203 | } else { |
| 204 | // Non-native palette with dithering disabled: simple quantization |
| 205 | color = quantize(adjustPixel(lum), currentX, prevRowY); |
| 206 | } |
| 207 | } |
| 208 | currentOutByte |= (color << bitShift); |
| 209 | if (bitShift == 0) { |
| 210 | *outPtr++ = currentOutByte; |
| 211 | currentOutByte = 0; |
| 212 | bitShift = 6; |
| 213 | } else { |
| 214 | bitShift -= 2; |
| 215 | } |
| 216 | currentX++; |
| 217 | }; |
| 218 | |
| 219 | uint8_t lum; |
| 220 | |
| 221 | switch (bpp) { |
| 222 | case 32: { |
| 223 | const uint8_t* p = rowBuffer; |
| 224 | for (int x = 0; x < width; x++) { |
| 225 | lum = (77u * p[2] + 150u * p[1] + 29u * p[0]) >> 8; |
| 226 | packPixel(lum); |
| 227 | p += 4; |
| 228 | } |
| 229 | break; |
| 230 | } |
| 231 | case 24: { |
| 232 | const uint8_t* p = rowBuffer; |
| 233 | for (int x = 0; x < width; x++) { |
| 234 | lum = (77u * p[2] + 150u * p[1] + 29u * p[0]) >> 8; |
| 235 | packPixel(lum); |
| 236 | p += 3; |
| 237 | } |
| 238 | break; |
no test coverage detected