{"version":3,"file":"show-font-action.mjs","names":[],"sources":["../../src/actions/show-font-action.ts"],"sourcesContent":["import type { Command } from 'commander';\nimport sharp from 'sharp';\nimport { writeFile, readFile } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\n\nimport { CGA_PALETTE } from '@4bitlabs/color/palettes';\nimport { decompress, parseFont, ResourceTypes } from '@4bitlabs/sci0';\nimport {\n  createImageData,\n  createPaletteFilter,\n  padPixelsFilter,\n  renderPixelData,\n} from '@4bitlabs/image';\nimport { getRootOptions } from './get-root-options.js';\nimport { loadContentFromMap } from './load-content-from-map.js';\nimport { fontMatcher } from '../helpers/resource-matchers.js';\nimport { chunk } from '../helpers/chunk.js';\nimport { nearestNeighbor } from '@4bitlabs/resize-filters';\n\nconst getFontData = async (\n  fontNum: number,\n  options: { output?: string; aspectRatio?: boolean; input?: string },\n  thisCmd: Command,\n): Promise<Uint8Array> => {\n  const { root, engine } = getRootOptions(thisCmd);\n\n  if (options?.input) {\n    const bytes = await readFile(join(root, options.input));\n    if (bytes[0] !== (ResourceTypes.FONT_TYPE | 0x80)) {\n      console.error(`warn: unexpected resource type ${bytes[0] ^ 0x80}`);\n    }\n    return bytes.subarray(2);\n  }\n\n  const [header, bytes] = await loadContentFromMap(root, fontMatcher(fontNum));\n\n  return decompress(engine, header.compression, bytes);\n};\n\nexport const showFontAction = async (\n  fontNum: number,\n  options: { output?: string; aspectRatio?: boolean; input?: string },\n  thisCmd: Command,\n) => {\n  const { root } = getRootOptions(thisCmd);\n  const payload = await getFontData(fontNum, options, thisCmd);\n  const { characters } = parseFont(payload);\n\n  const glyphs = characters.map((ch) =>\n    renderPixelData(ch, {\n      pre: [padPixelsFilter([0, 0, 1, 0])],\n      render: createPaletteFilter(CGA_PALETTE),\n      post: [options.aspectRatio ? nearestNeighbor([5, 6]) : undefined],\n    }),\n  );\n\n  const lines = [...chunk(glyphs, 16)];\n\n  const canvasW = lines.reduce((w, line) => {\n    const lW = line.reduce((w2, gl) => w2 + gl.width, 0);\n    return Math.max(lW, w);\n  }, 0);\n\n  const lineMaxHeight = glyphs.reduce((h, gl) => Math.max(gl.height, h), 0);\n  const canvasH = lineMaxHeight * lines.length;\n\n  const canvas = createImageData(canvasW, canvasH);\n  const cStride = canvasW * 4;\n\n  lines.forEach((line, idx) => {\n    const y = idx * lineMaxHeight;\n    line.reduce((x, { width, height, data }) => {\n      const glStride = width * 4;\n      for (let glY = 0; glY < height; glY += 1) {\n        const source = glY * glStride;\n        const row = data.subarray(source, source + glStride);\n\n        const dest = (y + glY) * cStride + x * 4;\n        canvas.data.set(row, dest);\n      }\n      return x + width;\n    }, 0);\n  });\n\n  const image = sharp(canvas.data, {\n    raw: {\n      width: canvasW,\n      height: canvasH,\n      channels: 4,\n    },\n  });\n\n  const output = (\n    options.output ??\n    `font.${fontNum.toString(10).padStart(3, '0')}.${basename(root)}.png`\n  ).trim();\n\n  if (output === '-') {\n    process.stdout.write(await image.png().toBuffer());\n  } else {\n    await writeFile(output, await image.png().toBuffer());\n  }\n};\n"],"mappings":";;;;;;;;;;;;AAmBA,MAAM,cAAc,OAClB,SACA,SACA,YACwB;CACxB,MAAM,EAAE,MAAM,WAAW,eAAe,OAAO;CAE/C,IAAI,SAAS,OAAO;EAClB,MAAM,QAAQ,MAAM,SAAS,KAAK,MAAM,QAAQ,KAAK,CAAC;EACtD,IAAI,MAAM,QAAQ,cAAc,YAAY,MAC1C,QAAQ,MAAM,kCAAkC,MAAM,KAAK,KAAM;EAEnE,OAAO,MAAM,SAAS,CAAC;CACzB;CAEA,MAAM,CAAC,QAAQ,SAAS,MAAM,mBAAmB,MAAM,YAAY,OAAO,CAAC;CAE3E,OAAO,WAAW,QAAQ,OAAO,aAAa,KAAK;AACrD;AAEA,MAAa,iBAAiB,OAC5B,SACA,SACA,YACG;CACH,MAAM,EAAE,SAAS,eAAe,OAAO;CACvC,MAAM,UAAU,MAAM,YAAY,SAAS,SAAS,OAAO;CAC3D,MAAM,EAAE,eAAe,UAAU,OAAO;CAExC,MAAM,SAAS,WAAW,KAAK,OAC7B,gBAAgB,IAAI;EAClB,KAAK,CAAC,gBAAgB;GAAC;GAAG;GAAG;GAAG;EAAC,CAAC,CAAC;EACnC,QAAQ,oBAAoB,WAAW;EACvC,MAAM,CAAC,QAAQ,cAAc,gBAAgB,CAAC,GAAG,CAAC,CAAC,IAAI,KAAA,CAAS;CAClE,CAAC,CACH;CAEA,MAAM,QAAQ,CAAC,GAAG,MAAM,QAAQ,EAAE,CAAC;CAEnC,MAAM,UAAU,MAAM,QAAQ,GAAG,SAAS;EACxC,MAAM,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,GAAG,OAAO,CAAC;EACnD,OAAO,KAAK,IAAI,IAAI,CAAC;CACvB,GAAG,CAAC;CAEJ,MAAM,gBAAgB,OAAO,QAAQ,GAAG,OAAO,KAAK,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC;CACxE,MAAM,UAAU,gBAAgB,MAAM;CAEtC,MAAM,SAAS,gBAAgB,SAAS,OAAO;CAC/C,MAAM,UAAU,UAAU;CAE1B,MAAM,SAAS,MAAM,QAAQ;EAC3B,MAAM,IAAI,MAAM;EAChB,KAAK,QAAQ,GAAG,EAAE,OAAO,QAAQ,WAAW;GAC1C,MAAM,WAAW,QAAQ;GACzB,KAAK,IAAI,MAAM,GAAG,MAAM,QAAQ,OAAO,GAAG;IACxC,MAAM,SAAS,MAAM;IACrB,MAAM,MAAM,KAAK,SAAS,QAAQ,SAAS,QAAQ;IAEnD,MAAM,QAAQ,IAAI,OAAO,UAAU,IAAI;IACvC,OAAO,KAAK,IAAI,KAAK,IAAI;GAC3B;GACA,OAAO,IAAI;EACb,GAAG,CAAC;CACN,CAAC;CAED,MAAM,QAAQ,MAAM,OAAO,MAAM,EAC/B,KAAK;EACH,OAAO;EACP,QAAQ;EACR,UAAU;CACZ,EACF,CAAC;CAED,MAAM,UACJ,QAAQ,UACR,QAAQ,QAAQ,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE,GAAG,SAAS,IAAI,EAAE,MAAA,CAChE,KAAK;CAEP,IAAI,WAAW,KACb,QAAQ,OAAO,MAAM,MAAM,MAAM,IAAI,CAAC,CAAC,SAAS,CAAC;MAEjD,MAAM,UAAU,QAAQ,MAAM,MAAM,IAAI,CAAC,CAAC,SAAS,CAAC;AAExD"}