Please bookmark this page to avoid losing your image tool!

Image Slideshow Creator 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.
function processImage(originalImg, additionalImageUrls = "", intervalParam = 3000, widthParam = 0, heightParam = 0) {
    // Parse numerical parameters
    // intervalParam could be string or number. parseInt handles strings.
    // If intervalParam is already a number, it's used as is.
    const interval = (typeof intervalParam === 'string' && !isNaN(parseInt(intervalParam, 10))) ? parseInt(intervalParam, 10) : Number(intervalParam);
    
    let desiredWidth = (typeof widthParam === 'string' && !isNaN(parseInt(widthParam, 10))) ? parseInt(widthParam, 10) : Number(widthParam);
    let desiredHeight = (typeof heightParam === 'string' && !isNaN(parseInt(heightParam, 10))) ? parseInt(heightParam, 10) : Number(heightParam);

    // Validate parsed width/height. 0 or invalid means auto-size based on the first image.
    if (isNaN(desiredWidth) || desiredWidth < 0) desiredWidth = 0;
    if (isNaN(desiredHeight) || desiredHeight < 0) desiredHeight = 0;

    const slideshowContainer = document.createElement('div');
    slideshowContainer.style.position = 'relative'; // For potential controls or overlays
    slideshowContainer.style.display = 'inline-block'; // Ensures container wraps canvas size
    slideshowContainer.style.overflow = 'hidden'; // Prevents content spill if errors occur

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    slideshowContainer.appendChild(canvas);

    // Initial canvas setup for "Loading..." message
    // Use desired dimensions if provided, otherwise a default placeholder size.
    const preliminaryWidth = desiredWidth > 0 ? desiredWidth : 300;
    const preliminaryHeight = desiredHeight > 0 ? desiredHeight : 200;
    canvas.width = preliminaryWidth;
    canvas.height = preliminaryHeight;
    slideshowContainer.style.width = `${preliminaryWidth}px`;
    slideshowContainer.style.height = `${preliminaryHeight}px`;

    ctx.fillStyle = "lightgray"; // Background for loading message
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "black"; // Text color for loading message
    ctx.textAlign = "center";
    ctx.textBaseline = "middle"; // Vertically center text
    ctx.font = "16px Arial";
    ctx.fillText("Loading slideshow...", canvas.width / 2, canvas.height / 2);

    const loadedImageObjects = []; // This will store successfully loaded Image objects
    let currentImageIndex = 0;
    let slideshowIntervalId = null;

    function drawImageOnCanvas(imgToDraw) {
        if (!canvas || !ctx) return; // Canvas context might not be available

        // Set a background color for the canvas. This is visible for letter/pillarboxing
        // or if images have transparency.
        ctx.fillStyle = 'black'; 
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        if (!imgToDraw || !(imgToDraw instanceof Image) || !imgToDraw.complete || imgToDraw.naturalWidth === 0) {
            console.warn("processImage: Attempted to draw an invalid or improperly loaded image.");
            // Display an error message on the canvas for this specific problematic image
            ctx.fillStyle = "gray"; // Placeholder for image error
            ctx.fillRect(0,0, canvas.width, canvas.height); // Fill with placeholder color
            ctx.fillStyle = "white"; // Text color for error message
            ctx.font = "16px Arial"; // Ensure font is set for this message
            ctx.textAlign = "center"; // Ensure text alignment is set
            ctx.textBaseline = "middle"; // Ensure vertical alignment is set
            ctx.fillText("Image Error", canvas.width / 2, canvas.height / 2);
            return;
        }
        
        const imgAspectRatio = imgToDraw.naturalWidth / imgToDraw.naturalHeight;
        const canvasAspectRatio = canvas.width / canvas.height;
        let drawWidth, drawHeight, offsetX, offsetY;

        // Calculate dimensions to fit the image within the canvas while maintaining aspect ratio
        if (imgAspectRatio > canvasAspectRatio) { // Image is wider than canvas aspect ratio (letterboxed)
            drawWidth = canvas.width;
            drawHeight = drawWidth / imgAspectRatio;
            offsetX = 0;
            offsetY = (canvas.height - drawHeight) / 2;
        } else { // Image is taller or same aspect ratio as canvas (pillarboxed)
            drawHeight = canvas.height;
            drawWidth = drawHeight * imgAspectRatio;
            offsetX = (canvas.width - drawWidth) / 2;
            offsetY = 0;
        }
        ctx.drawImage(imgToDraw, offsetX, offsetY, drawWidth, drawHeight);
    }

    function showNextImage() {
        if (loadedImageObjects.length === 0) return; // No images to show
        currentImageIndex = (currentImageIndex + 1) % loadedImageObjects.length;
        drawImageOnCanvas(loadedImageObjects[currentImageIndex]);
    }
    
    const sourcesToProcess = []; // Array to hold Image objects or URL strings for loading
    
    // Validate originalImg parameter
    if (!(originalImg instanceof Image)) {
        console.error("processImage: originalImg parameter is not a valid Image object.");
        ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear "Loading..."
        ctx.fillStyle = "red"; // Error background
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = "white"; // Error text color
        ctx.fillText("Error: Invalid originalImg", canvas.width / 2, canvas.height / 2);
        return slideshowContainer; // Return immediately with error displayed
    }
    sourcesToProcess.push(originalImg); // Add the original Image object to sources

    // Process additional image URLs
    if (additionalImageUrls && typeof additionalImageUrls === 'string' && additionalImageUrls.trim() !== '') {
        additionalImageUrls.split(',')
            .map(url => url.trim()) // Trim whitespace
            .filter(url => url.length > 0) // Filter out empty strings (e.g., from "url1,,url2")
            .forEach(urlStr => sourcesToProcess.push(urlStr)); // Add URL strings to sources
    }

    // If, after all, there are no sources (e.g. originalImg was valid but no src, and no additional URLs)
    // This check is more robustly handled by the loading logic leading to empty loadedImageObjects.
    // However, if sourcesToProcess is empty due to logic error, it's a fallback.
    if (sourcesToProcess.length === 0) {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.fillText("No images specified.", canvas.width / 2, canvas.height / 2);
        return slideshowContainer;
    }
    
    let imagesAttemptedCount = 0;
    // Use an intermediate array to store loaded/failed images, preserving initial order
    const intermediateImageStore = new Array(sourcesToProcess.length).fill(null);

    const finalizeSlideshowSetup = () => {
        // Populate loadedImageObjects with successfully loaded images from intermediateStore
        loadedImageObjects.length = 0; // Clear array before repopulating
        for (const img of intermediateImageStore) {
            if (img) { // Check if img is not null (i.e., successfully loaded)
                loadedImageObjects.push(img);
            }
        }

        if (loadedImageObjects.length === 0) {
            // All images failed to load or no valid images were found
            console.error("processImage: All images failed to load or no valid images provided.");
            ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear "Loading..."
            ctx.fillStyle = "darkred"; // Error background for "all failed"
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            ctx.fillStyle = "white"; // Error text color
            // Ensure text properties are set correctly for this error message
            ctx.font = "16px Arial";
            ctx.textAlign = "center";
            ctx.textBaseline = "middle";
            ctx.fillText("Error: No images could be loaded.", canvas.width / 2, canvas.height / 2);
            // Canvas size remains as preliminary or desired fixed size
            return;
        }

        // Determine final canvas dimensions. Use desiredWidth/Height if specified,
        // otherwise use dimensions of the first successfully loaded image.
        const firstSuccessfullyLoadedImage = loadedImageObjects[0];
        const finalCanvasWidth = desiredWidth > 0 ? desiredWidth : firstSuccessfullyLoadedImage.naturalWidth;
        const finalCanvasHeight = desiredHeight > 0 ? desiredHeight : firstSuccessfullyLoadedImage.naturalHeight;

        canvas.width = finalCanvasWidth;
        canvas.height = finalCanvasHeight;
        slideshowContainer.style.width = `${finalCanvasWidth}px`;
        slideshowContainer.style.height = `${finalCanvasHeight}px`;
        
        // Initial draw of the first image in the slideshow
        currentImageIndex = 0; // Ensure we start with the first image from the filtered list
        drawImageOnCanvas(loadedImageObjects[currentImageIndex]);

        // Start the slideshow interval if there's more than one image and interval is valid
        if (slideshowIntervalId) clearInterval(slideshowIntervalId); // Clear any existing interval
        
        // Check if interval is a valid positive number
        if (loadedImageObjects.length > 1 && !isNaN(interval) && interval > 0) {
            slideshowIntervalId = setInterval(showNextImage, interval);
        }
    };

    sourcesToProcess.forEach((srcOrImageObject, idx) => {
        // If srcOrImageObject is already an Image object (like originalImg), use it directly.
        // Otherwise, create a new Image object for URL strings.
        const img = (srcOrImageObject instanceof Image) ? srcOrImageObject : new Image();
        
        // For images loaded from URLs (not originalImg if it's pre-loaded/configured)
        if (!(srcOrImageObject instanceof Image)) {
            img.crossOrigin = "Anonymous"; // crucial for canvas use if images are from other domains
        }

        img.onload = () => {
            intermediateImageStore[idx] = img; // Store successfully loaded image
            imagesAttemptedCount++;
            if (imagesAttemptedCount === sourcesToProcess.length) {
                finalizeSlideshowSetup(); // All images have been attempted (loaded or failed)
            }
        };
        img.onerror = () => {
            let errorSrc = typeof srcOrImageObject === 'string' ? srcOrImageObject : img.src;
            if (!errorSrc && srcOrImageObject === originalImg) errorSrc = 'originalImg object (no src or invalid)';
            else if (!errorSrc) errorSrc = 'unknown source';
            console.warn(`processImage: Failed to load image from source: ${errorSrc}`);
            
            intermediateImageStore[idx] = null; // Mark as failed
            imagesAttemptedCount++;
            if (imagesAttemptedCount === sourcesToProcess.length) {
                finalizeSlideshowSetup(); // All images have been attempted
            }
        };

        if (srcOrImageObject instanceof Image) { // Special handling for pre-existing Image objects (e.g. originalImg)
            if (img.complete) { // If the Image object reports it's 'complete'
                if (img.naturalWidth > 0 && img.naturalHeight > 0) { // And has valid dimensions (likely loaded)
                    img.onload(); // Manually trigger our onload handler
                } else if (img.src) { // Complete, but no dimensions, and has a 'src' (indicates an error state)
                    img.onerror(); // Manually trigger our onerror handler
                } else { // Complete, but no 'src' and no dimensions (e.g., `new Image()`)
                    console.warn("processImage: An Image object was provided that is 'complete' but has no 'src' attribute and no dimensions. Treated as error.");
                    img.onerror(); // Treat as an error
                }
            } else if (!img.src) {
                // Not 'complete' and no 'src' attribute. This Image object will not load anything.
                console.warn("processImage: An Image object was provided that is not 'complete' and has no 'src' attribute. Treated as error.");
                img.onerror(); // Treat as an error
            }
            // If it's not 'complete' but *has* a 'src', our onload/onerror handlers are now attached
            // and will fire when the browser finishes loading or encounters an error.
        } else { // It's a URL string, so set its 'src' to trigger loading
            img.src = srcOrImageObject;
        }
    });
    
    // Attach a method to the container to allow manual cleanup of the interval
    slideshowContainer.destroySlideshow = () => {
        if (slideshowIntervalId) {
            clearInterval(slideshowIntervalId);
            slideshowIntervalId = null;
        }
        // console.log("processImage: Slideshow stopped and interval cleared.");
        // Optionally, add more cleanup like clearing the canvas:
        // if(ctx) ctx.clearRect(0,0,canvas.width,canvas.height);
    };

    return slideshowContainer;
}

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 Slideshow Creator Tool allows users to create a dynamic slideshow of images, displaying them one after another at customizable intervals. Users can initiate the slideshow with a starting image and add additional images through URLs. This tool is useful for presentations, galleries, and online portfolios, where users want to visually showcase a series of images in an engaging manner. The slideshow can adapt to specified dimensions or automatically adjust based on the images, providing versatility for different display contexts.

Leave a Reply

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