Please bookmark this page to avoid losing your image tool!

Image Video Reverser

(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.
/**
 * Reverses an animated image (like a GIF).
 * This function interprets "Image Video Reverser" as reversing the frames of an animated image,
 * as the required input is a JavaScript Image object, not a video stream or file.
 * The primary use case for this is reversing animated GIFs.
 *
 * It uses the 'omggif' library to read and write GIF data, which is loaded dynamically from a CDN.
 *
 * Note: The image's source must be accessible via fetch(). If the image is hosted on a different
 * origin, it must be served with appropriate CORS headers (e.g., Access-Control-Allow-Origin: *).
 *
 * @param {HTMLImageElement} originalImg The original Image object, which is expected to be an animated GIF.
 * @param {number} [speedMultiplier=1] A multiplier for the playback speed of the reversed GIF.
 *                                     Values greater than 1 speed up the animation (shorter delays),
 *                                     and values between 0 and 1 slow it down (longer delays).
 * @returns {Promise<HTMLImageElement|HTMLParagraphElement>} A promise that resolves to a new <img> element
 * containing the reversed animation, or a <p> element displaying an error message if the process fails.
 */
async function processImage(originalImg, speedMultiplier = 1) {

    // A self-contained helper function to dynamically load a script if it's not already present.
    const loadScript = (url, globalName) => {
        return new Promise((resolve, reject) => {
            // Resolve immediately if the library is already available on the window object.
            if (window[globalName]) {
                return resolve();
            }

            // Check if a script tag with the same src already exists to avoid duplicates.
            let script = document.querySelector(`script[src="${url}"]`);
            if (!script) {
                script = document.createElement('script');
                script.src = url;
                script.async = true;
                document.head.appendChild(script);
            }

            // Both new and existing script tags will get these listeners.
            script.addEventListener('load', () => resolve());
            script.addEventListener('error', () => reject(new Error(`Failed to load script: ${url}`)));
        });
    };

    const OMGGIF_URL = 'https://cdn.jsdelivr.net/npm/omggif@1.0.10/omggif.min.js';

    try {
        await loadScript(OMGGIF_URL, 'omggif');
    } catch (error) {
        console.error(error);
        const errorEl = document.createElement('p');
        errorEl.textContent = 'Error: Could not load the required GIF processing library.';
        errorEl.style.color = 'red';
        return errorEl;
    }

    try {
        // Fetch the raw image data as an ArrayBuffer.
        const response = await fetch(originalImg.src);
        if (!response.ok) {
            throw new Error(`Failed to fetch image data. Status: ${response.status}`);
        }
        const buffer = await response.arrayBuffer();

        // Use omggif to read the GIF data.
        const reader = new omggif.GifReader(new Uint8Array(buffer));

        const {
            width,
            height
        } = reader;
        const numFrames = reader.numFrames();

        // If it's a static image or single-frame GIF, there's nothing to reverse.
        // Return a new image element with the original source.
        if (numFrames <= 1) {
            const newImg = document.createElement('img');
            newImg.src = originalImg.src;
            newImg.width = width;
            newImg.height = height;
            return newImg;
        }

        const safeSpeedMultiplier = Math.max(0.01, Number(speedMultiplier) || 1);

        const allFrames = [];
        // Create a temporary buffer to hold the fully rendered pixel data for each frame.
        const framePixelDataBuffer = new Uint8Array(width * height * 4);

        // Decode each frame and store its fully composited version and delay info.
        for (let i = 0; i < numFrames; i++) {
            // The `decodeAndBlitFrameRGBA` method correctly composites the current frame
            // on top of the pixel data from the previous frame in the buffer.
            reader.decodeAndBlitFrameRGBA(i, framePixelDataBuffer);

            // Store a copy of the fully rendered frame's pixel data.
            allFrames.push({
                data: new Uint8Array(framePixelDataBuffer),
                delay: reader.frameInfo(i).delay // Delay is in 1/100ths of a second.
            });
        }

        // Re-encode the frames into a new GIF, but in reverse order.
        // We allocate a new buffer for the output. A 50% margin over the original size is usually safe.
        const outputBuffer = new Uint8Array(buffer.byteLength * 1.5 + 4096);
        const writer = new omggif.GifWriter(outputBuffer, width, height, {
            loop: 0, // A value of 0 means loop indefinitely.
        });

        for (let i = allFrames.length - 1; i >= 0; i--) {
            const frame = allFrames[i];
            writer.addFrame(0, 0, width, height, frame.data, {
                // Adjust a frame's delay based on the speed multiplier.
                delay: Math.round(frame.delay / safeSpeedMultiplier)
            });
        }

        const gifByteLength = writer.end();

        // Create a Blob from the generated byte array.
        const blob = new Blob([outputBuffer.subarray(0, gifByteLength)], {
            type: 'image/gif'
        });
        const reversedImgSrc = URL.createObjectURL(blob);

        // Create a new image element to display the reversed GIF.
        const reversedImg = document.createElement('img');
        reversedImg.src = reversedImgSrc;
        reversedImg.width = width;
        reversedImg.height = height;
        reversedImg.alt = "Reversed animated image";

        // The created Object URL will be released by the browser when the document is unloaded.
        // For applications where many objects are created, manual revocation might be necessary.

        return reversedImg;

    } catch (error) {
        console.error('Error during GIF reversal:', error);
        const errorEl = document.createElement('p');
        errorEl.textContent = 'Failed to reverse image. Please ensure it is a valid, accessible animated GIF file.';
        errorEl.style.color = 'red';
        return errorEl;
    }
}

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 Video Reverser tool allows users to reverse the playback of animated images, specifically GIF files. This tool takes an animated GIF as input and outputs a new GIF that plays the frames in reverse order. Users can also adjust the playback speed of the reversed animation to allow for a faster or slower display of frames. This functionality is particularly useful for creating humorous or artistic effects in animations, enhancing presentations, or generating unique content for social media.

Leave a Reply

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