You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, focusPosition = 0.5, focusRange = 0.2, blurAmount = 5, saturation = 1.4, contrast = 1.1) {
// Ensure parameters are numbers
focusPosition = Number(focusPosition);
focusRange = Number(focusRange); // Range of the focused area, 0.0 to 1.0 (percentage of image height)
blurAmount = Number(blurAmount); // Pixel radius for blur
saturation = Number(saturation); // 1.0 is original, >1 increases saturation
contrast = Number(contrast); // 1.0 is original, >1 increases contrast
const width = originalImg.naturalWidth || originalImg.width;
const height = originalImg.naturalHeight || originalImg.height;
if (width === 0 || height === 0) {
console.warn("Image Diorama: Input image has zero width or height. Returning empty canvas.");
const emptyCanvas = document.createElement('canvas');
emptyCanvas.width = width;
emptyCanvas.height = height;
return emptyCanvas;
}
// 1. Create the final canvas to return
const finalCanvas = document.createElement('canvas');
finalCanvas.width = width;
finalCanvas.height = height;
const finalCtx = finalCanvas.getContext('2d');
// 2. Prepare the sharp, enhanced layer
const sharpCanvas = document.createElement('canvas');
sharpCanvas.width = width;
sharpCanvas.height = height;
const sharpCtx = sharpCanvas.getContext('2d');
let enhancementFilter = '';
if (saturation !== 1 || contrast !== 1) {
enhancementFilter = `saturate(${saturation}) contrast(${contrast})`;
}
if (enhancementFilter) {
sharpCtx.filter = enhancementFilter;
}
sharpCtx.drawImage(originalImg, 0, 0, width, height);
sharpCtx.filter = 'none'; // Reset filter
// 3. Prepare the blurred, enhanced layer
const blurredCanvas = document.createElement('canvas');
blurredCanvas.width = width;
blurredCanvas.height = height;
const blurredCtx = blurredCanvas.getContext('2d');
let fullFilterArray = [];
if (enhancementFilter) {
fullFilterArray.push(enhancementFilter);
}
if (blurAmount > 0) {
fullFilterArray.push(`blur(${blurAmount}px)`);
}
if (fullFilterArray.length > 0) {
blurredCtx.filter = fullFilterArray.join(' ');
}
blurredCtx.drawImage(originalImg, 0, 0, width, height);
blurredCtx.filter = 'none'; // Reset filter
// 4. Draw the blurred layer as the base on the final canvas
finalCtx.drawImage(blurredCanvas, 0, 0);
// 5. Create a masked version of the sharp layer to overlay
const maskedSharpCanvas = document.createElement('canvas');
maskedSharpCanvas.width = width;
maskedSharpCanvas.height = height;
const maskedSharpCtx = maskedSharpCanvas.getContext('2d');
// Draw the sharp (but enhanced) image onto this temporary canvas
maskedSharpCtx.drawImage(sharpCanvas, 0, 0);
// Helper function to create a robust gradient for the mask
const createFocusGradient = (ctxForGrad, imgHeight, fPos, fRangeNormalized, bAmt) => {
const grad = ctxForGrad.createLinearGradient(0, 0, 0, imgHeight);
const clampedFocusRange = Math.max(0, Math.min(1, fRangeNormalized));
// Handle full focus: entire image is sharp
if (clampedFocusRange >= 1.0) {
grad.addColorStop(0, 'rgba(0,0,0,1)');
grad.addColorStop(1, 'rgba(0,0,0,1)');
return grad;
}
// Handle no focus: entire image uses the blurred version (mask is fully transparent)
if (clampedFocusRange <= 0 && bAmt > 0) { // Only if blur is active, otherwise no real effect from no focus
grad.addColorStop(0, 'rgba(0,0,0,0)');
grad.addColorStop(1, 'rgba(0,0,0,0)');
return grad;
}
const focusCenterPx = imgHeight * fPos;
const focusRangePxHalf = (imgHeight * clampedFocusRange) / 2;
const focusBandStartPx = focusCenterPx - focusRangePxHalf;
const focusBandEndPx = focusCenterPx + focusRangePxHalf;
// Transition zone width, proportional to blur radius, capped
let transitionWidthPx = bAmt * 3; // Heuristic: feathering proportional to blur
transitionWidthPx = Math.min(transitionWidthPx, imgHeight * 0.25); // Cap at 25% of image height
transitionWidthPx = Math.max(transitionWidthPx, bAmt > 0 ? 1 : 0); // Min 1px transition if blur is active, else 0
const stops = new Map();
// Define normalized stop points for the gradient
const p0_norm = 0; // Top of image
const p5_norm = 1; // Bottom of image
// Point where transparency starts before sharp band (top feather starts)
const p1_norm = Math.max(0, focusBandStartPx - transitionWidthPx) / imgHeight;
// Point where sharp band begins (top feather ends, full opacity)
const p2_norm = Math.max(0, focusBandStartPx) / imgHeight;
// Point where sharp band ends (bottom feather starts, full opacity)
const p3_norm = Math.min(1, focusBandEndPx / imgHeight);
// Point where transparency starts after sharp band (bottom feather ends)
const p4_norm = Math.min(1, focusBandEndPx + transitionWidthPx) / imgHeight;
stops.set(p0_norm, 'rgba(0,0,0,0)'); // Fully transparent at the top edge
if (p1_norm > p0_norm && p1_norm < p2_norm) {
stops.set(p1_norm, 'rgba(0,0,0,0)'); // End of top transparent area, start of feather
}
// Start of fully opaque (sharp) area
stops.set(Math.min(p2_norm, p3_norm), 'rgba(0,0,0,1)'); // Use min in case focus range is 0 or negative
// End of fully opaque (sharp) area
stops.set(Math.max(p2_norm,p3_norm), 'rgba(0,0,0,1)'); // Max for same reason
if (p4_norm < p5_norm && p4_norm > p3_norm) {
stops.set(p4_norm, 'rgba(0,0,0,0)'); // Start of bottom transparent area, end of feather
}
stops.set(p5_norm, 'rgba(0,0,0,0)'); // Fully transparent at the bottom edge
const sortedStopOffsets = Array.from(stops.keys()).sort((a, b) => a - b);
for (const offset of sortedStopOffsets) {
grad.addColorStop(offset, stops.get(offset));
}
return grad;
};
const gradientMask = createFocusGradient(maskedSharpCtx, height, focusPosition, focusRange, blurAmount);
// Apply the gradient as an alpha mask to the sharp layer
maskedSharpCtx.globalCompositeOperation = 'destination-in';
maskedSharpCtx.fillStyle = gradientMask;
maskedSharpCtx.fillRect(0, 0, width, height);
maskedSharpCtx.globalCompositeOperation = 'source-over'; // Reset composite operation
// 6. Draw the masked sharp layer onto the final canvas (over the blurred base)
finalCtx.drawImage(maskedSharpCanvas, 0, 0);
return finalCanvas;
}
Apply Changes