remote-rdr / utils /bubble /bg-utils.js
shiveshnavin's picture
Bubble text
bdadca1
import sharp from 'sharp';
import fs from 'fs';
import { tempPath, escapeXml } from './helpers.js';
// Accept positional args for compatibility with Bubble.js caller
export async function createTextBackgroundPng(text, fontSize=40, fontName='Arial', boxColor='#ffffff', boxBorderW=0, paddingX=20, paddingY=8, radius=10, fontColor='#000000'){
// estimate size and create an SVG with rounded rect only (text is drawn by ffmpeg drawtext to ensure crisp font)
const paddingXPx = Math.round(paddingX || 20);
const paddingYPx = Math.round(paddingY || 8);
const safeText = (text == null) ? '' : String(text);
const estimatedWidth = Math.max(60, Math.round((fontSize || 40) * Math.max(1, safeText.length) * 0.6) + paddingXPx * 2);
const estimatedHeight = Math.max(24, Math.round((fontSize || 40) * 1.4) + paddingYPx * 2);
const rx = Math.max(0, Math.round(radius || 0));
const svg = `<?xml version="1.0" encoding="utf-8"?>\n<svg xmlns='http://www.w3.org/2000/svg' width='${estimatedWidth}' height='${estimatedHeight}'>\n <rect x='0' y='0' width='100%' height='100%' rx='${rx}' ry='${rx}' fill='${boxColor || '#ffffff'}' stroke='none' />\n</svg>`;
const tmp = tempPath('text-bg','png');
await sharp(Buffer.from(svg)).png().toFile(tmp);
const meta = await sharp(tmp).metadata();
return { path: tmp, width: meta.width, height: meta.height };
}
// Accept positional args for compatibility
export async function processImageWithBg(srcPath, width, height, backgroundColor=null, radius=0){
const tmp = tempPath('img-out','png');
const rx = Math.max(0, Math.round(radius || 0));
let img = sharp(srcPath).resize(width, height, { fit: 'cover', position: 'centre' });
const overlayBuf = await img.png().toBuffer();
if (rx > 0) {
const maskSvg = `<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}"><rect x="0" y="0" rx="${rx}" ry="${rx}" width="${width}" height="${height}" fill="#fff"/></svg>`;
const rounded = await sharp(overlayBuf).composite([{ input: Buffer.from(maskSvg), blend: 'dest-in' }]).png().toBuffer();
if (backgroundColor) {
const bg = sharp({ create: { width, height, channels: 4, background: backgroundColor } }).png();
const out = tempPath('img-composite','png');
await bg.composite([{ input: rounded, gravity: 'centre' }]).png().toFile(out);
return out;
}
await sharp(rounded).png().toFile(tmp);
return tmp;
}
if (backgroundColor) {
const bg = sharp({ create: { width, height, channels: 4, background: backgroundColor } }).png();
const out = tempPath('img-composite','png');
await bg.composite([{ input: overlayBuf, gravity: 'centre' }]).png().toFile(out);
return out;
}
await sharp(overlayBuf).png().toFile(tmp);
return tmp;
}