@apocaliss92/nodedreame 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +311 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -5
- package/dist/index.d.ts +30 -5
- package/dist/index.js +311 -29
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -81,7 +81,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
81
81
|
|
|
82
82
|
// src/support/version.ts
|
|
83
83
|
var LIBRARY_NAME = "nodedreame";
|
|
84
|
-
var LIBRARY_VERSION = "1.
|
|
84
|
+
var LIBRARY_VERSION = "1.9.0";
|
|
85
85
|
|
|
86
86
|
// src/transport/errors.ts
|
|
87
87
|
var DreameError = class extends Error {
|
|
@@ -1963,11 +1963,43 @@ function unwrapEnvelope(value, opts = {}) {
|
|
|
1963
1963
|
}
|
|
1964
1964
|
bytes = aesCbcDecrypt(bytes, key2, opts.iv);
|
|
1965
1965
|
}
|
|
1966
|
+
let inflated;
|
|
1966
1967
|
try {
|
|
1967
|
-
|
|
1968
|
+
inflated = zlib.inflateSync(bytes);
|
|
1968
1969
|
} catch (err) {
|
|
1969
1970
|
throw new MapDecodeError("envelope: zlib inflate failed", { cause: err });
|
|
1970
1971
|
}
|
|
1972
|
+
let guard = 0;
|
|
1973
|
+
while (guard < MAX_EXTRA_WRAP_LAYERS && looksLikeBase64Zlib(inflated)) {
|
|
1974
|
+
const text = inflated.toString("latin1").replace(/-/g, "+").replace(/_/g, "/");
|
|
1975
|
+
try {
|
|
1976
|
+
inflated = zlib.inflateSync(Buffer.from(text, "base64"));
|
|
1977
|
+
} catch (err) {
|
|
1978
|
+
throw new MapDecodeError("envelope: nested zlib inflate failed", { cause: err });
|
|
1979
|
+
}
|
|
1980
|
+
guard += 1;
|
|
1981
|
+
}
|
|
1982
|
+
return inflated;
|
|
1983
|
+
}
|
|
1984
|
+
var MAX_EXTRA_WRAP_LAYERS = 4;
|
|
1985
|
+
function looksLikeBase64Zlib(buf) {
|
|
1986
|
+
if (buf.length < 8) return false;
|
|
1987
|
+
for (const b of buf) {
|
|
1988
|
+
const isB64 = b >= 65 && b <= 90 || // A-Z
|
|
1989
|
+
b >= 97 && b <= 122 || // a-z
|
|
1990
|
+
b >= 48 && b <= 57 || // 0-9
|
|
1991
|
+
b === 43 || b === 47 || // + /
|
|
1992
|
+
b === 45 || b === 95 || // - _ (url-safe)
|
|
1993
|
+
b === 61;
|
|
1994
|
+
if (!isB64) return false;
|
|
1995
|
+
}
|
|
1996
|
+
try {
|
|
1997
|
+
const prefix = buf.subarray(0, 16).toString("latin1").replace(/-/g, "+").replace(/_/g, "/");
|
|
1998
|
+
const decoded = Buffer.from(prefix, "base64");
|
|
1999
|
+
return decoded.length >= 2 && decoded[0] === 120;
|
|
2000
|
+
} catch {
|
|
2001
|
+
return false;
|
|
2002
|
+
}
|
|
1971
2003
|
}
|
|
1972
2004
|
function aesCbcDecrypt(cipher, rawKey, iv) {
|
|
1973
2005
|
const keyBytes = Buffer.from(
|
|
@@ -2603,7 +2635,7 @@ function decodeCleanedAreaPixels(pixels, width, height) {
|
|
|
2603
2635
|
|
|
2604
2636
|
// src/models/vacuum/map/decode.ts
|
|
2605
2637
|
function decodeVacuumMap(input, opts = {}) {
|
|
2606
|
-
const inflated = typeof input === "string" ? unwrapEnvelope(input, opts) : input;
|
|
2638
|
+
const inflated = typeof input === "string" ? unwrapEnvelope(input, opts) : looksLikeBase64Zlib(input) ? unwrapEnvelope(input.toString("latin1"), opts) : input;
|
|
2607
2639
|
const { header, tail } = parseFrame(inflated);
|
|
2608
2640
|
const dimensions = mergeDimensions(header, tail);
|
|
2609
2641
|
const robot = pose(header.robotX, header.robotY, header.robotA, tail.nr === true);
|
|
@@ -2665,10 +2697,79 @@ function pose(x, y, angle, absent) {
|
|
|
2665
2697
|
|
|
2666
2698
|
// src/models/vacuum/map/render.ts
|
|
2667
2699
|
var import_pngjs = require("pngjs");
|
|
2668
|
-
var
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2700
|
+
var SCHEMES = {
|
|
2701
|
+
"dreame-light": {
|
|
2702
|
+
floor: [210, 222, 235, 255],
|
|
2703
|
+
wall: [60, 60, 60, 255],
|
|
2704
|
+
carpet: [180, 150, 120, 200],
|
|
2705
|
+
segSat: 0.45,
|
|
2706
|
+
segVal: 0.95,
|
|
2707
|
+
path: [60, 110, 180, 235],
|
|
2708
|
+
robotBody: [40, 70, 110, 255],
|
|
2709
|
+
robotHeading: [255, 255, 255, 255],
|
|
2710
|
+
charger: [40, 160, 80, 255],
|
|
2711
|
+
noGoFill: [220, 60, 60, 70],
|
|
2712
|
+
noGoBorder: [200, 40, 40, 220],
|
|
2713
|
+
noMopFill: [60, 120, 220, 60],
|
|
2714
|
+
noMopBorder: [40, 90, 200, 200],
|
|
2715
|
+
virtualWall: [200, 40, 40, 230],
|
|
2716
|
+
obstacle: [230, 150, 30, 255],
|
|
2717
|
+
label: [40, 40, 40, 255]
|
|
2718
|
+
},
|
|
2719
|
+
"dreame-dark": {
|
|
2720
|
+
floor: [40, 46, 56, 255],
|
|
2721
|
+
wall: [15, 15, 18, 255],
|
|
2722
|
+
carpet: [80, 66, 52, 200],
|
|
2723
|
+
segSat: 0.5,
|
|
2724
|
+
segVal: 0.62,
|
|
2725
|
+
path: [120, 170, 230, 235],
|
|
2726
|
+
robotBody: [120, 170, 230, 255],
|
|
2727
|
+
robotHeading: [20, 24, 30, 255],
|
|
2728
|
+
charger: [60, 200, 110, 255],
|
|
2729
|
+
noGoFill: [220, 70, 70, 80],
|
|
2730
|
+
noGoBorder: [230, 70, 70, 220],
|
|
2731
|
+
noMopFill: [70, 130, 230, 70],
|
|
2732
|
+
noMopBorder: [80, 140, 235, 210],
|
|
2733
|
+
virtualWall: [230, 70, 70, 235],
|
|
2734
|
+
obstacle: [240, 180, 60, 255],
|
|
2735
|
+
label: [225, 230, 240, 255]
|
|
2736
|
+
},
|
|
2737
|
+
"mijia-light": {
|
|
2738
|
+
floor: [225, 232, 240, 255],
|
|
2739
|
+
wall: [70, 78, 92, 255],
|
|
2740
|
+
carpet: [188, 162, 132, 200],
|
|
2741
|
+
segSat: 0.35,
|
|
2742
|
+
segVal: 0.98,
|
|
2743
|
+
path: [80, 130, 200, 230],
|
|
2744
|
+
robotBody: [30, 100, 200, 255],
|
|
2745
|
+
robotHeading: [255, 255, 255, 255],
|
|
2746
|
+
charger: [40, 170, 90, 255],
|
|
2747
|
+
noGoFill: [225, 70, 70, 70],
|
|
2748
|
+
noGoBorder: [205, 45, 45, 220],
|
|
2749
|
+
noMopFill: [70, 130, 225, 60],
|
|
2750
|
+
noMopBorder: [50, 100, 205, 200],
|
|
2751
|
+
virtualWall: [205, 45, 45, 230],
|
|
2752
|
+
obstacle: [235, 160, 35, 255],
|
|
2753
|
+
label: [45, 52, 64, 255]
|
|
2754
|
+
},
|
|
2755
|
+
tasshack: {
|
|
2756
|
+
floor: [200, 210, 225, 255],
|
|
2757
|
+
wall: [80, 80, 95, 255],
|
|
2758
|
+
carpet: [176, 148, 118, 205],
|
|
2759
|
+
segSat: 0.5,
|
|
2760
|
+
segVal: 0.9,
|
|
2761
|
+
path: [50, 100, 170, 235],
|
|
2762
|
+
robotBody: [35, 60, 100, 255],
|
|
2763
|
+
robotHeading: [255, 255, 255, 255],
|
|
2764
|
+
charger: [35, 150, 75, 255],
|
|
2765
|
+
noGoFill: [215, 55, 55, 75],
|
|
2766
|
+
noGoBorder: [195, 35, 35, 220],
|
|
2767
|
+
noMopFill: [55, 115, 215, 65],
|
|
2768
|
+
noMopBorder: [35, 85, 195, 205],
|
|
2769
|
+
virtualWall: [195, 35, 35, 230],
|
|
2770
|
+
obstacle: [225, 145, 25, 255],
|
|
2771
|
+
label: [35, 42, 54, 255]
|
|
2772
|
+
}
|
|
2672
2773
|
};
|
|
2673
2774
|
function hsvToRgba(h, s, v) {
|
|
2674
2775
|
const c = v * s;
|
|
@@ -2699,49 +2800,230 @@ function hsvToRgba(h, s, v) {
|
|
|
2699
2800
|
const m = v - c;
|
|
2700
2801
|
return [Math.round((r + m) * 255), Math.round((g + m) * 255), Math.round((b + m) * 255), 255];
|
|
2701
2802
|
}
|
|
2702
|
-
function segmentColor(id) {
|
|
2803
|
+
function segmentColor(id, pal) {
|
|
2703
2804
|
const hue = id * 137.508 % 360;
|
|
2704
|
-
return hsvToRgba(hue,
|
|
2805
|
+
return hsvToRgba(hue, pal.segSat, pal.segVal);
|
|
2705
2806
|
}
|
|
2706
2807
|
function renderVacuumPng(map, opts = {}) {
|
|
2707
2808
|
const scale = Math.max(1, Math.trunc(opts.scale ?? 1));
|
|
2708
|
-
const
|
|
2709
|
-
const
|
|
2710
|
-
const
|
|
2809
|
+
const pal = SCHEMES[opts.colorScheme ?? "dreame-light"];
|
|
2810
|
+
const w = Math.max(1, map.dimensions.width * scale);
|
|
2811
|
+
const h = Math.max(1, map.dimensions.height * scale);
|
|
2812
|
+
const png = new import_pngjs.PNG({ width: w, height: h });
|
|
2711
2813
|
png.data.fill(0);
|
|
2712
2814
|
for (const layer of map.layers) {
|
|
2713
|
-
paintLayer(png, layer, scale);
|
|
2815
|
+
paintLayer(png, layer, scale, pal);
|
|
2816
|
+
}
|
|
2817
|
+
const dim = map.dimensions;
|
|
2818
|
+
if (opts.showNoGo !== false) {
|
|
2819
|
+
for (const area of map.restrictedAreas) {
|
|
2820
|
+
const fill = area.kind === "noMop" ? pal.noMopFill : pal.noGoFill;
|
|
2821
|
+
const border = area.kind === "noMop" ? pal.noMopBorder : pal.noGoBorder;
|
|
2822
|
+
const a = worldToPx(area.bbox.xMin, area.bbox.yMin, dim, scale);
|
|
2823
|
+
const b = worldToPx(area.bbox.xMax, area.bbox.yMax, dim, scale);
|
|
2824
|
+
fillRect(png, a.x, a.y, b.x, b.y, fill);
|
|
2825
|
+
strokeRect(png, a.x, a.y, b.x, b.y, border);
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
if (opts.showVirtualWalls !== false) {
|
|
2829
|
+
for (const vw of map.virtualWalls) {
|
|
2830
|
+
const a = worldToPx(vw.from.x, vw.from.y, dim, scale);
|
|
2831
|
+
const b = worldToPx(vw.to.x, vw.to.y, dim, scale);
|
|
2832
|
+
drawLine(png, a.x, a.y, b.x, b.y, pal.virtualWall, Math.max(1, scale));
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
if (opts.showPath !== false) {
|
|
2836
|
+
for (const path of map.paths) {
|
|
2837
|
+
drawPolyline(png, path.points, dim, scale, pal.path, Math.max(1, scale));
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
if (opts.showObstacles !== false) {
|
|
2841
|
+
for (const ob of map.obstacles) {
|
|
2842
|
+
const p = worldToPx(ob.x, ob.y, dim, scale);
|
|
2843
|
+
drawDisk(png, p.x, p.y, Math.max(2, scale * 2), pal.obstacle);
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
if (opts.showCharger !== false && map.dock !== null) {
|
|
2847
|
+
drawCharger(png, map.dock, dim, scale, pal);
|
|
2848
|
+
}
|
|
2849
|
+
if (opts.showRobot !== false && map.robot !== null) {
|
|
2850
|
+
drawRobot(png, map.robot, dim, scale, pal);
|
|
2851
|
+
}
|
|
2852
|
+
if (opts.showSegmentLabels === true) {
|
|
2853
|
+
for (const seg of map.segments) {
|
|
2854
|
+
const p = worldToPx(seg.centroid.x, seg.centroid.y, dim, scale);
|
|
2855
|
+
drawLabel(png, p.x, p.y, String(seg.id), pal.label, Math.max(1, scale));
|
|
2856
|
+
}
|
|
2714
2857
|
}
|
|
2715
2858
|
return import_pngjs.PNG.sync.write(png);
|
|
2716
2859
|
}
|
|
2717
|
-
function
|
|
2718
|
-
|
|
2860
|
+
function worldToPx(worldX, worldY, dim, scale) {
|
|
2861
|
+
return {
|
|
2862
|
+
x: Math.round((worldX - dim.left) / dim.gridSize * scale),
|
|
2863
|
+
y: Math.round((worldY - dim.top) / dim.gridSize * scale)
|
|
2864
|
+
};
|
|
2865
|
+
}
|
|
2866
|
+
function paintLayer(png, layer, scale, pal) {
|
|
2867
|
+
const color = layer.type === "segment" ? segmentColor(layer.segmentId ?? 0, pal) : layer.type === "wall" ? pal.wall : layer.type === "carpet" ? pal.carpet : pal.floor;
|
|
2719
2868
|
for (const run of layer.runs) {
|
|
2720
|
-
paintRun(png, run, color, scale
|
|
2869
|
+
paintRun(png, run, color, scale);
|
|
2721
2870
|
}
|
|
2722
2871
|
}
|
|
2723
|
-
function paintRun(png, run, color, scale
|
|
2872
|
+
function paintRun(png, run, color, scale) {
|
|
2724
2873
|
const [xPx, yPx, len] = run;
|
|
2725
2874
|
for (let i = 0; i < len; i += 1) {
|
|
2726
2875
|
const baseX = (xPx + i) * scale;
|
|
2727
2876
|
const baseY = yPx * scale;
|
|
2728
2877
|
for (let dy = 0; dy < scale; dy += 1) {
|
|
2729
|
-
const py = baseY + dy;
|
|
2730
|
-
if (py < 0 || py >= height) {
|
|
2731
|
-
continue;
|
|
2732
|
-
}
|
|
2733
2878
|
for (let dx = 0; dx < scale; dx += 1) {
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2879
|
+
setPixel(png, baseX + dx, baseY + dy, color);
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
function setPixel(png, x, y, color) {
|
|
2885
|
+
if (x < 0 || y < 0 || x >= png.width || y >= png.height) return;
|
|
2886
|
+
const off = (y * png.width + x) * 4;
|
|
2887
|
+
const a = color[3];
|
|
2888
|
+
if (a >= 255) {
|
|
2889
|
+
png.data[off] = color[0];
|
|
2890
|
+
png.data[off + 1] = color[1];
|
|
2891
|
+
png.data[off + 2] = color[2];
|
|
2892
|
+
png.data[off + 3] = 255;
|
|
2893
|
+
return;
|
|
2894
|
+
}
|
|
2895
|
+
const sa = a / 255;
|
|
2896
|
+
const da = (png.data[off + 3] ?? 0) / 255;
|
|
2897
|
+
const outA = sa + da * (1 - sa);
|
|
2898
|
+
if (outA <= 0) return;
|
|
2899
|
+
for (let k = 0; k < 3; k += 1) {
|
|
2900
|
+
const src = color[k] ?? 0;
|
|
2901
|
+
const dst = png.data[off + k] ?? 0;
|
|
2902
|
+
png.data[off + k] = Math.round((src * sa + dst * da * (1 - sa)) / outA);
|
|
2903
|
+
}
|
|
2904
|
+
png.data[off + 3] = Math.round(outA * 255);
|
|
2905
|
+
}
|
|
2906
|
+
function fillRect(png, x0, y0, x1, y1, color) {
|
|
2907
|
+
const xa = Math.min(x0, x1);
|
|
2908
|
+
const xb = Math.max(x0, x1);
|
|
2909
|
+
const ya = Math.min(y0, y1);
|
|
2910
|
+
const yb = Math.max(y0, y1);
|
|
2911
|
+
for (let y = ya; y <= yb; y += 1) {
|
|
2912
|
+
for (let x = xa; x <= xb; x += 1) {
|
|
2913
|
+
setPixel(png, x, y, color);
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
function strokeRect(png, x0, y0, x1, y1, color) {
|
|
2918
|
+
const xa = Math.min(x0, x1);
|
|
2919
|
+
const xb = Math.max(x0, x1);
|
|
2920
|
+
const ya = Math.min(y0, y1);
|
|
2921
|
+
const yb = Math.max(y0, y1);
|
|
2922
|
+
for (let x = xa; x <= xb; x += 1) {
|
|
2923
|
+
setPixel(png, x, ya, color);
|
|
2924
|
+
setPixel(png, x, yb, color);
|
|
2925
|
+
}
|
|
2926
|
+
for (let y = ya; y <= yb; y += 1) {
|
|
2927
|
+
setPixel(png, xa, y, color);
|
|
2928
|
+
setPixel(png, xb, y, color);
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2931
|
+
function drawLine(png, x0, y0, x1, y1, color, thickness) {
|
|
2932
|
+
let x = x0;
|
|
2933
|
+
let y = y0;
|
|
2934
|
+
const dx = Math.abs(x1 - x0);
|
|
2935
|
+
const dy = -Math.abs(y1 - y0);
|
|
2936
|
+
const sx = x0 < x1 ? 1 : -1;
|
|
2937
|
+
const sy = y0 < y1 ? 1 : -1;
|
|
2938
|
+
let err = dx + dy;
|
|
2939
|
+
const r = Math.max(0, Math.trunc((thickness - 1) / 2));
|
|
2940
|
+
for (; ; ) {
|
|
2941
|
+
for (let oy = -r; oy <= r; oy += 1) {
|
|
2942
|
+
for (let ox = -r; ox <= r; ox += 1) {
|
|
2943
|
+
setPixel(png, x + ox, y + oy, color);
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2946
|
+
if (x === x1 && y === y1) break;
|
|
2947
|
+
const e2 = 2 * err;
|
|
2948
|
+
if (e2 >= dy) {
|
|
2949
|
+
err += dy;
|
|
2950
|
+
x += sx;
|
|
2951
|
+
}
|
|
2952
|
+
if (e2 <= dx) {
|
|
2953
|
+
err += dx;
|
|
2954
|
+
y += sy;
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
function drawPolyline(png, points, dim, scale, color, thickness) {
|
|
2959
|
+
for (let i = 1; i < points.length; i += 1) {
|
|
2960
|
+
const p0 = points[i - 1];
|
|
2961
|
+
const p1 = points[i];
|
|
2962
|
+
if (p0 === void 0 || p1 === void 0) continue;
|
|
2963
|
+
const a = worldToPx(p0.x, p0.y, dim, scale);
|
|
2964
|
+
const b = worldToPx(p1.x, p1.y, dim, scale);
|
|
2965
|
+
drawLine(png, a.x, a.y, b.x, b.y, color, thickness);
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
function drawDisk(png, cx, cy, r, color) {
|
|
2969
|
+
const rr = r * r;
|
|
2970
|
+
for (let dy = -r; dy <= r; dy += 1) {
|
|
2971
|
+
for (let dx = -r; dx <= r; dx += 1) {
|
|
2972
|
+
if (dx * dx + dy * dy <= rr) setPixel(png, cx + dx, cy + dy, color);
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
function drawRobot(png, robot, dim, scale, pal) {
|
|
2977
|
+
const p = worldToPx(robot.x, robot.y, dim, scale);
|
|
2978
|
+
const r = Math.max(3, scale * 3);
|
|
2979
|
+
drawDisk(png, p.x, p.y, r, pal.robotBody);
|
|
2980
|
+
const rad = robot.angle * Math.PI / 180;
|
|
2981
|
+
const hx = Math.round(p.x + Math.cos(rad) * r);
|
|
2982
|
+
const hy = Math.round(p.y + Math.sin(rad) * r);
|
|
2983
|
+
drawLine(png, p.x, p.y, hx, hy, pal.robotHeading, Math.max(1, Math.trunc(scale / 2) + 1));
|
|
2984
|
+
}
|
|
2985
|
+
function drawCharger(png, dock, dim, scale, pal) {
|
|
2986
|
+
const p = worldToPx(dock.x, dock.y, dim, scale);
|
|
2987
|
+
const r = Math.max(2, scale * 2);
|
|
2988
|
+
fillRect(png, p.x - r, p.y - r, p.x + r, p.y + r, pal.charger);
|
|
2989
|
+
}
|
|
2990
|
+
var GLYPHS = {
|
|
2991
|
+
"0": [7, 5, 5, 5, 7],
|
|
2992
|
+
"1": [2, 6, 2, 2, 7],
|
|
2993
|
+
"2": [7, 1, 7, 4, 7],
|
|
2994
|
+
"3": [7, 1, 7, 1, 7],
|
|
2995
|
+
"4": [5, 5, 7, 1, 1],
|
|
2996
|
+
"5": [7, 4, 7, 1, 7],
|
|
2997
|
+
"6": [7, 4, 7, 5, 7],
|
|
2998
|
+
"7": [7, 1, 2, 2, 2],
|
|
2999
|
+
"8": [7, 5, 7, 5, 7],
|
|
3000
|
+
"9": [7, 5, 7, 1, 7],
|
|
3001
|
+
"-": [0, 0, 7, 0, 0]
|
|
3002
|
+
};
|
|
3003
|
+
function drawLabel(png, cx, cy, text, color, px) {
|
|
3004
|
+
const glyphW = 3 * px;
|
|
3005
|
+
const glyphH = 5 * px;
|
|
3006
|
+
const gap = px;
|
|
3007
|
+
const totalW = text.length * glyphW + Math.max(0, text.length - 1) * gap;
|
|
3008
|
+
let originX = Math.round(cx - totalW / 2);
|
|
3009
|
+
const originY = Math.round(cy - glyphH / 2);
|
|
3010
|
+
for (const ch of text) {
|
|
3011
|
+
const glyph = GLYPHS[ch];
|
|
3012
|
+
if (glyph !== void 0) {
|
|
3013
|
+
for (let row = 0; row < 5; row += 1) {
|
|
3014
|
+
const bits = glyph[row];
|
|
3015
|
+
if (bits === void 0) continue;
|
|
3016
|
+
for (let col = 0; col < 3; col += 1) {
|
|
3017
|
+
if ((bits & 1 << 2 - col) === 0) continue;
|
|
3018
|
+
for (let sy = 0; sy < px; sy += 1) {
|
|
3019
|
+
for (let sx = 0; sx < px; sx += 1) {
|
|
3020
|
+
setPixel(png, originX + col * px + sx, originY + row * px + sy, color);
|
|
3021
|
+
}
|
|
3022
|
+
}
|
|
2737
3023
|
}
|
|
2738
|
-
const off = (py * width + px) * 4;
|
|
2739
|
-
png.data[off] = color[0];
|
|
2740
|
-
png.data[off + 1] = color[1];
|
|
2741
|
-
png.data[off + 2] = color[2];
|
|
2742
|
-
png.data[off + 3] = color[3];
|
|
2743
3024
|
}
|
|
2744
3025
|
}
|
|
3026
|
+
originX += glyphW + gap;
|
|
2745
3027
|
}
|
|
2746
3028
|
}
|
|
2747
3029
|
|