// Name: Contact Sheet
// Description: Creates a contact sheet from images in a dir
// Author: tayiorbeii
import Jimp from 'jimp';
// Pick directory of images
const dirPath = await path({ onlyDirs: true, placeholder: "Pick a directory of images" });
// Read files from directory
let files: string[];
try {
files = await readdir(dirPath);
} catch (error) { console.error("Error reading directory:", error);
await div("Error reading directory. Check console.");
exit();
}
// Filter for image files (jpg, jpeg, png, gif)
const imageFiles = files.filter(file => /\.(jpe?g|png|gif)$/i.test(file));
// Check if images were found
if (imageFiles.length === 0) {
await div("No images found in the selected directory.");
exit();
}
// Read images using Jimp
let images = await Promise.all(imageFiles.map(async file => {
try {
return await Jimp.read(path.join(dirPath, file));
} catch (error) {
console.error(`Error reading ${file}:`, error);
return null; // Return null for failed images, filter later.
}
}));
// Filter out null images (failed reads)
images = images.filter(image => image !== null) as Jimp[];
// Configuration
const thumbSize = 200;
const padding = 20;
const imagesPerRow = 5;
const rows = Math.ceil(images.length / imagesPerRow);
// Calculate composite dimensions
const compositeWidth = imagesPerRow * (thumbSize + padding) + padding;
const compositeHeight = rows * (thumbSize + padding) + padding;
// Create composite image
const composite = new Jimp(compositeWidth, compositeHeight, 0xFFFFFFFF);
// Loop through and composite images
for (let i = 0; i < images.length; i++) {
const row = Math.floor(i / imagesPerRow);
const col = i % imagesPerRow;
const x = padding + col * (thumbSize + padding);
const y = padding + row * (thumbSize + padding);
images[i].scaleToFit(thumbSize, thumbSize);
composite.composite(images[i], x, y);
}
// Output name
const outputName = path.join(dirPath, `contact-sheet-${Date.now()}.png`);
// Write the composite image
try { await composite.writeAsync(outputName);
} catch (error) {
console.error("Error writing composite image:", error);
await div("Error writing image. Check console.");
exit();
}
// Show success message and open file
await div(md(`## Contact Sheet Created!`),
{
onInit: async () => {
open(outputName);
}
});