Vendor OpenClaw source as Adolf fork baseline
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11), free to diverge. Tree copied sans upstream .git; upstream remote added for future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19. Preserves docs/ARCHITECTURE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
This commit is contained in:
461
test/helpers/live-image-probe.ts
Normal file
461
test/helpers/live-image-probe.ts
Normal file
@@ -0,0 +1,461 @@
|
||||
// Live image probe helpers build tiny image fixtures for live provider tests.
|
||||
import { encodePngRgba, fillPixel } from "../../src/media/png-encode.js";
|
||||
|
||||
const GLYPH_ROWS_5X7: Record<string, number[]> = {
|
||||
"0": [0b01110, 0b10001, 0b10011, 0b10101, 0b11001, 0b10001, 0b01110],
|
||||
"1": [0b00100, 0b01100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110],
|
||||
"2": [0b01110, 0b10001, 0b00001, 0b00010, 0b00100, 0b01000, 0b11111],
|
||||
"3": [0b11110, 0b00001, 0b00001, 0b01110, 0b00001, 0b00001, 0b11110],
|
||||
"4": [0b00010, 0b00110, 0b01010, 0b10010, 0b11111, 0b00010, 0b00010],
|
||||
"5": [0b11111, 0b10000, 0b11110, 0b00001, 0b00001, 0b10001, 0b01110],
|
||||
"6": [0b00110, 0b01000, 0b10000, 0b11110, 0b10001, 0b10001, 0b01110],
|
||||
"7": [0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b01000, 0b01000],
|
||||
"8": [0b01110, 0b10001, 0b10001, 0b01110, 0b10001, 0b10001, 0b01110],
|
||||
"9": [0b01110, 0b10001, 0b10001, 0b01111, 0b00001, 0b00010, 0b01100],
|
||||
|
||||
A: [0b01110, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001],
|
||||
B: [0b11110, 0b10001, 0b10001, 0b11110, 0b10001, 0b10001, 0b11110],
|
||||
C: [0b01110, 0b10001, 0b10000, 0b10000, 0b10000, 0b10001, 0b01110],
|
||||
D: [0b11110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b11110],
|
||||
E: [0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b11111],
|
||||
F: [0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b10000],
|
||||
T: [0b11111, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100],
|
||||
};
|
||||
|
||||
function drawGlyph5x7(params: {
|
||||
buf: Buffer;
|
||||
width: number;
|
||||
x: number;
|
||||
y: number;
|
||||
char: string;
|
||||
scale: number;
|
||||
color: { r: number; g: number; b: number; a?: number };
|
||||
}) {
|
||||
const rows = GLYPH_ROWS_5X7[params.char];
|
||||
if (!rows) {
|
||||
return;
|
||||
}
|
||||
for (let row = 0; row < 7; row += 1) {
|
||||
const bits = rows[row] ?? 0;
|
||||
for (let col = 0; col < 5; col += 1) {
|
||||
const on = (bits & (1 << (4 - col))) !== 0;
|
||||
if (!on) {
|
||||
continue;
|
||||
}
|
||||
for (let dy = 0; dy < params.scale; dy += 1) {
|
||||
for (let dx = 0; dx < params.scale; dx += 1) {
|
||||
fillPixel(
|
||||
params.buf,
|
||||
params.x + col * params.scale + dx,
|
||||
params.y + row * params.scale + dy,
|
||||
params.width,
|
||||
params.color.r,
|
||||
params.color.g,
|
||||
params.color.b,
|
||||
params.color.a ?? 255,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawText(params: {
|
||||
buf: Buffer;
|
||||
width: number;
|
||||
x: number;
|
||||
y: number;
|
||||
text: string;
|
||||
scale: number;
|
||||
color: { r: number; g: number; b: number; a?: number };
|
||||
}) {
|
||||
const text = params.text.toUpperCase();
|
||||
let cursorX = params.x;
|
||||
for (const raw of text) {
|
||||
const ch = raw in GLYPH_ROWS_5X7 ? raw : raw.toUpperCase();
|
||||
drawGlyph5x7({
|
||||
buf: params.buf,
|
||||
width: params.width,
|
||||
x: cursorX,
|
||||
y: params.y,
|
||||
char: ch,
|
||||
scale: params.scale,
|
||||
color: params.color,
|
||||
});
|
||||
cursorX += 6 * params.scale;
|
||||
}
|
||||
}
|
||||
|
||||
function measureTextWidthPx(text: string, scale: number) {
|
||||
return text.length * 6 * scale - scale; // 5px glyph + 1px space
|
||||
}
|
||||
|
||||
export function renderBitmapTextPngBase64(
|
||||
text: string,
|
||||
options: {
|
||||
background?: { r: number; g: number; b: number; a?: number };
|
||||
foreground?: { r: number; g: number; b: number; a?: number };
|
||||
padding?: number;
|
||||
scale?: number;
|
||||
} = {},
|
||||
): string {
|
||||
const normalized = text.trim().toUpperCase();
|
||||
if (!normalized) {
|
||||
throw new Error("bitmap text image requires non-empty text");
|
||||
}
|
||||
const unsupported = Array.from(normalized).filter((ch) => !(ch in GLYPH_ROWS_5X7));
|
||||
if (unsupported.length > 0) {
|
||||
throw new Error(`bitmap text image contains unsupported glyphs: ${unsupported.join(",")}`);
|
||||
}
|
||||
const scale = Math.max(1, Math.floor(options.scale ?? 4));
|
||||
const padding = Math.max(0, Math.floor(options.padding ?? 8));
|
||||
const width = measureTextWidthPx(normalized, scale) + padding * 2;
|
||||
const height = 7 * scale + padding * 2;
|
||||
const background = options.background ?? { r: 245, g: 247, b: 250, a: 255 };
|
||||
const foreground = options.foreground ?? { r: 18, g: 24, b: 33, a: 255 };
|
||||
const buf = Buffer.alloc(width * height * 4);
|
||||
fillRect({
|
||||
buf,
|
||||
width,
|
||||
height,
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: width,
|
||||
h: height,
|
||||
color: background,
|
||||
});
|
||||
drawText({
|
||||
buf,
|
||||
width,
|
||||
x: padding,
|
||||
y: padding,
|
||||
text: normalized,
|
||||
scale,
|
||||
color: foreground,
|
||||
});
|
||||
return encodePngRgba(buf, width, height).toString("base64");
|
||||
}
|
||||
|
||||
function fillRect(params: {
|
||||
buf: Buffer;
|
||||
width: number;
|
||||
height: number;
|
||||
x: number;
|
||||
y: number;
|
||||
w: number;
|
||||
h: number;
|
||||
color: { r: number; g: number; b: number; a?: number };
|
||||
}) {
|
||||
const startX = Math.max(0, params.x);
|
||||
const startY = Math.max(0, params.y);
|
||||
const endX = Math.min(params.width, params.x + params.w);
|
||||
const endY = Math.min(params.height, params.y + params.h);
|
||||
for (let y = startY; y < endY; y += 1) {
|
||||
for (let x = startX; x < endX; x += 1) {
|
||||
fillPixel(
|
||||
params.buf,
|
||||
x,
|
||||
y,
|
||||
params.width,
|
||||
params.color.r,
|
||||
params.color.g,
|
||||
params.color.b,
|
||||
params.color.a ?? 255,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fillEllipse(params: {
|
||||
buf: Buffer;
|
||||
width: number;
|
||||
height: number;
|
||||
cx: number;
|
||||
cy: number;
|
||||
rx: number;
|
||||
ry: number;
|
||||
color: { r: number; g: number; b: number; a?: number };
|
||||
}) {
|
||||
for (
|
||||
let y = Math.max(0, params.cy - params.ry);
|
||||
y <= Math.min(params.height - 1, params.cy + params.ry);
|
||||
y += 1
|
||||
) {
|
||||
for (
|
||||
let x = Math.max(0, params.cx - params.rx);
|
||||
x <= Math.min(params.width - 1, params.cx + params.rx);
|
||||
x += 1
|
||||
) {
|
||||
const dx = (x - params.cx) / params.rx;
|
||||
const dy = (y - params.cy) / params.ry;
|
||||
if (dx * dx + dy * dy <= 1) {
|
||||
fillPixel(
|
||||
params.buf,
|
||||
x,
|
||||
y,
|
||||
params.width,
|
||||
params.color.r,
|
||||
params.color.g,
|
||||
params.color.b,
|
||||
params.color.a ?? 255,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fillTriangle(params: {
|
||||
buf: Buffer;
|
||||
width: number;
|
||||
height: number;
|
||||
a: { x: number; y: number };
|
||||
b: { x: number; y: number };
|
||||
c: { x: number; y: number };
|
||||
color: { r: number; g: number; b: number; a?: number };
|
||||
}) {
|
||||
const minX = Math.max(0, Math.min(params.a.x, params.b.x, params.c.x));
|
||||
const maxX = Math.min(params.width - 1, Math.max(params.a.x, params.b.x, params.c.x));
|
||||
const minY = Math.max(0, Math.min(params.a.y, params.b.y, params.c.y));
|
||||
const maxY = Math.min(params.height - 1, Math.max(params.a.y, params.b.y, params.c.y));
|
||||
const area =
|
||||
(params.b.x - params.a.x) * (params.c.y - params.a.y) -
|
||||
(params.b.y - params.a.y) * (params.c.x - params.a.x);
|
||||
if (area === 0) {
|
||||
return;
|
||||
}
|
||||
for (let y = minY; y <= maxY; y += 1) {
|
||||
for (let x = minX; x <= maxX; x += 1) {
|
||||
const w0 =
|
||||
(params.b.x - params.a.x) * (y - params.a.y) - (params.b.y - params.a.y) * (x - params.a.x);
|
||||
const w1 =
|
||||
(params.c.x - params.b.x) * (y - params.b.y) - (params.c.y - params.b.y) * (x - params.b.x);
|
||||
const w2 =
|
||||
(params.a.x - params.c.x) * (y - params.c.y) - (params.a.y - params.c.y) * (x - params.c.x);
|
||||
if ((w0 <= 0 && w1 <= 0 && w2 <= 0) || (w0 >= 0 && w1 >= 0 && w2 >= 0)) {
|
||||
fillPixel(
|
||||
params.buf,
|
||||
x,
|
||||
y,
|
||||
params.width,
|
||||
params.color.r,
|
||||
params.color.g,
|
||||
params.color.b,
|
||||
params.color.a ?? 255,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawBlockCatLabel(params: {
|
||||
buf: Buffer;
|
||||
width: number;
|
||||
height: number;
|
||||
x: number;
|
||||
y: number;
|
||||
color: { r: number; g: number; b: number; a?: number };
|
||||
}) {
|
||||
const t = 12;
|
||||
const h = 78;
|
||||
const w = 58;
|
||||
const gap = 20;
|
||||
const cX = params.x;
|
||||
const aX = cX + w + gap;
|
||||
const tX = aX + w + gap;
|
||||
|
||||
fillRect({ ...params, x: cX, y: params.y, w, h: t, color: params.color });
|
||||
fillRect({ ...params, x: cX, y: params.y, w: t, h, color: params.color });
|
||||
fillRect({ ...params, x: cX, y: params.y + h - t, w, h: t, color: params.color });
|
||||
|
||||
fillRect({ ...params, x: aX, y: params.y, w, h: t, color: params.color });
|
||||
fillRect({ ...params, x: aX, y: params.y, w: t, h, color: params.color });
|
||||
fillRect({ ...params, x: aX + w - t, y: params.y, w: t, h, color: params.color });
|
||||
fillRect({
|
||||
...params,
|
||||
x: aX,
|
||||
y: params.y + Math.floor((h - t) / 2),
|
||||
w,
|
||||
h: t,
|
||||
color: params.color,
|
||||
});
|
||||
|
||||
fillRect({ ...params, x: tX, y: params.y, w, h: t, color: params.color });
|
||||
fillRect({
|
||||
...params,
|
||||
x: tX + Math.floor((w - t) / 2),
|
||||
y: params.y,
|
||||
w: t,
|
||||
h,
|
||||
color: params.color,
|
||||
});
|
||||
}
|
||||
|
||||
export function renderCatNoncePngBase64(nonce: string): string {
|
||||
const top = "CAT";
|
||||
const bottom = nonce.toUpperCase();
|
||||
|
||||
const scale = 12;
|
||||
const pad = 18;
|
||||
const gap = 18;
|
||||
|
||||
const topWidth = measureTextWidthPx(top, scale);
|
||||
const bottomWidth = measureTextWidthPx(bottom, scale);
|
||||
const width = Math.max(topWidth, bottomWidth) + pad * 2;
|
||||
const height = pad * 2 + 7 * scale + gap + 7 * scale;
|
||||
|
||||
const buf = Buffer.alloc(width * height * 4, 255);
|
||||
const black = { r: 0, g: 0, b: 0 };
|
||||
|
||||
drawText({
|
||||
buf,
|
||||
width,
|
||||
x: Math.floor((width - topWidth) / 2),
|
||||
y: pad,
|
||||
text: top,
|
||||
scale,
|
||||
color: black,
|
||||
});
|
||||
|
||||
drawText({
|
||||
buf,
|
||||
width,
|
||||
x: Math.floor((width - bottomWidth) / 2),
|
||||
y: pad + 7 * scale + gap,
|
||||
text: bottom,
|
||||
scale,
|
||||
color: black,
|
||||
});
|
||||
|
||||
const png = encodePngRgba(buf, width, height);
|
||||
return png.toString("base64");
|
||||
}
|
||||
|
||||
export function renderSolidColorPngBase64(color: { r: number; g: number; b: number }): string {
|
||||
const width = 192;
|
||||
const height = 192;
|
||||
const buf = Buffer.alloc(width * height * 4, 255);
|
||||
fillRect({
|
||||
buf,
|
||||
width,
|
||||
height,
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: width,
|
||||
h: height,
|
||||
color,
|
||||
});
|
||||
const png = encodePngRgba(buf, width, height);
|
||||
return png.toString("base64");
|
||||
}
|
||||
|
||||
export function renderCatFacePngBase64(): string {
|
||||
const width = 256;
|
||||
const height = 288;
|
||||
const buf = Buffer.alloc(width * height * 4, 255);
|
||||
const outline = { r: 40, g: 40, b: 40 };
|
||||
const innerEar = { r: 245, g: 182, b: 193 };
|
||||
const nose = { r: 222, g: 102, b: 138 };
|
||||
const whisker = { r: 30, g: 30, b: 30 };
|
||||
|
||||
fillTriangle({
|
||||
buf,
|
||||
width,
|
||||
height,
|
||||
a: { x: 62, y: 74 },
|
||||
b: { x: 106, y: 12 },
|
||||
c: { x: 134, y: 88 },
|
||||
color: outline,
|
||||
});
|
||||
fillTriangle({
|
||||
buf,
|
||||
width,
|
||||
height,
|
||||
a: { x: 194, y: 74 },
|
||||
b: { x: 150, y: 12 },
|
||||
c: { x: 122, y: 88 },
|
||||
color: outline,
|
||||
});
|
||||
fillTriangle({
|
||||
buf,
|
||||
width,
|
||||
height,
|
||||
a: { x: 80, y: 70 },
|
||||
b: { x: 106, y: 34 },
|
||||
c: { x: 122, y: 80 },
|
||||
color: innerEar,
|
||||
});
|
||||
fillTriangle({
|
||||
buf,
|
||||
width,
|
||||
height,
|
||||
a: { x: 176, y: 70 },
|
||||
b: { x: 150, y: 34 },
|
||||
c: { x: 134, y: 80 },
|
||||
color: innerEar,
|
||||
});
|
||||
fillEllipse({
|
||||
buf,
|
||||
width,
|
||||
height,
|
||||
cx: 128,
|
||||
cy: 112,
|
||||
rx: 78,
|
||||
ry: 66,
|
||||
color: outline,
|
||||
});
|
||||
fillEllipse({
|
||||
buf,
|
||||
width,
|
||||
height,
|
||||
cx: 98,
|
||||
cy: 100,
|
||||
rx: 9,
|
||||
ry: 12,
|
||||
color: { r: 255, g: 255, b: 255 },
|
||||
});
|
||||
fillEllipse({
|
||||
buf,
|
||||
width,
|
||||
height,
|
||||
cx: 158,
|
||||
cy: 100,
|
||||
rx: 9,
|
||||
ry: 12,
|
||||
color: { r: 255, g: 255, b: 255 },
|
||||
});
|
||||
fillEllipse({
|
||||
buf,
|
||||
width,
|
||||
height,
|
||||
cx: 128,
|
||||
cy: 130,
|
||||
rx: 22,
|
||||
ry: 17,
|
||||
color: { r: 255, g: 255, b: 255 },
|
||||
});
|
||||
fillTriangle({
|
||||
buf,
|
||||
width,
|
||||
height,
|
||||
a: { x: 128, y: 122 },
|
||||
b: { x: 118, y: 136 },
|
||||
c: { x: 138, y: 136 },
|
||||
color: nose,
|
||||
});
|
||||
fillRect({ buf, width, height, x: 127, y: 136, w: 2, h: 15, color: whisker });
|
||||
fillRect({ buf, width, height, x: 74, y: 134, w: 42, h: 2, color: whisker });
|
||||
fillRect({ buf, width, height, x: 140, y: 134, w: 42, h: 2, color: whisker });
|
||||
fillRect({ buf, width, height, x: 80, y: 146, w: 34, h: 2, color: whisker });
|
||||
fillRect({ buf, width, height, x: 142, y: 146, w: 34, h: 2, color: whisker });
|
||||
drawBlockCatLabel({
|
||||
buf,
|
||||
width,
|
||||
height,
|
||||
x: 21,
|
||||
y: 190,
|
||||
color: outline,
|
||||
});
|
||||
|
||||
const png = encodePngRgba(buf, width, height);
|
||||
return png.toString("base64");
|
||||
}
|
||||
Reference in New Issue
Block a user