You can edit the below JavaScript code to customize the image tool.
Apply Changes
/**
* Processes an image by applying a selected visual effect from a collection.
* This function acts as a "render pack" by offering several modern effects.
*
* @param {Image} originalImg The source image object to process.
* @param {string} [effectName='glitch'] The name of the effect to apply. Available options: 'glitch', 'duotone', 'halftone', 'scanlines', 'anaglyph'.
* @param {number} [amount=10] A generic parameter controlling the intensity or a key metric of the effect.
* - for 'glitch': The glitch intensity (1-50).
* - for 'duotone': Not used.
* - for 'halftone': The dot spacing/size (2-50).
* - for 'scanlines': The line spacing (2-20).
* - for 'anaglyph': The pixel shift amount for the 3D effect (1-50).
* @param {string} [color1='#FF0055'] A generic color parameter.
* - for 'glitch': Not used.
* - for 'duotone': The dark/"shadow" color of the gradient (hex).
* - for 'halftone': The color of the dots (hex).
* - for 'scanlines': The color of the lines (any CSS color string, e.g., '#000' or 'rgba(0,0,0,0.5)').
* - for 'anaglyph': Not used.
* @param {string} [color2='#00FFFF'] A second generic color parameter.
* - for 'glitch': Not used.
* - for 'duotone': The light/"highlight" color of the gradient (hex).
* - for 'halftone': The background color (hex).
* - for 'scanlines': Not used.
* - for 'anaglyph': Not used.
* @returns {HTMLCanvasElement} A canvas element with the processed image.
*/
function processImage(originalImg, effectName = 'glitch', amount = 10, color1 = '#FF0055', color2 = '#00FFFF') {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });
const w = originalImg.naturalWidth;
const h = originalImg.naturalHeight;
canvas.width = w;
canvas.height = h;
// Helper function to parse hex colors to an {r, g, b} object
const hexToRgb = (hex) => {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
};
switch (effectName.toLowerCase()) {
case 'glitch': {
const intensity = Math.max(1, Math.min(50, amount));
ctx.drawImage(originalImg, 0, 0);
const imgData = ctx.getImageData(0, 0, w, h);
const data = imgData.data;
const sourceData = new Uint8ClampedArray(data);
// Apply RGB channel shift
for (let i = 0; i < data.length; i += 4) {
const x = (i / 4) % w;
// Shift red to the right, blue to the left, only within the same row
const redIndex = (x + intensity < w) ? i + intensity * 4 : i;
const blueIndex = (x - intensity >= 0) ? i - intensity * 4 : i;
data[i] = sourceData[redIndex]; // Red
data[i + 1] = sourceData[i + 1]; // Green (no change)
data[i + 2] = sourceData[blueIndex + 2]; // Blue
}
ctx.putImageData(imgData, 0, 0);
// Apply horizontal block displacement
for (let i = 0; i < intensity; i++) {
const y = Math.floor(Math.random() * h);
const sliceHeight = Math.floor(Math.random() * (h / 10));
const xOffset = Math.floor((Math.random() - 0.5) * (w / 15));
if (y + sliceHeight > h) continue;
ctx.drawImage(canvas, 0, y, w, sliceHeight, xOffset, y, w, sliceHeight);
}
break;
}
case 'duotone': {
const c1 = hexToRgb(color1);
const c2 = hexToRgb(color2);
if (!c1 || !c2) { // Fallback if colors are invalid
ctx.drawImage(originalImg, 0, 0);
break;
}
ctx.drawImage(originalImg, 0, 0);
const imageData = ctx.getImageData(0, 0, w, h);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
const r = data[i], g = data[i + 1], b = data[i + 2];
const gray = 0.299 * r + 0.587 * g + 0.114 * b;
const t = gray / 255; // Normalized brightness (0-1)
data[i] = c1.r * (1 - t) + c2.r * t;
data[i + 1] = c1.g * (1 - t) + c2.g * t;
data[i + 2] = c1.b * (1 - t) + c2.b * t;
}
ctx.putImageData(imageData, 0, 0);
break;
}
case 'halftone': {
const space = Math.max(2, Math.min(50, amount));
const dotRgb = hexToRgb(color1) || { r: 0, g: 0, b: 0 };
const bgRgb = hexToRgb(color2) || { r: 255, g: 255, b: 255 };
ctx.drawImage(originalImg, 0, 0);
const imageData = ctx.getImageData(0, 0, w, h);
const data = imageData.data;
ctx.fillStyle = `rgb(${bgRgb.r}, ${bgRgb.g}, ${bgRgb.b})`;
ctx.fillRect(0, 0, w, h);
ctx.fillStyle = `rgb(${dotRgb.r}, ${dotRgb.g}, ${dotRgb.b})`;
for (let y = 0; y < h; y += space) {
for (let x = 0; x < w; x += space) {
const centerX = Math.min(w - 1, Math.floor(x + space / 2));
const centerY = Math.min(h - 1, Math.floor(y + space / 2));
const index = (centerY * w + centerX) * 4;
const gray = 0.299 * data[index] + 0.587 * data[index + 1] + 0.114 * data[index + 2];
const brightness = gray / 255;
const radius = (1 - brightness) * (space * 0.6);
if (radius > 0.5) {
ctx.beginPath();
ctx.arc(x + space / 2, y + space / 2, radius, 0, 2 * Math.PI, true);
ctx.fill();
}
}
}
break;
}
case 'scanlines': {
ctx.drawImage(originalImg, 0, 0);
const spacing = Math.max(2, Math.min(20, amount));
const lineThickness = Math.max(1, Math.floor(spacing / 2));
ctx.fillStyle = color1;
if (color1.startsWith('#')) {
const rgb = hexToRgb(color1);
if (rgb) ctx.fillStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.5)`;
}
for (let y = 0; y < h; y += spacing) {
ctx.fillRect(0, y, w, lineThickness);
}
break;
}
case 'anaglyph': {
const shift = Math.round(Math.max(1, Math.min(50, amount)));
ctx.drawImage(originalImg, 0, 0);
const imgData = ctx.getImageData(0, 0, w, h);
const data = imgData.data;
const sourceData = new Uint8ClampedArray(data);
for (let i = 0; i < data.length; i += 4) {
const x = (i / 4) % w;
const redX = Math.max(0, x - shift);
const redIndex = (Math.floor(i / (w * 4)) * w + redX) * 4;
data[i] = sourceData[redIndex]; // Red from left-shifted pixel
data[i + 1] = sourceData[i + 1]; // Green from original pixel
data[i + 2] = sourceData[i + 2]; // Blue from original pixel
}
ctx.putImageData(imgData, 0, 0);
break;
}
default:
ctx.drawImage(originalImg, 0, 0);
break;
}
return canvas;
}
Apply Changes