You can edit the below JavaScript code to customize the image tool.
/**
* Applies a Contax T2/T3-like film filter effect to an image.
* This effect typically includes adjustments to saturation, contrast, grain,
* color temperature, and vignetting to emulate a film photography look.
*
* @param {Image} originalImg The original image object (e.g., from new Image() or <img> tag).
* @param {number} [saturationLevel=0.85] Saturation level. 1.0 is original, 0.0 is grayscale. (e.g., 0.85 for 15% desaturation).
* @param {number} [contrastFactor=1.15] Contrast factor. 1.0 is no change. (e.g., 1.15 for 15% more contrast).
* @param {number} [grainIntensity=10] Intensity of the grain effect. Consider values 0-30 for typical usage. (e.g., 10 for subtle grain).
* @param {number} [vignetteStrength=0.5] Strength of the vignette effect (darkening at edges). Range 0 (no vignette) to 1 (fully black edges).
* @param {number} [vignetteOuterRadiusFactor=0.9] Outer radius of the vignette as a factor of the image's half-diagonal. Defines where the vignette reaches full strength. (e.g., 0.9).
* @param {number} [vignetteInnerRadiusFactor=0.4] Inner radius of the vignette as a factor of the image's half-diagonal. Defines where the vignette effect begins (center is transparent). (e.g., 0.4). Must be less than vignetteOuterRadiusFactor.
* @param {number} [temperature=8] Color temperature adjustment. Positive values make the image warmer (more red/yellow), negative values make it cooler (more blue). (e.g., 8 for slight warmth).
* @returns {HTMLCanvasElement} A new canvas element with the processed image.
*/
function processImage(originalImg, saturationLevel = 0.85, contrastFactor = 1.15, grainIntensity = 10, vignetteStrength = 0.5, vignetteOuterRadiusFactor = 0.9, vignetteInnerRadiusFactor = 0.4, temperature = 8) {
const canvas = document.createElement('canvas');
// Using { willReadFrequently: true } can be a performance hint if getImageData is used often.
const ctx = canvas.getContext('2d', { willReadFrequently: true });
canvas.width = originalImg.naturalWidth || originalImg.width;
canvas.height = originalImg.naturalHeight || originalImg.height;
if (canvas.width === 0 || canvas.height === 0) {
console.error("Image has zero width or height. Ensure the image is loaded and has valid dimensions before processing.");
// Return an empty or minimally sized canvas, or could throw an error.
return canvas;
}
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
// Get pixel data from the canvas to manipulate
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data; // This is a Uint8ClampedArray: [R, G, B, A, R, G, B, A, ...]
const clamp = (value, min, max) => Math.max(min, Math.min(value, max));
// Iterate over each pixel (each pixel has 4 components: R, G, B, A)
for (let i = 0; i < data.length; i += 4) {
let r = data[i];
let g = data[i + 1];
let b = data[i + 2];
// 1. Temperature adjustment
if (temperature !== 0) {
r = clamp(r + temperature, 0, 255);
// Green channel is often less affected in simple warm/cool temperature shifts.
// For warming (positive temperature): R increases, B decreases. Vice-versa for cooling.
b = clamp(b - temperature, 0, 255);
}
// 2. Saturation adjustment
// Formula: NewColor = Gray + (OldColor - Gray) * saturationLevel
// Where Gray is luminance, OldColor is current R, G, or B value.
if (saturationLevel !== 1.0) {
// Calculate grayscale value based on current r, g, b (which might have been temperature-adjusted)
const gray = 0.299 * r + 0.587 * g + 0.114 * b;
r = clamp(gray + (r - gray) * saturationLevel, 0, 255);
g = clamp(gray + (g - gray) * saturationLevel, 0, 255);
b = clamp(gray + (b - gray) * saturationLevel, 0, 255);
}
// 3. Contrast adjustment
// Formula: NewColor = (OldColor - 127.5) * contrastFactor + 127.5
// This centers the color range around 127.5 (mid-gray), scales it by the factor, then re-centers.
if (contrastFactor !== 1.0) {
r = clamp((r - 127.5) * contrastFactor + 127.5, 0, 255);
g = clamp((g - 127.5) * contrastFactor + 127.5, 0, 255);
b = clamp((b - 127.5) * contrastFactor + 127.5, 0, 255);
}
// 4. Grain
if (grainIntensity > 0) {
// Generate monochromatic grain by adding the same random value to R, G, B.
// This simulates film grain which is usually grayscale.
const grainAmount = (Math.random() - 0.5) * grainIntensity * 2; // Random value between -grainIntensity and +grainIntensity
r = clamp(r + grainAmount, 0, 255);
g = clamp(g + grainAmount, 0, 255);
b = clamp(b + grainAmount, 0, 255);
}
// Assign new RGB values back to the imageData array
data[i] = r;
data[i + 1] = g;
data[i + 2] = b;
// Alpha channel (data[i+3]) is preserved.
}
// Put the modified pixel data back onto the canvas
ctx.putImageData(imageData, 0, 0);
// 5. Vignette
// Apply vignette if strength is positive and radius factors are logical.
if (vignetteStrength > 0 && vignetteOuterRadiusFactor > vignetteInnerRadiusFactor && vignetteInnerRadiusFactor >= 0) {
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
// Calculate the maximum distance from center to a corner (half-diagonal).
const maxDist = Math.sqrt(centerX * centerX + centerY * centerY);
// Calculate actual pixel radii for the gradient based on factors.
// Ensure inner radius is not negative and outer radius is greater than inner.
const radiusInner = maxDist * Math.max(0, vignetteInnerRadiusFactor);
const radiusOuter = maxDist * Math.max(radiusInner + 0.001, vignetteOuterRadiusFactor); // Outer must be > Inner. Adding small epsilon if factors are equal.
const gradient = ctx.createRadialGradient(
centerX, centerY, radiusInner,
centerX, centerY, radiusOuter
);
// Center of the vignette is transparent.
gradient.addColorStop(0, `rgba(0,0,0,0)`);
// Edge of the vignette is semi-transparent black, determined by vignetteStrength.
gradient.addColorStop(1, `rgba(0,0,0,${clamp(vignetteStrength, 0, 1)})`);
// Ensure drawing happens on top of existing image data without blending issues.
ctx.globalCompositeOperation = 'source-over'; // Default, but good to be explicit.
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
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 Contax T2/T3 Filter Effect Application allows users to apply a vintage film-like effect to images, reminiscent of the aesthetics produced by the Contax T2 and T3 cameras. This tool enables adjustments to saturation, contrast, grain, color temperature, and vignetting, enhancing images with a nostalgic and artistic quality. It is suitable for photographers, graphic designers, and enthusiasts who want to create a classic film look for their digital photos, perfect for social media posts, artistic projects, and personal collections.