You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, vignetteIntensityParam = 0.6, desaturationParam = 0.3, warmthParam = 0.2) {
const canvas = document.createElement('canvas');
// Use naturalWidth/Height for intrinsic image dimensions, fallback to width/height
canvas.width = originalImg.naturalWidth || originalImg.width;
canvas.height = originalImg.naturalHeight || originalImg.height;
// Handle cases where image dimensions might be zero (e.g., image not loaded or invalid)
if (canvas.width === 0 || canvas.height === 0) {
// Return a minimal 1x1 canvas, as a canvas element is an expected return type.
canvas.width = Math.max(1, canvas.width);
canvas.height = Math.max(1, canvas.height);
return canvas;
}
const ctx = canvas.getContext('2d');
if (!ctx) {
// This should ideally not happen in modern browsers if a canvas element can be created.
console.error("Could not get 2D rendering context.");
// Return the canvas element as per function requirements, even if unusable.
return canvas;
}
// Clamp parameters to their logical ranges [0, 1]
const vignetteIntensity = Math.min(1, Math.max(0, vignetteIntensityParam));
const desaturation = Math.min(1, Math.max(0, desaturationParam));
const warmth = Math.min(1, Math.max(0, warmthParam));
// 1. Apply base image tonal and color effects using CanvasRenderingContext2D.filter
let filterString = '';
// Desaturation: saturate(0) is grayscale, saturate(1) is original color.
// We map desaturation (0=none, 1=full) to saturate(1..0).
// If desaturation is 0 (no desaturation wanted), (1-0)=1. saturate(1) is original.
// We only add the filter if it's not a no-op.
if (desaturation > 0) { // If desaturation is 0, (1-0)=1 (saturate(1)), which is often a no-op.
filterString += `saturate(${1 - desaturation}) `;
}
// Sepia: sepia(0) is no effect, sepia(1) is full sepia.
// If warmth is 0, sepia(0) is original color (no sepia effect).
if (warmth > 0) { // Only add if warmth > 0, as sepia(0) is a no-op.
filterString += `sepia(${warmth}) `;
}
// Adding fixed adjustments for the "Shen-Hao Large Format" inspired look.
// These are stylistic choices. Large format photography often values rich tonality and sharpness.
// Slight contrast boost and minor brightness lift.
filterString += `contrast(1.1) brightness(1.02)`;
filterString = filterString.trim(); // Clean up any leading/trailing spaces if first filters were skipped.
if (filterString !== '') {
ctx.filter = filterString;
}
// Draw the image onto the canvas. Filters are applied at draw time.
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
// Reset filter before drawing vignette. This ensures the vignette itself is not altered
// by the previously set image filters (e.g., we don't want a sepia-toned vignette).
ctx.filter = 'none';
// 2. Apply Vignetting
// Vignette is applied as an overlay on top of the already filtered image.
if (vignetteIntensity > 0) {
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
// Outer radius is distance from center to a corner, ensuring full coverage.
const outerRadius = Math.sqrt(Math.pow(centerX, 2) + Math.pow(centerY, 2));
// vignetteIntensity: 0 (implies mildest/no vignette) -> 1 (strongest vignette)
// innerRadiusRatio determines how far from the center the vignette effect starts to become opaque.
// A smaller innerRadiusRatio means vignette starts closer to center (stronger perceived effect).
// Formula maps intensity [0,1] to ratio [0.7, 0.2].
// e.g., intensity 0 -> ratio 0.7 (large transparent center)
// e.g., intensity 1 -> ratio 0.2 (small transparent center)
const innerRadiusRatio = 0.2 + (1 - vignetteIntensity) * 0.5;
const innerRadius = outerRadius * innerRadiusRatio;
const gradient = ctx.createRadialGradient(
centerX, centerY, innerRadius,
centerX, centerY, outerRadius
);
// vignetteDarkness: Higher intensity means darker vignette edges.
// Max opacity for the dark part of vignette (using black color).
const vignetteDarkness = vignetteIntensity * 0.7; // Max alpha of 0.7 for black
gradient.addColorStop(0, 'rgba(0,0,0,0)'); // Center of vignette is fully transparent
// Mid-point of vignette ramp: controls how quickly it darkens.
// A stop at 0.65 means the transparency holds for a good portion from the center.
// The darkness at this mid-point is a fraction of the full vignetteDarkness for a smoother transition.
gradient.addColorStop(0.65, `rgba(0,0,0,${vignetteDarkness * 0.35})`);
gradient.addColorStop(1, `rgba(0,0,0,${vignetteDarkness})`); // Edges are at full vignetteDarkness
ctx.fillStyle = gradient;
// Using default 'source-over' to draw the vignette on top of the image.
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 Shen-Hao Large Format Filter Effect Tool enables users to enhance their images by applying a set of stylistic adjustments inspired by large format photography. This tool provides options for adjusting the vignette intensity, desaturation, and warmth of the image, allowing for a range of artistic effects. Ideal for photographers, graphic designers, and hobbyists, this tool can be used to create vintage-style images, enhance portraits, or add a distinct visual flair to digital art. Users can tailor the appearance of their images to evoke a specific mood or aesthetic, making it suitable for social media posts, art projects, and professional portfolios.