Please bookmark this page to avoid losing your image tool!

Image Boomerang Path Filter Effect Tool

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, numEchoesPerArm = 5, trajectoryLength = 50, trajectoryWidth = 30, trajectoryAngleDeg = 0, startOpacity = 0.3, opacityStepFactor = 0.8) {
    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;

    // Ensure numEchoesPerArm is a non-negative integer
    const echoesCount = Math.max(0, Math.floor(numEchoesPerArm));

    if (imgWidth === 0 || imgHeight === 0) {
        // Create and return a tiny empty canvas if image is invalid
        const emptyCanvas = document.createElement('canvas');
        emptyCanvas.width = 1;
        emptyCanvas.height = 1;
        return emptyCanvas;
    }
    
    // Calculate the maximum displacement of echoes to determine canvas padding.
    // This is the distance from the cusp (center of effect) to the tip of an arm of the parabola.
    const maxDim = Math.sqrt(trajectoryLength * trajectoryLength + trajectoryWidth * trajectoryWidth);

    const canvas = document.createElement('canvas');
    // Add padding around the image to accommodate echoes that might extend beyond original bounds.
    const padding = Math.ceil(Math.abs(maxDim)); // Use Math.abs in case trajectoryLength makes maxDim complex (though sqrt should handle it)
    
    canvas.width = imgWidth + 2 * padding;
    canvas.height = imgHeight + 2 * padding;
    
    const ctx = canvas.getContext('2d');

    // The mainImageDrawX/Y is the top-left corner where the original, central image instance is drawn.
    const mainImageDrawX = padding;
    const mainImageDrawY = padding;

    const angleRad = trajectoryAngleDeg * Math.PI / 180;
    const cosA = Math.cos(angleRad);
    const sinA = Math.sin(angleRad);

    // Draw echoes
    // Loop from furthest echo (most transparent, largest i) to closest (i=0)
    // This ensures echoes closer to the main image are drawn on top of further ones.
    for (let i = echoesCount - 1; i >= 0; i--) {
        // param_t ranges from (i+1)/echoesCount, effectively from 1/N to 1.0.
        // 1.0 means it's at the tip of the trajectory arm.
        // 1/N means it's closest to the main image.
        const param_t = (i + 1) / echoesCount;
        
        // Opacity: i=0 (closest echo) gets startOpacity. i=echoesCount-1 (furthest) gets startOpacity * factor^(N-1).
        const currentOpacity = startOpacity * Math.pow(opacityStepFactor, i);

        let x_local, y_local_arm1, y_local_arm2;

        if (trajectoryWidth === 0) { // Linear path
            x_local = param_t * trajectoryLength; // Echoes spread linearly along the trajectoryLength
            y_local_arm1 = 0;
            // y_local_arm2 is not used because the second arm drawing is skipped
        } else { // Parabolic path (V-shape or C-shape)
            // x = (y/W)^2 * L simplified to x = t_param^2 * L
            // y = t_param * W
            x_local = param_t * param_t * trajectoryLength; 
            y_local_arm1 = param_t * trajectoryWidth;
            y_local_arm2 = -param_t * trajectoryWidth;
        }
        
        ctx.globalAlpha = currentOpacity;

        // Calculate position for Arm 1 echo
        const rotatedX1 = x_local * cosA - y_local_arm1 * sinA;
        const rotatedY1 = x_local * sinA + y_local_arm1 * cosA;
        // Draw echo for Arm 1
        // Positions are relative to the main image's top-left corner.
        ctx.drawImage(originalImg, mainImageDrawX + rotatedX1, mainImageDrawY + rotatedY1, imgWidth, imgHeight);

        // Draw Arm 2 echo only if it's distinct from Arm 1 (i.e., trajectoryWidth != 0)
        if (trajectoryWidth !== 0) {
            const rotatedX2 = x_local * cosA - y_local_arm2 * sinA;
            const rotatedY2 = x_local * sinA + y_local_arm2 * cosA;
            ctx.drawImage(originalImg, mainImageDrawX + rotatedX2, mainImageDrawY + rotatedY2, imgWidth, imgHeight);
        }
    }

    // DravirtualImgw the main image instance on top of all echoes, fully opaque
    ctx.globalAlpha = 1.0;
    ctx.drawImage(originalImg, mainImageDrawX, mainImageDrawY, imgWidth, imgHeight);

    return canvas;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Image Boomerang Path Filter Effect Tool allows users to create a visually appealing echo effect for images. By adjusting parameters such as the number of echoes, trajectory length and width, and angle, users can generate unique artistic images that create the appearance of motion or depth. This tool is suitable for enhancing photographs, creating graphic designs, or adding creative flair to social media posts.

Leave a Reply

Your email address will not be published. Required fields are marked *