painbrush
1.0.21.1.0
src-packer/pipeline.js+
src-packer/pipeline.jsNew file+77
Index: package/src-packer/pipeline.js
===================================================================
--- package/src-packer/pipeline.js
+++ package/src-packer/pipeline.js
@@ -0,0 +1,77 @@
+import path from "path/posix";
+import { decode } from "fast-bmp";
+import { solidFillBrush } from "../src/color.js";
+import { toImage } from "../src/image.js";
+import { padLayer, makeTextLayer, overlayLayerOver, makeRectangleLayer, } from "../src/layer.js";
+import { useFont } from "../src/typography.js";
+export const generateCharacters = async ({ img, fontMeta, }) => {
+ const { metrics } = fontMeta;
+ const data = decode(img);
+ const rawCharacters = [[]];
+ const colspan = fontMeta.cols * metrics.width;
+ data.data.forEach((item, index) => {
+ const pixelX = index % colspan;
+ const pixelY = ~~(index / colspan);
+ const charX = ~~(pixelX / metrics.width);
+ const charY = ~~(pixelY / metrics.height);
+ const charXPixelOffset = pixelX - charX * metrics.width;
+ const charYPixelOffset = pixelY - charY * metrics.height;
+ const charPos = charX + charY * fontMeta.cols;
+ if (!rawCharacters[charPos]) {
+ rawCharacters[charPos] = [];
+ }
+ const charPixelPos = charXPixelOffset + charYPixelOffset * metrics.width;
+ rawCharacters[charPos][charPixelPos] = item;
+ });
+ const alphabet = fontMeta.alphabet.join("");
+ return rawCharacters.map((char, index) => {
+ const letter = alphabet[index];
+ const maybeTrim = fontMeta.trim[letter] ?? fontMeta.trim["__DEFAULT__"];
+ if (!maybeTrim) {
+ return [metrics.width, char];
+ }
+ let newChar = [];
+ for (let i = 0; i < char.length; i++) {
+ const pos = i % metrics.width;
+ if (pos < metrics.width - maybeTrim) {
+ newChar.push(char[i]);
+ }
+ }
+ return [metrics.width - maybeTrim, newChar];
+ });
+};
+export const generatePxFontFile = (characters, { fontName, fontMeta, cwd, outDir }) => {
+ const fontFileAt = path.join(cwd, outDir, fontName + ".pxfont");
+ const alphabet = fontMeta.alphabet.join("");
+ const metrics = fontMeta.metrics;
+ return [
+ fontFileAt,
+ JSON.stringify({
+ metrics,
+ alphabet,
+ characters,
+ }, null, 2),
+ ];
+};
+export const generateSpecimenImage = async ([_, pxFontFile], { fontName, fontMeta, cwd, outDir }) => {
+ const alphabet = fontMeta.alphabet.join("");
+ const specimenImgPd = padLayer(await makeTextLayer(fontName.toUpperCase() +
+ "\n" +
+ "\n" +
+ "? " +
+ alphabet
+ .split("")
+ .map((s) => s.trim())
+ .filter(Boolean)
+ .sort()
+ .join(""), await useFont(Promise.resolve(pxFontFile)), solidFillBrush(fontMeta.specimen?.color ?? [0, 0, 0]), {
+ maxLengthPx: fontMeta.metrics.width * 12,
+ breakLinesOn: "", // break on anything
+ }), { x: fontMeta.metrics.width, y: fontMeta.metrics.height });
+ const specimenImg = overlayLayerOver(makeRectangleLayer({
+ x: specimenImgPd.width,
+ y: specimenImgPd.height,
+ }, solidFillBrush(fontMeta.specimen?.background ?? [255, 255, 255])), specimenImgPd);
+ const specimenFileAt = path.join(cwd, outDir, fontName + "-specimen.bmp");
+ return [specimenFileAt, toImage(specimenImg)];
+};