cdc4b82931
HQ 指定一张活动图为勾选主合伙人合成 PNG/zip;城市合伙人页增加快链与单下/导出。 Co-authored-by: Cursor <cursoragent@cursor.com>
65 lines
2.2 KiB
TypeScript
65 lines
2.2 KiB
TypeScript
/**
|
||
* Sequential Sharp compose bench (1 / 10 / 50) on a 1080×1920 template.
|
||
* Usage: node scripts/with-api-env.cjs npx ts-node --transpile-only scripts/bench-activity-poster-pack.ts
|
||
* or from dukang-api: npx ts-node --transpile-only scripts/bench-activity-poster-pack.ts
|
||
*/
|
||
import sharp from 'sharp';
|
||
import {
|
||
DEFAULT_ACTIVITY_POSTER_QR_SLOT,
|
||
activityPosterQrSlotPx,
|
||
activityPosterTemplateTooLarge,
|
||
} from '@dukang/shared-types';
|
||
|
||
async function png(width: number, height: number, r: number, g: number, b: number) {
|
||
return sharp({
|
||
create: { width, height, channels: 3, background: { r, g, b } },
|
||
})
|
||
.png()
|
||
.toBuffer();
|
||
}
|
||
|
||
async function compose(template: Buffer, qrPng: Buffer) {
|
||
const meta = await sharp(template).metadata();
|
||
if (!meta.width || !meta.height) throw new Error('no size');
|
||
if (activityPosterTemplateTooLarge(meta.width, meta.height)) throw new Error('too large');
|
||
const { left, top, size } = activityPosterQrSlotPx(
|
||
meta.width,
|
||
meta.height,
|
||
DEFAULT_ACTIVITY_POSTER_QR_SLOT.qrXPct,
|
||
DEFAULT_ACTIVITY_POSTER_QR_SLOT.qrYPct,
|
||
DEFAULT_ACTIVITY_POSTER_QR_SLOT.qrSizePct,
|
||
);
|
||
const qr = await sharp(qrPng).resize(size, size, { fit: 'fill' }).png().toBuffer();
|
||
return sharp(template).composite([{ input: qr, left, top }]).png().toBuffer();
|
||
}
|
||
|
||
function rssMb() {
|
||
return Math.round(process.memoryUsage().rss / 1024 / 1024);
|
||
}
|
||
|
||
async function bench(n: number, template: Buffer, qr: Buffer) {
|
||
const t0 = Date.now();
|
||
const rss0 = rssMb();
|
||
let last = 0;
|
||
for (let i = 0; i < n; i += 1) {
|
||
const out = await compose(template, qr);
|
||
last = out.length;
|
||
}
|
||
const ms = Date.now() - t0;
|
||
return { n, ms, avgMs: Math.round(ms / n), rss0, rss1: rssMb(), lastKb: Math.round(last / 1024) };
|
||
}
|
||
|
||
async function main() {
|
||
const template = await png(1080, 1920, 160, 32, 32);
|
||
const qr = await png(430, 430, 255, 255, 255);
|
||
console.log(`template=${Math.round(template.length / 1024)}KB qr=${Math.round(qr.length / 1024)}KB rss=${rssMb()}MB`);
|
||
for (const n of [1, 10, 50]) {
|
||
const row = await bench(n, template, qr);
|
||
console.log(
|
||
`n=${row.n} total=${row.ms}ms avg=${row.avgMs}ms rss ${row.rss0}->${row.rss1}MB out≈${row.lastKb}KB`,
|
||
);
|
||
}
|
||
}
|
||
|
||
void main();
|