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!
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.