You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, p_waveAmplitude = 10, p_numWaves = 3, p_startAlpha = 0.7, p_endAlpha = 0.0) {
// Parameter parsing and validation
let waveAmplitude = Number(p_waveAmplitude);
let numWaves = Number(p_numWaves);
let startAlpha = Number(p_startAlpha);
let endAlpha = Number(p_endAlpha);
// Defaulting logic for NaN or otherwise invalid inputs
waveAmplitude = isNaN(waveAmplitude) ? 10 : waveAmplitude;
// Ensure numWaves is non-negative; if NaN or negative, default to 3.
numWaves = (isNaN(numWaves) || numWaves < 0) ? 3 : numWaves;
// Clamp alpha values to the [0,1] range; if NaN, use defaults.
startAlpha = isNaN(startAlpha) ? 0.7 : Math.max(0, Math.min(1, startAlpha));
endAlpha = isNaN(endAlpha) ? 0.0 : Math.max(0, Math.min(1, endAlpha));
const imgWidth = originalImg.width;
const imgHeight = originalImg.height;
// Handle cases where the image might not be loaded or has zero dimensions
if (imgWidth === 0 || imgHeight === 0) {
const emptyCanvas = document.createElement('canvas');
emptyCanvas.width = 1;
emptyCanvas.height = 1;
// Optional: clear to ensure it's blank transparent
const ctx = emptyCanvas.getContext('2d');
if (ctx) {
ctx.clearRect(0,0,1,1);
}
return emptyCanvas;
}
// Main canvas that will contain the original image and its reflection
const mainCanvas = document.createElement('canvas');
mainCanvas.width = imgWidth;
mainCanvas.height = imgHeight * 2; // Double height for reflection
const mainCtx = mainCanvas.getContext('2d', { willReadFrequently: true });
// 1. Draw the original image onto the top half of the main canvas
mainCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
// 2. Create the reflection
// Temporary canvas to prepare the reflection (flipped and rippled)
const reflectionCanvas = document.createElement('canvas');
reflectionCanvas.width = imgWidth;
reflectionCanvas.height = imgHeight;
const reflectionCtx = reflectionCanvas.getContext('2d', { willReadFrequently: true });
// Flip the image vertically and draw it onto the reflectionCanvas
reflectionCtx.save();
reflectionCtx.translate(0, imgHeight);
reflectionCtx.scale(1, -1);
reflectionCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
reflectionCtx.restore(); // Restore context to normal for getImageData/putImageData
// Apply ripple effect if waveAmplitude and numWaves are effective
if (waveAmplitude !== 0 && numWaves > 0) {
const sourceImageData = reflectionCtx.getImageData(0, 0, imgWidth, imgHeight);
const sourceData = sourceImageData.data;
const outputImageData = reflectionCtx.createImageData(imgWidth, imgHeight);
const outputData = outputImageData.data;
const effectiveWaveFrequency = (numWaves * 2 * Math.PI) / imgHeight;
for (let y = 0; y < imgHeight; y++) {
// Calculate horizontal displacement for this row
const displacement = waveAmplitude * Math.sin(y * effectiveWaveFrequency);
for (let x = 0; x < imgWidth; x++) {
// Determine the source X coordinate, applying the displacement
let srcX = Math.round(x - displacement);
// Clamp source X to be within image bounds to avoid reading outside pixels
srcX = Math.max(0, Math.min(imgWidth - 1, srcX));
const dstIdx = (y * imgWidth + x) * 4; // Destination pixel index
const srcIdx = (y * imgWidth + srcX) * 4; // Source pixel index
// Copy RGBA pixel data
outputData[dstIdx] = sourceData[srcIdx];
outputData[dstIdx + 1] = sourceData[srcIdx + 1];
outputData[dstIdx + 2] = sourceData[srcIdx + 2];
outputData[dstIdx + 3] = sourceData[srcIdx + 3];
}
}
// Put the rippled image data back onto the reflectionCanvas, overwriting the simply-flipped image
reflectionCtx.putImageData(outputImageData, 0, 0);
}
// At this point, reflectionCanvas holds the flipped image, possibly with ripples.
// Draw the prepared reflection (from reflectionCanvas) onto the bottom half of the main canvas
mainCtx.drawImage(reflectionCanvas, 0, imgHeight);
// 3. Apply a vertical alpha gradient to make the reflection fade out
mainCtx.save();
// Use 'destination-in' composite operation: the existing content (reflection) is kept
// where it's covered by the new shape (gradient rectangle). The alpha of the new shape
// determines the alpha of the kept content.
mainCtx.globalCompositeOperation = 'destination-in';
const gradient = mainCtx.createLinearGradient(0, imgHeight, 0, imgHeight * 2);
gradient.addColorStop(0, `rgba(0,0,0,${startAlpha})`); // Alpha at the reflection line (top of reflection)
gradient.addColorStop(1, `rgba(0,0,0,${endAlpha})`); // Alpha at the bottom of the reflection
mainCtx.fillStyle = gradient;
mainCtx.fillRect(0, imgHeight, imgWidth, imgHeight); // Apply gradient to the reflection area
mainCtx.restore(); // Restore globalCompositeOperation to default ('source-over')
return mainCanvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Oasis Reflection Filter Effect Tool allows users to create stunning reflective effects on images. By applying a ripple effect to the reflection, users can modify parameters such as wave amplitude and number of waves to achieve a variety of artistic looks. This tool is particularly useful for graphic designers, photographers, or anyone looking to enhance their images for presentations, social media posts, or digital art. The gradient alpha feature provides an option for the reflection to fade out, adding a professional touch to the final result.