You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg) {
'use strict';
const canvas = document.createElement('canvas');
// Use { willReadFrequently: true } as a performance hint for repeated getImageData/putImageData calls.
const ctx = canvas.getContext('2d', { willReadFrequently: true });
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
if (imgWidth === 0 || imgHeight === 0) {
// If image has no dimensions (e.g., not loaded or invalid), return an empty canvas.
canvas.width = 0;
canvas.height = 0;
return canvas;
}
canvas.width = imgWidth;
canvas.height = imgHeight;
try {
// Draw the original image onto the canvas.
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
} catch (e) {
// This catch block handles errors during the drawing of the original image,
// which might occur if the Image object is invalid or in a state that prevents drawing.
// Return the canvas, which might be blank or partially drawn, or draw an error.
// For robustness, we'll draw a minimal error message.
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "rgba(128, 128, 128, 0.8)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.font = "16px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("Error: Could not draw original image.", canvas.width / 2, canvas.height / 2);
return canvas;
}
let imageData;
try {
// Get the pixel data from the canvas.
imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
} catch (e) {
// This primarily catches security errors (SecurityError DOMException) if the image source
// is cross-origin and the canvas becomes "tainted", preventing pixel manipulation.
// Draw an error message on the canvas indicating the filter cannot be applied.
ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the originally drawn image
ctx.fillStyle = "rgba(128, 128, 128, 0.8)"; // A neutral background
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black"; // Text color
ctx.font = "16px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
const messageLine1 = "Error: Cannot apply filter.";
const messageLine2 = "Image may be cross-origin restricted.";
ctx.fillText(messageLine1, canvas.width / 2, canvas.height / 2 - 10); // Position first line
ctx.fillText(messageLine2, canvas.width / 2, canvas.height / 2 + 10); // Position second line
return canvas;
}
const data = imageData.data; // This is a Uint8ClampedArray: R,G,B,A, R,G,B,A,...
// Filter parameters tuned for a "Fujifilm Superia" like effect.
// These values are heuristics based on common descriptions of the film.
const contrastLevel = 25; // Defines contrast enhancement. Range approx. -100 to 100.
const saturationBoost = 1.20; // 1.0 means no change, >1 boosts saturation. 1.20 is a 20% boost.
// Color channel multipliers to achieve Superia's typical color response:
// - Rich, slightly warm reds.
// - Vibrant, signature greens (often a key Superia trait).
// - Deep, pleasing blues.
const redChannelMultiplier = 1.03;
const greenChannelMultiplier = 1.12;
const blueChannelMultiplier = 1.08;
// Pre-calculate the contrast factor based on contrastLevel.
// This formula maps a contrastLevel (commonly -255 to 255) to a multiplicative factor.
const contrastFactor = (259 * (contrastLevel + 255)) / (255 * (259 - contrastLevel));
for (let i = 0; i < data.length; i += 4) {
let r = data[i];
let g = data[i + 1];
let b = data[i + 2];
// Alpha (data[i+3]) is preserved.
// 1. Apply Contrast adjustment
// This formula adjusts pixel values relative to mid-gray (128) to increase or decrease contrast.
r = contrastFactor * (r - 128) + 128;
g = contrastFactor * (g - 128) + 128;
b = contrastFactor * (b - 128) + 128;
// Clamp values to the valid [0, 255] range after contrast adjustment.
r = Math.max(0, Math.min(255, r));
g = Math.max(0, Math.min(255, g));
b = Math.max(0, Math.min(255, b));
// 2. Apply Saturation boost
// Calculate luminance (brightness) of the (now contrasted) pixel.
// Standard luminance weights for sRGB.
const luminance = 0.299 * r + 0.587 * g + 0.114 * b;
// Interpolate each color channel between its grayscale value (luminance) and its current value.
// A saturationBoost > 1 increases the distance from gray, enhancing color.
r = luminance + saturationBoost * (r - luminance);
g = luminance + saturationBoost * (g - luminance);
b = luminance + saturationBoost * (b - luminance);
// Clamp values after saturation.
r = Math.max(0, Math.min(255, r));
g = Math.max(0, Math.min(255, g));
b = Math.max(0, Math.min(255, b));
// 3. Apply Superia-specific Color Channel Multipliers
// These multipliers subtly tint the image by adjusting the intensity of each color channel.
r *= redChannelMultiplier;
g *= greenChannelMultiplier;
b *= blueChannelMultiplier;
// Final clamp and round to ensure values are valid 8-bit integers for pixel data.
data[i] = Math.max(0, Math.min(255, Math.round(r)));
data[i + 1] = Math.max(0, Math.min(255, Math.round(g)));
data[i + 2] = Math.max(0, Math.min(255, Math.round(b)));
// Alpha channel (data[i+3]) remains untouched.
}
// Write the modified 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 Fujifilm Superia Filter Effect Tool allows users to enhance their photos by mimicking the iconic Fujifilm Superia film aesthetic. This tool applies a unique combination of contrast adjustments and color balancing that emphasizes warm reds, vibrant greens, and rich blues, reminiscent of the classic film’s look. It’s ideal for photography enthusiasts looking to add a nostalgic touch to their images, as well as for social media users wanting to achieve a specific visual style in their photo edits.