You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, tintColor = "#40C040", tintIntensity = 0.6, contrast = 1.2, brightness = 1.0, enableScanLines = 1, scanLineColor = "black", scanLineOpacity = 0.1, scanStripeHeight = 1, scanGapHeight = 1) {
// Helper function to parse color string (hex, rgb, name) to {r, g, b} object
// This function works by temporarily applying the color to a DOM element
// and then reading its computed style.
function parseColor(colorStr) {
const tempDiv = document.createElement('div');
tempDiv.style.display = 'none'; // Keep it hidden
tempDiv.style.color = colorStr; // Assign color string
// Append to body to ensure computed style is accurate
document.body.appendChild(tempDiv);
const computedColor = window.getComputedStyle(tempDiv).color;
document.body.removeChild(tempDiv); // Clean up the temporary div
// computedColor is typically in "rgb(r, g, b)" or "rgba(r, g, b, a)" format
// Regex to extract R, G, B values
const match = computedColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
if (match) {
return { r: parseInt(match[1]), g: parseInt(match[2]), b: parseInt(match[3]) };
}
// Fallback for invalid color string (e.g., if parsing fails)
console.warn(`Could not parse color string: "${colorStr}". Defaulting to black.`);
return { r: 0, g: 0, b: 0 }; // Default to black
}
const canvas = document.createElement('canvas');
// Use { willReadFrequently: true } for potential performance optimization with getImageData/putImageData
const ctx = canvas.getContext('2d', { willReadFrequently: true });
// It's assumed originalImg is fully loaded. If not, naturalWidth/Height might be 0.
// Robust applications might add checks here:
// if (!originalImg.complete || originalImg.naturalWidth === 0) {
// console.error("Image is not loaded or has no dimensions.");
// // Optionally, set canvas to a small error indicator size or return null.
// canvas.width = 100; canvas.height = 30;
// ctx.fillText("Error: Image not loaded.", 5, 20);
// return canvas;
// }
canvas.width = originalImg.naturalWidth;
canvas.height = originalImg.naturalHeight;
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
// Get the pixel data from the canvas
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data; // This is a Uint8ClampedArray
const parsedMainTint = parseColor(tintColor);
// Normalize tint components to 0-1 range for calculations
const Tr_norm = parsedMainTint.r / 255;
const Tg_norm = parsedMainTint.g / 255;
const Tb_norm = parsedMainTint.b / 255;
// Clamp intensity parameters to their logical ranges
tintIntensity = Math.max(0, Math.min(1, tintIntensity));
scanLineOpacity = Math.max(0, Math.min(1, scanLineOpacity));
// Process each pixel
for (let i = 0; i < data.length; i += 4) {
const r_orig = data[i]; // Original Red
const g_orig = data[i + 1]; // Original Green
const b_orig = data[i + 2]; // Original Blue
// Alpha (data[i+3]) will be preserved
// 1. Convert to grayscale (luminance)
let L = 0.299 * r_orig + 0.587 * g_orig + 0.114 * b_orig;
// 2. Apply contrast
// Formula: NewVal = (OldVal - MidPoint) * ContrastFactor + MidPoint
// MidPoint for 0-255 range is 127.5
L = (L - 127.5) * contrast + 127.5;
L = Math.max(0, Math.min(255, L)); // Clamp to 0-255
// 3. Apply color tint
// Interpolate between pure grayscale (L,L,L) and fully tinted L
// FinalR = L * [(1-intensity)*1 + intensity*TintR_norm]
let R_eff = L * ((1 - tintIntensity) + tintIntensity * Tr_norm);
let G_eff = L * ((1 - tintIntensity) + tintIntensity * Tg_norm);
let B_eff = L * ((1 - tintIntensity) + tintIntensity * Tb_norm);
// 4. Apply brightness
R_eff *= brightness;
G_eff *= brightness;
B_eff *= brightness;
// 5. Clamp final values and assign back to pixel data (rounding is good practice)
data[i] = Math.max(0, Math.min(255, Math.round(R_eff)));
data[i + 1] = Math.max(0, Math.min(255, Math.round(G_eff)));
data[i + 2] = Math.max(0, Math.min(255, Math.round(B_eff)));
}
// Write the modified pixel data back to the canvas
ctx.putImageData(imageData, 0, 0);
// 6. Optional: Add scan lines overlay
// enableScanLines is 1 for true, 0 for false, as per string/number param type rule.
if (enableScanLines === 1 && scanStripeHeight > 0 && scanLineOpacity > 0) {
const parsedScanColor = parseColor(scanLineColor);
// Set fillStyle using parsed RGB from scanLineColor and scanLineOpacity for alpha
ctx.fillStyle = `rgba(${parsedScanColor.r}, ${parsedScanColor.g}, ${parsedScanColor.b}, ${scanLineOpacity})`;
// Ensure scanGapHeight is not negative for cycle calculation
const currentScanGapHeight = Math.max(0, scanGapHeight);
const totalLineHeightCycle = scanStripeHeight + currentScanGapHeight;
if (totalLineHeightCycle > 0) { // Prevent infinite loop if cycle height is zero
for (let y = 0; y < canvas.height; y += totalLineHeightCycle) {
ctx.fillRect(0, y, canvas.width, scanStripeHeight);
}
}
}
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 Bank Vault Filter Effect Tool allows users to apply a variety of artistic effects to their images. With this tool, you can customize aspects such as color tinting, contrast, brightness, and the addition of scan lines. It is particularly useful for enhancing images for creative projects, social media posts, or digital artwork. Whether you want to create vintage effects, adjust the mood of your photographs, or simply explore new artistic styles, this tool offers flexible options to tailor the effect according to your needs.