You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, bloomStrength = 0.5, highlightThreshold = 210, bloomRadiusFactor = 1.0, contrastReduction = 0.05, overallSoftness = 0.2) {
const canvas = document.createElement('canvas');
// Add willReadFrequently hint for performance if getImageData is used multiple times
const ctx = canvas.getContext('2d', { willReadFrequently: true });
// Use naturalWidth/Height if available for Image objects, fallback to width/height
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
canvas.width = imgWidth;
canvas.height = imgHeight;
// Ensure parameters are numbers and clamp them to sensible ranges
bloomStrength = Math.max(0, Math.min(1, Number(bloomStrength)));
highlightThreshold = Math.max(0, Math.min(255, Number(highlightThreshold)));
// Allow bloomRadiusFactor = 0, meaning no blur for highlights (though less "misty")
bloomRadiusFactor = Math.max(0, Number(bloomRadiusFactor));
contrastReduction = Math.max(0, Math.min(1, Number(contrastReduction))); // 0 (no reduction) to 1 (full reduction to gray)
overallSoftness = Math.max(0, Number(overallSoftness)); // Min 0 (no softness)
// 1. Draw original image to the main canvas
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
// --- Create Bloom Effect ---
// Bloom effect requires strength and some radius for the blur to be meaningful as "mist"
if (bloomStrength > 0 && bloomRadiusFactor > 0) {
const highlightsCanvas = document.createElement('canvas');
// Add willReadFrequently hint for performance
const hCtx = highlightsCanvas.getContext('2d', { willReadFrequently: true });
highlightsCanvas.width = canvas.width;
highlightsCanvas.height = canvas.height;
// Get image data from the main canvas (which currently holds the original image)
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
// Create new image data for highlights to be put on highlightsCanvas
const highlightData = hCtx.createImageData(canvas.width, canvas.height);
const hData = highlightData.data;
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
const a = data[i + 3];
// Perceptually weighted luminance calculation
const luminance = 0.299 * r + 0.587 * g + 0.114 * b;
if (luminance > highlightThreshold && a > 0) { // Only consider opaque/semi-opaque pixels
hData[i] = r;
hData[i + 1] = g;
hData[i + 2] = b;
hData[i + 3] = a; // Preserve original alpha for the highlight
} else {
// Fill with transparent black for non-highlight pixels
hData[i] = 0; hData[i + 1] = 0; hData[i + 2] = 0; hData[i + 3] = 0;
}
}
hCtx.putImageData(highlightData, 0, 0);
// Calculate actual bloom radius
// Base radius scales with image size, min 1px. 2% of smaller dimension.
const baseRadius = Math.max(1, Math.min(canvas.width, canvas.height) * 0.02);
const actualBloomRadius = baseRadius * bloomRadiusFactor;
if (actualBloomRadius > 0) { // Apply blur only if radius is positive
hCtx.filter = `blur(${actualBloomRadius}px)`;
// Draw the highlightsCanvas onto itself to apply the filter.
hCtx.drawImage(highlightsCanvas, 0, 0);
hCtx.filter = 'none'; // Reset filter for hCtx
}
// Blend blurred highlights back to the main canvas
ctx.save(); // Save current state (e.g., globalAlpha, globalCompositeOperation)
ctx.globalCompositeOperation = 'screen'; // 'screen' or 'lighter' are good for bloom
ctx.globalAlpha = bloomStrength;
ctx.drawImage(highlightsCanvas, 0, 0);
ctx.restore(); // Restore to previous state
}
// --- Adjust Contrast ---
if (contrastReduction > 0) {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
// Factor: 1.0 means no change, 0 maps all to 128 (mid-gray)
const factor = 1.0 - contrastReduction;
for (let i = 0; i < data.length; i += 4) {
// Adjust R, G, B channels towards mid-gray (128)
data[i] = 128 + (data[i] - 128) * factor; // R
data[i + 1] = 128 + (data[i + 1] - 128) * factor; // G
data[i + 2] = 128 + (data[i + 2] - 128) * factor; // B
// Alpha channel (data[i+3]) remains unchanged
// Clamp values to the 0-255 range
data[i] = Math.max(0, Math.min(255, data[i]));
data[i + 1] = Math.max(0, Math.min(255, data[i + 1]));
data[i + 2] = Math.max(0, Math.min(255, data[i + 2]));
}
ctx.putImageData(imageData, 0, 0);
}
// --- Apply Overall Softness ---
if (overallSoftness > 0) {
// Create a temporary canvas to hold the current state of the main canvas
const tempCanvas = document.createElement('canvas');
tempCanvas.width = canvas.width;
tempCanvas.height = canvas.height;
const tempCtx = tempCanvas.getContext('2d');
tempCtx.drawImage(canvas, 0, 0); // Copy current main canvas content to tempCanvas
// Set the blur filter on the main canvas's context
ctx.filter = `blur(${overallSoftness}px)`;
// Clear the main canvas before drawing the blurred image to avoid compounding effects,
// especially with transparent images or if blur extends content.
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw the temporary canvas (holding the unblurred intermediate image) onto the main canvas.
// The filter will be applied during this draw operation.
ctx.drawImage(tempCanvas, 0, 0);
// Reset the filter on the main canvas's context
ctx.filter = 'none';
}
return canvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Pro-Mist Filter Effect Application allows users to apply a bloom filter effect to images, enhancing their visual appeal by creating a soft and misty atmosphere. This tool enables adjustments to various parameters including bloom strength, highlight threshold, bloom radius, contrast reduction, and overall softness, allowing for personalized image enhancement. Use cases include adding a dreamlike quality to photography, enhancing artistic images for social media, or improving visuals for presentations. Ideal for photographers, graphic designers, and content creators looking to add a unique aesthetic to their work.