You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, warmth = 0.5, contrastLevel = 0.2, desaturationLevel = 0.3, brightnessOffset = -10, vignetteIntensity = 0.6, noiseAmount = 0.05) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Use originalImg.width and originalImg.height, assuming Image object is loaded.
// For HTMLImageElement, naturalWidth/Height might be more robust if CSS/attributes changed display size.
// Given "javascript Image object", .width and .height are its intrinsic dimensions after loading.
const imgWidth = originalImg.width;
const imgHeight = originalImg.height;
// Handle cases where the image might not be fully loaded or has no dimensions
if (imgWidth === 0 || imgHeight === 0) {
// console.warn("Image has zero dimensions. Ensure it's loaded before calling processImage.");
// Return a minimal canvas to prevent errors further down.
canvas.width = 1;
canvas.height = 1;
return canvas;
}
canvas.width = imgWidth;
canvas.height = imgHeight;
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
// Get pixel data
const imageData = ctx.getImageData(0, 0, imgWidth, imgHeight);
const data = imageData.data;
const noiseScaleFactor = 50; // Determines the maximum pixel value change for noise at noiseAmount = 1
// Iterate over each pixel
for (let i = 0; i < data.length; i += 4) {
let r = data[i];
let g = data[i + 1];
let b = data[i + 2];
// 1. Brightness Adjustment
// brightnessOffset typically ranges from -255 to 255. Default is -10 for a slightly darker rustic feel.
if (brightnessOffset !== 0) {
r += brightnessOffset;
g += brightnessOffset;
b += brightnessOffset;
}
// 2. Contrast Adjustment
// contrastLevel [0, 1]. 0 means no change, 1 means high contrast.
// Map to C in range e.g. [0, 100] for the formula.
if (contrastLevel > 0) {
const C = contrastLevel * 100; // Example: C maps to [0, 100]
// Standard contrast formula factor. If C=0, factor=1 (no change).
const factor = (259 * (C + 255)) / (255 * (259 - C));
r = factor * (r - 128) + 128;
g = factor * (g - 128) + 128;
b = factor * (b - 128) + 128;
}
// 3. Desaturation
// desaturationLevel [0, 1]. 0 means no desaturation, 1 means fully grayscale.
if (desaturationLevel > 0) {
const gray = 0.299 * r + 0.587 * g + 0.114 * b; // Luminance calculation
r = r * (1 - desaturationLevel) + gray * desaturationLevel;
g = g * (1 - desaturationLevel) + gray * desaturationLevel;
b = b * (1 - desaturationLevel) + gray * desaturationLevel;
}
// 4. Warmth (Rustic/Sepia Tint)
// warmth [0, 1]. 0 means no tint, 1 means full sepia-like tint.
if (warmth > 0) {
// Applying classic sepia matrix coefficients, interpolated by warmth
const sr = r * 0.393 + g * 0.769 + b * 0.189;
const sg = r * 0.349 + g * 0.686 + b * 0.168;
const sb = r * 0.272 + g * 0.534 + b * 0.131;
r = r * (1 - warmth) + sr * warmth;
g = g * (1 - warmth) + sg * warmth;
b = b * (1 - warmth) + sb * warmth;
}
// 5. Noise
// noiseAmount [0, 1]. 0 means no noise.
if (noiseAmount > 0) {
// Add monochromatic noise for a film grain like effect
const noiseVal = (Math.random() - 0.5) * noiseScaleFactor * noiseAmount;
r += noiseVal;
g += noiseVal;
b += noiseVal;
}
// Clamp values to the valid [0, 255] range
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]) is preserved
}
// Put the modified pixel data back onto the canvas
ctx.putImageData(imageData, 0, 0);
// 6. Vignette
// vignetteIntensity [0, 1]. 0 means no vignette.
if (vignetteIntensity > 0) {
const centerX = imgWidth / 2;
const centerY = imgHeight / 2;
// Outer radius extends to the furthest corner
const maxRadius = Math.sqrt(centerX * centerX + centerY * centerY);
// Inner radius of the vignette's transparent part.
// Higher intensity means a smaller transparent center (stronger effect).
// innerRadiusFactor determines the size of the transparent central area, relative to image smallest dimension.
// Range for innerRadiusFactor: e.g. [0.2 for strong intensidad, 0.5 for weak intensidad]
const innerRadiusFactor = 0.3 * (1 - vignetteIntensity) + 0.2;
const innerRadius = Math.min(imgWidth, imgHeight) * innerRadiusFactor;
const gradient = ctx.createRadialGradient(centerX, centerY, innerRadius, centerX, centerY, maxRadius);
gradient.addColorStop(0, 'rgba(0,0,0,0)'); // Center is transparent
// Darkness of the vignette edge. Max opacity factor K.
const K = 0.8; // Max opacity for vignette darkness, e.g., 0.8 for 80% black.
gradient.addColorStop(1, `rgba(0,0,0,${vignetteIntensity * K})`);
// Apply the vignette gradient
ctx.fillStyle = gradient;
// Default globalCompositeOperation is 'source-over', which is fine.
// ctx.globalCompositeOperation = 'source-over';
ctx.fillRect(0, 0, imgWidth, imgHeight);
}
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 Rustic Photo Filter Application allows users to enhance their images with a range of customizable effects to create a vintage or rustic aesthetic. Users can adjust settings such as warmth, contrast, desaturation, brightness, vignette, and noise amount to transform their photos. This tool is particularly useful for photographers, social media enthusiasts, or anyone looking to add a nostalgic touch to their images, making it ideal for personal projects, blog posts, or enhancing visual storytelling.