You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, leafColor1 = '#FF4500', leafColor2 = '#FFD700', glowIntensity = 15, lightCount = 200) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const width = originalImg.width;
const height = originalImg.height;
canvas.width = width;
canvas.height = height;
/**
* Helper function to draw a single maple leaf shape.
* @param {CanvasRenderingContext2D} ctx - The canvas context.
* @param {number} x - The x-coordinate of the leaf's anchor.
* @param {number} y - The y-coordinate of the leaf's anchor.
* @param {number} size - The overall size of the leaf.
* @param {number} angle - The rotation angle in radians.
* @param {string} color - The fill color of the leaf.
*/
function drawMapleLeaf(ctx, x, y, size, angle, color) {
ctx.save();
ctx.translate(x, y);
ctx.rotate(angle);
ctx.scale(size, size);
ctx.fillStyle = color;
ctx.shadowColor = color;
ctx.shadowBlur = glowIntensity;
// Draw the main body of the leaf
ctx.beginPath();
ctx.moveTo(0, -1);
ctx.lineTo(0.2, -0.5);
ctx.lineTo(1, -0.6);
ctx.lineTo(0.4, -0.2);
ctx.lineTo(0.6, 0.3);
ctx.lineTo(0, 0.1);
ctx.lineTo(-0.6, 0.3);
ctx.lineTo(-0.4, -0.2);
ctx.lineTo(-1, -0.6);
ctx.lineTo(-0.2, -0.5);
ctx.closePath();
ctx.fill();
// Draw a simple stem
ctx.shadowBlur = 0;
ctx.strokeStyle = '#4a2a0a';
ctx.lineWidth = 0.1;
ctx.beginPath();
ctx.moveTo(0, 0.1);
ctx.lineTo(0, 0.6);
ctx.stroke();
ctx.restore();
}
/**
* Helper function to draw branches recursively to create a tree-like structure.
* @param {CanvasRenderingContext2D} ctx - The canvas context.
* @param {number} x - The starting x-coordinate.
* @param {number} y - The starting y-coordinate.
* @param {number} angle - The initial angle of the branch.
* @param {number} length - The length of the branch.
* @param {number} branchWidth - The width of the branch.
* @param {string} c1 - The first color for leaves.
* @param {string} c2 - The second color for leaves.
* @param {number} depth - The current recursion depth.
*/
function drawBranch(ctx, x, y, angle, length, branchWidth, c1, c2, depth) {
if (depth < 0 || length < 2) return;
ctx.save();
ctx.strokeStyle = '#2a1a0a';
ctx.lineWidth = branchWidth;
ctx.lineCap = 'round';
ctx.beginPath();
ctx.moveTo(x, y);
const endX = x + Math.cos(angle) * length;
const endY = y + Math.sin(angle) * length;
ctx.lineTo(endX, endY);
ctx.stroke();
// Sporadically draw leaves at the end of smaller branches
if (length < 30 && Math.random() > 0.3) {
const leafCount = Math.floor(Math.random() * 3) + 1;
for(let i=0; i<leafCount; i++) {
const leafColor = Math.random() > 0.5 ? c1 : c2;
drawMapleLeaf(ctx, endX + (Math.random()-0.5)*20, endY + (Math.random()-0.5)*20, Math.random() * 10 + 5, Math.random() * Math.PI * 2, leafColor);
}
}
// Recurse for new branches
const newLength = length * (0.7 + Math.random() * 0.2);
const newWidth = branchWidth * 0.7;
drawBranch(ctx, endX, endY, angle - (Math.random() * 0.5 + 0.1), newLength, newWidth, c1, c2, depth - 1);
if (Math.random() > 0.4) {
drawBranch(ctx, endX, endY, angle + (Math.random() * 0.5 + 0.1), newLength * (0.8 + Math.random()*0.2), newWidth, c1, c2, depth - 1);
}
ctx.restore();
}
// STEP 1: Draw the sunset sky
const skyGradient = ctx.createLinearGradient(0, 0, 0, height * 0.8);
skyGradient.addColorStop(0, '#ff8c00'); // Orange
skyGradient.addColorStop(0.3, '#ffbf00'); // Amber
skyGradient.addColorStop(0.6, '#8A2BE2'); // Violet
skyGradient.addColorStop(1, '#0c0c2c'); // Deep Navy
ctx.fillStyle = skyGradient;
ctx.fillRect(0, 0, width, height);
// STEP 2: Draw soft flowing curves of light in the sky
ctx.save();
ctx.globalCompositeOperation = 'overlay';
ctx.strokeStyle = 'rgba(255, 255, 220, 0.1)';
ctx.lineWidth = height * 0.1;
ctx.filter = `blur(${height/50}px)`;
ctx.beginPath();
ctx.moveTo(-width * 0.1, height * 0.2);
ctx.bezierCurveTo(width * 0.3, height * 0.1, width * 0.7, height * 0.4, width * 1.1, height * 0.3);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(-width * 0.1, height * 0.5);
ctx.bezierCurveTo(width * 0.4, height * 0.6, width * 0.6, height * 0.3, width * 1.1, height * 0.4);
ctx.stroke();
ctx.restore();
// STEP 3: Draw the Seoul skyline from the provided image
const skylineY = height * 0.55;
const skylineHeight = height - skylineY;
ctx.drawImage(originalImg, 0, skylineY, width, skylineHeight);
// Apply sunset glow overlays
ctx.save();
ctx.globalCompositeOperation = 'color-dodge';
ctx.fillStyle = 'rgba(255, 165, 0, 0.2)';
ctx.fillRect(0, skylineY, width, skylineHeight);
ctx.restore();
ctx.save();
ctx.globalCompositeOperation = 'multiply';
ctx.fillStyle = 'rgba(138, 43, 226, 0.2)';
ctx.fillRect(0, skylineY, width, skylineHeight);
ctx.restore();
// STEP 4: Draw sparkling city lights
ctx.save();
for (let i = 0; i < lightCount; i++) {
const x = Math.random() * width;
const y = skylineY + Math.random() * skylineHeight;
const radius = Math.random() * 1.5 + 0.5;
const alpha = Math.random() * 0.7 + 0.3;
const lightGradient = ctx.createRadialGradient(x, y, 0, x, y, radius * 2);
lightGradient.addColorStop(0, `rgba(255, 255, 224, ${alpha})`);
lightGradient.addColorStop(1, 'rgba(255, 255, 224, 0)');
ctx.fillStyle = lightGradient;
ctx.beginPath();
ctx.arc(x, y, radius * 2, 0, Math.PI * 2);
ctx.fill();
}
ctx.restore();
// STEP 5: Draw the terrace railing silhouette
ctx.save();
ctx.fillStyle = 'rgba(10, 5, 5, 0.85)';
ctx.shadowColor = 'black';
ctx.shadowBlur = 15;
const railY = height * 0.6;
const railTopHeight = height * 0.025;
const postHeight = height - railY;
const postWidth = width * 0.015;
// Top rail
ctx.fillRect(0, railY, width, railTopHeight);
// Vertical posts
for (let i = 0; i <= 10; i++) {
const postX = (width / 10) * i - postWidth / 2;
ctx.fillRect(postX, railY, postWidth, postHeight);
}
ctx.restore();
// STEP 6: Draw framing maple branches and leaves
// Left side
drawBranch(ctx, -10, height * 0.8, -Math.PI / 3, height/6, width*0.02, leafColor1, leafColor2, 6);
drawBranch(ctx, width * 0.1, height, -Math.PI / 2.2, height/5, width*0.03, leafColor1, leafColor2, 7);
// Right side
drawBranch(ctx, width + 10, height * 0.7, -Math.PI * 2 / 3, height/6, width*0.02, leafColor1, leafColor2, 6);
drawBranch(ctx, width * 0.9, height, -Math.PI / 1.8, height/5, width*0.03, leafColor1, leafColor2, 7);
// Add some loose, floating leaves for atmosphere
ctx.save();
for (let i = 0; i < 20; i++) {
const x = Math.random() * width;
const y = Math.random() * height;
const size = Math.random() * 8 + 4;
const angle = Math.random() * Math.PI * 2;
const color = Math.random() > 0.5 ? leafColor1 : leafColor2;
ctx.globalAlpha = Math.random() * 0.5 + 0.3;
drawMapleLeaf(ctx, x, y, size, angle, color);
}
ctx.restore();
// STEP 7: Apply final cinematic and textural touches
ctx.save();
// Vignette effect
const vignetteGradient = ctx.createRadialGradient(width/2, height/2, width/3, width/2, height/2, width/1.5);
vignetteGradient.addColorStop(0, 'rgba(0,0,0,0)');
vignetteGradient.addColorStop(1, 'rgba(0,0,0,0.4)');
ctx.fillStyle = vignetteGradient;
ctx.fillRect(0, 0, width, height);
// Subtle impressionist/stained-glass texture
ctx.globalCompositeOperation = 'overlay';
ctx.fillStyle = 'rgba(200, 180, 255, 0.05)';
for(let i=0; i<10000; i++){
ctx.fillRect(Math.random()*width, Math.random()*height, Math.random()*3+1, Math.random()*3+1);
}
ctx.restore();
return canvas;
}
Apply Changes