You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
color1 = "#ff0055",
color2 = "#00ccff",
orientation = "horizontal",
blendMode = "color",
intensity = 0.8,
lightSpread = 0.8,
vignetteStrength = 0.5
) {
// Set up canvas and context
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
const w = originalImg.width;
const h = originalImg.height;
canvas.width = w;
canvas.height = h;
// 1. Draw the original image naturally
ctx.drawImage(originalImg, 0, 0, w, h);
// 2. Add Vignette (darken the edges) to make lighting pop more realistically
if (vignetteStrength > 0) {
const cx = w / 2;
const cy = h / 2;
// Radius safely reaches the corners
const radius = Math.hypot(w / 2, h / 2);
const vigGrad = ctx.createRadialGradient(cx, cy, radius * 0.3, cx, cy, radius);
// Fading from transparent black to semi-transparent black prevents gray-mud in some browsers
vigGrad.addColorStop(0, "rgba(0, 0, 0, 0)");
vigGrad.addColorStop(1, `rgba(0, 0, 0, ${Math.min(1, vignetteStrength)})`);
ctx.globalCompositeOperation = "multiply";
ctx.fillStyle = vigGrad;
ctx.fillRect(0, 0, w, h);
}
// A helper to safely parse any valid CSS color into RGB components
function parseColor(colorStr) {
const tempCanvas = document.createElement("canvas");
tempCanvas.width = 1;
tempCanvas.height = 1;
const tempCtx = tempCanvas.getContext("2d", { willReadFrequently: true });
tempCtx.fillStyle = colorStr;
tempCtx.fillRect(0, 0, 1, 1);
const data = tempCtx.getImageData(0, 0, 1, 1).data;
return { r: data[0], g: data[1], b: data[2] };
}
const c1 = parseColor(color1);
const c2 = parseColor(color2);
// Clamp spread parameter
const spread = Math.max(0.01, Math.min(1.0, lightSpread));
const safeIntensity = Math.max(0, Math.min(1.0, intensity));
// Calculate light gradient coordinates based on orientation
let x1_start = 0, y1_start = 0, x1_end = 0, y1_end = 0;
let x2_start = 0, y2_start = 0, x2_end = 0, y2_end = 0;
if (orientation === "vertical") {
// Top to Bottom
x1_start = 0; y1_start = 0;
x1_end = 0; y1_end = h * spread;
// Bottom to Top
x2_start = 0; y2_start = h;
x2_end = 0; y2_end = h - (h * spread);
} else if (orientation === "diagonal") {
// Top-Left to Center
x1_start = 0; y1_start = 0;
x1_end = w * spread; y1_end = h * spread;
// Bottom-Right to Center
x2_start = w; y2_start = h;
x2_end = w - (w * spread); y2_end = h - (h * spread);
} else {
// horizontal fallback (Left and Right)
x1_start = 0; y1_start = 0;
x1_end = w * spread; y1_end = 0;
x2_start = w; y2_start = 0;
x2_end = w - (w * spread); y2_end = 0;
}
// Apply valid blend mode fallback
const validModes = [
"source-over", "multiply", "screen", "overlay", "darken", "lighten",
"color-dodge", "color-burn", "hard-light", "soft-light", "difference",
"exclusion", "hue", "saturation", "color", "luminosity"
];
ctx.globalCompositeOperation = validModes.includes(blendMode) ? blendMode : "color";
// 3. Draw Light 1 (Color 1)
const grad1 = ctx.createLinearGradient(x1_start, y1_start, x1_end, y1_end);
grad1.addColorStop(0, `rgba(${c1.r}, ${c1.g}, ${c1.b}, ${safeIntensity})`);
grad1.addColorStop(1, `rgba(${c1.r}, ${c1.g}, ${c1.b}, 0)`); // Same RGB to prevent muddy interpolation
ctx.fillStyle = grad1;
ctx.fillRect(0, 0, w, h);
// 4. Draw Light 2 (Color 2)
const grad2 = ctx.createLinearGradient(x2_start, y2_start, x2_end, y2_end);
grad2.addColorStop(0, `rgba(${c2.r}, ${c2.g}, ${c2.b}, ${safeIntensity})`);
grad2.addColorStop(1, `rgba(${c2.r}, ${c2.g}, ${c2.b}, 0)`);
ctx.fillStyle = grad2;
ctx.fillRect(0, 0, w, h);
// Reset composite operation to default
ctx.globalCompositeOperation = "source-over";
return canvas;
}
Apply Changes