| 2708 | } |
| 2709 | |
| 2710 | function buildMonoBitmapFromImageData(imageData, w, h, alphaThreshold = 16, lumaThreshold = 0.35) { |
| 2711 | // U8g2 drawXBMP expects XBM bit order: LSB first within each byte, row-major. |
| 2712 | const bytesPerRow = Math.ceil(w / 8); |
| 2713 | const out = new Uint8Array(bytesPerRow * h); |
| 2714 | const d = imageData.data; |
| 2715 | for (let y = 0; y < h; y++) { |
| 2716 | for (let x = 0; x < w; x++) { |
| 2717 | const i = (y * w + x) * 4; |
| 2718 | const r = d[i], g = d[i + 1], b = d[i + 2], a = d[i + 3]; |
| 2719 | const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255; |
| 2720 | const on = a >= alphaThreshold && lum >= lumaThreshold; |
| 2721 | if (on) { |
| 2722 | const byteIndex = y * bytesPerRow + (x >> 3); |
| 2723 | const bit = x & 7; // LSB first |
| 2724 | out[byteIndex] |= (1 << bit); |
| 2725 | } |
| 2726 | } |
| 2727 | } |
| 2728 | return Array.from(out); |
| 2729 | } |
| 2730 | |
| 2731 | function loadPngToRgb565(src, bgHex, targetW, targetH, tintHex) { |
| 2732 | return new Promise((resolve, reject) => { |