* Blit one glyph into the RGBA buffer at (x,y), scaled by `scale` * (nearest-neighbor). Alpha-composites over the existing background. Bold is * synthesized by boosting alpha toward opaque — a cheap approximation that * reads as heavier weight without needing a second font.
( px: Uint8Array, width: number, x: number, y: number, glyph: Uint8Array, color: AnsiColor, bold: boolean, scale: number, )
| 211 | * reads as heavier weight without needing a second font. |
| 212 | */ |
| 213 | function blitGlyph( |
| 214 | px: Uint8Array, |
| 215 | width: number, |
| 216 | x: number, |
| 217 | y: number, |
| 218 | glyph: Uint8Array, |
| 219 | color: AnsiColor, |
| 220 | bold: boolean, |
| 221 | scale: number, |
| 222 | ): void { |
| 223 | for (let gy = 0; gy < GLYPH_H; gy++) { |
| 224 | for (let gx = 0; gx < GLYPH_W; gx++) { |
| 225 | let a = glyph[gy * GLYPH_W + gx]! |
| 226 | if (a === 0) continue |
| 227 | if (bold) a = Math.min(255, a * 1.4) |
| 228 | const inv = 255 - a |
| 229 | for (let sy = 0; sy < scale; sy++) { |
| 230 | const rowBase = ((y + gy * scale + sy) * width + x + gx * scale) * 4 |
| 231 | for (let sx = 0; sx < scale; sx++) { |
| 232 | const i = rowBase + sx * 4 |
| 233 | px[i] = (color.r * a + px[i]! * inv) >> 8 |
| 234 | px[i + 1] = (color.g * a + px[i + 1]! * inv) >> 8 |
| 235 | px[i + 2] = (color.b * a + px[i + 2]! * inv) >> 8 |
| 236 | } |
| 237 | } |
| 238 | } |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | /** |
| 243 | * Zero out the alpha channel in the four corner regions outside a |