You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, contrastValue = 0.15, brightnessValue = 0.05, warmOverlayStrength = 0.2, desaturationValue = 0.1, vignetteStrength = 0.4) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const width = originalImg.naturalWidth || originalImg.width;
const height = originalImg.naturalHeight || originalImg.height;
if (width === 0 || height === 0) {
console.error("Image dimensions are zero. Ensure the image is loaded and valid.");
// Return a small, empty canvas or handle as an error appropriately
canvas.width = 1;
canvas.height = 1;
return canvas;
}
canvas.width = width;
canvas.height = height;
try {
ctx.drawImage(originalImg, 0, 0, width, height);
} catch (e) {
console.error("Error drawing image onto canvas. Ensure image is valid:", e);
// Fallback for drawing error
ctx.fillStyle = 'lightgray';
ctx.fillRect(0, 0, width, height);
ctx.font = "16px Arial";
ctx.fillStyle = "black";
ctx.textAlign = "center";
ctx.fillText("Error: Could not draw image.", width / 2, height / 2);
return canvas;
}
let imageData;
try {
imageData = ctx.getImageData(0, 0, width, height);
} catch (e) {
// This can happen due to CORS issues if the image is from another domain and canvas is tainted
console.error("Could not get image data, possibly due to CORS policy:", e);
// Draw a placeholder indicating the error.
ctx.fillStyle = 'rgba(255, 0, 0, 0.7)'; // Semi-transparent red
ctx.fillRect(0, 0, width, height);
ctx.font = "bold 16px Arial";
ctx.fillStyle = "white";
ctx.textAlign = "center";
const message = "Error: Cannot process cross-origin image.";
const textY = height / 2 - (message.split('\n').length -1) * 8 ; // Adjust for multi-line
ctx.fillText(message, width / 2, textY);
ctx.font =_UTIL.HELPER_FUNCTIONS.canvasDrawMultilineText = function(ctx, text, x, y, maxWidth, lineHeight) {
const words = text.split(' ');
let line = '';
let currentY = y;
for (let n = 0; n < words.length; n++) {
const testLine = line + words[n] + ' ';
const metrics = ctx.measureText(testLine);
const testWidth = metrics.width;
if (testWidth > maxWidth && n > 0) {
ctx.fillText(line, x, currentY);
line = words[n] + ' ';
currentY += lineHeight;
} else {
line = testLine;
}
}
ctx.fillText(line, x, currentY);
}
return canvas;
}
const data = imageData.data;
const centerX = width / 2;
const centerY = height / 2;
// Distance from center to a corner, used for normalizing vignette distance
const maxDistToCorner = (width === 0 && height === 0) ? 0 : Math.sqrt(centerX * centerX + centerY * centerY);
function clamp(value, min = 0, max = 255) {
return Math.max(min, Math.min(max, value));
}
// Convert parameter ranges (typically 0-1) to effect magnitudes
const brightnessOffset = brightnessValue * 50; // e.g., 0.05 -> 2.5 offset
// For contrast, map 0-1 to a 0-100 scale for the formula.
// 0 means no change (factor 1), positive values increase contrast.
const contrastInput = contrastValue * 100;
const contrastFactor = (259 * (contrastInput + 255)) / (255 * (259 - contrastInput));
// Warm overlay color (orangey-yellow)
const warmColorR = 255;
const warmColorG = 200;
const warmColorB = 100;
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
if (brightnessOffset !== 0) {
r += brightnessOffset;
g += brightnessOffset;
b += brightnessOffset;
}
// 2. Contrast Adjustment
// Only apply if contrastInput is not 0. If 0, factor is 1, no change.
if (contrastInput !== 0) {
r = contrastFactor * (r - 128) + 128;
g = contrastFactor * (g - 128) + 128;
b = contrastFactor * (b - 128) + 128;
}
// Clamp after combined brightness and contrast
r = clamp(r);
g = clamp(g);
b = clamp(b);
// 3. Desaturation
// If desaturationValue is 0, this step is skipped.
if (desaturationValue > 0) {
const gray = 0.299 * r + 0.587 * g + 0.114 * b;
r = r * (1 - desaturationValue) + gray * desaturationValue;
g = g * (1 - desaturationValue) + gray * desaturationValue;
b = b * (1 - desaturationValue) + gray * desaturationValue;
// No clamp needed: r,g,b are already clamped, gray is weighted avg, result is interpolation.
}
// 4. Warm Overlay
// If warmOverlayStrength is 0, this step is skipped.
if (warmOverlayStrength > 0) {
r = r * (1 - warmOverlayStrength) + warmColorR * warmOverlayStrength;
g = g * (1 - warmOverlayStrength) + warmColorG * warmOverlayStrength;
b = b * (1 - warmOverlayStrength) + warmColorB * warmOverlayStrength;
// Clamp after overlay, as warm color components can push values > 255
r = clamp(r);
g = clamp(g);
b = clamp(b);
}
// 5. Vignette
// If vignetteStrength is 0 or image is too small, skip.
if (vignetteStrength > 0 && maxDistToCorner > 0) {
const pixelX = (i / 4) % width;
const pixelY = Math.floor((i / 4) / width);
const dx = pixelX - centerX;
const dy = pixelY - centerY;
const distFromCenter = Math.sqrt(dx * dx + dy * dy);
// Normalized distance: 0 at center, 1 at corners.
const normalizedDist = distFromCenter / maxDistToCorner;
let vignetteAmount = 0;
const vignetteStartRatio = 0.2; // Vignette starts affecting pixels beyond 20% of radius from center
const vignetteFullRatio = 0.85; // Vignette reaches full strength at 85% of radius
if (normalizedDist > vignetteStartRatio) {
// Calculate how far into the vignette band (startRatio to fullRatio) this pixel is
vignetteAmount = (normalizedDist - vignetteStartRatio) / (vignetteFullRatio - vignetteStartRatio);
vignetteAmount = clamp(vignetteAmount, 0, 1); // Intensity of vignette for this pixel (0 to 1)
}
const darkenFactor = 1.0 - vignetteAmount * vignetteStrength;
r *= darkenFactor;
g *= darkenFactor;
b *= darkenFactor;
// Clamp after darkening
r = clamp(r);
g = clamp(g);
b = clamp(b);
}
data[i] = r;
data[i+1] = g;
data[i+2] = b;
// Alpha channel (data[i+3]) is preserved
}
ctx.putImageData(imageData, 0, 0);
return canvas;
}
Apply Changes