You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, distortionAmount = 0.03, waveFrequency = 8, colorIntensity = 1.0) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true }); // Optimization hint for frequent getImageData/putImageData
// Determine image dimensions, ensuring they are positive
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
if (imgWidth <= 0 || imgHeight <= 0) {
// console.error("Image dimensions must be valid and positive for processing.");
// Create a small canvas with an error message
const errCanvas = document.createElement('canvas');
errCanvas.width = Math.max(1, imgWidth || 100); // Use a default if dimensions are truly zero
errCanvas.height = Math.max(1, imgHeight || 100);
const errCtx = errCanvas.getContext('2d');
errCtx.fillStyle = 'lightgray';
errCtx.fillRect(0, 0, errCanvas.width, errCanvas.height);
if (typeof errCtx.fillText === 'function') { // Check if fillText is available (browser env)
errCtx.fillStyle = 'red';
errCtx.textAlign = 'center';
errCtx.font = '12px Arial';
errCtx.fillText('Invalid Image Dimensions', errCanvas.width / 2, errCanvas.height / 2);
}
return errCanvas;
}
canvas.width = imgWidth;
canvas.height = imgHeight;
// Draw the original image onto the canvas
try {
ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
} catch (e) {
// console.error("Error drawing image to canvas: ", e);
// Fallback: render error message on canvas
ctx.fillStyle = 'lightgray';
ctx.fillRect(0, 0, canvas.width, canvas.height);
if (typeof ctx.fillText === 'function') {
ctx.fillStyle = 'red';
ctx.textAlign = 'center';
ctx.font = '16px Arial';
ctx.fillText('Error loading image', canvas.width / 2, canvas.height / 2);
}
return canvas; // Return the canvas with the error message
}
let imageData;
try {
imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
} catch (e) {
// This can happen due to tainted canvas if image is cross-origin and server doesn't allow.
// console.error("Error getting ImageData (possibly tainted canvas): ", e);
ctx.fillStyle = 'lightgray';
ctx.fillRect(0, 0, canvas.width, canvas.height);
if (typeof ctx.fillText === 'function') {
ctx.font = '14px Arial'; // Adjusted font size
ctx.fillStyle = 'darkred';
ctx.textAlign = 'center';
const msg = 'Cannot process: Image from another domain?';
// Basic text fitting
const textMetrics = ctx.measureText(msg);
if (textMetrics.width > canvas.width - 20) { // If text is too wide, use smaller font
ctx.font = '10px Arial';
}
ctx.fillText(msg, canvas.width / 2, canvas.height / 2);
if (canvas.height > 40) { // Add note if space allows
ctx.font = '10px Arial';
ctx.fillText('(Enable CORS or use same-domain image)', canvas.width / 2, canvas.height / 2 + 15);
}
}
return canvas;
}
const data = imageData.data;
const width = canvas.width;
const height = canvas.height;
// Create a copy of the original pixel data to read from.
// This is crucial because we're modifying `data` while needing original values for distortion.
const originalPixelData = new Uint8ClampedArray(imageData.data);
// Normalize parameters to prevent extreme values if necessary
distortionAmount = Math.max(0, Math.min(0.2, distortionAmount)); // Cap distortion
waveFrequency = Math.max(1, Math.min(50, waveFrequency)); // Cap frequency
colorIntensity = Math.max(0, Math.min(1, colorIntensity)); // Clamp intensity
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
// Normalize coordinates for consistent wave calculation regardless of image size
const normalizedY = y / height; // Ranges from 0 to 1
const normalizedX = x / width; // Ranges from 0 to 1
// Calculate distortion offsets for the "pool" effect
// X-offset ripple based on Y-position, Y-offset ripple based on X-position
const angleYWave = normalizedY * waveFrequency * Math.PI * 2; // waveFrequency full waves across Y
const angleXWave = normalizedX * waveFrequency * Math.PI * 2; // waveFrequency full waves across X
const offsetX = Math.sin(angleYWave) * width * distortionAmount;
const offsetY = Math.cos(angleXWave) * height * distortionAmount; // Using cos for Y for varied pattern
// Calculate the source pixel coordinates after applying distortion
let srcX = Math.round(x + offsetX);
let srcY = Math.round(y + offsetY);
// Clamp source coordinates to be within the image bounds
srcX = Math.max(0, Math.min(width - 1, srcX));
srcY = Math.max(0, Math.min(height - 1, srcY));
const srcIndex = (srcY * width + srcX) * 4;
// Get original pixel color from the (distorted) source location
let r_src = originalPixelData[srcIndex];
let g_src = originalPixelData[srcIndex + 1];
let b_src = originalPixelData[srcIndex + 2];
const a_src = originalPixelData[srcIndex + 3]; // Alpha channel
// Apply "Acid" color transformation: R -> G, G -> B, B -> R (GBR cyclcic shift)
// This creates a psychedelic color effect.
let r_acid = g_src;
let g_acid = b_src;
let b_acid = r_src;
// Blend the "acid" color with the original source color based on colorIntensity parameter
const destIndex = (y * width + x) * 4;
data[destIndex] = (1 - colorIntensity) * r_src + colorIntensity * r_acid;
data[destIndex + 1] = (1 - colorIntensity) * g_src + colorIntensity * g_acid;
data[destIndex + 2] = (1 - colorIntensity) * b_src + colorIntensity * b_acid;
data[destIndex + 3] = a_src; // Preserve the original alpha
}
}
// Write the modified pixel data back to the canvas
ctx.putImageData(imageData, 0, 0);
return canvas;
}
Apply Changes