imgconvert-cli
Advanced tools
+1
-1
| { | ||
| "name": "imgconvert-cli", | ||
| "version": "1.7.3", | ||
| "version": "1.7.4", | ||
| "description": "A CLI tool for compressing and converting images", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
+31
-7
@@ -202,3 +202,3 @@ # imgconvert-cli | ||
| When using `--fit cover`, controls which part of the image to preserve: | ||
| When using `--fit cover`, `--fit contain`, or `--canvas`, controls which part of the image to preserve or focus on: | ||
@@ -243,7 +243,14 @@ | Position | Description | Best For | | ||
| - **Transparency**: Adds transparent padding for PNG/WebP, white for JPEG | ||
| - **Position Control**: Use `--position` to control where the image is placed within the expanded canvas | ||
| ```bash | ||
| imgconvert photo.png --canvas -h 1660 | ||
| # 1024x1536 → 1024x1660 (original image + transparent padding) | ||
| # 1024x1536 → 1024x1660 (original image centered + transparent padding) | ||
| imgconvert photo.png --canvas -h 1660 --position top | ||
| # 1024x1536 → 1024x1660 (original image at top + transparent padding at bottom) | ||
| imgconvert photo.png --canvas -h 1660 --position bottom | ||
| # 1024x1536 → 1024x1660 (original image at bottom + transparent padding at top) | ||
| imgconvert photo.png --canvas -h 1660 -b "#ff0000" | ||
@@ -258,2 +265,3 @@ # 1024x1536 → 1024x1660 (original image + red padding) | ||
| | **Transparency** | Preserves existing | ✅ Adds transparent padding | | ||
| | **Position control** | Via `--position` | ✅ Via `--position` (NEW) | | ||
| | **Use case** | Photo resizing | Design layouts, mockups | | ||
@@ -349,4 +357,13 @@ | ||
| 6. **Manual cropping before resizing:** | ||
| 6. **Control positioning with contain strategy (letterboxing):** | ||
| ```bash | ||
| # Position image at top of canvas when letterboxing | ||
| imgconvert wide-image.jpg --fit contain --position top -w 400 -h 400 | ||
| # Position image at bottom-right when letterboxing | ||
| imgconvert landscape.jpg --fit contain --position "bottom right" -w 600 -h 600 | ||
| ``` | ||
| 7. **Manual cropping before resizing:** | ||
| ```bash | ||
| # Crop specific region then resize | ||
@@ -359,8 +376,15 @@ imgconvert image.png --crop 100,50,300,200 -w 200 -h 150 | ||
| 7. **Canvas resizing (maintain original image, add padding):** | ||
| 8. **Canvas resizing (maintain original image, add padding):** | ||
| ```bash | ||
| # Resize canvas to larger dimensions with transparent padding | ||
| imgconvert photo.png --canvas -h 1660 | ||
| # Original 1024x1536 → Output 1024x1660 with transparent padding | ||
| # Original 1024x1536 → Output 1024x1660 with transparent padding (centered) | ||
| # Control position within the expanded canvas | ||
| imgconvert photo.png --canvas -h 1660 --position top | ||
| # Original 1024x1536 → Output 1024x1660 with image at top, transparent padding at bottom | ||
| imgconvert photo.png --canvas -h 1660 --position bottom | ||
| # Original 1024x1536 → Output 1024x1660 with image at bottom, transparent padding at top | ||
| # Resize canvas with custom background color | ||
@@ -377,3 +401,3 @@ imgconvert photo.png --canvas -h 1660 -b "#ffffff" | ||
| 7. **Custom naming for single files:** | ||
| 9. **Custom naming for single files:** | ||
| ```bash | ||
@@ -389,3 +413,3 @@ # Rename during conversion | ||
| 8. **Batch renaming strategies:** | ||
| 10. **Batch renaming strategies:** | ||
| ```bash | ||
@@ -392,0 +416,0 @@ # Add sequential numbers |
@@ -31,4 +31,9 @@ /** | ||
| boolean: ['replace-originals', 'debug', 'help', 'version', 'canvas'], | ||
| string: ['crop', 'fit', 'position', 'rename'], | ||
| unknown: (arg) => { | ||
| if (arg.startsWith('-')) { | ||
| // Allow negative numbers (they will be validated later) | ||
| if (/^-\d+$/.test(arg)) { | ||
| return true; | ||
| } | ||
| logger.error(`Error: Unknown option '${arg}'`); | ||
@@ -35,0 +40,0 @@ logger.error(`Run 'imgconvert --help' to see available options.`); |
@@ -37,2 +37,45 @@ /** | ||
| /** | ||
| * Map user-friendly position names to Sharp gravity constants | ||
| * @param {string} position - User-provided position string | ||
| * @returns {number} Sharp gravity constant | ||
| */ | ||
| function mapPositionToGravity(position) { | ||
| if (!position) return sharp.gravity.center; | ||
| // Normalize position string | ||
| const normalizedPosition = position.toLowerCase().trim(); | ||
| // Map user-friendly positions to Sharp gravity constants | ||
| const positionMap = { | ||
| // Single positions | ||
| 'center': sharp.gravity.center, | ||
| 'centre': sharp.gravity.centre, | ||
| 'top': sharp.gravity.north, | ||
| 'bottom': sharp.gravity.south, | ||
| 'left': sharp.gravity.west, | ||
| 'right': sharp.gravity.east, | ||
| 'north': sharp.gravity.north, | ||
| 'south': sharp.gravity.south, | ||
| 'east': sharp.gravity.east, | ||
| 'west': sharp.gravity.west, | ||
| // Corner positions | ||
| 'top left': sharp.gravity.northwest, | ||
| 'top right': sharp.gravity.northeast, | ||
| 'bottom left': sharp.gravity.southwest, | ||
| 'bottom right': sharp.gravity.southeast, | ||
| 'left top': sharp.gravity.northwest, | ||
| 'right top': sharp.gravity.northeast, | ||
| 'left bottom': sharp.gravity.southwest, | ||
| 'right bottom': sharp.gravity.southeast, | ||
| 'northwest': sharp.gravity.northwest, | ||
| 'northeast': sharp.gravity.northeast, | ||
| 'southwest': sharp.gravity.southwest, | ||
| 'southeast': sharp.gravity.southeast | ||
| }; | ||
| return positionMap[normalizedPosition] || sharp.gravity.center; | ||
| } | ||
| /** | ||
| * Generate filename based on rename strategies | ||
@@ -137,3 +180,3 @@ * @param {string} originalName - Original filename without extension | ||
| fit: sharp.fit[options.fit] || sharp.fit.contain, | ||
| position: sharp.gravity[options.position] || sharp.gravity.center | ||
| position: mapPositionToGravity(options.position) | ||
| }; | ||
@@ -144,2 +187,4 @@ | ||
| resizeOptions.fit = sharp.fit.contain; // Force contain for canvas resize | ||
| // In canvas mode, respect user's position preference (top, center, bottom, etc.) | ||
| // This allows positioning the image within the expanded canvas | ||
@@ -175,3 +220,3 @@ // For canvas mode, we need to force exact dimensions to ensure padding | ||
| } else { | ||
| // Normal resize mode (not canvas) - only apply background if user specified one | ||
| // Normal resize mode (not canvas) - apply smart background defaults | ||
| if (options.background) { | ||
@@ -182,2 +227,8 @@ const rgba = parseHexToRgba(options.background); | ||
| } | ||
| } else { | ||
| // For non-canvas mode with contain/cover, apply transparent background for formats that support it | ||
| if ((resizeOptions.fit === sharp.fit.contain || resizeOptions.fit === sharp.fit.cover) && | ||
| (sharpFormat === 'png' || sharpFormat === 'webp' || sharpFormat === 'avif')) { | ||
| resizeOptions.background = { r: 0, g: 0, b: 0, alpha: 0 }; // Transparent | ||
| } | ||
| } | ||
@@ -184,0 +235,0 @@ } |
@@ -57,4 +57,3 @@ /** | ||
| console.log(chalk.green(` | ||
| Processing complete! Summary: | ||
| console.log(chalk.green(`Processing complete! Summary: | ||
| - Processed files: ${chalk.yellow(processedCount)} | ||
@@ -64,4 +63,3 @@ - Total original size: ${chalk.yellow(this.formatBytes(totalOriginalSize))} | ||
| - Total savings: ${chalk.yellow(savings + '%')} | ||
| - Duration: ${chalk.yellow(duration + ' seconds')} | ||
| `)); | ||
| - Duration: ${chalk.yellow(duration + ' seconds')}`)); | ||
| } | ||
@@ -68,0 +66,0 @@ |
@@ -142,6 +142,6 @@ /** | ||
| } else if (inputPath) { | ||
| const inputDir = fs.lstatSync(inputPath).isDirectory() ? inputPath : path.dirname(inputPath); | ||
| const inputName = path.basename(inputDir); | ||
| const parentDir = path.dirname(inputDir); | ||
| return path.join(parentDir, `${inputName}-converted`); | ||
| const isDirectory = fs.lstatSync(inputPath).isDirectory(); | ||
| const baseDir = isDirectory ? path.dirname(inputPath) : path.dirname(inputPath); | ||
| const outputName = isDirectory ? `${path.basename(inputPath)}-converted` : 'converted'; | ||
| return path.join(baseDir, outputName); | ||
| } | ||
@@ -148,0 +148,0 @@ return null; |
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
115868
3.01%1529
3.31%1513
1.61%