(
ansiText: string,
options: AnsiToPngOptions = {},
)
| 89 | * Returns a Buffer containing a valid PNG (RGBA, 8-bit). |
| 90 | */ |
| 91 | export function ansiToPng( |
| 92 | ansiText: string, |
| 93 | options: AnsiToPngOptions = {}, |
| 94 | ): Buffer { |
| 95 | const { |
| 96 | scale = 1, |
| 97 | paddingX = 48, |
| 98 | paddingY = 48, |
| 99 | borderRadius = 16, |
| 100 | background = DEFAULT_BG, |
| 101 | } = options |
| 102 | |
| 103 | const lines = parseAnsi(ansiText) |
| 104 | // Trim trailing blank lines (same behavior as ansiToSvg). |
| 105 | while ( |
| 106 | lines.length > 0 && |
| 107 | lines[lines.length - 1]!.every(span => span.text.trim() === '') |
| 108 | ) { |
| 109 | lines.pop() |
| 110 | } |
| 111 | if (lines.length === 0) { |
| 112 | lines.push([{ text: '', color: background, bold: false }]) |
| 113 | } |
| 114 | |
| 115 | const cols = Math.max(1, ...lines.map(lineWidthCells)) |
| 116 | const rows = lines.length |
| 117 | |
| 118 | const width = (cols * GLYPH_W + paddingX * 2) * scale |
| 119 | const height = (rows * GLYPH_H + paddingY * 2) * scale |
| 120 | |
| 121 | // RGBA buffer, pre-filled with the background color. |
| 122 | const px = new Uint8Array(width * height * 4) |
| 123 | fillBackground(px, background) |
| 124 | if (borderRadius > 0) { |
| 125 | roundCorners(px, width, height, borderRadius * scale) |
| 126 | } |
| 127 | |
| 128 | // Blit glyphs. |
| 129 | const padX = paddingX * scale |
| 130 | const padY = paddingY * scale |
| 131 | for (let row = 0; row < rows; row++) { |
| 132 | let col = 0 |
| 133 | for (const span of lines[row]!) { |
| 134 | for (const ch of span.text) { |
| 135 | const cp = ch.codePointAt(0)! |
| 136 | const cellW = stringWidth(ch) |
| 137 | if (cellW === 0) continue // zero-width (combining marks, etc.) |
| 138 | const x = padX + col * GLYPH_W * scale |
| 139 | const y = padY + row * GLYPH_H * scale |
| 140 | const shade = SHADE_ALPHA[cp] |
| 141 | if (shade !== undefined) { |
| 142 | blitShade(px, width, x, y, span.color, background, shade, scale) |
| 143 | } else { |
| 144 | const glyph = FONT.get(cp) ?? FALLBACK_GLYPH |
| 145 | blitGlyph(px, width, x, y, glyph, span.color, span.bold, scale) |
| 146 | } |
| 147 | col += cellW |
| 148 | } |
no test coverage detected