Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork0
🏞️ Make your images load faster. A better save for the web.
License
stacksjs/imgx
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
A powerful image optimization toolkit for modern web development.
- Features
- Installation
- Getting Started
- Configuration
- CLI Reference
- Feature Documentation
- Contributing
- Community
- Credits
- License
Advanced Image Optimization
- Lossy & lossless compression
- Smart quality optimization
- Metadata stripping
- Color profile management
Format Support
- WebP, AVIF conversion
- JPEG, PNG optimization
- SVG minification
- Animated GIF optimization
Modern Web Features
- Responsive image generation
- Art direction support
- Lazy loading helpers
- ThumbHash placeholders
- Sprite sheet generation
- OG Image generation
- Low-resolution image placeholders
- Batch image processing
Developer Experience
- Watch mode for development
- Development server with on-the-fly optimization
- CI/CD integration
- Detailed analysis and reporting
- Progress indicators
Privacy & Performance
- Metadata stripping
- Configurable optimization levels
- Cache control
- Web-optimized by default
bun install -d @stacksjs/imgxnpm install --save-dev @stacksjs/imgxyarn add -D @stacksjs/imgxpnpm add -D @stacksjs/imgx
Basic optimization:
# Optimize a single imageimgx optimize input.jpg -q 75# Convert to WebPimgx optimize input.jpg output.webp -f webp# Optimize a directory of imagesimgx optimize ./images -R -f webp# Watch mode for developmentimgx optimize ./src/images -w -f webp
Advanced features:
# Generate responsive imagesimgx optimize hero.jpg --responsive --responsive-sizes 320,768,1024,1920# Create sprite sheetimgx sprite ./icons ./dist --retina --optimize# Generate thumbnails with ThumbHashimgx optimize input.jpg -t --thumbhash-size 64x64# Analyze image optimization potentialimgx analyze ./images -o report.json --ci
Development server:
# Start dev server with on-the-fly optimizationimgx serve ./public -p 3000# Access optimized images:# http://localhost:3000/image.jpg?format=webp&quality=75&size=800x600
import{analyzeImage,batchProcessImages,convertImageFormat,generatePlaceholder,generateSprite,process}from'@stacksjs/imgx'// Basic optimizationawaitprocess({input:'input.jpg',output:'output.webp',quality:75,format:'webp'})// Generate responsive imagesawaitprocess({input:'hero.jpg',responsive:true,responsiveSizes:[320,768,1024,1920],format:'webp'})// Create sprite sheetawaitgenerateSprite({images:['icon1.png','icon2.png'],output:'./dist',retina:true,format:'webp'})// Generate low-resolution placeholderconstplaceholder=awaitgeneratePlaceholder('hero.jpg',{width:20,blurLevel:40,quality:50,format:'webp',base64Encode:true,// Get base64 data URL})// Use placeholder.dataURL in your HTML for LQIP technique// Generate thumbhash placeholderconstthumbhashPlaceholder=awaitgeneratePlaceholder('hero.jpg',{thumbhash:true,})// Use thumbhashPlaceholder.dataURL for an efficient placeholder// Convert image to a different formatconstwebpPath=awaitconvertImageFormat('image.jpg','webp',{quality:80,outputDir:'./dist',})// Process a directory of images in batchconstresults=awaitanalyzeImage('image.jpg')console.log(report.optimizationPotential)
Create animgx.config.ts
file:
importtype{ImgxConfig}from'@stacksjs/imgx'exportdefault{// General optionsverbose:true,cache:true,cacheDir:'.imgx-cache',// Default optimization settingsquality:75,format:'webp',progressive:true,stripMetadata:true,// Responsive image settingsresponsive:{sizes:[320,768,1024,1920],formats:['webp','avif'],quality:75},// Sprite generationsprites:{retina:true,padding:2,prefix:'icon',format:'webp'},// Development serverserver:{port:3000,cache:true,cors:true}}satisfiesImgxConfig
imgx optimize [input] [output]Options: -q, --quality<number> Image quality (1-100) (default: 80) -r, --resize<string> Resize image (e.g.,"50%" or"800x600") -f, --format<string> Output format (jpeg, png, webp, avif) -p, --progressive Enable progressive mode (default: true) -m, --preserve-metadata Preserve image metadata -w, --watch Watchfor file changes -R, --recursive Process directories recursively -t, --thumbhash Generate ThumbHash placeholder --responsive Generate responsive images --skip-existing Skip already optimized files --backup Create backup of original filesExamples: $ imgx optimize input.jpg -q 75 -r 50% $ imgx optimize ./images -f webp -R $ imgx optimize input.jpg -t --thumbhash-size 64x64 $ imgx sprite ./icons ./dist --retina --optimize $ imgx analyze ./images --ci --threshold 500KB
For more detailed documentation on each feature, visit ourdocumentation site.
You can now use imgx to generate properly sized app icons for macOS and iOS applications from a single source image.
Read the full App Icon documentation →
# Generate app icons for all platforms (macOS and iOS)imgx app-icon source-icon.png# Generate only macOS app iconsimgx app-icon source-icon.png -p macos# Generate only iOS app iconsimgx app-icon source-icon.png -p ios# Specify a custom output directoryimgx app-icon source-icon.png -o ./my-app/assets
import{generateAppIcons}from'imgx'// Generate app icons for all platformsawaitgenerateAppIcons('path/to/source-icon.png')// Generate only macOS app iconsawaitgenerateAppIcons('path/to/source-icon.png',{platform:'macos',outputDir:'./my-app/assets'})
You can configure the app icon generation in yourimgx.config.ts
file:
importtype{ImgxConfig}from'imgx'constconfig:ImgxConfig={// Other configuration options...appIcon:{outputDir:'assets/app-icons',// Default output directoryplatform:'all',// Default platform target ('macos', 'ios', or 'all')},}exportdefaultconfig
The tool will generate:
- All required app icon sizes for the selected platform(s)
- A properly formatted
Contents.json
file for Xcode - A README.md with installation instructions
Imgx provides powerful image placeholder generation for improved page load performance:
Read the full Image Placeholders documentation →
// Generate a low-resolution blurred placeholderconstplaceholder=awaitgeneratePlaceholder('image.jpg',{width:20,// Small width for efficiencyblurLevel:40,// Higher values = more blurquality:50,// Lower quality for smaller sizeformat:'webp',// WebP is usually smaller})// Use in HTMLconsthtml=`<div> <img src="image.jpg" loading="lazy" width="${placeholder.width}" height="${placeholder.height}"></div>`// ThumbHash alternative (even smaller, fixed quality)constthumbHash=awaitgeneratePlaceholder('image.jpg',{strategy:'thumbhash',})// Use dominant color as placeholder for even faster loadingconstcolorPlaceholder=awaitgeneratePlaceholder('image.jpg',{strategy:'dominant-color',})// Pixelated placeholder for a retro effectconstpixelatedPlaceholder=awaitgeneratePlaceholder('image.jpg',{strategy:'pixelate',width:30,})// Generate with CSS helperconstplaceholderWithCSS=awaitgeneratePlaceholder('image.jpg',{strategy:'blur',cssFilter:true,})// Use the CSS class in your HTMLconsole.log(placeholderWithCSS.css)// .placeholder-image { background-size: cover; ... }
Process entire directories of images:
Read the full Batch Processing documentation →
// Convert all JPG/PNG images to WebP and AVIFconst{ results, summary}=awaitbatchProcessImages('./images',{formats:['webp','avif'],quality:75,resize:{width:1200},// Optional resizerecursive:true,// Process subdirectoriesskipExisting:true,// Skip already processed filespreserveStructure:true,// Keep directory structurefilenameTemplate:'[name]-optimized.[format]',// Custom naming})console.log(`Processed${summary.successCount} of${summary.totalFiles} images`)console.log(`Total saved:${summary.saved} bytes (${summary.savedPercentage.toFixed(2)}%)`)// With progress trackingawaitbatchProcessImages('./images',{formats:['webp'],progressCallback:(progress)=>{console.log(`Progress:${progress.percentage.toFixed(2)}% (${progress.completed}/${progress.total})`)}})// With optimization presetsawaitbatchProcessImages('./images',{formats:['webp','jpeg'],optimizationPreset:'quality',// 'web', 'quality', 'performance'})// With custom transformationsawaitbatchProcessImages('./images',{formats:['webp'],transformations:[{type:'grayscale'},{type:'blur',options:{sigma:2}},]})// Format-specific quality settingsawaitbatchProcessImages('./images',{formats:['webp','avif','jpeg'],quality:{webp:80,avif:70,jpeg:85}})
Easily convert between image formats:
Read the full Format Conversion documentation →
// Convert a JPEG to WebPconstresult=awaitconvertImageFormat('photo.jpg','webp')console.log(`Converted to${result.outputPath} (saved${result.savedPercentage.toFixed(2)}%)`)// Convert an image with optionsconstavifResult=awaitconvertImageFormat('photo.jpg','avif',{quality:80,outputDir:'./optimized',lossless:false,filenamePrefix:'converted-',filenameSuffix:'-hq',})// Convert with resizeawaitconvertImageFormat('photo.jpg','webp',{resize:{width:800,height:600},quality:85,})// Format-specific optimizationsawaitconvertImageFormat('photo.png','jpeg',{quality:90,progressive:true,chromaSubsampling:'4:4:4',// High quality chroma})// Batch convert all PNG files to WebPconstpngFiles=awaitgetFiles('./images',{patterns:['**/*.png']})awaitPromise.all(pngFiles.map(file=>convertImageFormat(file,'webp',{outputDir:'./webp'})))
Add text or image watermarks to your images:
// Add text watermarkconstwatermarked=awaitapplyWatermark('image.jpg',{text:'Copyright 2023',position:'bottom-right',// 'center', 'top-left', 'bottom-right', etc.opacity:0.7,output:'watermarked-image.jpg',textOptions:{fontSize:24,color:'rgba(255, 255, 255, 0.8)',background:'rgba(0, 0, 0, 0.5)',padding:10,}})// Add image watermarkawaitapplyWatermark('photo.jpg',{image:'logo.png',position:'bottom-right',scale:0.2,// 20% of the main image sizeopacity:0.5,output:'branded-photo.jpg',})// Create a tiled watermark patternawaitapplyWatermark('background.jpg',{image:'small-logo.png',tiled:true,opacity:0.15,output:'watermarked-background.jpg',})// Apply rotated watermarkawaitapplyWatermark('certificate.jpg',{text:'VERIFIED',position:'center',rotate:45,// 45 degrees rotationopacity:0.3,textOptions:{fontSize:72,color:'rgba(255, 0, 0, 0.5)',}})// Apply watermark to images in batchconstimages=awaitgetFiles('./photos',{patterns:['**/*.jpg']})awaitPromise.all(images.map(image=>applyWatermark(image,{text:'© Company Name',position:'bottom-right',output:image.replace('.jpg','.watermarked.jpg'),})))
Optimize SVG files for web use with comprehensive options:
Read the full SVG Optimization documentation →
// Basic SVG optimizationconstresult=awaitoptimizeSvg('icon.svg',{output:'optimized-icon.svg',})console.log(`Optimized SVG: saved${result.savedPercentage.toFixed(2)}%`)// Advanced SVG optimization with detailed optionsawaitoptimizeSvg('logo.svg',{output:'optimized-logo.svg',multipass:true,// Run multiple optimization passesremoveComments:true,// Remove commentscleanupIDs:true,// Clean up ID attributesremoveHiddenElements:true,// Remove hidden elementsremoveEmptyAttrs:true,// Remove empty attributesremoveEmptyContainers:true,// Remove empty containersmergePaths:true,// Merge paths when possibleconvertShapeToPath:true,// Convert basic shapes to pathsremoveViewBox:false,// Keep viewBox attribute (important for responsive SVGs)prettify:false,// Minify output for smaller file size})// Optimize SVG string contentconstsvgContent='<svg>...</svg>'constoptimized=awaitoptimizeSvg(svgContent,{removeComments:true,cleanupIDs:true,})console.log(optimized.content)// Get the optimized SVG content// Optimize with prefix IDs (useful for embedding multiple SVGs)awaitoptimizeSvg('icon.svg',{output:'prefixed-icon.svg',prefixIds:'icon-',// All IDs will be prefixed with 'icon-'})
Convert raster images to scalable SVG using tracing:
Read the full Image to SVG Conversion documentation →
// Convert image to black and white SVGconstresult=awaitimageToSvg('photo.jpg',{output:'photo.svg',mode:'bw',// Black and white modethreshold:128,// Threshold for black/white conversion (0-255)})// Convert image to color SVGawaitimageToSvg('logo.png',{output:'logo.svg',mode:'color',// Full color tracingcolorCount:16,// Number of colors to use (lower = simpler SVG)})// Convert with posterization effectawaitimageToSvg('image.jpg',{output:'posterized.svg',mode:'posterized',// Posterized effectsteps:8,// Number of color levels})// Add background color to resulting SVGawaitimageToSvg('icon.png',{output:'icon-with-bg.svg',mode:'bw',background:'#f0f0f0',// Add light gray background})// Convert and optimize in one stepawaitimageToSvg('photo.jpg',{output:'photo.svg',mode:'bw',optionsSvg:{// Apply SVG optimization optionsremoveComments:true,cleanupIDs:true,convertShapeToPath:true,}})
Please review theContributing Guide for details.
For help, discussion about best practices, or any other conversation that would benefit from being searchable:
For casual chit-chat with others using this package:
Join the Stacks Discord Server
“Software that is free, but hopes for a postcard.” We love receiving postcards from around the world showing whereimgx
is being used! We showcase them on our website too.
Our address: Stacks.js, 12665 Village Ln #2306, Playa Vista, CA 90094, United States 🌎
We would like to extend our thanks to the following sponsors for funding Stacks development. If you are interested in becoming a sponsor, please reach out to us.
The MIT License (MIT). Please seeLICENSE for more information.
Made with 💙
About
🏞️ Make your images load faster. A better save for the web.
Topics
Resources
License
Code of conduct
Security policy
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Sponsor this project
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Contributors3
Uh oh!
There was an error while loading.Please reload this page.