thumbkit
v1.0.0
Published
A comprehensive TypeScript library for generating thumbnails from images, PDFs, videos, office documents, and archives.
Downloads
4
Maintainers
Readme
Universal Thumbnail Generator
A comprehensive TypeScript library for generating thumbnails from various file formats including images, PDFs, videos, office documents, and archives.
Features
- 🖼️ Image Support: JPEG, PNG, GIF, WebP, TIFF, BMP, SVG, AVIF, HEIC, HEIF
- 📄 Document Support: PDF, TXT, MD, RTF
- 🎥 Video Support: MP4, AVI, MOV, WMV, FLV, WebM, MKV, M4V, 3GP, OGV
- 📊 Office Support: DOC, DOCX, XLS, XLSX, PPT, PPTX, ODT, ODS, ODP
- 🗜️ Archive Support: ZIP, RAR, 7Z, TAR, GZ, BZ2
- ⚡ High Performance: Built with Sharp for fast image processing
- 🛡️ Type Safe: Full TypeScript support with comprehensive type definitions
- 🔧 Configurable: Extensive configuration options for all output formats
- 📦 Batch Processing: Generate multiple thumbnails efficiently
- 🎨 Multiple Formats: Output as JPEG, PNG, WebP, or AVIF
Installation
npm install universal-thumbnail-generatorDependencies
The package requires some peer dependencies based on what file types you want to support:
# For basic image and PDF support (always required)
npm install sharp canvas pdfjs-dist
# For video thumbnail support (optional)
npm install ffmpeg-static
# For office document support (optional)
npm install libreoffice-convertQuick Start
import { UniversalThumbnailGenerator } from "universal-thumbnail-generator";
const generator = new UniversalThumbnailGenerator({
width: 300,
height: 300,
quality: 90,
format: "jpeg",
});
// Generate thumbnail from file path
const result = await generator.generate("./path/to/image.jpg");
// Generate thumbnail from buffer
const fileBuffer = await fs.readFile("./document.pdf");
const result = await generator.generate(fileBuffer, "document.pdf");
// Save the thumbnail
await fs.writeFile(result.fileName, result.fileBuffer);Configuration Options
interface ThumbnailConfig {
width?: number; // Default: 200
height?: number; // Default: 200
quality?: number; // Default: 80 (1-100)
suffix?: string; // Default: '_thumb'
format?: "jpeg" | "png" | "webp" | "avif"; // Default: 'jpeg'
fit?: "cover" | "contain" | "fill" | "inside" | "outside"; // Default: 'inside'
withoutEnlargement?: boolean; // Default: true
background?: {
// Default: white
r: number;
g: number;
b: number;
alpha: number;
};
position?: string; // Default: 'center'
}Usage Examples
Basic Usage
import { UniversalThumbnailGenerator } from "universal-thumbnail-generator";
const generator = new UniversalThumbnailGenerator();
// From file path
const thumbnail = await generator.generate("./image.jpg");
// From buffer with filename
const buffer = await fs.readFile("./document.pdf");
const thumbnail = await generator.generate(buffer, "document.pdf");
// From FileInput object
const thumbnail = await generator.generate({
buffer: fileBuffer,
fileName: "presentation.pptx",
});Advanced Configuration
const generator = new UniversalThumbnailGenerator({
width: 400,
height: 300,
quality: 95,
format: "webp",
fit: "cover",
background: { r: 240, g: 240, b: 240, alpha: 1 },
suffix: "_preview",
});
const thumbnail = await generator.generate("./video.mp4");Batch Processing
const files = [
"./image1.jpg",
"./document.pdf",
{ buffer: videoBuffer, fileName: "video.mp4" },
];
const batchResult = await generator.generateBatch(files, {
width: 150,
height: 150,
});
console.log(`Generated ${batchResult.results.length} thumbnails`);
console.log(`Failed: ${batchResult.errors.length} files`);
// Process results
batchResult.results.forEach(async (result) => {
await fs.writeFile(`./thumbnails/${result.fileName}`, result.fileBuffer);
});
// Handle errors
batchResult.errors.forEach((error) => {
console.error(`Error processing ${error.fileName}: ${error.error}`);
});Dynamic Configuration
const generator = new UniversalThumbnailGenerator();
// Override config for specific generation
const thumbnail = await generator.generate("./image.jpg", undefined, {
width: 500,
height: 500,
format: "png",
});
// Update global config
generator.updateConfig({
quality: 100,
format: "avif",
});
// Reset to defaults
generator.resetConfig();File Type Support
Images
- Formats: JPEG, PNG, GIF, WebP, TIFF, BMP, SVG, AVIF, HEIC, HEIF
- Features: Full metadata extraction, format conversion, quality control
Documents
- PDF: First page rendering with high quality
- Text files: Placeholder thumbnails with file type indicators
Videos
- Formats: MP4, AVI, MOV, WMV, FLV, WebM, MKV, M4V, 3GP, OGV
- Note: Currently generates placeholder thumbnails. Full video frame extraction requires ffmpeg integration.
Office Documents
- Formats: Microsoft Office (DOC, DOCX, XLS, XLSX, PPT, PPTX) and OpenDocument (ODT, ODS, ODP)
- Features: Color-coded thumbnails based on document type
Archives
- Formats: ZIP, RAR, 7Z, TAR, GZ, BZ2
- Features: Distinctive archive-style thumbnails
API Reference
Constructor
new UniversalThumbnailGenerator(options?: ThumbnailConfig)Methods
generate(input, fileName?, options?)
Generate a single thumbnail.
Parameters:
input:Buffer | string | FileInput- File buffer, path, or FileInput objectfileName?:string- Required when input is Bufferoptions?:Partial<ThumbnailConfig>- Override default config
Returns: Promise<ThumbnailResult>
generateBatch(files, options?)
Generate multiple thumbnails.
Parameters:
files:Array<string | FileInput>- Array of file paths or FileInput objectsoptions?:Partial<ThumbnailConfig>- Override default config
Returns: Promise<BatchResult>
isSupported(fileName)
Check if file type is supported.
Parameters:
fileName:string- File name with extension
Returns: boolean
getFileType(fileName)
Get file type category.
Parameters:
fileName:string- File name with extension
Returns: FileType - 'image' | 'document' | 'video' | 'office' | 'archive' | 'unsupported'
getSupportedTypes()
Get all supported file extensions grouped by category.
Returns: SupportedTypes
getSupportedExtensions()
Get flat array of all supported extensions.
Returns: string[]
updateConfig(newConfig)
Update configuration.
Parameters:
newConfig:Partial<ThumbnailConfig>- New configuration options
getConfig()
Get current configuration.
Returns: Required<ThumbnailConfig>
resetConfig()
Reset configuration to defaults.
Response Types
ThumbnailResult
interface ThumbnailResult {
fileName: string; // Generated thumbnail filename
originalFileName: string; // Original file name
fileBuffer: Buffer; // Thumbnail image buffer
fileSizeInBytes: number; // Thumbnail file size
mimeType: string; // Output MIME type
md5Hash: string; // MD5 hash of thumbnail
fileType: FileType; // File type category
dimensions: {
// Thumbnail dimensions
width: number;
height: number;
};
quality: number; // Quality setting used
createdAt: string; // ISO timestamp
isThumbnail: boolean; // Always true
metadata?: Record<string, any>; // Additional metadata
}BatchResult
interface BatchResult {
results: ThumbnailResult[];
errors: Array<{
index: number;
fileName?: string;
error: string;
}>;
}Error Handling
The library provides detailed error messages for different failure scenarios:
try {
const thumbnail = await generator.generate("./invalid-file.xyz");
} catch (error) {
if (error.message.includes("Unsupported file type")) {
console.log("File type not supported");
} else if (error.message.includes("generation failed")) {
console.log("Processing error:", error.message);
}
}Performance Tips
- Batch Processing: Use
generateBatch()for multiple files to improve performance - Configuration: Set configuration once and reuse the generator instance
- Format Selection: Use JPEG for smaller file sizes, PNG for transparency, WebP for modern browsers
- Quality Settings: Lower quality (60-80) significantly reduces file size with minimal visual impact
- Size Optimization: Choose appropriate dimensions based on your use case
Examples
Web Server Integration (Express.js)
import express from "express";
import multer from "multer";
import { UniversalThumbnailGenerator } from "universal-thumbnail-generator";
const app = express();
const upload = multer();
const generator = new UniversalThumbnailGenerator({
width: 200,
height: 200,
quality: 80,
});
app.post("/upload", upload.single("file"), async (req, res) => {
try {
if (!req.file) {
return res.status(400).json({ error: "No file uploaded" });
}
const thumbnail = await generator.generate(
req.file.buffer,
req.file.originalname
);
res.json({
success: true,
thumbnail: {
fileName: thumbnail.fileName,
size: thumbnail.fileSizeInBytes,
dimensions: thumbnail.dimensions,
},
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});File Processing Pipeline
import { UniversalThumbnailGenerator } from "universal-thumbnail-generator";
import { promises as fs } from "fs";
import path from "path";
async function processDirectory(inputDir: string, outputDir: string) {
const generator = new UniversalThumbnailGenerator({
width: 300,
height: 300,
quality: 85,
format: "webp",
});
const files = await fs.readdir(inputDir);
const supportedFiles = files.filter((file) => generator.isSupported(file));
console.log(`Processing ${supportedFiles.length} supported files...`);
const filePaths = supportedFiles.map((file) => path.join(inputDir, file));
const batchResult = await generator.generateBatch(filePaths);
// Save thumbnails
for (const result of batchResult.results) {
const outputPath = path.join(outputDir, result.fileName);
await fs.writeFile(outputPath, result.fileBuffer);
console.log(`✓ Generated: ${result.fileName}`);
}
// Report errors
for (const error of batchResult.errors) {
console.error(`✗ Failed: ${error.fileName} - ${error.error}`);
}
console.log(
`\nCompleted: ${batchResult.results.length} thumbnails generated`
);
}Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
v1.0.0
- Initial release
- Support for images, PDFs, videos (placeholder), office documents, and archives
- TypeScript support with full type definitions
- Batch processing capabilities
- Comprehensive configuration options
Support
If you encounter any issues or have questions, please file an issue on the GitHub repository.
