You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, theme = 'classic', title = 'image.png') {
/**
* Helper function to draw a 3D-style button, characteristic of classic UI themes.
* @param {CanvasRenderingContext2D} ctx The canvas rendering context.
* @param {number} x The x-coordinate of the button's top-left corner.
* @param {number} y The y-coordinate of the button's top-left corner.
* @param {number} width The width of the button.
* @param {number} height The height of the button.
* @param {object} colors The theme colors object.
*/
const drawClassicButton = (ctx, x, y, width, height, colors) => {
ctx.fillStyle = colors.buttonFace;
ctx.fillRect(x, y, width, height);
ctx.strokeStyle = colors.buttonHighlight;
ctx.beginPath();
ctx.moveTo(x, y + height - 1);
ctx.lineTo(x, y);
ctx.lineTo(x + width - 1, y);
ctx.stroke();
ctx.strokeStyle = colors.buttonShadow;
ctx.beginPath();
ctx.moveTo(x + width - 1, y);
ctx.lineTo(x + width - 1, y + height - 1);
ctx.lineTo(x, y + height - 1);
ctx.stroke();
};
// UI layout constants
const PADDING = 4;
const BORDER_WIDTH = 2;
const TITLE_BAR_HEIGHT = 30;
const BUTTON_SIZE = 18;
const BUTTON_MARGIN_Y = (TITLE_BAR_HEIGHT - BUTTON_SIZE) / 2;
const BUTTON_MARGIN_X = 6;
// Calculate dynamic dimensions
const contentAreaWidth = originalImg.width + BORDER_WIDTH * 2;
const contentAreaHeight = originalImg.height + BORDER_WIDTH * 2;
const canvasWidth = contentAreaWidth + PADDING * 2;
const canvasHeight = contentAreaHeight + TITLE_BAR_HEIGHT + PADDING * 2;
const canvas = document.createElement('canvas');
canvas.width = canvasWidth;
canvas.height = canvasHeight;
const ctx = canvas.getContext('2d');
ctx.lineWidth = 1;
// --- Theme setup ---
let colors = {};
const safeTheme = theme.toLowerCase();
switch (safeTheme) {
case 'dark':
colors = {
background: '#3c3c3c', titleBar: '#2b2b2b', titleBarText: '#e0e0e0',
borderLight: '#4a4a4a', borderDark: '#1e1e1e', buttonClose: '#ff5f57',
buttonMinimize: '#ffbd2e', buttonMaximize: '#28c940'
};
break;
case 'mac':
colors = {
background: '#f0f0f0', titleBar: '#e8e8e8', titleBarText: '#555555',
borderLight: '#ffffff', borderDark: '#b0b0b0', buttonClose: '#ff5f57',
buttonMinimize: '#ffbd2e', buttonMaximize: '#28c940'
};
break;
case 'classic': default:
colors = {
background: '#c0c0c0', titleBar: '#000080', titleBarText: '#ffffff',
borderLight: '#ffffff', borderDark: '#808080', buttonFace: '#c0c0c0',
buttonShadow: '#404040', buttonHighlight: '#dfdfdf'
};
break;
}
// --- Drawing ---
// 1. Main background
ctx.fillStyle = colors.background;
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
// 2. Title Bar
const titleBarX = PADDING;
const titleBarY = PADDING;
const titleBarWidth = canvasWidth - PADDING * 2;
ctx.fillStyle = colors.titleBar;
ctx.fillRect(titleBarX, titleBarY, titleBarWidth, TITLE_BAR_HEIGHT);
// 3. Title Text & Buttons
ctx.fillStyle = colors.titleBarText;
ctx.font = 'bold 14px "Segoe UI", Arial, sans-serif';
ctx.textBaseline = 'middle';
const buttonsY = titleBarY + BUTTON_MARGIN_Y;
if (safeTheme === 'mac' || safeTheme === 'dark') {
ctx.textAlign = 'center';
ctx.fillText(title, titleBarX + titleBarWidth / 2, titleBarY + TITLE_BAR_HEIGHT / 2);
const btnRadius = BUTTON_SIZE / 2;
const closeX = titleBarX + BUTTON_MARGIN_X + btnRadius;
const minimizeX = closeX + BUTTON_SIZE + BUTTON_MARGIN_X;
const maximizeX = minimizeX + BUTTON_SIZE + BUTTON_MARGIN_X;
ctx.fillStyle = colors.buttonClose;
ctx.beginPath(); ctx.arc(closeX, buttonsY + btnRadius, btnRadius, 0, 2 * Math.PI); ctx.fill();
ctx.fillStyle = colors.buttonMinimize;
ctx.beginPath(); ctx.arc(minimizeX, buttonsY + btnRadius, btnRadius, 0, 2 * Math.PI); ctx.fill();
ctx.fillStyle = colors.buttonMaximize;
ctx.beginPath(); ctx.arc(maximizeX, buttonsY + btnRadius, btnRadius, 0, 2 * Math.PI); ctx.fill();
} else { // Classic theme
ctx.textAlign = 'left';
ctx.fillText(title, titleBarX + 8, titleBarY + TITLE_BAR_HEIGHT / 2);
const closeX = titleBarX + titleBarWidth - BUTTON_MARGIN_X - BUTTON_SIZE;
drawClassicButton(ctx, closeX, buttonsY, BUTTON_SIZE, BUTTON_SIZE, colors);
ctx.strokeStyle = '#000000';
ctx.lineWidth = 2;
const crossMargin = 5;
ctx.beginPath();
ctx.moveTo(closeX + crossMargin, buttonsY + crossMargin);
ctx.lineTo(closeX + BUTTON_SIZE - crossMargin, buttonsY + BUTTON_SIZE - crossMargin);
ctx.moveTo(closeX + BUTTON_SIZE - crossMargin, buttonsY + crossMargin);
ctx.lineTo(closeX + crossMargin, buttonsY + BUTTON_SIZE - crossMargin);
ctx.stroke();
}
// 4. Content Area with inset border
const contentX = PADDING;
const contentY = PADDING + TITLE_BAR_HEIGHT;
ctx.lineWidth = 1;
for (let i = 0; i < BORDER_WIDTH; i++) {
// Dark shadow on top/left
ctx.strokeStyle = colors.borderDark;
ctx.beginPath();
ctx.moveTo(contentX + i, contentY + contentAreaHeight - 1 - i);
ctx.lineTo(contentX + i, contentY + i);
ctx.lineTo(contentX + contentAreaWidth - 1 - i, contentY + i);
ctx.stroke();
// Light highlight on bottom/right
ctx.strokeStyle = colors.borderLight;
ctx.beginPath();
ctx.moveTo(contentX + contentAreaWidth - 1 - i, contentY + i);
ctx.lineTo(contentX + contentAreaWidth - 1 - i, contentY + contentAreaHeight - 1 - i);
ctx.lineTo(contentX + i, contentY + contentAreaHeight - 1 - i);
ctx.stroke();
}
// 5. The Image
const imageX = PADDING + BORDER_WIDTH;
const imageY = PADDING + TITLE_BAR_HEIGHT + BORDER_WIDTH;
ctx.drawImage(originalImg, imageX, imageY);
return canvas;
}
Apply Changes