You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
topText = "Not Responding...",
bottomText = "",
enableTrailEffect = "1",
trailCount = "8",
trailOffsetX = "30",
trailOffsetY = "30",
backgroundColor = "#ffffff",
textColor = "#000000"
) {
let workingWidth = originalImg.width;
let workingHeight = originalImg.height;
let imageSource = originalImg;
const isTrailEnabled = parseInt(enableTrailEffect, 10) === 1;
const tCount = Math.max(1, parseInt(trailCount, 10) || 8);
const tOffsetX = parseInt(trailOffsetX, 10) || 30;
const tOffsetY = parseInt(trailOffsetY, 10) || 30;
// Apply the "Not Responding" cascade / trailing visual effect
if (isTrailEnabled) {
const trailCanvas = document.createElement('canvas');
const tCtx = trailCanvas.getContext('2d');
const totalTrailShiftX = tOffsetX * tCount;
const totalTrailShiftY = tOffsetY * tCount;
trailCanvas.width = workingWidth + Math.abs(totalTrailShiftX);
trailCanvas.height = workingHeight + Math.abs(totalTrailShiftY);
const startX = tOffsetX < 0 ? Math.abs(totalTrailShiftX) : 0;
const startY = tOffsetY < 0 ? Math.abs(totalTrailShiftY) : 0;
for (let i = 0; i <= tCount; i++) {
const x = startX + (i * tOffsetX);
const y = startY + (i * tOffsetY);
tCtx.drawImage(originalImg, x, y, workingWidth, workingHeight);
// The final most-forward image gets a slight white overlay to look "frozen"
if (i === tCount) {
tCtx.fillStyle = 'rgba(255, 255, 255, 0.4)';
tCtx.fillRect(x, y, workingWidth, workingHeight);
}
}
imageSource = trailCanvas;
workingWidth = trailCanvas.width;
workingHeight = trailCanvas.height;
}
const finalCanvas = document.createElement('canvas');
const fCtx = finalCanvas.getContext('2d');
const fontSize = Math.max(16, Math.floor(workingWidth * 0.04));
const fontFamily = '"Segoe UI", Roboto, Helvetica, Arial, sans-serif';
fCtx.font = `bold ${fontSize}px ${fontFamily}`;
// Helper to wrap standard responsive/reaction text
const wrapText = (ctx, text, maxWidth) => {
if (!text) return [];
const words = text.split(' ');
let lines = [];
let line = '';
for (let i = 0; i < words.length; i++) {
let testLine = line + words[i] + ' ';
let metrics = ctx.measureText(testLine);
if (metrics.width > maxWidth && i > 0) {
lines.push(line.trim());
line = words[i] + ' ';
} else {
line = testLine;
}
}
lines.push(line.trim());
return lines;
};
const textPadding = fontSize * 0.8;
const topLines = wrapText(fCtx, topText, workingWidth - (textPadding * 2));
const bottomLines = wrapText(fCtx, bottomText, workingWidth - (textPadding * 2));
const topPaddedHeight = topLines.length > 0 ? (topLines.length * fontSize * 1.3) + (textPadding * 2) : 0;
const bottomPaddedHeight = bottomLines.length > 0 ? (bottomLines.length * fontSize * 1.3) + (textPadding * 2) : 0;
finalCanvas.width = workingWidth;
finalCanvas.height = workingHeight + topPaddedHeight + bottomPaddedHeight;
// Draw background
fCtx.fillStyle = backgroundColor;
fCtx.fillRect(0, 0, finalCanvas.width, finalCanvas.height);
// Draw generated image inside the reaction text frame
fCtx.drawImage(imageSource, 0, topPaddedHeight);
// Render Text
const drawTextLines = (lines, startY) => {
fCtx.fillStyle = textColor;
fCtx.font = `bold ${fontSize}px ${fontFamily}`;
fCtx.textAlign = 'center';
fCtx.textBaseline = 'top';
lines.forEach((line, index) => {
const y = startY + (index * fontSize * 1.3) + textPadding;
fCtx.fillText(line, finalCanvas.width / 2, y);
});
};
if (topLines.length > 0) {
drawTextLines(topLines, 0);
}
if (bottomLines.length > 0) {
drawTextLines(bottomLines, finalCanvas.height - bottomPaddedHeight);
}
return finalCanvas;
}
Apply Changes