Xteink-X4-crosspoint-reader/lib/Epub/Epub/converters/DitherUtils.h
Martin Brook b8e61130f2 refactor: extract shared DitherUtils.h and PixelCache.h
Address review comments #2, #3, and #10:
- Extract duplicated bayer4x4 matrix, applyBayerDither4Level(), and
  drawPixelWithRenderMode() into shared DitherUtils.h
- Extract duplicated PixelCache struct into shared PixelCache.h so both
  JPEG and PNG decoders use the same implementation
- Add MAX_CACHE_BYTES (256KB) size limit to PixelCache::allocate() to
  proactively guard against oversized allocations on embedded targets
2026-02-01 09:24:04 +00:00

41 lines
1.3 KiB
C

#pragma once
#include <GfxRenderer.h>
#include <stdint.h>
// 4x4 Bayer matrix for ordered dithering
inline const uint8_t bayer4x4[4][4] = {
{0, 8, 2, 10},
{12, 4, 14, 6},
{3, 11, 1, 9},
{15, 7, 13, 5},
};
// Apply Bayer dithering and quantize to 4 levels (0-3)
// Stateless - works correctly with any pixel processing order
inline uint8_t applyBayerDither4Level(uint8_t gray, int x, int y) {
int bayer = bayer4x4[y & 3][x & 3];
int dither = (bayer - 8) * 5; // Scale to +/-40 (half of quantization step 85)
int adjusted = gray + dither;
if (adjusted < 0) adjusted = 0;
if (adjusted > 255) adjusted = 255;
if (adjusted < 64) return 0;
if (adjusted < 128) return 1;
if (adjusted < 192) return 2;
return 3;
}
// Draw a pixel respecting the current render mode for grayscale support
inline void drawPixelWithRenderMode(GfxRenderer& renderer, int x, int y, uint8_t pixelValue) {
GfxRenderer::RenderMode renderMode = renderer.getRenderMode();
if (renderMode == GfxRenderer::BW && pixelValue < 3) {
renderer.drawPixel(x, y, true);
} else if (renderMode == GfxRenderer::GRAYSCALE_MSB && (pixelValue == 1 || pixelValue == 2)) {
renderer.drawPixel(x, y, false);
} else if (renderMode == GfxRenderer::GRAYSCALE_LSB && pixelValue == 1) {
renderer.drawPixel(x, y, false);
}
}