@mediaproc/image 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2516 -0
- package/bin/cli.js +6 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +89 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/auto-enhance.d.ts +3 -0
- package/dist/commands/auto-enhance.d.ts.map +1 -0
- package/dist/commands/auto-enhance.js +148 -0
- package/dist/commands/auto-enhance.js.map +1 -0
- package/dist/commands/batch.d.ts +3 -0
- package/dist/commands/batch.d.ts.map +1 -0
- package/dist/commands/batch.js +230 -0
- package/dist/commands/batch.js.map +1 -0
- package/dist/commands/blur.d.ts +3 -0
- package/dist/commands/blur.d.ts.map +1 -0
- package/dist/commands/blur.js +122 -0
- package/dist/commands/blur.js.map +1 -0
- package/dist/commands/border.d.ts +3 -0
- package/dist/commands/border.d.ts.map +1 -0
- package/dist/commands/border.js +122 -0
- package/dist/commands/border.js.map +1 -0
- package/dist/commands/clahe.d.ts +3 -0
- package/dist/commands/clahe.d.ts.map +1 -0
- package/dist/commands/clahe.js +121 -0
- package/dist/commands/clahe.js.map +1 -0
- package/dist/commands/composite.d.ts +3 -0
- package/dist/commands/composite.d.ts.map +1 -0
- package/dist/commands/composite.js +167 -0
- package/dist/commands/composite.js.map +1 -0
- package/dist/commands/convert.d.ts +3 -0
- package/dist/commands/convert.d.ts.map +1 -0
- package/dist/commands/convert.js +136 -0
- package/dist/commands/convert.js.map +1 -0
- package/dist/commands/convolve.d.ts +3 -0
- package/dist/commands/convolve.d.ts.map +1 -0
- package/dist/commands/convolve.js +171 -0
- package/dist/commands/convolve.js.map +1 -0
- package/dist/commands/crop.d.ts +3 -0
- package/dist/commands/crop.d.ts.map +1 -0
- package/dist/commands/crop.js +120 -0
- package/dist/commands/crop.js.map +1 -0
- package/dist/commands/dominant-color.d.ts +3 -0
- package/dist/commands/dominant-color.d.ts.map +1 -0
- package/dist/commands/dominant-color.js +175 -0
- package/dist/commands/dominant-color.js.map +1 -0
- package/dist/commands/extend.d.ts +3 -0
- package/dist/commands/extend.d.ts.map +1 -0
- package/dist/commands/extend.js +146 -0
- package/dist/commands/extend.js.map +1 -0
- package/dist/commands/extract.d.ts +3 -0
- package/dist/commands/extract.d.ts.map +1 -0
- package/dist/commands/extract.js +169 -0
- package/dist/commands/extract.js.map +1 -0
- package/dist/commands/flip.d.ts +3 -0
- package/dist/commands/flip.d.ts.map +1 -0
- package/dist/commands/flip.js +112 -0
- package/dist/commands/flip.js.map +1 -0
- package/dist/commands/gamma.d.ts +3 -0
- package/dist/commands/gamma.d.ts.map +1 -0
- package/dist/commands/gamma.js +129 -0
- package/dist/commands/gamma.js.map +1 -0
- package/dist/commands/grayscale.d.ts +3 -0
- package/dist/commands/grayscale.d.ts.map +1 -0
- package/dist/commands/grayscale.js +94 -0
- package/dist/commands/grayscale.js.map +1 -0
- package/dist/commands/grid.d.ts +3 -0
- package/dist/commands/grid.d.ts.map +1 -0
- package/dist/commands/grid.js +193 -0
- package/dist/commands/grid.js.map +1 -0
- package/dist/commands/median.d.ts +3 -0
- package/dist/commands/median.d.ts.map +1 -0
- package/dist/commands/median.js +132 -0
- package/dist/commands/median.js.map +1 -0
- package/dist/commands/metadata-cmd.d.ts +3 -0
- package/dist/commands/metadata-cmd.d.ts.map +1 -0
- package/dist/commands/metadata-cmd.js +201 -0
- package/dist/commands/metadata-cmd.js.map +1 -0
- package/dist/commands/mirror.d.ts +3 -0
- package/dist/commands/mirror.d.ts.map +1 -0
- package/dist/commands/mirror.js +218 -0
- package/dist/commands/mirror.js.map +1 -0
- package/dist/commands/modulate.d.ts +3 -0
- package/dist/commands/modulate.d.ts.map +1 -0
- package/dist/commands/modulate.js +151 -0
- package/dist/commands/modulate.js.map +1 -0
- package/dist/commands/negate.d.ts +3 -0
- package/dist/commands/negate.d.ts.map +1 -0
- package/dist/commands/negate.js +111 -0
- package/dist/commands/negate.js.map +1 -0
- package/dist/commands/normalize.d.ts +3 -0
- package/dist/commands/normalize.d.ts.map +1 -0
- package/dist/commands/normalize.js +119 -0
- package/dist/commands/normalize.js.map +1 -0
- package/dist/commands/optimize.d.ts +3 -0
- package/dist/commands/optimize.d.ts.map +1 -0
- package/dist/commands/optimize.js +137 -0
- package/dist/commands/optimize.js.map +1 -0
- package/dist/commands/palette.d.ts +3 -0
- package/dist/commands/palette.d.ts.map +1 -0
- package/dist/commands/palette.js +138 -0
- package/dist/commands/palette.js.map +1 -0
- package/dist/commands/pixelate.d.ts +3 -0
- package/dist/commands/pixelate.d.ts.map +1 -0
- package/dist/commands/pixelate.js +123 -0
- package/dist/commands/pixelate.js.map +1 -0
- package/dist/commands/resize.d.ts +3 -0
- package/dist/commands/resize.d.ts.map +1 -0
- package/dist/commands/resize.js +187 -0
- package/dist/commands/resize.js.map +1 -0
- package/dist/commands/rotate.d.ts +3 -0
- package/dist/commands/rotate.d.ts.map +1 -0
- package/dist/commands/rotate.js +103 -0
- package/dist/commands/rotate.js.map +1 -0
- package/dist/commands/sepia.d.ts +3 -0
- package/dist/commands/sepia.d.ts.map +1 -0
- package/dist/commands/sepia.js +119 -0
- package/dist/commands/sepia.js.map +1 -0
- package/dist/commands/sharpen.d.ts +3 -0
- package/dist/commands/sharpen.d.ts.map +1 -0
- package/dist/commands/sharpen.js +123 -0
- package/dist/commands/sharpen.js.map +1 -0
- package/dist/commands/smart-crop.d.ts +3 -0
- package/dist/commands/smart-crop.d.ts.map +1 -0
- package/dist/commands/smart-crop.js +137 -0
- package/dist/commands/smart-crop.js.map +1 -0
- package/dist/commands/split.d.ts +3 -0
- package/dist/commands/split.d.ts.map +1 -0
- package/dist/commands/split.js +177 -0
- package/dist/commands/split.js.map +1 -0
- package/dist/commands/stack.d.ts +3 -0
- package/dist/commands/stack.d.ts.map +1 -0
- package/dist/commands/stack.js +205 -0
- package/dist/commands/stack.js.map +1 -0
- package/dist/commands/stats.d.ts +3 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +187 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/thumbnail.d.ts +3 -0
- package/dist/commands/thumbnail.d.ts.map +1 -0
- package/dist/commands/thumbnail.js +131 -0
- package/dist/commands/thumbnail.js.map +1 -0
- package/dist/commands/tint.d.ts +3 -0
- package/dist/commands/tint.d.ts.map +1 -0
- package/dist/commands/tint.js +123 -0
- package/dist/commands/tint.js.map +1 -0
- package/dist/commands/trim.d.ts +3 -0
- package/dist/commands/trim.d.ts.map +1 -0
- package/dist/commands/trim.js +123 -0
- package/dist/commands/trim.js.map +1 -0
- package/dist/commands/vignette.d.ts +3 -0
- package/dist/commands/vignette.d.ts.map +1 -0
- package/dist/commands/vignette.js +139 -0
- package/dist/commands/vignette.js.map +1 -0
- package/dist/commands/watermark.d.ts +3 -0
- package/dist/commands/watermark.d.ts.map +1 -0
- package/dist/commands/watermark.js +172 -0
- package/dist/commands/watermark.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/register.d.ts +5 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +93 -0
- package/dist/register.js.map +1 -0
- package/dist/types.d.ts +91 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/helpFormatter.d.ts +63 -0
- package/dist/utils/helpFormatter.d.ts.map +1 -0
- package/dist/utils/helpFormatter.js +171 -0
- package/dist/utils/helpFormatter.js.map +1 -0
- package/dist/utils/sharp.d.ts +20 -0
- package/dist/utils/sharp.d.ts.map +1 -0
- package/dist/utils/sharp.js +14 -0
- package/dist/utils/sharp.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import { createSharpInstance } from '../utils/sharp.js';
|
|
6
|
+
import { createStandardHelp } from '../utils/helpFormatter.js';
|
|
7
|
+
export function medianCommand(imageCmd) {
|
|
8
|
+
imageCmd
|
|
9
|
+
.command('median <input>')
|
|
10
|
+
.description('Apply median filter (noise reduction)')
|
|
11
|
+
.option('-s, --size <size>', 'Filter size (1-50, default: 3)', parseInt, 3)
|
|
12
|
+
.option('-o, --output <path>', 'Output file path')
|
|
13
|
+
.option('-q, --quality <quality>', 'Quality (1-100)', parseInt, 90)
|
|
14
|
+
.option('--dry-run', 'Show what would be done without executing')
|
|
15
|
+
.option('-v, --verbose', 'Verbose output')
|
|
16
|
+
.option('--help', 'Display help for median command')
|
|
17
|
+
.action(async (input, options) => {
|
|
18
|
+
if (options.help) {
|
|
19
|
+
createStandardHelp({
|
|
20
|
+
commandName: 'median',
|
|
21
|
+
emoji: '🔇',
|
|
22
|
+
description: 'Apply median filter to reduce noise while preserving edges. Excellent for removing salt-and-pepper noise, scanner artifacts, and compression noise.',
|
|
23
|
+
usage: ['median <input>', 'median <input> -s <size>', 'median <input> -s 5'],
|
|
24
|
+
options: [
|
|
25
|
+
{ flag: '-s, --size <size>', description: 'Filter size 1-50 (default: 3, higher = more smoothing)' },
|
|
26
|
+
{ flag: '-o, --output <path>', description: 'Output file path (default: <input>-median.<ext>)' },
|
|
27
|
+
{ flag: '-q, --quality <quality>', description: 'Output quality 1-100 (default: 90)' },
|
|
28
|
+
{ flag: '--dry-run', description: 'Preview changes without executing' },
|
|
29
|
+
{ flag: '-v, --verbose', description: 'Show detailed output' }
|
|
30
|
+
],
|
|
31
|
+
examples: [
|
|
32
|
+
{ command: 'median photo.jpg', description: 'Apply default median filter (size 3)' },
|
|
33
|
+
{ command: 'median noisy-image.png -s 5', description: 'Stronger noise reduction' },
|
|
34
|
+
{ command: 'median scan.jpg -s 7', description: 'Remove scanner artifacts' },
|
|
35
|
+
{ command: 'median compressed.jpg -s 3', description: 'Reduce compression noise' }
|
|
36
|
+
],
|
|
37
|
+
additionalSections: [
|
|
38
|
+
{
|
|
39
|
+
title: 'Filter Size Guide',
|
|
40
|
+
items: [
|
|
41
|
+
'Size 1 - Minimal smoothing',
|
|
42
|
+
'Size 3 - Default (balanced)',
|
|
43
|
+
'Size 5-7 - Strong noise reduction',
|
|
44
|
+
'Size 10+ - Heavy smoothing (may blur)'
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
title: 'Best For',
|
|
49
|
+
items: [
|
|
50
|
+
'Salt-and-pepper noise removal',
|
|
51
|
+
'Scanner artifacts',
|
|
52
|
+
'JPEG compression noise',
|
|
53
|
+
'Old photo restoration',
|
|
54
|
+
'Low-light camera noise'
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
title: 'vs Blur',
|
|
59
|
+
items: [
|
|
60
|
+
'Median preserves edges better than blur',
|
|
61
|
+
'Better for noise, blur better for softness',
|
|
62
|
+
'Median maintains sharpness',
|
|
63
|
+
'Blur creates smooth gradient effect'
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
tips: [
|
|
68
|
+
'Start with size 3 and increase if needed',
|
|
69
|
+
'Better edge preservation than Gaussian blur',
|
|
70
|
+
'Perfect for restoring old scanned photos',
|
|
71
|
+
'Combine with sharpen for optimal results'
|
|
72
|
+
]
|
|
73
|
+
});
|
|
74
|
+
process.exit(0);
|
|
75
|
+
}
|
|
76
|
+
const spinner = ora('Processing image...').start();
|
|
77
|
+
try {
|
|
78
|
+
if (!fs.existsSync(input)) {
|
|
79
|
+
spinner.fail(chalk.red(`Input file not found: ${input}`));
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
const inputPath = path.parse(input);
|
|
83
|
+
const outputPath = options.output || path.join(process.cwd(), `${inputPath.name}-median${inputPath.ext}`);
|
|
84
|
+
if (options.verbose) {
|
|
85
|
+
spinner.info(chalk.blue('Configuration:'));
|
|
86
|
+
console.log(chalk.dim(` Input: ${input}`));
|
|
87
|
+
console.log(chalk.dim(` Output: ${outputPath}`));
|
|
88
|
+
console.log(chalk.dim(` Filter size: ${options.size || 3}`));
|
|
89
|
+
spinner.start('Processing...');
|
|
90
|
+
}
|
|
91
|
+
if (options.dryRun) {
|
|
92
|
+
spinner.info(chalk.yellow('Dry run mode - no changes will be made'));
|
|
93
|
+
console.log(chalk.green('✓ Would apply median filter:'));
|
|
94
|
+
console.log(chalk.dim(` From: ${input}`));
|
|
95
|
+
console.log(chalk.dim(` To: ${outputPath}`));
|
|
96
|
+
console.log(chalk.dim(` Size: ${options.size || 3}`));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const metadata = await createSharpInstance(input).metadata();
|
|
100
|
+
const pipeline = createSharpInstance(input).median(options.size || 3);
|
|
101
|
+
const outputExt = path.extname(outputPath).toLowerCase();
|
|
102
|
+
if (outputExt === '.jpg' || outputExt === '.jpeg') {
|
|
103
|
+
pipeline.jpeg({ quality: options.quality || 90 });
|
|
104
|
+
}
|
|
105
|
+
else if (outputExt === '.png') {
|
|
106
|
+
pipeline.png({ quality: options.quality || 90 });
|
|
107
|
+
}
|
|
108
|
+
else if (outputExt === '.webp') {
|
|
109
|
+
pipeline.webp({ quality: options.quality || 90 });
|
|
110
|
+
}
|
|
111
|
+
await pipeline.toFile(outputPath);
|
|
112
|
+
const outputStats = fs.statSync(outputPath);
|
|
113
|
+
spinner.succeed(chalk.green('✓ Median filter applied successfully!'));
|
|
114
|
+
console.log(chalk.dim(` Input: ${input}`));
|
|
115
|
+
console.log(chalk.dim(` Output: ${outputPath}`));
|
|
116
|
+
console.log(chalk.dim(` Size: ${metadata.width}x${metadata.height}`));
|
|
117
|
+
console.log(chalk.dim(` Filter size: ${options.size || 3}`));
|
|
118
|
+
console.log(chalk.dim(` File size: ${(outputStats.size / 1024).toFixed(2)}KB`));
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
spinner.fail(chalk.red('Failed to apply median filter'));
|
|
122
|
+
if (options.verbose) {
|
|
123
|
+
console.error(chalk.red('Error details:'), error);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
console.error(chalk.red(error.message));
|
|
127
|
+
}
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=median.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"median.js","sourceRoot":"","sources":["../../src/commands/median.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata-cmd.d.ts","sourceRoot":"","sources":["../../src/commands/metadata-cmd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBzC,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAqNvD"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import { createSharpInstance } from '../utils/sharp.js';
|
|
6
|
+
import { createStandardHelp } from '../utils/helpFormatter.js';
|
|
7
|
+
export function metadataCommand(imageCmd) {
|
|
8
|
+
imageCmd
|
|
9
|
+
.command('metadata <input>')
|
|
10
|
+
.description('View, export, or remove image metadata/EXIF data')
|
|
11
|
+
.option('--remove', 'Remove all metadata (create clean copy)')
|
|
12
|
+
.option('--remove-all', 'Alias for --remove')
|
|
13
|
+
.option('--export <path>', 'Export metadata to JSON file')
|
|
14
|
+
.option('-o, --output <path>', 'Output file (when removing metadata)')
|
|
15
|
+
.option('-v, --verbose', 'Show detailed metadata')
|
|
16
|
+
.option('--help', 'Display help for metadata command')
|
|
17
|
+
.action(async (input, options) => {
|
|
18
|
+
if (options.help) {
|
|
19
|
+
createStandardHelp({
|
|
20
|
+
commandName: 'metadata',
|
|
21
|
+
emoji: '🏷️',
|
|
22
|
+
description: 'View, export, or remove image metadata including EXIF, IPTC, XMP, and ICC profile data. Essential for privacy and optimization.',
|
|
23
|
+
usage: ['metadata <input>', 'metadata <input> --remove', 'metadata <input> --export data.json'],
|
|
24
|
+
options: [
|
|
25
|
+
{ flag: '--remove', description: 'Remove all metadata and create clean copy' },
|
|
26
|
+
{ flag: '--remove-all', description: 'Alias for --remove' },
|
|
27
|
+
{ flag: '--export <path>', description: 'Export metadata to JSON file' },
|
|
28
|
+
{ flag: '-o, --output <path>', description: 'Output file path (when removing metadata)' },
|
|
29
|
+
{ flag: '-v, --verbose', description: 'Show detailed metadata information' }
|
|
30
|
+
],
|
|
31
|
+
examples: [
|
|
32
|
+
{ command: 'metadata photo.jpg', description: 'View basic metadata' },
|
|
33
|
+
{ command: 'metadata photo.jpg -v', description: 'View detailed metadata' },
|
|
34
|
+
{ command: 'metadata photo.jpg --remove', description: 'Remove all metadata' },
|
|
35
|
+
{ command: 'metadata photo.jpg --export metadata.json', description: 'Export metadata to JSON' },
|
|
36
|
+
{ command: 'metadata photo.jpg --remove -o clean.jpg', description: 'Save clean copy without metadata' }
|
|
37
|
+
],
|
|
38
|
+
additionalSections: [
|
|
39
|
+
{
|
|
40
|
+
title: 'Metadata Types',
|
|
41
|
+
items: [
|
|
42
|
+
'EXIF - Camera settings, date, GPS location',
|
|
43
|
+
'IPTC - Copyright, caption, keywords',
|
|
44
|
+
'XMP - Extended metadata',
|
|
45
|
+
'ICC - Color profile information',
|
|
46
|
+
'Orientation - Image rotation data'
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
title: 'Why Remove Metadata?',
|
|
51
|
+
items: [
|
|
52
|
+
'Privacy - Remove GPS location data',
|
|
53
|
+
'File size - Metadata can be large',
|
|
54
|
+
'Security - Remove camera/device info',
|
|
55
|
+
'Web optimization - Smaller files',
|
|
56
|
+
'Clean sharing - Remove personal data'
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
title: 'Common EXIF Fields',
|
|
61
|
+
items: [
|
|
62
|
+
'Camera Make/Model',
|
|
63
|
+
'Date/Time taken',
|
|
64
|
+
'GPS Coordinates',
|
|
65
|
+
'Aperture, Shutter Speed, ISO',
|
|
66
|
+
'Focal Length',
|
|
67
|
+
'Copyright information',
|
|
68
|
+
'Software used'
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
tips: [
|
|
73
|
+
'Always remove GPS data before sharing online',
|
|
74
|
+
'Backup originals before removing metadata',
|
|
75
|
+
'Export metadata for record-keeping',
|
|
76
|
+
'Metadata removal reduces file size'
|
|
77
|
+
]
|
|
78
|
+
});
|
|
79
|
+
process.exit(0);
|
|
80
|
+
}
|
|
81
|
+
const spinner = ora('Reading metadata...').start();
|
|
82
|
+
try {
|
|
83
|
+
if (!fs.existsSync(input)) {
|
|
84
|
+
spinner.fail(chalk.red(`Input file not found: ${input}`));
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
const metadata = await createSharpInstance(input).metadata();
|
|
88
|
+
// Remove metadata mode
|
|
89
|
+
if (options.remove || options.removeAll) {
|
|
90
|
+
spinner.text = 'Removing metadata...';
|
|
91
|
+
const inputPath = path.parse(input);
|
|
92
|
+
const outputPath = options.output || path.join(inputPath.dir, `${inputPath.name}-clean${inputPath.ext}`);
|
|
93
|
+
await createSharpInstance(input)
|
|
94
|
+
.withMetadata({
|
|
95
|
+
// Remove all metadata
|
|
96
|
+
exif: {},
|
|
97
|
+
icc: undefined,
|
|
98
|
+
xmp: undefined
|
|
99
|
+
})
|
|
100
|
+
.toFile(outputPath);
|
|
101
|
+
const inputStats = fs.statSync(input);
|
|
102
|
+
const outputStats = fs.statSync(outputPath);
|
|
103
|
+
const savedBytes = inputStats.size - outputStats.size;
|
|
104
|
+
spinner.succeed(chalk.green('✓ Metadata removed successfully!'));
|
|
105
|
+
console.log(chalk.dim(` Input: ${input}`));
|
|
106
|
+
console.log(chalk.dim(` Output: ${outputPath}`));
|
|
107
|
+
console.log(chalk.dim(` Original size: ${(inputStats.size / 1024).toFixed(2)}KB`));
|
|
108
|
+
console.log(chalk.dim(` New size: ${(outputStats.size / 1024).toFixed(2)}KB`));
|
|
109
|
+
console.log(chalk.dim(` Saved: ${(savedBytes / 1024).toFixed(2)}KB (${((savedBytes / inputStats.size) * 100).toFixed(1)}%)`));
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
// Export metadata mode
|
|
113
|
+
if (options.export) {
|
|
114
|
+
spinner.text = 'Exporting metadata...';
|
|
115
|
+
const metadataObj = {
|
|
116
|
+
file: {
|
|
117
|
+
path: input,
|
|
118
|
+
size: fs.statSync(input).size,
|
|
119
|
+
modified: fs.statSync(input).mtime
|
|
120
|
+
},
|
|
121
|
+
image: {
|
|
122
|
+
format: metadata.format,
|
|
123
|
+
width: metadata.width,
|
|
124
|
+
height: metadata.height,
|
|
125
|
+
space: metadata.space,
|
|
126
|
+
channels: metadata.channels,
|
|
127
|
+
depth: metadata.depth,
|
|
128
|
+
density: metadata.density,
|
|
129
|
+
hasAlpha: metadata.hasAlpha,
|
|
130
|
+
orientation: metadata.orientation,
|
|
131
|
+
isProgressive: metadata.isProgressive
|
|
132
|
+
},
|
|
133
|
+
exif: metadata.exif ? Buffer.from(metadata.exif).toString('base64') : null,
|
|
134
|
+
icc: metadata.icc ? Buffer.from(metadata.icc).toString('base64') : null,
|
|
135
|
+
iptc: metadata.iptc ? Buffer.from(metadata.iptc).toString('base64') : null,
|
|
136
|
+
xmp: metadata.xmp ? Buffer.from(metadata.xmp).toString('base64') : null
|
|
137
|
+
};
|
|
138
|
+
fs.writeFileSync(options.export, JSON.stringify(metadataObj, null, 2));
|
|
139
|
+
spinner.succeed(chalk.green('✓ Metadata exported!'));
|
|
140
|
+
console.log(chalk.dim(` Exported to: ${options.export}`));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
// View metadata mode (default)
|
|
144
|
+
spinner.succeed(chalk.green('✓ Metadata retrieved!\n'));
|
|
145
|
+
console.log(chalk.bold.cyan('📁 File Information:'));
|
|
146
|
+
console.log(chalk.dim(` Path: ${input}`));
|
|
147
|
+
const fileStats = fs.statSync(input);
|
|
148
|
+
console.log(chalk.dim(` Size: ${(fileStats.size / 1024).toFixed(2)} KB`));
|
|
149
|
+
console.log(chalk.dim(` Modified: ${fileStats.mtime.toLocaleString()}`));
|
|
150
|
+
console.log('');
|
|
151
|
+
console.log(chalk.bold.cyan('🖼️ Image Properties:'));
|
|
152
|
+
console.log(chalk.dim(` Format: ${metadata.format?.toUpperCase()}`));
|
|
153
|
+
console.log(chalk.dim(` Dimensions: ${metadata.width} × ${metadata.height} pixels`));
|
|
154
|
+
console.log(chalk.dim(` Color Space: ${metadata.space}`));
|
|
155
|
+
console.log(chalk.dim(` Channels: ${metadata.channels}`));
|
|
156
|
+
console.log(chalk.dim(` Bit Depth: ${metadata.depth}`));
|
|
157
|
+
if (metadata.density) {
|
|
158
|
+
console.log(chalk.dim(` Density: ${metadata.density} DPI`));
|
|
159
|
+
}
|
|
160
|
+
if (metadata.hasAlpha) {
|
|
161
|
+
console.log(chalk.dim(` Alpha Channel: Yes`));
|
|
162
|
+
}
|
|
163
|
+
if (metadata.orientation) {
|
|
164
|
+
console.log(chalk.dim(` Orientation: ${metadata.orientation}`));
|
|
165
|
+
}
|
|
166
|
+
console.log('');
|
|
167
|
+
console.log(chalk.bold.cyan('📋 Metadata Summary:'));
|
|
168
|
+
console.log(chalk.dim(` EXIF Data: ${metadata.exif ? `${metadata.exif.length} bytes` : 'None'}`));
|
|
169
|
+
console.log(chalk.dim(` ICC Profile: ${metadata.icc ? `${metadata.icc.length} bytes` : 'None'}`));
|
|
170
|
+
console.log(chalk.dim(` IPTC Data: ${metadata.iptc ? `${metadata.iptc.length} bytes` : 'None'}`));
|
|
171
|
+
console.log(chalk.dim(` XMP Data: ${metadata.xmp ? `${metadata.xmp.length} bytes` : 'None'}`));
|
|
172
|
+
const totalMetadataSize = (metadata.exif?.length || 0) +
|
|
173
|
+
(metadata.icc?.length || 0) +
|
|
174
|
+
(metadata.iptc?.length || 0) +
|
|
175
|
+
(metadata.xmp?.length || 0);
|
|
176
|
+
if (totalMetadataSize > 0) {
|
|
177
|
+
console.log(chalk.dim(` Total Metadata: ${(totalMetadataSize / 1024).toFixed(2)} KB (${((totalMetadataSize / fileStats.size) * 100).toFixed(1)}% of file)`));
|
|
178
|
+
}
|
|
179
|
+
if (options.verbose && metadata.exif) {
|
|
180
|
+
console.log('');
|
|
181
|
+
console.log(chalk.yellow('💡 Tip: Use --export to save metadata to JSON file'));
|
|
182
|
+
console.log(chalk.yellow('💡 Tip: Use --remove to create a clean copy without metadata'));
|
|
183
|
+
}
|
|
184
|
+
if (!metadata.exif && !metadata.iptc && !metadata.xmp) {
|
|
185
|
+
console.log('');
|
|
186
|
+
console.log(chalk.yellow('ℹ️ This image has no embedded metadata'));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
spinner.fail(chalk.red('Failed to process metadata'));
|
|
191
|
+
if (options.verbose) {
|
|
192
|
+
console.error(chalk.red('Error details:'), error);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
console.error(chalk.red(error.message));
|
|
196
|
+
}
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=metadata-cmd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata-cmd.js","sourceRoot":"","sources":["../../src/commands/metadata-cmd.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mirror.d.ts","sourceRoot":"","sources":["../../src/commands/mirror.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBzC,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAoOrD"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import { createSharpInstance } from '../utils/sharp.js';
|
|
6
|
+
import { createStandardHelp } from '../utils/helpFormatter.js';
|
|
7
|
+
export function mirrorCommand(imageCmd) {
|
|
8
|
+
imageCmd
|
|
9
|
+
.command('mirror <input>')
|
|
10
|
+
.description('Create mirror/kaleidoscope effects')
|
|
11
|
+
.option('-m, --mode <mode>', 'Mirror mode: horizontal, vertical, both, quad (kaleidoscope) (default: horizontal)', 'horizontal')
|
|
12
|
+
.option('-o, --output <path>', 'Output file path')
|
|
13
|
+
.option('--dry-run', 'Show what would be done without executing')
|
|
14
|
+
.option('-v, --verbose', 'Verbose output')
|
|
15
|
+
.option('--help', 'Display help for mirror command')
|
|
16
|
+
.action(async (input, options) => {
|
|
17
|
+
if (options.help) {
|
|
18
|
+
createStandardHelp({
|
|
19
|
+
commandName: 'mirror',
|
|
20
|
+
emoji: '🪞',
|
|
21
|
+
description: 'Create stunning mirror and kaleidoscope effects by reflecting images horizontally, vertically, or in quadrants. Generate artistic symmetrical images.',
|
|
22
|
+
usage: ['mirror <input>', 'mirror <input> --mode vertical', 'mirror photo.jpg -m quad -o kaleidoscope.jpg'],
|
|
23
|
+
options: [
|
|
24
|
+
{ flag: '-m, --mode <mode>', description: 'Mirror mode: horizontal, vertical, both, quad (default: horizontal)' },
|
|
25
|
+
{ flag: '-o, --output <path>', description: 'Output file path (default: <input>-mirror-<mode>.ext)' },
|
|
26
|
+
{ flag: '--dry-run', description: 'Preview changes without executing' },
|
|
27
|
+
{ flag: '-v, --verbose', description: 'Show detailed output' }
|
|
28
|
+
],
|
|
29
|
+
examples: [
|
|
30
|
+
{ command: 'mirror photo.jpg', description: 'Horizontal mirror (left-right symmetry)' },
|
|
31
|
+
{ command: 'mirror photo.jpg --mode vertical', description: 'Vertical mirror (top-bottom symmetry)' },
|
|
32
|
+
{ command: 'mirror photo.jpg --mode both', description: 'Both horizontal and vertical mirroring' },
|
|
33
|
+
{ command: 'mirror photo.jpg --mode quad', description: 'Quadrant kaleidoscope effect' },
|
|
34
|
+
{ command: 'mirror landscape.jpg -m vertical -o reflection.jpg', description: 'Water reflection effect' }
|
|
35
|
+
],
|
|
36
|
+
additionalSections: [
|
|
37
|
+
{
|
|
38
|
+
title: 'Mirror Modes',
|
|
39
|
+
items: [
|
|
40
|
+
'horizontal - Mirror left to right (creates left-right symmetry)',
|
|
41
|
+
'vertical - Mirror top to bottom (creates top-bottom symmetry)',
|
|
42
|
+
'both - Mirror both axes (4-way symmetry)',
|
|
43
|
+
'quad - Kaleidoscope (mirrors each quadrant for artistic effect)'
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
title: 'Creative Uses',
|
|
48
|
+
items: [
|
|
49
|
+
'Water reflections (vertical mode)',
|
|
50
|
+
'Symmetrical portraits',
|
|
51
|
+
'Kaleidoscope art (quad mode)',
|
|
52
|
+
'Abstract patterns',
|
|
53
|
+
'Rorschach test style images',
|
|
54
|
+
'Architectural symmetry',
|
|
55
|
+
'Mandala-like designs'
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
title: 'Best Practices',
|
|
60
|
+
items: [
|
|
61
|
+
'Works best with asymmetric input images',
|
|
62
|
+
'Use vertical mode for water/reflection effects',
|
|
63
|
+
'Use quad mode for psychedelic art',
|
|
64
|
+
'Experiment with different modes on the same image',
|
|
65
|
+
'Combine with other effects for unique results'
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
tips: [
|
|
70
|
+
'Horizontal mode: great for face symmetry',
|
|
71
|
+
'Vertical mode: perfect for reflections',
|
|
72
|
+
'Quad mode: creates mandala-like patterns',
|
|
73
|
+
'Try mirroring already processed images'
|
|
74
|
+
]
|
|
75
|
+
});
|
|
76
|
+
process.exit(0);
|
|
77
|
+
}
|
|
78
|
+
const spinner = ora('Creating mirror effect...').start();
|
|
79
|
+
try {
|
|
80
|
+
if (!fs.existsSync(input)) {
|
|
81
|
+
spinner.fail(chalk.red(`Input file not found: ${input}`));
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
const mode = options.mode || 'horizontal';
|
|
85
|
+
const validModes = ['horizontal', 'vertical', 'both', 'quad'];
|
|
86
|
+
if (!validModes.includes(mode)) {
|
|
87
|
+
spinner.fail(chalk.red(`Invalid mode: ${mode}. Use: ${validModes.join(', ')}`));
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
const inputPath = path.parse(input);
|
|
91
|
+
const outputPath = options.output || path.join(inputPath.dir, `${inputPath.name}-mirror-${mode}${inputPath.ext}`);
|
|
92
|
+
const sharpInstance = createSharpInstance(input);
|
|
93
|
+
const metadata = await sharpInstance.metadata();
|
|
94
|
+
const width = metadata.width;
|
|
95
|
+
const height = metadata.height;
|
|
96
|
+
if (options.verbose) {
|
|
97
|
+
spinner.info(chalk.blue('Configuration:'));
|
|
98
|
+
console.log(chalk.dim(` Input: ${input} (${width}x${height})`));
|
|
99
|
+
console.log(chalk.dim(` Mode: ${mode}`));
|
|
100
|
+
console.log(chalk.dim(` Output: ${outputPath}`));
|
|
101
|
+
spinner.start('Processing...');
|
|
102
|
+
}
|
|
103
|
+
if (options.dryRun) {
|
|
104
|
+
spinner.info(chalk.yellow('Dry run mode - no changes will be made'));
|
|
105
|
+
console.log(chalk.green(`✓ Would create ${mode} mirror effect`));
|
|
106
|
+
console.log(chalk.dim(` Output: ${outputPath}`));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
let resultBuffer;
|
|
110
|
+
if (mode === 'horizontal') {
|
|
111
|
+
// Mirror left to right
|
|
112
|
+
const originalBuffer = await sharpInstance.toBuffer();
|
|
113
|
+
const flippedBuffer = await createSharpInstance(originalBuffer).flop().toBuffer();
|
|
114
|
+
// Stack side by side
|
|
115
|
+
resultBuffer = await createSharpInstance({
|
|
116
|
+
create: {
|
|
117
|
+
width: width * 2,
|
|
118
|
+
height: height,
|
|
119
|
+
channels: 4,
|
|
120
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
.composite([
|
|
124
|
+
{ input: originalBuffer, left: 0, top: 0 },
|
|
125
|
+
{ input: flippedBuffer, left: width, top: 0 }
|
|
126
|
+
])
|
|
127
|
+
.toBuffer();
|
|
128
|
+
}
|
|
129
|
+
else if (mode === 'vertical') {
|
|
130
|
+
// Mirror top to bottom
|
|
131
|
+
const originalBuffer = await sharpInstance.toBuffer();
|
|
132
|
+
const flippedBuffer = await createSharpInstance(originalBuffer).flip().toBuffer();
|
|
133
|
+
// Stack top and bottom
|
|
134
|
+
resultBuffer = await createSharpInstance({
|
|
135
|
+
create: {
|
|
136
|
+
width: width,
|
|
137
|
+
height: height * 2,
|
|
138
|
+
channels: 4,
|
|
139
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
|
140
|
+
}
|
|
141
|
+
})
|
|
142
|
+
.composite([
|
|
143
|
+
{ input: originalBuffer, left: 0, top: 0 },
|
|
144
|
+
{ input: flippedBuffer, left: 0, top: height }
|
|
145
|
+
])
|
|
146
|
+
.toBuffer();
|
|
147
|
+
}
|
|
148
|
+
else if (mode === 'both') {
|
|
149
|
+
// Mirror both axes (2x2 grid)
|
|
150
|
+
const originalBuffer = await sharpInstance.toBuffer();
|
|
151
|
+
const flopBuffer = await createSharpInstance(originalBuffer).flop().toBuffer();
|
|
152
|
+
const flipBuffer = await createSharpInstance(originalBuffer).flip().toBuffer();
|
|
153
|
+
const bothBuffer = await createSharpInstance(originalBuffer).flop().flip().toBuffer();
|
|
154
|
+
resultBuffer = await createSharpInstance({
|
|
155
|
+
create: {
|
|
156
|
+
width: width * 2,
|
|
157
|
+
height: height * 2,
|
|
158
|
+
channels: 4,
|
|
159
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
.composite([
|
|
163
|
+
{ input: originalBuffer, left: 0, top: 0 },
|
|
164
|
+
{ input: flopBuffer, left: width, top: 0 },
|
|
165
|
+
{ input: flipBuffer, left: 0, top: height },
|
|
166
|
+
{ input: bothBuffer, left: width, top: height }
|
|
167
|
+
])
|
|
168
|
+
.toBuffer();
|
|
169
|
+
}
|
|
170
|
+
else { // quad
|
|
171
|
+
// Kaleidoscope: take center portion and mirror in all 4 quadrants
|
|
172
|
+
const halfWidth = Math.floor(width / 2);
|
|
173
|
+
const halfHeight = Math.floor(height / 2);
|
|
174
|
+
// Extract center quarter
|
|
175
|
+
const centerBuffer = await sharpInstance
|
|
176
|
+
.extract({ left: halfWidth - Math.floor(halfWidth / 2), top: halfHeight - Math.floor(halfHeight / 2), width: halfWidth, height: halfHeight })
|
|
177
|
+
.toBuffer();
|
|
178
|
+
const flopBuffer = await createSharpInstance(centerBuffer).flop().toBuffer();
|
|
179
|
+
const flipBuffer = await createSharpInstance(centerBuffer).flip().toBuffer();
|
|
180
|
+
const bothBuffer = await createSharpInstance(centerBuffer).flop().flip().toBuffer();
|
|
181
|
+
resultBuffer = await createSharpInstance({
|
|
182
|
+
create: {
|
|
183
|
+
width: halfWidth * 2,
|
|
184
|
+
height: halfHeight * 2,
|
|
185
|
+
channels: 4,
|
|
186
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
|
187
|
+
}
|
|
188
|
+
})
|
|
189
|
+
.composite([
|
|
190
|
+
{ input: centerBuffer, left: 0, top: 0 },
|
|
191
|
+
{ input: flopBuffer, left: halfWidth, top: 0 },
|
|
192
|
+
{ input: flipBuffer, left: 0, top: halfHeight },
|
|
193
|
+
{ input: bothBuffer, left: halfWidth, top: halfHeight }
|
|
194
|
+
])
|
|
195
|
+
.toBuffer();
|
|
196
|
+
}
|
|
197
|
+
// Save result
|
|
198
|
+
await createSharpInstance(resultBuffer).toFile(outputPath);
|
|
199
|
+
const outputStats = fs.statSync(outputPath);
|
|
200
|
+
spinner.succeed(chalk.green('✓ Mirror effect created successfully!'));
|
|
201
|
+
console.log(chalk.dim(` Mode: ${mode}`));
|
|
202
|
+
console.log(chalk.dim(` Input: ${input}`));
|
|
203
|
+
console.log(chalk.dim(` Output: ${outputPath}`));
|
|
204
|
+
console.log(chalk.dim(` Size: ${(outputStats.size / 1024).toFixed(2)}KB`));
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
spinner.fail(chalk.red('Failed to create mirror effect'));
|
|
208
|
+
if (options.verbose) {
|
|
209
|
+
console.error(chalk.red('Error details:'), error);
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
console.error(chalk.red(error.message));
|
|
213
|
+
}
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=mirror.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mirror.js","sourceRoot":"","sources":["../../src/commands/mirror.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modulate.d.ts","sourceRoot":"","sources":["../../src/commands/modulate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBzC,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAsJvD"}
|