You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, plaqueText = "Петин талант", frameStyle = "wood") {
const w = originalImg.width;
const h = originalImg.height;
// Calculate dimensions dynamically relative to the image size
// For very small images, we provide a minimum base size to ensure the frame stays visible
const baseDim = Math.max(300, (w + h) / 2);
const matW = Math.max(40, baseDim * 0.12);
const frameW = Math.max(20, baseDim * 0.08);
const totalW = w + (matW + frameW) * 2;
const totalH = h + (matW + frameW) * 2;
const canvas = document.createElement('canvas');
canvas.width = totalW;
canvas.height = totalH;
const ctx = canvas.getContext('2d');
// --- 1. Draw Outer Frame Background ---
let frameColorBase, lightEdge, darkEdge;
if (frameStyle.toLowerCase() === 'gold') {
frameColorBase = '#cca73b';
lightEdge = 'rgba(255, 255, 255, 0.4)';
darkEdge = 'rgba(0, 0, 0, 0.3)';
} else if (frameStyle.toLowerCase() === 'black') {
frameColorBase = '#1a1a1a';
lightEdge = 'rgba(255, 255, 255, 0.15)';
darkEdge = 'rgba(0, 0, 0, 0.5)';
} else { // wood / default
frameColorBase = '#4a2c11';
lightEdge = 'rgba(255, 255, 255, 0.15)';
darkEdge = 'rgba(0, 0, 0, 0.5)';
}
ctx.fillStyle = frameColorBase;
ctx.fillRect(0, 0, totalW, totalH);
// Frame Top Edge (Highlight)
ctx.fillStyle = lightEdge;
ctx.beginPath();
ctx.moveTo(0, 0); ctx.lineTo(totalW, 0);
ctx.lineTo(totalW - frameW, frameW); ctx.lineTo(frameW, frameW);
ctx.fill();
// Frame Bottom Edge (Shadow)
ctx.fillStyle = darkEdge;
ctx.beginPath();
ctx.moveTo(0, totalH); ctx.lineTo(totalW, totalH);
ctx.lineTo(totalW - frameW, totalH - frameW); ctx.lineTo(frameW, totalH - frameW);
ctx.fill();
// Frame Right Edge (Subtle Shadow)
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
ctx.beginPath();
ctx.moveTo(totalW, 0); ctx.lineTo(totalW, totalH);
ctx.lineTo(totalW - frameW, totalH - frameW); ctx.lineTo(totalW - frameW, frameW);
ctx.fill();
// Frame Left Edge (Subtle Highlight)
ctx.fillStyle = 'rgba(255, 255, 255, 0.05)';
ctx.beginPath();
ctx.moveTo(0, 0); ctx.lineTo(0, totalH);
ctx.lineTo(frameW, totalH - frameW); ctx.lineTo(frameW, frameW);
ctx.fill();
// --- 2. Draw Passe-partout (Museum Mat) ---
const matX = frameW;
const matY = frameW;
const matWidth = totalW - frameW * 2;
const matHeight = totalH - frameW * 2;
ctx.fillStyle = '#faebd7'; // Antique white for the museum pass-partout
ctx.fillRect(matX, matY, matWidth, matHeight);
// Mat dark outer bevel
ctx.strokeStyle = 'rgba(0,0,0,0.5)';
ctx.lineWidth = 1;
ctx.strokeRect(matX, matY, matWidth, matHeight);
// --- 3. Draw The Masterpiece Image ---
const imgX = matX + matW;
const imgY = matY + matW;
ctx.drawImage(originalImg, imgX, imgY, w, h);
// --- 4. Inner Shadow (Sunken Frame Effect) ---
ctx.save();
ctx.beginPath();
ctx.rect(imgX, imgY, w, h);
ctx.clip(); // Restrict dropshadow effect strictly to the interior of the image box
ctx.strokeStyle = "rgba(0,0,0,1)";
ctx.lineWidth = 2; // Edge trigger width
ctx.shadowColor = "rgba(0,0,0,0.6)";
ctx.shadowBlur = matW * 0.15;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
// Draw the rect slightly outside the clipping mask so only the inner shadow bleeds inside
ctx.strokeRect(imgX - 2, imgY - 2, w + 4, h + 4);
ctx.restore();
// Inner subtle lip to transition the mat nicely to the picture
ctx.strokeStyle = "#e3d3be";
ctx.lineWidth = Math.max(1, baseDim * 0.005);
ctx.strokeRect(imgX - ctx.lineWidth/2, imgY - ctx.lineWidth/2, w + ctx.lineWidth, h + ctx.lineWidth);
// --- 5. Draw the Honorary Brass Plaque ---
const plaqueW = Math.min(matWidth * 0.7, Math.max(250, baseDim * 0.4));
const plaqueH = Math.max(30, baseDim * 0.08);
const plaqueX = totalW / 2 - plaqueW / 2;
// Position beautifully in the center of the bottom mat
const plaqueY = totalH - frameW - matW * 0.5 - plaqueH / 2;
// Plaque Brassy Gradient
const plaqueGrad = ctx.createLinearGradient(plaqueX, plaqueY, plaqueX, plaqueY + plaqueH);
plaqueGrad.addColorStop(0, '#f2d588');
plaqueGrad.addColorStop(0.5, '#d4af37');
plaqueGrad.addColorStop(1, '#aa8222');
ctx.fillStyle = plaqueGrad;
// Plaque Drop Shadow
ctx.shadowColor = 'rgba(0,0,0,0.4)';
ctx.shadowBlur = Math.max(3, baseDim * 0.005);
ctx.shadowOffsetY = Math.max(2, baseDim * 0.003);
ctx.fillRect(plaqueX, plaqueY, plaqueW, plaqueH);
// Clear Shadow Context
ctx.shadowColor = 'transparent';
ctx.shadowBlur = 0;
ctx.shadowOffsetY = 0;
// Plaque Inner Rim Border
const borderW = Math.max(1, plaqueH * 0.05);
ctx.strokeStyle = 'rgba(80, 50, 0, 0.4)';
ctx.lineWidth = borderW;
ctx.strokeRect(plaqueX + borderW*1.5, plaqueY + borderW*1.5, plaqueW - borderW*3, plaqueH - borderW*3);
// Simulated Screws Holding the Plaque
ctx.fillStyle = '#4a3307';
const screwMargin = Math.max(6, plaqueH * 0.15);
const radius = Math.max(1.5, plaqueH * 0.05);
const drawScrew = (x, y) => {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fill();
};
drawScrew(plaqueX + screwMargin, plaqueY + screwMargin);
drawScrew(plaqueX + plaqueW - screwMargin, plaqueY + screwMargin);
drawScrew(plaqueX + screwMargin, plaqueY + plaqueH - screwMargin);
drawScrew(plaqueX + plaqueW - screwMargin, plaqueY + plaqueH - screwMargin);
// Plaque Text Engraving
const fontSize = plaqueH * 0.5;
ctx.font = `italic 700 ${fontSize}px Georgia, serif`;
ctx.fillStyle = '#221a0f'; // Darkened sepia tint for text
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// Subtly bevel down the text for an engraved brass effect
ctx.shadowColor = 'rgba(255,255,255,0.4)';
ctx.shadowBlur = 0;
ctx.shadowOffsetY = 1;
// Render the text tightly bounded by the plaque width (padding for the screws)
ctx.fillText(plaqueText, totalW / 2, plaqueY + plaqueH / 2, plaqueW - screwMargin * 4);
return canvas;
}
Apply Changes