You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, theme = "mac", url = "https://www.example.com", padding = 40, bgColor = "#e0e5ec", headerColor = "#f1f5f9") {
const pad = Number(padding);
const w = originalImg.width;
const h = originalImg.height;
const headerHeight = 50;
const radius = 10;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Setting canvas dimensions adding padding and header
canvas.width = w + pad * 2;
canvas.height = h + headerHeight + pad * 2;
// 1. Draw outer background
ctx.fillStyle = String(bgColor);
ctx.fillRect(0, 0, canvas.width, canvas.height);
const winX = pad;
const winY = pad;
const winW = w;
const winH = h + headerHeight;
// 2. Setup shadow for browser window
ctx.shadowColor = 'rgba(0, 0, 0, 0.2)';
ctx.shadowBlur = 20;
ctx.shadowOffsetY = 10;
ctx.shadowOffsetX = 0;
// Main window boundary path builder
const drawWindowPath = () => {
ctx.beginPath();
ctx.moveTo(winX + radius, winY);
ctx.lineTo(winX + winW - radius, winY);
ctx.quadraticCurveTo(winX + winW, winY, winX + winW, winY + radius);
ctx.lineTo(winX + winW, winY + winH - radius);
ctx.quadraticCurveTo(winX + winW, winY + winH, winX + winW - radius, winY + winH);
ctx.lineTo(winX + radius, winY + winH);
ctx.quadraticCurveTo(winX, winY + winH, winX, winY + winH - radius);
ctx.lineTo(winX, winY + radius);
ctx.quadraticCurveTo(winX, winY, winX + radius, winY);
ctx.closePath();
};
// Draw main window background to apply shadow
drawWindowPath();
ctx.fillStyle = '#ffffff';
ctx.fill();
// Reset shadow for internal rendering
ctx.shadowColor = 'transparent';
ctx.shadowBlur = 0;
ctx.shadowOffsetY = 0;
ctx.shadowOffsetX = 0;
// Clip rendering inside the browser window
ctx.save();
drawWindowPath();
ctx.clip();
// Draw internal white background (useful for transparent images)
ctx.fillStyle = '#ffffff';
ctx.fillRect(winX, winY, winW, winH);
// 3. Draw browser header
ctx.fillStyle = String(headerColor);
ctx.fillRect(winX, winY, winW, headerHeight);
// Separator line underneath the header
ctx.strokeStyle = '#e2e8f0';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(winX, winY + headerHeight);
ctx.lineTo(winX + winW, winY + headerHeight);
ctx.stroke();
// 4. Draw Window Controls (Mac/Windows)
if (String(theme).toLowerCase() === 'windows') {
// Windows style controls (Top-Right)
ctx.strokeStyle = '#475569';
ctx.lineWidth = 1.2;
// Close (X)
const closeX = winX + winW - 24;
const btnY = winY + headerHeight / 2;
ctx.beginPath();
ctx.moveTo(closeX - 5, btnY - 5);
ctx.lineTo(closeX + 5, btnY + 5);
ctx.moveTo(closeX + 5, btnY - 5);
ctx.lineTo(closeX - 5, btnY + 5);
ctx.stroke();
// Maximize (Square)
ctx.strokeRect(winX + winW - 55, btnY - 4.5, 9, 9);
// Minimize (Line)
ctx.beginPath();
ctx.moveTo(winX + winW - 85, btnY + 1);
ctx.lineTo(winX + winW - 75, btnY + 1);
ctx.stroke();
} else {
// Mac style controls (Top-Left)
const colors = ['#FF605C', '#FFBD44', '#00CA4E'];
colors.forEach((c, i) => {
ctx.beginPath();
ctx.arc(winX + 20 + i * 18, winY + headerHeight / 2, 5.5, 0, Math.PI * 2);
ctx.fillStyle = c;
ctx.fill();
});
}
// 5. Draw URL Bar
// Calculate URL bar width dynamically based on window width
let urlW = winW * 0.5;
if (urlW > 400) urlW = 400;
if (winW - urlW < 160) urlW = Math.max(30, winW - 160);
if (urlW > 40) {
const urlH = 26;
const urlX = winX + (winW - urlW) / 2;
const urlY = winY + (headerHeight - urlH) / 2;
const urlRadius = 4;
// URL Box Background
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.moveTo(urlX + urlRadius, urlY);
ctx.lineTo(urlX + urlW - urlRadius, urlY);
ctx.quadraticCurveTo(urlX + urlW, urlY, urlX + urlW, urlY + urlRadius);
ctx.lineTo(urlX + urlW, urlY + urlH - urlRadius);
ctx.quadraticCurveTo(urlX + urlW, urlY + urlH, urlX + urlW - urlRadius, urlY + urlH);
ctx.lineTo(urlX + urlRadius, urlY + urlH);
ctx.quadraticCurveTo(urlX, urlY + urlH, urlX, urlY + urlH - urlRadius);
ctx.lineTo(urlX, urlY + urlRadius);
ctx.quadraticCurveTo(urlX, urlY, urlX + urlRadius, urlY);
ctx.closePath();
ctx.fill();
// URL Box Stroke
ctx.strokeStyle = '#cbd5e1';
ctx.lineWidth = 1;
ctx.stroke();
// Lock Icon
if (urlW > 100) {
ctx.strokeStyle = '#64748b';
ctx.lineWidth = 1.2;
const lockX = urlX + 16;
const lockY = urlY + urlH / 2 + 2;
ctx.strokeRect(lockX - 4, lockY - 2.5, 8, 5.5);
ctx.beginPath();
ctx.arc(lockX, lockY - 2.5, 2.5, Math.PI, 0);
ctx.stroke();
}
// URL Text Mapping
ctx.fillStyle = '#475569';
ctx.font = '12px "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// Overflow and string truncation check
let displayUrl = String(url);
let textMaxW = urlW - 40;
let pUrl = displayUrl;
while(ctx.measureText(pUrl).width > textMaxW && pUrl.length > 3) {
pUrl = pUrl.slice(0, -1);
}
if(pUrl !== displayUrl) pUrl += '...';
const textOffsetX = urlW > 100 ? 5 : 0;
ctx.fillText(pUrl, urlX + urlW / 2 + textOffsetX, urlY + urlH / 2 + 1);
}
// 6. Draw original photo
ctx.drawImage(originalImg, winX, winY + headerHeight, w, h);
// End Clipping
ctx.restore();
// 7. Add a subtle border overlay to crisp the edges of the window
drawWindowPath();
ctx.strokeStyle = 'rgba(0, 0, 0, 0.1)';
ctx.lineWidth = 1;
ctx.stroke();
return canvas;
}
Apply Changes