You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, reflectionFactor = 0.5, reflectionOpacity = 0.5, reflectionGap = 0) {
// Ensure parameters are numbers and clamp them to sensible ranges.
const factor = Math.max(0, Math.min(1, Number(reflectionFactor)));
const opacity = Math.max(0, Math.min(1, Number(reflectionOpacity)));
const gap = Math.max(0, Number(reflectionGap));
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
// Handle cases where the image might not be loaded or has no dimensions.
if (imgWidth === 0 || imgHeight === 0) {
console.warn("Image Reflection Filter: Original image has zero width or height.");
// Return a small placeholder canvas to indicate an issue.
const errorCanvas = document.createElement('canvas');
errorCanvas.width = 1;
errorCanvas.height = 1;
const errCtx = errorCanvas.getContext('2d');
if (errCtx) {
// Optionally draw something to indicate error.
// errCtx.fillStyle = 'red';
// errCtx.fillRect(0, 0, 1, 1);
}
return errorCanvas;
}
const reflectionVisibleHeight = imgHeight * factor;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Set canvas dimensions to accommodate the original image, gap, and reflection.
canvas.width = imgWidth;
canvas.height = imgHeight + gap + reflectionVisibleHeight;
// 1. Draw the original image onto the canvas.
ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
// If reflection factor results in no visible reflection, return early.
// Using < 1 to catch very small float values that are effectively zero.
if (reflectionVisibleHeight < 1) {
return canvas;
}
// 2. Draw the reflection.
// The reflection area starts vertically at `imgHeight + gap`.
const reflectionYStart = imgHeight + gap;
ctx.save(); // Save current context state before applying transformations.
// Translate to the baseline of the reflection (bottom of reflection area) and flip vertically.
// The origin (0,0) of the transformed context will be at canvas coordinates
// (0, reflectionYStart + reflectionVisibleHeight), and the Y-axis will point upwards.
ctx.translate(0, reflectionYStart + reflectionVisibleHeight);
ctx.scale(1, -1); // Flip the context vertically.
// Draw the original image into the transformed context.
// Source rectangle: (0, 0, imgWidth, imgHeight) - the entire original image.
// Destination rectangle in transformed space: (0, 0, imgWidth, reflectionVisibleHeight).
// This draws the image, scaled vertically to reflectionVisibleHeight, and flipped.
// Its top (in original image) will appear at the bottom of the reflection.
ctx.drawImage(originalImg,
0, 0, imgWidth, imgHeight, // Source rectangle (full image)
0, 0, imgWidth, reflectionVisibleHeight // Destination rectangle in transformed space
);
ctx.restore(); // Restore context state (removes transformations).
// 3. Apply a fading gradient to the reflection area.
// This creates the illusion of the reflection fading into the background.
ctx.save(); // Save context state before applying globalCompositeOperation.
// Create a linear gradient for the reflection area.
// The gradient goes from the top of the reflection (reflectionYStart)
// to the bottom of the reflection (reflectionYStart + reflectionVisibleHeight).
const gradient = ctx.createLinearGradient(
0, reflectionYStart, // Gradient start point (x0, y0)
0, reflectionYStart + reflectionVisibleHeight // Gradient end point (x1, y1)
);
// Add color stops to the gradient.
// - Starts with the specified 'opacity' at the top of the reflection.
// - Fades to fully transparent at the bottom of the reflection.
// The color (e.g., black 'rgba(0,0,0,A)') doesn't affect the composite mode 'destination-in' outcome, only alpha.
gradient.addColorStop(0, `rgba(0, 0, 0, ${opacity})`); // Max opacity at the top of reflection
gradient.addColorStop(1, `rgba(0, 0, 0, 0)`); // Fully transparent at the bottom
// Apply the gradient using 'destination-in' global composite operation.
// 'destination-in': Keeps the existing canvas content (the drawn reflection)
// where it overlaps with the new shape (the gradient-filled rectangle).
// The alpha of the existing content is multiplied by the alpha of the new shape.
ctx.globalCompositeOperation = 'destination-in';
// Fill a rectangle covering the reflection area with the created gradient.
ctx.fillStyle = gradient;
ctx.fillRect(
0, reflectionYStart, // x, y of the rectangle (top-left of reflection area)
imgWidth, reflectionVisibleHeight // width, height of the rectangle
);
ctx.restore(); // Restore context state (notably, globalCompositeOperation).
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 Reflection Filter Application allows users to create a reflective effect of an image with customizable parameters. Users can specify the reflection height, opacity, and gap between the original image and its reflection. This tool is particularly useful for enhancing images in graphic design, web development, and social media posts, where a sophisticated visual effect can improve aesthetics and draw attention.