You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, frameWidth = 50, mainGoldColor = "#DAA520", shadowAccentColor = "#8B4513", highlightAccentColor = "#FFD700") {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const imgWidth = originalImg.width;
const imgHeight = originalImg.height;
canvas.width = imgWidth + 2 * frameWidth;
canvas.height = imgHeight + 2 * frameWidth;
// Helper to darken or lighten a hex color
// factor < 1 to darken, factor > 1 to lighten
function multiplyHexColor(hex, factor) {
if (!hex || typeof hex !== 'string' || !hex.startsWith('#')) return hex; // Return original if not valid hex
let r = parseInt(hex.slice(1, 3), 16);
let g = parseInt(hex.slice(3, 5), 16);
let b = parseInt(hex.slice(5, 7), 16);
r = Math.min(255, Math.max(0, Math.round(r * factor)));
g = Math.min(255, Math.max(0, Math.round(g * factor)));
b = Math.min(255, Math.max(0, Math.round(b * factor)));
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
}
// Helper function for drawing acanthus-like ornament
function drawAcanthusElement(cx, cy, size, rotation, color) {
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(rotation);
ctx.fillStyle = color;
ctx.shadowColor = 'rgba(0,0,0,0.3)';
ctx.shadowBlur = Math.max(1, Math.floor(size * 0.08));
ctx.shadowOffsetX = Math.max(1, Math.floor(size * 0.03));
ctx.shadowOffsetY = Math.max(1, Math.floor(size * 0.03));
// Simplified acanthus scroll/leaf shape
ctx.beginPath();
ctx.moveTo(0, -size * 0.5); // Tip of the leaf
// Right side of the leaf
ctx.bezierCurveTo(size * 0.3, -size * 0.5, size * 0.4, -size * 0.25, size * 0.35, 0); // Outer curve to mid-point horizontal
ctx.bezierCurveTo(size * 0.5, size * 0.1, size * 0.2, size * 0.35, 0, size * 0.5); // Inner curve from mid-point to base center
// Left side of the leaf (mirrored)
ctx.bezierCurveTo(-size * 0.2, size * 0.35, -size * 0.5, size * 0.1, -size * 0.35, 0); // Base center to mid-point horizontal (inner)
ctx.bezierCurveTo(-size * 0.4, -size * 0.25, -size * 0.3, -size * 0.5, 0, -size * 0.5); // Mid-point horizontal to tip (outer)
ctx.closePath();
ctx.fill();
// Clear shadow for subsequent drawings
ctx.shadowColor = 'transparent';
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.restore();
}
// Proportions for frame features
const outerEdgeRatio = 0.05;
const profileRatio = 0.10;
const bevelDepthRatio = 0.20;
const outerEdgeSize = Math.max(1, Math.floor(frameWidth * outerEdgeRatio));
const profileThickness = Math.max(1, Math.floor(frameWidth * profileRatio));
const bevelDepthActual = Math.max(2, Math.floor(frameWidth * bevelDepthRatio));
// Layer 1: Outer edge/shadow
ctx.fillStyle = shadowAccentColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Layer 2: Main Frame Body
ctx.fillStyle = mainGoldColor;
ctx.fillRect(outerEdgeSize, outerEdgeSize,
canvas.width - 2 * outerEdgeSize, canvas.height - 2 * outerEdgeSize);
// Layer 2a: Highlight/Shadow on Main Frame Body for 3D profile
ctx.fillStyle = highlightAccentColor;
ctx.fillRect(outerEdgeSize, outerEdgeSize,
canvas.width - 2 * outerEdgeSize, profileThickness); // Top highlight
ctx.fillRect(outerEdgeSize, outerEdgeSize + profileThickness,
profileThickness, canvas.height - 2 * outerEdgeSize - profileThickness); // Left highlight
ctx.fillStyle = shadowAccentColor;
ctx.fillRect(outerEdgeSize + profileThickness, canvas.height - outerEdgeSize - profileThickness,
canvas.width - 2 * outerEdgeSize - profileThickness, profileThickness); // Bottom shadow
ctx.fillRect(canvas.width - outerEdgeSize - profileThickness, outerEdgeSize + profileThickness,
profileThickness, canvas.height - 2 * outerEdgeSize - profileThickness * 2); // Right shadow (adjust height to not overlap top/bottom shadows)
// Layer 3: Inner Bevel leading to the image
const bevelStartOffset = outerEdgeSize + profileThickness;
ctx.fillStyle = highlightAccentColor;
ctx.beginPath(); // Top bevel
ctx.moveTo(bevelStartOffset, bevelStartOffset);
ctx.lineTo(canvas.width - bevelStartOffset, bevelStartOffset);
ctx.lineTo(canvas.width - bevelStartOffset - bevelDepthActual, bevelStartOffset + bevelDepthActual);
ctx.lineTo(bevelStartOffset + bevelDepthActual, bevelStartOffset + bevelDepthActual);
ctx.closePath();
ctx.fill();
ctx.beginPath(); // Left bevel
ctx.moveTo(bevelStartOffset, bevelStartOffset);
ctx.lineTo(bevelStartOffset, canvas.height - bevelStartOffset);
ctx.lineTo(bevelStartOffset + bevelDepthActual, canvas.height - bevelStartOffset - bevelDepthActual);
ctx.lineTo(bevelStartOffset + bevelDepthActual, bevelStartOffset + bevelDepthActual);
ctx.closePath();
ctx.fill();
ctx.fillStyle = shadowAccentColor;
ctx.beginPath(); // Bottom bevel
ctx.moveTo(bevelStartOffset + bevelDepthActual, canvas.height - bevelStartOffset - bevelDepthActual);
ctx.lineTo(canvas.width - bevelStartOffset - bevelDepthActual, canvas.height - bevelStartOffset - bevelDepthActual);
ctx.lineTo(canvas.width - bevelStartOffset, canvas.height - bevelStartOffset);
ctx.lineTo(bevelStartOffset, canvas.height - bevelStartOffset);
ctx.closePath();
ctx.fill();
ctx.beginPath(); // Right bevel
ctx.moveTo(canvas.width - bevelStartOffset - bevelDepthActual, bevelStartOffset + bevelDepthActual);
ctx.lineTo(canvas.width - bevelStartOffset - bevelDepthActual, canvas.height - bevelStartOffset - bevelDepthActual);
ctx.lineTo(canvas.width - bevelStartOffset, canvas.height - bevelStartOffset);
ctx.lineTo(canvas.width - bevelStartOffset, bevelStartOffset);
ctx.closePath();
ctx.fill();
// Layer 4: Ornaments
const flatPartXStart = outerEdgeSize + profileThickness;
const flatBandThickness = frameWidth - (outerEdgeSize + profileThickness + bevelDepthActual);
if (flatBandThickness >= Math.max(5, frameWidth * 0.1)) {
const ornamentPlacementOffset = flatPartXStart + flatBandThickness / 2;
const ornamentSizeMax = flatBandThickness * 0.85; // Ornament size fills most of the band
const ornamentColor = multiplyHexColor(mainGoldColor, 0.80); // Darker gold for carved look
if (ornamentSizeMax >= 3) { // Min practical size
drawAcanthusElement(ornamentPlacementOffset, ornamentPlacementOffset, ornamentSizeMax, -Math.PI / 4, ornamentColor); // TL
drawAcanthusElement(canvas.width - ornamentPlacementOffset, ornamentPlacementOffset, ornamentSizeMax, Math.PI / 4, ornamentColor); // TR
drawAcanthusElement(ornamentPlacementOffset, canvas.height - ornamentPlacementOffset, ornamentSizeMax, -3 * Math.PI / 4, ornamentColor); // BL
drawAcanthusElement(canvas.width - ornamentPlacementOffset, canvas.height - ornamentPlacementOffset, ornamentSizeMax, 3 * Math.PI / 4, ornamentColor); // BR
const midOrnamentSize = ornamentSizeMax * 0.7;
if (midOrnamentSize >= 3) {
if (imgWidth > midOrnamentSize * 2) { // Image wide enough for side ornaments
drawAcanthusElement(canvas.width / 2, ornamentPlacementOffset, midOrnamentSize, 0, ornamentColor); // Top mid
drawAcanthusElement(canvas.width / 2, canvas.height - ornamentPlacementOffset, midOrnamentSize, Math.PI, ornamentColor); // Bottom mid
}
if (imgHeight > midOrnamentSize * 2) { // Image tall enough for side ornaments
drawAcanthusElement(ornamentPlacementOffset, canvas.height / 2, midOrnamentSize, -Math.PI / 2, ornamentColor); // Left mid
drawAcanthusElement(canvas.width - ornamentPlacementOffset, canvas.height / 2, midOrnamentSize, Math.PI / 2, ornamentColor); // Right mid
}
}
}
}
// --- Draw the image ---
ctx.drawImage(originalImg, frameWidth, frameWidth, imgWidth, imgHeight);
return canvas;
}
Apply Changes