pixeli 0.1.9 → 1.0.3
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 +341 -88
- package/dist/cli/commands/collage/index.d.ts +2 -0
- package/dist/cli/commands/collage/index.js +125 -0
- package/dist/cli/commands/grid/index.d.ts +2 -0
- package/dist/cli/commands/grid/index.js +127 -0
- package/dist/cli/commands/masonry/index.d.ts +2 -0
- package/dist/cli/commands/masonry/index.js +129 -0
- package/dist/cli/commands/template/index.d.ts +2 -0
- package/dist/cli/commands/template/index.js +123 -0
- package/dist/cli/commands/template/presets/artGallery.d.ts +15 -0
- package/dist/cli/commands/template/presets/artGallery.js +15 -0
- package/dist/cli/commands/template/presets/dashboardShot.d.ts +15 -0
- package/dist/cli/commands/template/presets/dashboardShot.js +16 -0
- package/dist/cli/commands/template/presets/horizontalBookSpread.d.ts +15 -0
- package/dist/cli/commands/template/presets/horizontalBookSpread.js +13 -0
- package/dist/cli/commands/template/presets/instagramGrid.d.ts +15 -0
- package/dist/cli/commands/template/presets/instagramGrid.js +16 -0
- package/dist/cli/commands/template/presets/verticalBookSpread.d.ts +15 -0
- package/dist/cli/commands/template/presets/verticalBookSpread.js +13 -0
- package/dist/cli/commands/template/presets.d.ts +73 -0
- package/{lib/merges/collage-merge → dist/cli/commands/template}/presets.js +6 -8
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +24 -0
- package/dist/cli/modules/loadImages.d.ts +15 -0
- package/dist/cli/modules/loadImages.js +74 -0
- package/dist/cli/modules/progressBar.d.ts +10 -0
- package/dist/cli/modules/progressBar.js +34 -0
- package/dist/cli/schemas/collage.d.ts +29 -0
- package/dist/cli/schemas/collage.js +38 -0
- package/dist/cli/schemas/grid.d.ts +34 -0
- package/dist/cli/schemas/grid.js +38 -0
- package/dist/cli/schemas/masonry.d.ts +62 -0
- package/dist/cli/schemas/masonry.js +62 -0
- package/dist/cli/schemas/template.d.ts +31 -0
- package/dist/cli/schemas/template.js +49 -0
- package/dist/cli/utils/buildCommandFromSchema.d.ts +8 -0
- package/dist/cli/utils/buildCommandFromSchema.js +55 -0
- package/dist/cli/utils/configureCommandErrors.d.ts +2 -0
- package/dist/cli/utils/configureCommandErrors.js +22 -0
- package/dist/cli/utils/stringFormatter.d.ts +1 -0
- package/dist/cli/utils/stringFormatter.js +3 -0
- package/dist/cli/utils/toErrorMessage.d.ts +4 -0
- package/dist/cli/utils/toErrorMessage.js +22 -0
- package/dist/core/helpers.d.ts +10 -0
- package/dist/core/helpers.js +42 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +1 -0
- package/dist/core/mergeError.d.ts +9 -0
- package/dist/core/mergeError.js +10 -0
- package/dist/core/merges/collage/index.d.ts +9 -0
- package/dist/core/merges/collage/index.js +32 -0
- package/dist/core/merges/collage/steps/calculateImageDimensions.d.ts +12 -0
- package/dist/core/merges/collage/steps/calculateImageDimensions.js +18 -0
- package/dist/core/merges/collage/steps/createComposites.d.ts +8 -0
- package/dist/core/merges/collage/steps/createComposites.js +58 -0
- package/dist/core/merges/collage/steps/resizeAndBorderImages.d.ts +12 -0
- package/dist/core/merges/collage/steps/resizeAndBorderImages.js +26 -0
- package/dist/core/merges/collage/steps/rotateImages.d.ts +7 -0
- package/dist/core/merges/collage/steps/rotateImages.js +9 -0
- package/dist/core/merges/grid/index.d.ts +12 -0
- package/dist/core/merges/grid/index.js +36 -0
- package/dist/core/merges/grid/steps/calculateCanvasDimensions.d.ts +8 -0
- package/dist/core/merges/grid/steps/calculateCanvasDimensions.js +18 -0
- package/dist/core/merges/grid/steps/calculateFontSize.d.ts +7 -0
- package/dist/core/merges/grid/steps/calculateFontSize.js +19 -0
- package/dist/core/merges/grid/steps/calculateImageDimensions.d.ts +8 -0
- package/dist/core/merges/grid/steps/calculateImageDimensions.js +18 -0
- package/dist/core/merges/grid/steps/createComposites.d.ts +10 -0
- package/dist/core/merges/grid/steps/createComposites.js +63 -0
- package/dist/core/merges/grid/steps/prepareImages.d.ts +10 -0
- package/dist/core/merges/grid/steps/prepareImages.js +29 -0
- package/dist/core/merges/grid/steps/shuffleImagesAndCaptions.d.ts +7 -0
- package/dist/core/merges/grid/steps/shuffleImagesAndCaptions.js +17 -0
- package/dist/core/merges/index.d.ts +3 -0
- package/dist/core/merges/index.js +3 -0
- package/dist/core/merges/masonry/index.d.ts +10 -0
- package/dist/core/merges/masonry/index.js +32 -0
- package/dist/core/merges/masonry/steps/calculateCanvasDimensions.d.ts +15 -0
- package/dist/core/merges/masonry/steps/calculateCanvasDimensions.js +17 -0
- package/dist/core/merges/masonry/steps/calculateLaneSize.d.ts +9 -0
- package/dist/core/merges/masonry/steps/calculateLaneSize.js +27 -0
- package/dist/core/merges/masonry/steps/createComposites.d.ts +25 -0
- package/dist/core/merges/masonry/steps/createComposites.js +108 -0
- package/dist/core/merges/masonry/steps/resizeImages.d.ts +7 -0
- package/dist/core/merges/masonry/steps/resizeImages.js +14 -0
- package/dist/core/merges/masonry/steps/splitIntoLanes.d.ts +17 -0
- package/dist/core/merges/masonry/steps/splitIntoLanes.js +78 -0
- package/dist/core/merges/shared-steps/applyComposites.d.ts +2 -0
- package/dist/core/merges/shared-steps/applyComposites.js +16 -0
- package/dist/core/merges/shared-steps/createCanvas.d.ts +11 -0
- package/dist/core/merges/shared-steps/createCanvas.js +17 -0
- package/dist/core/merges/shared-steps/exportCanvas.d.ts +7 -0
- package/dist/core/merges/shared-steps/exportCanvas.js +25 -0
- package/dist/core/merges/shared-steps/finalizeImagePipelines.d.ts +2 -0
- package/dist/core/merges/shared-steps/finalizeImagePipelines.js +9 -0
- package/dist/core/merges/shared-steps/loadImages.d.ts +2 -0
- package/dist/core/merges/shared-steps/loadImages.js +26 -0
- package/dist/core/merges/shared-steps/validateCaptions.d.ts +10 -0
- package/dist/core/merges/shared-steps/validateCaptions.js +17 -0
- package/dist/core/merges/template/index.d.ts +10 -0
- package/dist/core/merges/template/index.js +28 -0
- package/dist/core/merges/template/steps/calculateSlotDimensions.d.ts +9 -0
- package/dist/core/merges/template/steps/calculateSlotDimensions.js +12 -0
- package/dist/core/merges/template/steps/createComposites.d.ts +10 -0
- package/dist/core/merges/template/steps/createComposites.js +25 -0
- package/dist/core/merges/template/steps/getBlocks.d.ts +13 -0
- package/dist/core/merges/template/steps/getBlocks.js +28 -0
- package/dist/core/merges/template/types.d.ts +21 -0
- package/dist/core/merges/template/types.js +1 -0
- package/dist/core/merges/types.d.ts +102 -0
- package/dist/core/merges/types.js +1 -0
- package/dist/core/modules/messages.d.ts +32 -0
- package/dist/core/modules/messages.js +54 -0
- package/dist/core/pipeline/guards.d.ts +4 -0
- package/dist/core/pipeline/guards.js +23 -0
- package/dist/core/pipeline/mergePipeline.d.ts +60 -0
- package/dist/core/pipeline/mergePipeline.js +122 -0
- package/dist/core/schemas/collage.d.ts +26 -0
- package/dist/core/schemas/collage.js +17 -0
- package/dist/core/schemas/grid.d.ts +32 -0
- package/dist/core/schemas/grid.js +29 -0
- package/dist/core/schemas/masonry.d.ts +56 -0
- package/dist/core/schemas/masonry.js +43 -0
- package/dist/core/schemas/template.d.ts +34 -0
- package/dist/core/schemas/template.js +88 -0
- package/dist/core/utils/colors/hexToRgba.d.ts +2 -0
- package/dist/core/utils/colors/hexToRgba.js +25 -0
- package/dist/core/utils/colors/rgbaToHex.d.ts +2 -0
- package/dist/core/utils/colors/rgbaToHex.js +15 -0
- package/dist/core/utils/colors/types.d.ts +7 -0
- package/dist/core/utils/colors/types.js +1 -0
- package/dist/core/utils/fonts/getFontSize.d.ts +9 -0
- package/dist/core/utils/fonts/getFontSize.js +40 -0
- package/dist/core/utils/images/addImageBorder.d.ts +13 -0
- package/dist/core/utils/images/addImageBorder.js +33 -0
- package/dist/core/utils/images/getImageHeights.d.ts +2 -0
- package/dist/core/utils/images/getImageHeights.js +9 -0
- package/dist/core/utils/images/getImageWidths.d.ts +2 -0
- package/dist/core/utils/images/getImageWidths.js +9 -0
- package/dist/core/utils/images/getSmallestImageDimensions.d.ts +5 -0
- package/dist/core/utils/images/getSmallestImageDimensions.js +9 -0
- package/dist/core/utils/images/handleImageEdges.d.ts +13 -0
- package/dist/core/utils/images/handleImageEdges.js +39 -0
- package/dist/core/utils/images/isActualImage.d.ts +5 -0
- package/dist/core/utils/images/isActualImage.js +26 -0
- package/dist/core/utils/images/parseAspectRatio.d.ts +1 -0
- package/dist/core/utils/images/parseAspectRatio.js +22 -0
- package/dist/core/utils/images/roundImage.d.ts +9 -0
- package/dist/core/utils/images/roundImage.js +27 -0
- package/dist/core/utils/images/roundImages.d.ts +8 -0
- package/dist/core/utils/images/roundImages.js +19 -0
- package/dist/core/utils/images/scaleImage.d.ts +8 -0
- package/dist/core/utils/images/scaleImage.js +36 -0
- package/dist/core/utils/images/scaleImages.d.ts +8 -0
- package/dist/core/utils/images/scaleImages.js +38 -0
- package/dist/core/utils/math/median.d.ts +1 -0
- package/dist/core/utils/math/median.js +12 -0
- package/dist/core/utils/math/randint.d.ts +6 -0
- package/dist/core/utils/math/randint.js +11 -0
- package/dist/core/utils/math/trimmedMedian.d.ts +1 -0
- package/dist/core/utils/math/trimmedMedian.js +12 -0
- package/dist/core/utils/svg/createSvgTextBuffer.d.ts +9 -0
- package/dist/core/utils/svg/createSvgTextBuffer.js +21 -0
- package/dist/validators/aspectRatio.d.ts +2 -0
- package/dist/validators/aspectRatio.js +15 -0
- package/dist/validators/coercion.d.ts +2 -0
- package/dist/validators/coercion.js +12 -0
- package/dist/validators/format.d.ts +2 -0
- package/dist/validators/format.js +15 -0
- package/dist/validators/hexColor.d.ts +7 -0
- package/dist/validators/hexColor.js +27 -0
- package/dist/validators/index.d.ts +95 -0
- package/dist/validators/index.js +64 -0
- package/dist/validators/outputFile.d.ts +2 -0
- package/dist/validators/outputFile.js +7 -0
- package/dist/validators/path.d.ts +3 -0
- package/dist/validators/path.js +18 -0
- package/dist/validators/sharpImageInput.d.ts +3 -0
- package/dist/validators/sharpImageInput.js +6 -0
- package/dist/validators/template.d.ts +15 -0
- package/dist/validators/template.js +41 -0
- package/package.json +26 -9
- package/bin/pixeli.js +0 -26
- package/commands/merge/collage.js +0 -83
- package/commands/merge/grid.js +0 -71
- package/commands/merge/helpers/utils.js +0 -11
- package/commands/merge/helpers/validations.js +0 -269
- package/commands/merge/index.js +0 -12
- package/commands/merge/masonry.js +0 -72
- package/lib/helpers/loadImages.js +0 -94
- package/lib/helpers/progressBar.js +0 -20
- package/lib/helpers/templateValidator.js +0 -139
- package/lib/helpers/utils.js +0 -208
- package/lib/merges/collage-merge/index.js +0 -110
- package/lib/merges/collage-merge/presets/artGallery.js +0 -17
- package/lib/merges/collage-merge/presets/dashboardShot.js +0 -18
- package/lib/merges/collage-merge/presets/horizontalBookSpread.js +0 -15
- package/lib/merges/collage-merge/presets/instagramGrid.js +0 -18
- package/lib/merges/collage-merge/presets/verticalBookSpread.js +0 -15
- package/lib/merges/grid-merge/index.js +0 -152
- package/lib/merges/masonry-merge/horizontal.js +0 -157
- package/lib/merges/masonry-merge/index.js +0 -57
- package/lib/merges/masonry-merge/vertical.js +0 -152
- package/lib/merges/merge-utils.js +0 -176
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import { buildCommandFromSchema } from '../../utils/buildCommandFromSchema.js';
|
|
4
|
+
import { collageMerge } from '../../../core/merges/collage/index.js';
|
|
5
|
+
import { loadImages } from '../../modules/loadImages.js';
|
|
6
|
+
import { MergeProgressBar } from '../../modules/progressBar.js';
|
|
7
|
+
import { MessageRenderer, MESSAGES } from '../../../core/modules/messages.js';
|
|
8
|
+
import { toErrorMessage } from '../../utils/toErrorMessage.js';
|
|
9
|
+
import { cliCollageSchema } from '../../schemas/collage.js';
|
|
10
|
+
const collageCommand = buildCommandFromSchema('collage', 'Arranges images in a messy, photo wall style grid.', cliCollageSchema, {
|
|
11
|
+
files: {
|
|
12
|
+
flags: '[files...]',
|
|
13
|
+
description: 'Image filepaths to merge (use --dir for directories)',
|
|
14
|
+
},
|
|
15
|
+
}, {
|
|
16
|
+
dir: {
|
|
17
|
+
flags: '-d, --dir <path>',
|
|
18
|
+
description: 'Directory of images to merge',
|
|
19
|
+
},
|
|
20
|
+
recursive: {
|
|
21
|
+
flags: '-r, --recursive',
|
|
22
|
+
description: 'Recursively include subdirectories',
|
|
23
|
+
},
|
|
24
|
+
shuffle: {
|
|
25
|
+
flags: '--sh, --shuffle',
|
|
26
|
+
description: 'Shuffle up images to randomize order in the grid',
|
|
27
|
+
},
|
|
28
|
+
cornerRadius: {
|
|
29
|
+
flags: '--cr, --corner-radius <px>',
|
|
30
|
+
description: 'How much to round the corners of each image',
|
|
31
|
+
},
|
|
32
|
+
gap: {
|
|
33
|
+
flags: '-g, --gap <px>',
|
|
34
|
+
description: 'Gap between images',
|
|
35
|
+
},
|
|
36
|
+
canvasColor: {
|
|
37
|
+
flags: '--bg, --canvas-color <hex|transparent>',
|
|
38
|
+
description: 'Background color for canvas',
|
|
39
|
+
},
|
|
40
|
+
borderWidth: {
|
|
41
|
+
flags: '--bw, --border-width <px>',
|
|
42
|
+
description: 'Width of the border around each image. Borders are placed internally in each image',
|
|
43
|
+
},
|
|
44
|
+
borderColor: {
|
|
45
|
+
flags: '--bc, --border-color <hex>',
|
|
46
|
+
description: 'Color of the border around each image',
|
|
47
|
+
},
|
|
48
|
+
output: {
|
|
49
|
+
flags: '-o, --output <file>',
|
|
50
|
+
description: 'Output file path',
|
|
51
|
+
},
|
|
52
|
+
aspectRatio: {
|
|
53
|
+
flags: '--ar, --aspect-ratio <width/height|number>',
|
|
54
|
+
description: 'The aspect ratio of all the images (examples: 16/9, 4:3, 1.777)',
|
|
55
|
+
},
|
|
56
|
+
imageWidth: {
|
|
57
|
+
flags: '-w, --image-width <px>',
|
|
58
|
+
description: 'The width of each image, defaults to the smallest image',
|
|
59
|
+
},
|
|
60
|
+
columns: {
|
|
61
|
+
flags: '-c, --columns <n>',
|
|
62
|
+
description: 'The number of columns',
|
|
63
|
+
},
|
|
64
|
+
overlapPercentage: {
|
|
65
|
+
flags: '--op, --overlap-percentage <percent>',
|
|
66
|
+
description: 'The estimated percentage of overlap for every image pair. A higher percentage creates a tighter collage',
|
|
67
|
+
},
|
|
68
|
+
rotationRange: {
|
|
69
|
+
flags: '--rr, --rotation-range <deg>',
|
|
70
|
+
description: 'The maximum and minimum degrees to randomly rotate each image',
|
|
71
|
+
},
|
|
72
|
+
imageWidthVariance: {
|
|
73
|
+
flags: '--wv, --image-width-variance <px>',
|
|
74
|
+
description: 'The number of pixels to potentially variate imageWidth by. Used to create random-sized images in the collage',
|
|
75
|
+
},
|
|
76
|
+
}).action(async (files, opts) => {
|
|
77
|
+
const input = { files, ...opts };
|
|
78
|
+
// Use progress bar module to track progress
|
|
79
|
+
const bar = new MergeProgressBar();
|
|
80
|
+
try {
|
|
81
|
+
const validatedOptions = await cliCollageSchema.parseAsync(input);
|
|
82
|
+
// Use load images module
|
|
83
|
+
const { images, ignoredPaths } = await loadImages({
|
|
84
|
+
input: { files: validatedOptions.files, dir: validatedOptions.dir },
|
|
85
|
+
recursive: validatedOptions.recursive,
|
|
86
|
+
});
|
|
87
|
+
// Ensure user knows about ignored files
|
|
88
|
+
if (ignoredPaths.length) {
|
|
89
|
+
const warning = new MessageRenderer(MESSAGES.WARNINGS.IGNORED_FILES, ignoredPaths.join('\n') + '\n');
|
|
90
|
+
const confirmation = await warning.confirm();
|
|
91
|
+
if (!confirmation)
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
// Collect merge options
|
|
95
|
+
const { recursive, output, files, dir, ...cliOptions } = validatedOptions;
|
|
96
|
+
const format = path.extname(output).replace('.', '');
|
|
97
|
+
const mergeOptions = {
|
|
98
|
+
format,
|
|
99
|
+
...cliOptions,
|
|
100
|
+
};
|
|
101
|
+
// Get grid buffer
|
|
102
|
+
const buffer = await collageMerge(images, mergeOptions, (progressInfo) => {
|
|
103
|
+
if (!bar.progressBar.isActive) {
|
|
104
|
+
bar.startBar(progressInfo.phase);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
bar.updateBar(progressInfo);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
// Write file and display success message
|
|
111
|
+
await fs.writeFile(output, buffer);
|
|
112
|
+
bar.endBar();
|
|
113
|
+
const success = new MessageRenderer(MESSAGES.SUCCESS.OUTPUT, output);
|
|
114
|
+
success.render();
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
// End the progress bar
|
|
118
|
+
bar.endBar();
|
|
119
|
+
// Create and render error
|
|
120
|
+
const errorMessage = toErrorMessage(err);
|
|
121
|
+
const error = new MessageRenderer(errorMessage);
|
|
122
|
+
error.render();
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
export default collageCommand;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import { buildCommandFromSchema } from '../../utils/buildCommandFromSchema.js';
|
|
4
|
+
import { gridMerge } from '../../../core/merges/grid/index.js';
|
|
5
|
+
import { cliGridSchema } from '../../schemas/grid.js';
|
|
6
|
+
import { loadImages } from '../../modules/loadImages.js';
|
|
7
|
+
import { MergeProgressBar } from '../../modules/progressBar.js';
|
|
8
|
+
import { MessageRenderer, MESSAGES } from '../../../core/modules/messages.js';
|
|
9
|
+
import { toErrorMessage } from '../../utils/toErrorMessage.js';
|
|
10
|
+
const gridCommand = buildCommandFromSchema('grid', 'Arranges images in an organized grid.', cliGridSchema, {
|
|
11
|
+
files: {
|
|
12
|
+
flags: '[files...]',
|
|
13
|
+
description: 'Image filepaths to merge (use --dir for directories)',
|
|
14
|
+
},
|
|
15
|
+
}, {
|
|
16
|
+
dir: {
|
|
17
|
+
flags: '-d, --dir <path>',
|
|
18
|
+
description: 'Directory of images to merge',
|
|
19
|
+
},
|
|
20
|
+
recursive: {
|
|
21
|
+
flags: '-r, --recursive',
|
|
22
|
+
description: 'Recursively include subdirectories',
|
|
23
|
+
},
|
|
24
|
+
shuffle: {
|
|
25
|
+
flags: '--sh, --shuffle',
|
|
26
|
+
description: 'Shuffle up images to randomize order in the grid',
|
|
27
|
+
},
|
|
28
|
+
cornerRadius: {
|
|
29
|
+
flags: '--cr, --corner-radius <px>',
|
|
30
|
+
description: 'How much to round the corners of each image',
|
|
31
|
+
},
|
|
32
|
+
gap: {
|
|
33
|
+
flags: '-g, --gap <px>',
|
|
34
|
+
description: 'Gap between images',
|
|
35
|
+
},
|
|
36
|
+
canvasColor: {
|
|
37
|
+
flags: '--bg, --canvas-color <hex|transparent>',
|
|
38
|
+
description: 'Background color for canvas',
|
|
39
|
+
},
|
|
40
|
+
borderWidth: {
|
|
41
|
+
flags: '--bw, --border-width <px>',
|
|
42
|
+
description: 'Width of the border around each image. Borders are placed internally in each image',
|
|
43
|
+
},
|
|
44
|
+
borderColor: {
|
|
45
|
+
flags: '--bc, --border-color <hex>',
|
|
46
|
+
description: 'Color of the border around each image',
|
|
47
|
+
},
|
|
48
|
+
output: {
|
|
49
|
+
flags: '-o, --output <file>',
|
|
50
|
+
description: 'Output file path',
|
|
51
|
+
},
|
|
52
|
+
aspectRatio: {
|
|
53
|
+
flags: '--ar, --aspect-ratio <width/height|number>',
|
|
54
|
+
description: 'The aspect ratio of all the images (examples: 16/9, 4:3, 1.777)',
|
|
55
|
+
},
|
|
56
|
+
imageWidth: {
|
|
57
|
+
flags: '-w, --image-width <px>',
|
|
58
|
+
description: 'The width of each image, defaults to the smallest image',
|
|
59
|
+
},
|
|
60
|
+
columns: {
|
|
61
|
+
flags: '-c, --columns <n>',
|
|
62
|
+
description: 'The number of columns',
|
|
63
|
+
},
|
|
64
|
+
caption: {
|
|
65
|
+
flags: '--ca, --caption',
|
|
66
|
+
description: 'Whether to caption each image',
|
|
67
|
+
},
|
|
68
|
+
captionColor: {
|
|
69
|
+
flags: '--cc, --caption-color <hex>',
|
|
70
|
+
description: 'Image caption color',
|
|
71
|
+
},
|
|
72
|
+
maxCaptionSize: {
|
|
73
|
+
flags: '--mcs, --max-caption-size <pt>',
|
|
74
|
+
description: 'The maximum allowed caption size',
|
|
75
|
+
},
|
|
76
|
+
}).action(async (files, opts) => {
|
|
77
|
+
const input = { files, ...opts };
|
|
78
|
+
// Use progress bar module to track progress
|
|
79
|
+
const bar = new MergeProgressBar();
|
|
80
|
+
try {
|
|
81
|
+
const validatedOptions = await cliGridSchema.parseAsync(input);
|
|
82
|
+
// Use load images module
|
|
83
|
+
const { images, imagePaths, ignoredPaths } = await loadImages({
|
|
84
|
+
input: { files: validatedOptions.files, dir: validatedOptions.dir },
|
|
85
|
+
recursive: validatedOptions.recursive,
|
|
86
|
+
});
|
|
87
|
+
// Ensure user knows about ignored files
|
|
88
|
+
if (ignoredPaths.length) {
|
|
89
|
+
const warning = new MessageRenderer(MESSAGES.WARNINGS.IGNORED_FILES, ignoredPaths.join('\n') + '\n');
|
|
90
|
+
const confirmation = await warning.confirm();
|
|
91
|
+
if (!confirmation)
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
// Collect merge options
|
|
95
|
+
const { recursive, output, files, dir, ...cliOptions } = validatedOptions;
|
|
96
|
+
const format = path.extname(output).replace('.', '');
|
|
97
|
+
const captions = imagePaths.map((p) => path.basename(p));
|
|
98
|
+
const mergeOptions = {
|
|
99
|
+
format,
|
|
100
|
+
captions,
|
|
101
|
+
...cliOptions,
|
|
102
|
+
};
|
|
103
|
+
// Get grid buffer
|
|
104
|
+
const buffer = await gridMerge(images, mergeOptions, (progressInfo) => {
|
|
105
|
+
if (!bar.progressBar.isActive) {
|
|
106
|
+
bar.startBar(progressInfo.phase);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
bar.updateBar(progressInfo);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
// Write file and display success message
|
|
113
|
+
await fs.writeFile(output, buffer);
|
|
114
|
+
bar.endBar();
|
|
115
|
+
const success = new MessageRenderer(MESSAGES.SUCCESS.OUTPUT, output);
|
|
116
|
+
success.render();
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
// End the progress bar
|
|
120
|
+
bar.endBar();
|
|
121
|
+
// Create and render error
|
|
122
|
+
const errorMessage = toErrorMessage(err);
|
|
123
|
+
const error = new MessageRenderer(errorMessage);
|
|
124
|
+
error.render();
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
export default gridCommand;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import { buildCommandFromSchema } from '../../utils/buildCommandFromSchema.js';
|
|
4
|
+
import { masonryMerge } from '../../../core/merges/masonry/index.js';
|
|
5
|
+
import { cliMasonrySchema } from '../../schemas/masonry.js';
|
|
6
|
+
import { loadImages } from '../../modules/loadImages.js';
|
|
7
|
+
import { MergeProgressBar } from '../../modules/progressBar.js';
|
|
8
|
+
import { MessageRenderer, MESSAGES } from '../../../core/modules/messages.js';
|
|
9
|
+
import { toErrorMessage } from '../../utils/toErrorMessage.js';
|
|
10
|
+
const masonryCommand = buildCommandFromSchema('masonry', "Use a ragged-grid layout, preserves images' aspect ratios", cliMasonrySchema, {
|
|
11
|
+
files: {
|
|
12
|
+
flags: '[files...]',
|
|
13
|
+
description: 'Image filepaths to merge (use --dir for directories)',
|
|
14
|
+
},
|
|
15
|
+
}, {
|
|
16
|
+
dir: {
|
|
17
|
+
flags: '-d, --dir <path>',
|
|
18
|
+
description: 'Directory of images to merge',
|
|
19
|
+
},
|
|
20
|
+
recursive: {
|
|
21
|
+
flags: '-r, --recursive',
|
|
22
|
+
description: 'Recursively include subdirectories',
|
|
23
|
+
},
|
|
24
|
+
shuffle: {
|
|
25
|
+
flags: '--sh, --shuffle',
|
|
26
|
+
description: 'Shuffle up images to randomize order in the grid',
|
|
27
|
+
},
|
|
28
|
+
cornerRadius: {
|
|
29
|
+
flags: '--cr, --corner-radius <px>',
|
|
30
|
+
description: 'How much to round the corners of each image',
|
|
31
|
+
},
|
|
32
|
+
gap: {
|
|
33
|
+
flags: '-g, --gap <px>',
|
|
34
|
+
description: 'Gap between images',
|
|
35
|
+
},
|
|
36
|
+
canvasColor: {
|
|
37
|
+
flags: '--bg, --canvas-color <hex|transparent>',
|
|
38
|
+
description: 'Background color for canvas',
|
|
39
|
+
},
|
|
40
|
+
borderWidth: {
|
|
41
|
+
flags: '--bw, --border-width <px>',
|
|
42
|
+
description: 'Width of the border around each image. Borders are placed internally in each image',
|
|
43
|
+
},
|
|
44
|
+
borderColor: {
|
|
45
|
+
flags: '--bc, --border-color <hex>',
|
|
46
|
+
description: 'Color of the border around each image',
|
|
47
|
+
},
|
|
48
|
+
output: {
|
|
49
|
+
flags: '-o, --output <file>',
|
|
50
|
+
description: 'Output file path',
|
|
51
|
+
},
|
|
52
|
+
rowHeight: {
|
|
53
|
+
flags: '--rh, --row-height <px>',
|
|
54
|
+
description: 'The height of each row, defaults to the trimmed median image height if undefined. Only applied in horizontal flows.',
|
|
55
|
+
},
|
|
56
|
+
columnWidth: {
|
|
57
|
+
flags: '--cw, --column-width <px>',
|
|
58
|
+
description: 'The width of each column, defaults to the trimmed median image width if undefined. Only applied in vertical flows.',
|
|
59
|
+
},
|
|
60
|
+
canvasWidth: {
|
|
61
|
+
flags: '--cvw, --canvas-width <px>',
|
|
62
|
+
description: 'The width of the entire canvas. Only required in horizontal flows.',
|
|
63
|
+
},
|
|
64
|
+
canvasHeight: {
|
|
65
|
+
flags: '--cvh, --canvas-height <px>',
|
|
66
|
+
description: 'The width of the entire canvas. Only required in vertical flows.',
|
|
67
|
+
},
|
|
68
|
+
flow: {
|
|
69
|
+
flags: '-f, --flow <horizontal|vertical>',
|
|
70
|
+
description: 'The orientation of the masonry layout.',
|
|
71
|
+
},
|
|
72
|
+
hAlign: {
|
|
73
|
+
flags: '--ha, --h-align <left|center|right|justified>',
|
|
74
|
+
description: 'The horizontal alignment of each row. Only applied in horizontal layouts.',
|
|
75
|
+
},
|
|
76
|
+
vAlign: {
|
|
77
|
+
flags: '--va, --v-align <top|middle|bottom|justified>',
|
|
78
|
+
description: 'The vertical alignment of each column. Only applied in vertical layouts.',
|
|
79
|
+
},
|
|
80
|
+
}).action(async (files, opts) => {
|
|
81
|
+
const input = { files, ...opts };
|
|
82
|
+
// Use progress bar module to track progress
|
|
83
|
+
const bar = new MergeProgressBar();
|
|
84
|
+
try {
|
|
85
|
+
const validatedOptions = await cliMasonrySchema.parseAsync(input);
|
|
86
|
+
// Use load images module
|
|
87
|
+
const { images, ignoredPaths } = await loadImages({
|
|
88
|
+
input: { files: validatedOptions.files, dir: validatedOptions.dir },
|
|
89
|
+
recursive: validatedOptions.recursive,
|
|
90
|
+
});
|
|
91
|
+
// Ensure user knows about ignored files
|
|
92
|
+
if (ignoredPaths.length) {
|
|
93
|
+
const warning = new MessageRenderer(MESSAGES.WARNINGS.IGNORED_FILES, ignoredPaths.join('\n') + '\n');
|
|
94
|
+
const confirmation = await warning.confirm();
|
|
95
|
+
if (!confirmation)
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
// Collect merge options
|
|
99
|
+
const { recursive, output, files, dir, ...cliOptions } = validatedOptions;
|
|
100
|
+
const format = path.extname(output).replace('.', '');
|
|
101
|
+
let mergeOptions = {
|
|
102
|
+
format,
|
|
103
|
+
...cliOptions,
|
|
104
|
+
};
|
|
105
|
+
// Get grid buffer
|
|
106
|
+
const buffer = await masonryMerge(images, mergeOptions, (progressInfo) => {
|
|
107
|
+
if (!bar.progressBar.isActive) {
|
|
108
|
+
bar.startBar(progressInfo.phase);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
bar.updateBar(progressInfo);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
// Write file and display success message
|
|
115
|
+
await fs.writeFile(output, buffer);
|
|
116
|
+
bar.endBar();
|
|
117
|
+
const success = new MessageRenderer(MESSAGES.SUCCESS.OUTPUT, output);
|
|
118
|
+
success.render();
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
// End the progress bar
|
|
122
|
+
bar.endBar();
|
|
123
|
+
// Create and render error
|
|
124
|
+
const errorMessage = toErrorMessage(err);
|
|
125
|
+
const error = new MessageRenderer(errorMessage);
|
|
126
|
+
error.render();
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
export default masonryCommand;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs, { readFile } from 'node:fs/promises';
|
|
3
|
+
import { buildCommandFromSchema } from '../../utils/buildCommandFromSchema.js';
|
|
4
|
+
import { templateMerge } from '../../../core/merges/template/index.js';
|
|
5
|
+
import { cliTemplateSchema } from '../../schemas/template.js';
|
|
6
|
+
import { PRESETS } from './presets.js';
|
|
7
|
+
import { loadImages } from '../../modules/loadImages.js';
|
|
8
|
+
import { MergeProgressBar } from '../../modules/progressBar.js';
|
|
9
|
+
import { MessageRenderer, MESSAGES } from '../../../core/modules/messages.js';
|
|
10
|
+
import { toErrorMessage } from '../../utils/toErrorMessage.js';
|
|
11
|
+
const templateCommand = buildCommandFromSchema('template', 'Use JSON layouts to build custom collages', cliTemplateSchema, {
|
|
12
|
+
files: {
|
|
13
|
+
flags: '[files...]',
|
|
14
|
+
description: 'Image filepaths to merge (use --dir for directories)',
|
|
15
|
+
},
|
|
16
|
+
}, {
|
|
17
|
+
dir: {
|
|
18
|
+
flags: '-d, --dir <path>',
|
|
19
|
+
description: 'Directory of images to merge',
|
|
20
|
+
},
|
|
21
|
+
recursive: {
|
|
22
|
+
flags: '-r, --recursive',
|
|
23
|
+
description: 'Recursively include subdirectories',
|
|
24
|
+
},
|
|
25
|
+
shuffle: {
|
|
26
|
+
flags: '--sh, --shuffle',
|
|
27
|
+
description: 'Shuffle up images to randomize order in the grid',
|
|
28
|
+
},
|
|
29
|
+
cornerRadius: {
|
|
30
|
+
flags: '--cr, --corner-radius <px>',
|
|
31
|
+
description: 'How much to round the corners of each image',
|
|
32
|
+
},
|
|
33
|
+
gap: {
|
|
34
|
+
flags: '-g, --gap <px>',
|
|
35
|
+
description: 'Gap between images',
|
|
36
|
+
},
|
|
37
|
+
canvasColor: {
|
|
38
|
+
flags: '--bg, --canvas-color <hex|transparent>',
|
|
39
|
+
description: 'Background color for canvas',
|
|
40
|
+
},
|
|
41
|
+
borderWidth: {
|
|
42
|
+
flags: '--bw, --border-width <px>',
|
|
43
|
+
description: 'Width of the border around each image. Borders are placed internally in each image',
|
|
44
|
+
},
|
|
45
|
+
borderColor: {
|
|
46
|
+
flags: '--bc, --border-color <hex>',
|
|
47
|
+
description: 'Color of the border around each image',
|
|
48
|
+
},
|
|
49
|
+
output: {
|
|
50
|
+
flags: '-o, --output <file>',
|
|
51
|
+
description: 'Output file path',
|
|
52
|
+
},
|
|
53
|
+
template: {
|
|
54
|
+
flags: '-t, --template <path>',
|
|
55
|
+
description: 'The path to the JSON file describing the template',
|
|
56
|
+
},
|
|
57
|
+
preset: {
|
|
58
|
+
flags: '-p, --preset <preset-id>',
|
|
59
|
+
description: `Template preset ID to use. Available collage IDs: ${Object.keys(PRESETS).join(', ')}`,
|
|
60
|
+
},
|
|
61
|
+
}).action(async (files, opts) => {
|
|
62
|
+
const input = { files, ...opts };
|
|
63
|
+
// Use progress bar module to track progress
|
|
64
|
+
const bar = new MergeProgressBar();
|
|
65
|
+
try {
|
|
66
|
+
const validatedOptions = await cliTemplateSchema.parseAsync(input);
|
|
67
|
+
// Use load images module
|
|
68
|
+
const { images, ignoredPaths } = await loadImages({
|
|
69
|
+
input: { files: validatedOptions.files, dir: validatedOptions.dir },
|
|
70
|
+
recursive: validatedOptions.recursive,
|
|
71
|
+
});
|
|
72
|
+
// Ensure user knows about ignored files
|
|
73
|
+
if (ignoredPaths.length) {
|
|
74
|
+
const warning = new MessageRenderer(MESSAGES.WARNINGS.IGNORED_FILES, ignoredPaths.join('\n') + '\n');
|
|
75
|
+
const confirmation = await warning.confirm();
|
|
76
|
+
if (!confirmation)
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// Collect merge options
|
|
80
|
+
const { recursive, output, files, dir, template, preset, ...cliOptions } = validatedOptions;
|
|
81
|
+
// Get the template file
|
|
82
|
+
let templateObj;
|
|
83
|
+
if (validatedOptions.template !== undefined) {
|
|
84
|
+
const templateJson = await readFile(validatedOptions.template, 'utf-8');
|
|
85
|
+
templateObj = JSON.parse(templateJson);
|
|
86
|
+
}
|
|
87
|
+
else if (validatedOptions.preset !== undefined) {
|
|
88
|
+
templateObj = PRESETS[validatedOptions.preset];
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
throw new Error(MESSAGES.ERROR.INTERNAL.message);
|
|
92
|
+
}
|
|
93
|
+
const format = path.extname(output).replace('.', '');
|
|
94
|
+
let mergeOptions = {
|
|
95
|
+
format,
|
|
96
|
+
template: templateObj,
|
|
97
|
+
...cliOptions,
|
|
98
|
+
};
|
|
99
|
+
// Get grid buffer
|
|
100
|
+
const buffer = await templateMerge(images, mergeOptions, (progressInfo) => {
|
|
101
|
+
if (!bar.progressBar.isActive) {
|
|
102
|
+
bar.startBar(progressInfo.phase);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
bar.updateBar(progressInfo);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
// Write file and display success message
|
|
109
|
+
await fs.writeFile(output, buffer);
|
|
110
|
+
bar.endBar();
|
|
111
|
+
const success = new MessageRenderer(MESSAGES.SUCCESS.OUTPUT, output);
|
|
112
|
+
success.render();
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
// End the progress bar
|
|
116
|
+
bar.endBar();
|
|
117
|
+
// Create and render error
|
|
118
|
+
const errorMessage = toErrorMessage(err);
|
|
119
|
+
const error = new MessageRenderer(errorMessage);
|
|
120
|
+
error.render();
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
export default templateCommand;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
canvas: {
|
|
3
|
+
width: 4000,
|
|
4
|
+
height: 3000,
|
|
5
|
+
columns: 5,
|
|
6
|
+
rows: 5,
|
|
7
|
+
},
|
|
8
|
+
slots: [
|
|
9
|
+
{ col: 1, row: 1, colSpan: 3, rowSpan: 3 },
|
|
10
|
+
{ col: 4, row: 1, colSpan: 2, rowSpan: 2 },
|
|
11
|
+
{ col: 4, row: 3, colSpan: 2, rowSpan: 1 },
|
|
12
|
+
{ col: 1, row: 4, colSpan: 2, rowSpan: 2 },
|
|
13
|
+
{ col: 3, row: 4, colSpan: 3, rowSpan: 2 },
|
|
14
|
+
],
|
|
15
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
canvas: {
|
|
3
|
+
width: 3600,
|
|
4
|
+
height: 2400,
|
|
5
|
+
columns: 6,
|
|
6
|
+
rows: 4,
|
|
7
|
+
},
|
|
8
|
+
slots: [
|
|
9
|
+
{ col: 1, row: 1, colSpan: 3, rowSpan: 2 },
|
|
10
|
+
{ col: 4, row: 1, colSpan: 3, rowSpan: 1 },
|
|
11
|
+
{ col: 4, row: 2, colSpan: 3, rowSpan: 1 },
|
|
12
|
+
{ col: 1, row: 3, colSpan: 2, rowSpan: 2 },
|
|
13
|
+
{ col: 3, row: 3, colSpan: 2, rowSpan: 2 },
|
|
14
|
+
{ col: 5, row: 3, colSpan: 2, rowSpan: 2 },
|
|
15
|
+
],
|
|
16
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
canvas: {
|
|
3
|
+
width: 2400,
|
|
4
|
+
height: 3200,
|
|
5
|
+
columns: 3,
|
|
6
|
+
rows: 6,
|
|
7
|
+
},
|
|
8
|
+
slots: [
|
|
9
|
+
{ col: 1, row: 1, colSpan: 2, rowSpan: 2 },
|
|
10
|
+
{ col: 3, row: 1, colSpan: 1, rowSpan: 1 },
|
|
11
|
+
{ col: 3, row: 2, colSpan: 1, rowSpan: 1 },
|
|
12
|
+
{ col: 1, row: 3, colSpan: 1, rowSpan: 2 },
|
|
13
|
+
{ col: 2, row: 3, colSpan: 2, rowSpan: 2 },
|
|
14
|
+
{ col: 1, row: 5, colSpan: 3, rowSpan: 2 },
|
|
15
|
+
],
|
|
16
|
+
};
|