You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, lanternColor = "#FFA500", blurAmount = 3, brightness = 1.1, noiseIntensity = 20, tintStrength = 0.5) {
// Helper function to clamp a value between min and max, and round it.
// Pixel component values must be integers in the range [0, 255].
const clamp = (value, min = 0, max = 255) => Math.min(Math.max(Math.round(value), min), max);
// Helper function to parse a hex color string to an [R, G, B] array.
// Supports #RGB and #RRGGBB formats. Defaults to a shade of orange on error.
const parseHexColor = (hex) => {
const hexString = String(hex).replace(/^#/, ''); // Ensure it's a string and remove '#'
let rHex, gHex, bHex;
if (hexString.length === 3) { // Expand #RGB to #RRGGBB
rHex = hexString[0] + hexString[0];
gHex = hexString[1] + hexString[1];
bHex = hexString[2] + hexString[2];
} else if (hexString.length === 6) { // #RRGGBB
rHex = hexString.substring(0, 2);
gHex = hexString.substring(2, 4);
bHex = hexString.substring(4, 6);
} else {
// Invalid format, log warning and default to a hardcoded orange
console.warn(`Invalid lanternColor format: "${hex}". Using default orange #FFA500.`);
return [255, 165, 0];
}
const r = parseInt(rHex, 16);
const g = parseInt(gHex, 16);
const b = parseInt(bHex, 16);
// Check if parsing resulted in valid numbers
if (isNaN(r) || isNaN(g) || isNaN(b)) {
console.warn(`Could not parse hex color components from: "${hexString}". Using default orange #FFA500.`);
return [255, 165, 0];
}
return [r, g, b];
};
const canvas = document.createElement('canvas');
// Using { willReadFrequently: true } can be an optimization hint for frequent getImageData/putImageData calls
const ctx = canvas.getContext('2d', { willReadFrequently: true });
// Use naturalWidth/Height for intrinsic dimensions, fallback to width/height
const width = originalImg.naturalWidth || originalImg.width;
const height = originalImg.naturalHeight || originalImg.height;
// Basic validation for image dimensions
if (!width || !height || width === 0 || height === 0) {
console.error("Image has invalid dimensions (e.g., 0 or undefined). Ensure it's properly loaded before processing.");
// Return a small, clearly marked error canvas to aid debugging
canvas.width = Math.max(1, 100); // Ensure non-zero width for text
canvas.height = Math.max(1, 30); // Ensure non-zero height
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'white';
ctx.font = '12px Arial';
ctx.fillText('Img Error', 5, canvas.height / 2 + 4);
return canvas;
}
canvas.width = width;
canvas.height = height;
// Step 1: Apply initial global filters (Blur & Brightness) to the image
// The ctx.filter property affects subsequent drawing operations.
let filterValues = [];
if (brightness !== 1.0) { // brightness(100%) is no-op
filterValues.push(`brightness(${brightness * 100}%)`);
}
if (blurAmount > 0) { // blur(0px) is no-op
filterValues.push(`blur(${blurAmount}px)`);
}
if (filterValues.length > 0) {
ctx.filter = filterValues.join(' ');
}
ctx.drawImage(originalImg, 0, 0, width, height);
ctx.filter = 'none'; // Reset filter to prevent affecting other canvas operations inadvertently
// Step 2: Apply Color Tint and Noise using pixel-by-pixel manipulation
// This is done after global filters are applied and the image is drawn.
const imageData = ctx.getImageData(0, 0, width, height);
const pixels = imageData.data;
const [tintR, tintG, tintB] = parseHexColor(lanternColor);
// Ensure tintStrength is within the valid range [0, 1] for blending
const currentTintStrength = Math.min(1, Math.max(0, Number(tintStrength) || 0));
for (let i = 0; i < pixels.length; i += 4) {
// Get original pixel values (which are already affected by blur/brightness filters)
let r = pixels[i];
let g = pixels[i+1];
let b = pixels[i+2];
// The alpha channel (pixels[i+3]) is generally preserved unless specified otherwise
// Apply color tint: R_new = R_old * (1 - strength) + TintColor_R * strength (linear interpolation)
r = r * (1 - currentTintStrength) + tintR * currentTintStrength;
g = g * (1 - currentTintStrength) + tintG * currentTintStrength;
b = b * (1 - currentTintStrength) + tintB * currentTintStrength;
// Noise is applied to the freshly tinted color to simulate paper texture
// Generates a random noise value (can be positive or negative), scaled by noiseIntensity
const randomNoise = (Math.random() - 0.5) * noiseIntensity;
// Apply noise and clamp the final RGB values to the 0-255 range
pixels[i] = clamp(r + randomNoise);
pixels[i+1] = clamp(g + randomNoise);
pixels[i+2] = clamp(b + randomNoise);
}
// Write the manipulated pixel data back to the canvas
ctx.putImageData(imageData, 0, 0);
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 Paper Lantern Filter Effect Tool allows users to apply a unique visual effect to their images, simulating the appearance of being filtered through a paper lantern. This tool lets you adjust settings such as lantern color, blur amount, brightness, noise intensity, and tint strength to achieve the desired aesthetic. It’s ideal for enhancing photos for social media, personal projects, or creative endeavors, giving images an artistic and whimsical touch.