You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, strength = 0.25) {
const G_STRENGTH_MIN = 0.0;
const G_STRENGTH_MAX = 1.0;
if (!originalImg || typeof originalImg.naturalWidth === 'undefined' && typeof originalImg.width === 'undefined') {
console.error("Invalid Image object provided to processImage.");
const errorCanvas = document.createElement('canvas');
errorCanvas.width = 1;
errorCanvas.height = 1;
return errorCanvas;
}
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
if (imgWidth === 0 || imgHeight === 0) {
console.warn("Original image has zero dimensions.");
const emptyCanvas = document.createElement('canvas');
emptyCanvas.width = 1;
emptyCanvas.height = 1;
return emptyCanvas;
}
// Clamp strength: Ensure strength is a number and within the defined range.
const effectStrength = Math.max(G_STRENGTH_MIN, Math.min(G_STRENGTH_MAX, Number(strength)));
// 1. Main Canvas Setup: This canvas will hold the original image, then the composited bloom.
const mainCanvas = document.createElement('canvas');
mainCanvas.width = imgWidth;
mainCanvas.height = imgHeight;
const mainCtx = mainCanvas.getContext('2d');
mainCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
// If strength is effectively zero, no need to process further. Return original image on a canvas.
if (effectStrength < 0.001) { // Using a small epsilon for float comparison
return mainCanvas;
}
// 2. Create Highlight Mask Canvas:
// This canvas will contain only the bright parts of the image that will contribute to the bloom.
const highlightMaskCanvas = document.createElement('canvas');
highlightMaskCanvas.width = imgWidth;
highlightMaskCanvas.height = imgHeight;
const highlightMaskCtx = highlightMaskCanvas.getContext('2d');
highlightMaskCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
const imageData = highlightMaskCtx.getImageData(0, 0, imgWidth, imgHeight);
const data = imageData.data;
// Highlight threshold: determines how bright a pixel needs to be to contribute to bloom.
// Higher strength results in a lower threshold, meaning more (less bright) pixels contribute.
// Range adjusted: e.g., strength 0.1 -> ~212, strength 0.5 -> ~140, strength 1.0 -> ~50.
const highlightThreshold = Math.max(50, 230 - effectStrength * 180);
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i+1];
const b = data[i+2];
// Standard luminance calculation
const luminance = 0.299 * r + 0.587 * g + 0.114 * b;
if (luminance < highlightThreshold) {
data[i+3] = 0; // Make pixel transparent if below threshold
} else {
// Ensure pixels contributing to bloom are fully opaque for the blur pass
data[i+3] = 255;
}
}
highlightMaskCtx.putImageData(imageData, 0, 0);
// 3. Create Blurred Bloom Canvas:
// This canvas takes the highlight mask and applies a blur to create the bloom effect.
const bloomCanvas = document.createElement('canvas');
bloomCanvas.width = imgWidth;
bloomCanvas.height = imgHeight;
const bloomCtx = bloomCanvas.getContext('2d');
// Blur radius: increases with effect strength for more pronounced halation.
// Range e.g., strength 0.1 -> ~3.5px, strength 0.5 -> ~13.5px, strength 1.0 -> ~26px.
const blurRadius = effectStrength * 25 + 1;
if (blurRadius > 0) {
bloomCtx.filter = `blur(${blurRadius}px)`;
}
bloomCtx.drawImage(highlightMaskCanvas, 0, 0);
bloomCtx.filter = 'none'; // Reset filter on the context
// 4. Composite Bloom onto Main Canvas:
// The original image is already on mainCtx. We draw the blurred highlights (bloomCanvas) on top.
mainCtx.save(); // Save current state (e.g., globalAlpha, globalCompositeOperation)
mainCtx.globalCompositeOperation = 'screen'; // 'Screen' blend mode is characteristic for light bloom effects.
// Bloom intensity: controls how strongly the bloom layer is blended.
// Range e.g., strength 0.1 -> ~0.145, strength 0.5 -> ~0.325, strength 1.0 -> ~0.55.
const bloomIntensity = effectStrength * 0.45 + 0.1;
mainCtx.globalAlpha = bloomIntensity;
mainCtx.drawImage(bloomCanvas, 0, 0);
mainCtx.restore(); // Restore previous context state
// 5. Final Adjustments (Contrast and slight Brightness compensation):
// Black Pro-Mist filters are known for lowering overall contrast.
const finalCanvas = document.createElement('canvas');
finalCanvas.width = imgWidth;
finalCanvas.height = imgHeight;
const finalCtx = finalCanvas.getContext('2d');
// Contrast factor: 1.0 is no change. Values < 1.0 reduce contrast.
// Range e.g., strength 0.1 -> 0.98, strength 0.5 -> 0.90, strength 1.0 -> 0.80.
const contrastFactor = 1.0 - (effectStrength * 0.20);
// Brightness factor: slightly increase brightness to compensate for potential darkening from contrast reduction.
// Range e.g., strength 0.1 -> 1.003, strength 0.5 -> 1.015, strength 1.0 -> 1.03.
const brightnessFactor = 1.0 + (effectStrength * 0.03);
let filtersToApply = [];
// Apply contrast filter if it makes a noticeable difference
if (Math.abs(contrastFactor - 1.0) > 0.001) {
filtersToApply.push(`contrast(${contrastFactor})`);
}
// Apply brightness filter if it makes a noticeable difference
if (Math.abs(brightnessFactor - 1.0) > 0.001) {
filtersToApply.push(`brightness(${brightnessFactor})`);
}
if (filtersToApply.length > 0) {
finalCtx.filter = filtersToApply.join(' ');
}
// Draw the image (original + bloom) from mainCanvas onto finalCanvas, applying the filters.
finalCtx.drawImage(mainCanvas, 0, 0);
finalCtx.filter = 'none'; // Reset filter on the context
return finalCanvas;
}
Apply Changes