I am making a nodeJS script that places black text in a white box on top of my input background image. I want the white box to resize it's height based on how much text input. I made a wrapText function to hopefully resize but it always returns 1 thus making the box not resize properly. Here's my current code.
const { createCanvas, loadImage } = require('canvas');
// Background image path
const backgroundImagePath = 'bg2.jpg';
// Text properties
const text = 'Sample Text\nWith multiple lines\nOf varying length';
const textColor = 'black';
const font = 'Arial';
const fontSize = 50;
const maxWidth = 1500;
// Padding properties
const paddingRatio = 0.1; // 10% padding relative to font size
const minPadding = 10;
// Output image path
const outputImagePath = 'output.jpg';
// Create canvas and context
const canvas = createCanvas(1080, 1920);
const ctx = canvas.getContext('2d');
// Load background image
loadImage(backgroundImagePath).then(image => {
// Draw background image
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
// Add white box with text in the middle
const boxWidth = Math.min(maxWidth, 0.8 * canvas.width);
const wrappedText = wrapText(ctx, text, boxWidth, fontSize);
const lineHeight = Math.min((canvas.height - 2 * minPadding) / wrappedText.lines.length, fontSize * 1.5);
const boxHeight = wrappedText.lines.length * lineHeight + 2 * minPadding;
const x = canvas.width / 2 - boxWidth / 2;
const y = canvas.height / 2 - boxHeight / 2;
ctx.fillStyle = 'white';
ctx.fillRect(x - minPadding, y - minPadding, boxWidth + 2 * minPadding, boxHeight);
ctx.font = `${fontSize}px ${font}`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = textColor;
wrappedText.lines.forEach((line, i) => {
ctx.fillText(line, x + boxWidth / 2, y + (i + 0.5) * lineHeight);
});
// Save output image
const out = require('fs').createWriteStream(outputImagePath);
const stream = canvas.createJPEGStream({ quality: 0.8 });
stream.pipe(out);
out.on('finish', () => console.log('Image created successfully'));
});
// Wrap text to fit inside a box with a given width
function wrapText(context, text, maxWidth, fontSize) {
const words = text.split(' ');
const lines = [];
let line = '';
let height = 0;
let lineWidth = 0;
const lineHeight = fontSize * 1.5;
for (let n = 0; n < words.length; n++) {
const metrics = context.measureText(words[n]);
const testWidth = metrics.width;
if (lineWidth + testWidth > maxWidth) {
lines.push(line.trim());
line = '';
lineWidth = 0;
height += lineHeight;
}
line += words[n] + ' ';
lineWidth += testWidth;
}
if (line) {
lines.push(line.trim());
height += lineHeight;
}
return { lines, height };
}
inside my wrapText function I tried to rewrite it several times and I can't get the box to resize properly.
I want the box to always remain in the center and middle of the background image. And I want it to resize based on the amount of text is input.
I used the following to do that
const lineHeight = Math.min((canvas.height - 2 * minPadding) / wrappedText.lines.length, fontSize * 1.5);
const boxHeight = wrappedText.lines.length * lineHeight + 2 * minPadding;
Here's my wrappedText function specifically
// Wrap text to fit inside a box with a given width
function wrapText(context, text, maxWidth, fontSize) {
const words = text.split(' ');
const lines = [];
let line = '';
let height = 0;
let lineWidth = 0;
const lineHeight = fontSize * 1.5;
for (let n = 0; n < words.length; n++) {
const metrics = context.measureText(words[n]);
const testWidth = metrics.width;
if (lineWidth + testWidth > maxWidth) {
lines.push(line.trim());
line = '';
lineWidth = 0;
height += lineHeight;
}
line += words[n] + ' ';
lineWidth += testWidth;
}
if (line) {
lines.push(line.trim());
height += lineHeight;
}
return { lines, height };
}