You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, address = "https://www.example.com", theme = "light", padding = 40) {
// Determine numeric padding, defaulting to 40
padding = Number(padding);
if (isNaN(padding) || padding < 0) padding = 40;
let imgW = originalImg.width;
let imgH = originalImg.height;
// Set a minimum width for the browser window so that the address bar doesn't break
const MIN_WIDTH = 450;
if (imgW < MIN_WIDTH) {
const ratio = MIN_WIDTH / imgW;
imgW = MIN_WIDTH;
imgH = imgH * ratio;
}
const width = imgW;
// Scale header height beautifully depending on window width
const headerHeight = Math.max(40, width * 0.06);
const cornerRadius = headerHeight * 0.2;
const canvas = document.createElement("canvas");
canvas.width = width + padding * 2;
canvas.height = imgH + headerHeight + padding * 2;
const ctx = canvas.getContext("2d");
const winX = padding;
const winY = padding;
// Theme Variables
const isDark = (theme || "light").trim().toLowerCase() === "dark";
const headerBg = isDark ? "#2d2d2d" : "#efefef";
const barBg = isDark ? "#1a1a1a" : "#ffffff";
const textColor = isDark ? "#cccccc" : "#333333";
const winBg = isDark ? "#1e1e1e" : "#ffffff";
/**
* Helper to trace a rounded rectangle path
*/
function drawRoundRect(x, y, w, h, r) {
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.lineTo(x + w - r, y);
ctx.arcTo(x + w, y, x + w, y + r, r);
ctx.lineTo(x + w, y + h - r);
ctx.arcTo(x + w, y + h, x + w - r, y + h, r);
ctx.lineTo(x + r, y + h);
ctx.arcTo(x, y + h, x, y + h - r, r);
ctx.lineTo(x, y + r);
ctx.arcTo(x, y, x + r, y, r);
ctx.closePath();
}
// 1. Draw smooth drop shadow if there is padding available
if (padding > 0) {
ctx.shadowColor = "rgba(0, 0, 0, 0.25)";
ctx.shadowBlur = padding * 0.6;
ctx.shadowOffsetY = padding * 0.25;
}
// Base background shape (creates the shadow)
drawRoundRect(winX, winY, width, imgH + headerHeight, cornerRadius);
ctx.fillStyle = winBg;
ctx.fill();
// Remove shadow for inner elements
ctx.shadowColor = "transparent";
ctx.shadowBlur = 0;
ctx.shadowOffsetY = 0;
// 2. Set clipping mask to ensure elements (like originalImg) don't bleed out of the rounded viewport
ctx.save();
drawRoundRect(winX, winY, width, imgH + headerHeight, cornerRadius);
ctx.clip();
// 3. Draw fallback window background (solves issues with transparent images)
ctx.fillStyle = winBg;
ctx.fillRect(winX, winY + headerHeight, width, imgH);
// 4. Draw Browser Interface Header
ctx.fillStyle = headerBg;
ctx.fillRect(winX, winY, width, headerHeight);
// 5. Draw Mac-style Window Controls (Dots)
const dotRadius = headerHeight * 0.15;
const dotSpacing = dotRadius * 2.5;
const startX = winX + headerHeight * 0.35;
const dotY = winY + headerHeight / 2;
const dotColors = ["#ff5f56", "#ffbd2e", "#27c93f"];
dotColors.forEach((color, i) => {
ctx.beginPath();
ctx.arc(startX + i * dotSpacing, dotY, dotRadius, 0, Math.PI * 2);
ctx.fillStyle = color;
ctx.fill();
});
// 6. Draw URL Address Bar
const barWidth = width * 0.6;
const barHeight = headerHeight * 0.55;
const barX = winX + (width - barWidth) / 2;
const barY = winY + (headerHeight - barHeight) / 2;
const barRadius = barHeight / 2;
drawRoundRect(barX, barY, barWidth, barHeight, barRadius);
ctx.fillStyle = barBg;
ctx.fill();
// 7. Draw Web Address Text
const fontSize = barHeight * 0.5;
ctx.font = `${fontSize}px sans-serif`;
ctx.fillStyle = textColor;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
// Text truncation max width
const maxTextWidth = barWidth * 0.9;
ctx.fillText(address, barX + barWidth / 2, barY + barHeight / 2 + 1, maxTextWidth);
// 8. Composite Original Image (scaled to browser viewport)
ctx.drawImage(originalImg, winX, winY + headerHeight, width, imgH);
// Remove clipping for outer borders
ctx.restore();
// 9. Draw a subtle 1px frame border structure
ctx.lineWidth = 1;
ctx.strokeStyle = isDark ? "#4a4a4a" : "#d1d1d1";
drawRoundRect(winX, winY, width, imgH + headerHeight, cornerRadius);
ctx.stroke();
return canvas;
}
Apply Changes