pixeli 0.1.9 → 1.0.4
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 +362 -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 +2 -0
- package/dist/core/index.js +2 -0
- package/dist/core/jobs/batchRunner.d.ts +44 -0
- package/dist/core/jobs/batchRunner.js +90 -0
- package/dist/core/jobs/types.d.ts +10 -0
- package/dist/core/jobs/types.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 +5 -0
- package/dist/core/merges/index.js +4 -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 +123 -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/modules/typedEventEmitter.d.ts +7 -0
- package/dist/core/modules/typedEventEmitter.js +9 -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/mergeJob.d.ts +11 -0
- package/dist/core/schemas/mergeJob.js +6 -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,9 @@
|
|
|
1
|
+
import sharp from 'sharp';
|
|
2
|
+
// Width and height do not necessarily have to be from the same image
|
|
3
|
+
export const getSmallestImageDimensions = async (images) => {
|
|
4
|
+
const metas = await Promise.all(images.map((img) => img.metadata()));
|
|
5
|
+
return metas.reduce((acc, meta) => ({
|
|
6
|
+
smallestWidth: Math.min(acc.smallestWidth, meta.width),
|
|
7
|
+
smallestHeight: Math.min(acc.smallestHeight, meta.height),
|
|
8
|
+
}), { smallestWidth: Infinity, smallestHeight: Infinity });
|
|
9
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import sharp from 'sharp';
|
|
2
|
+
import type { RGBA } from '../colors/types.js';
|
|
3
|
+
interface Options {
|
|
4
|
+
borderWidth: number;
|
|
5
|
+
borderHeight: number;
|
|
6
|
+
borderColor: RGBA;
|
|
7
|
+
cornerRadius: number;
|
|
8
|
+
imageWidth: number;
|
|
9
|
+
imageHeight: number;
|
|
10
|
+
finalizePipeline?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare const handleImageEdges: (image: sharp.Sharp, { borderWidth, borderHeight, borderColor, imageWidth, imageHeight, cornerRadius, finalizePipeline }: Options) => Promise<sharp.Sharp>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import sharp from 'sharp';
|
|
2
|
+
import { rgbaToHex } from '../colors/rgbaToHex.js';
|
|
3
|
+
export const handleImageEdges = async (image, { borderWidth, borderHeight, borderColor, imageWidth, imageHeight, cornerRadius = 0, finalizePipeline = false }) => {
|
|
4
|
+
// Only change the image's edges if needed
|
|
5
|
+
if (borderWidth <= 0 && borderHeight <= 0 && cornerRadius <= 0)
|
|
6
|
+
return image;
|
|
7
|
+
const maxBorderX = imageWidth / 2;
|
|
8
|
+
const maxBorderY = imageHeight / 2;
|
|
9
|
+
const effectiveBorderWidth = Math.min(borderWidth, maxBorderX);
|
|
10
|
+
const effectiveBorderHeight = Math.min(borderHeight, maxBorderY);
|
|
11
|
+
// Step 1 — Round corners mask
|
|
12
|
+
const mask = `
|
|
13
|
+
<svg width="${imageWidth}" height="${imageHeight}">
|
|
14
|
+
<rect x="0" y="0" width="${imageWidth}" height="${imageHeight}" rx="${cornerRadius}" ry="${cornerRadius}" fill="white"/>
|
|
15
|
+
</svg>
|
|
16
|
+
`;
|
|
17
|
+
// Step 2 — Optional border layer (draw inside the image)
|
|
18
|
+
const border = `
|
|
19
|
+
<svg width="${imageWidth}" height="${imageHeight}">
|
|
20
|
+
<rect x="${effectiveBorderWidth / 2}" y="${effectiveBorderHeight / 2}" width="${imageWidth - effectiveBorderWidth}" height="${imageHeight - effectiveBorderHeight}" rx="${cornerRadius}" ry="${cornerRadius}"
|
|
21
|
+
fill="none" stroke="${rgbaToHex(borderColor)}" stroke-width="${Math.max(effectiveBorderWidth, effectiveBorderHeight)}"/>
|
|
22
|
+
</svg>
|
|
23
|
+
`;
|
|
24
|
+
// Only pick needed composites
|
|
25
|
+
const composites = [];
|
|
26
|
+
if (cornerRadius > 0) {
|
|
27
|
+
composites.push({ input: Buffer.from(mask), blend: 'dest-in', top: 0, left: 0 });
|
|
28
|
+
}
|
|
29
|
+
if (effectiveBorderWidth > 0 || effectiveBorderHeight > 0) {
|
|
30
|
+
composites.push({ input: Buffer.from(border), blend: 'over', top: 0, left: 0 });
|
|
31
|
+
}
|
|
32
|
+
// Step 3 — Composite mask and border
|
|
33
|
+
const processed = composites.length > 0 ? image.toFormat('png').composite(composites) : image;
|
|
34
|
+
// Finalize image if needed
|
|
35
|
+
if (finalizePipeline) {
|
|
36
|
+
return sharp(await processed.toBuffer());
|
|
37
|
+
}
|
|
38
|
+
return processed;
|
|
39
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import sharp from 'sharp';
|
|
2
|
+
export const isActualImage = async (input) => {
|
|
3
|
+
try {
|
|
4
|
+
// Try to get metadata
|
|
5
|
+
const metadata = await sharp(input).metadata();
|
|
6
|
+
// Try to get width and height
|
|
7
|
+
/* v8 ignore start */
|
|
8
|
+
if (!metadata.width || !metadata.height) {
|
|
9
|
+
return {
|
|
10
|
+
isImage: false,
|
|
11
|
+
reason: 'Image metadata missing width or height',
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/* v8 ignore stop */
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
return {
|
|
18
|
+
isImage: false,
|
|
19
|
+
reason: err.message,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
isImage: true,
|
|
24
|
+
reason: '',
|
|
25
|
+
};
|
|
26
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const parseAspectRatio: (aspectRatio: string) => number | false;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const parseAspectRatio = (aspectRatio) => {
|
|
2
|
+
// return ratio straight away if its just a number
|
|
3
|
+
const ratio = Number(aspectRatio);
|
|
4
|
+
if (ratio) {
|
|
5
|
+
return ratio;
|
|
6
|
+
}
|
|
7
|
+
const ratioRegex = /^\s*(\d+)\s*(\/|:|x)\s*(\d+)\s*$/i;
|
|
8
|
+
const match = aspectRatio.match(ratioRegex);
|
|
9
|
+
// Ensure match exists
|
|
10
|
+
if (!match)
|
|
11
|
+
return false;
|
|
12
|
+
// Ensures absolute type safety
|
|
13
|
+
const [, wStr, , hStr] = match;
|
|
14
|
+
if (!wStr || !hStr)
|
|
15
|
+
return false;
|
|
16
|
+
// Return aspect ratio
|
|
17
|
+
const width = parseInt(wStr, 10);
|
|
18
|
+
const height = parseInt(hStr, 10);
|
|
19
|
+
if (width === 0 || height === 0)
|
|
20
|
+
return false;
|
|
21
|
+
return width / height;
|
|
22
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import sharp from 'sharp';
|
|
2
|
+
interface RoundImageOptions {
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
cornerRadius: number;
|
|
6
|
+
finalizePipeline?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare const roundImage: (image: sharp.Sharp, { width, height, cornerRadius, finalizePipeline }: RoundImageOptions) => Promise<sharp.Sharp>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import sharp from 'sharp';
|
|
2
|
+
export const roundImage = async (image, { width, height, cornerRadius, finalizePipeline = false }) => {
|
|
3
|
+
// Skip if the cornerRadius = zero
|
|
4
|
+
if (!cornerRadius)
|
|
5
|
+
return image;
|
|
6
|
+
// Create rounded svg mask
|
|
7
|
+
const mask = Buffer.from(`
|
|
8
|
+
<svg width="${width}" height="${height}">
|
|
9
|
+
<rect x="0" y="0" width="${width}" height="${height}" rx="${cornerRadius}" ry="${cornerRadius}" />
|
|
10
|
+
</svg>
|
|
11
|
+
`);
|
|
12
|
+
// Apply mask
|
|
13
|
+
const roundedImage = image
|
|
14
|
+
.composite([
|
|
15
|
+
{
|
|
16
|
+
input: mask,
|
|
17
|
+
blend: 'dest-in',
|
|
18
|
+
},
|
|
19
|
+
])
|
|
20
|
+
.toFormat('png');
|
|
21
|
+
// Finalize pipeline if needed
|
|
22
|
+
if (finalizePipeline) {
|
|
23
|
+
const buffer = await roundedImage.toBuffer();
|
|
24
|
+
return sharp(buffer);
|
|
25
|
+
}
|
|
26
|
+
return roundedImage;
|
|
27
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import sharp from 'sharp';
|
|
2
|
+
interface RoundImagesOptions {
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
cornerRadius: number;
|
|
6
|
+
}
|
|
7
|
+
export declare const roundImages: (images: sharp.Sharp[], { width, height, cornerRadius }: RoundImagesOptions) => Promise<sharp.Sharp[]>;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import sharp from 'sharp';
|
|
2
|
+
export const roundImages = async (images, { width, height, cornerRadius }) => {
|
|
3
|
+
// Skip if the cornerRadius = zero
|
|
4
|
+
if (!cornerRadius)
|
|
5
|
+
return images;
|
|
6
|
+
// Round images respectively
|
|
7
|
+
return await Promise.all(images.map(async (image) => {
|
|
8
|
+
const mask = Buffer.from(`
|
|
9
|
+
<svg width="${width}" height="${height}">
|
|
10
|
+
<rect x="0" y="0" width="${width}" height="${height}" rx="${cornerRadius}" ry="${cornerRadius}" />
|
|
11
|
+
</svg>
|
|
12
|
+
`);
|
|
13
|
+
const buff = await image
|
|
14
|
+
.composite([{ input: mask, blend: 'dest-in' }])
|
|
15
|
+
.png()
|
|
16
|
+
.toBuffer();
|
|
17
|
+
return sharp(buff);
|
|
18
|
+
}));
|
|
19
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import sharp from 'sharp';
|
|
2
|
+
interface ScaleImageOptions {
|
|
3
|
+
width?: number;
|
|
4
|
+
height?: number;
|
|
5
|
+
finalizePipeline?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const scaleImage: (image: sharp.Sharp, { width, height, finalizePipeline }: ScaleImageOptions) => Promise<sharp.Sharp>;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import sharp from 'sharp';
|
|
2
|
+
export const scaleImage = async (image, { width, height, finalizePipeline = false }) => {
|
|
3
|
+
// Ensure either width or height is provided
|
|
4
|
+
if (width == undefined && height === undefined) {
|
|
5
|
+
throw new Error('You must provide either width or height.');
|
|
6
|
+
}
|
|
7
|
+
let targetWidth, targetHeight;
|
|
8
|
+
const meta = await image.metadata();
|
|
9
|
+
// Set target width and height using size factor
|
|
10
|
+
if (width !== undefined && height !== undefined) {
|
|
11
|
+
targetWidth = width;
|
|
12
|
+
targetHeight = height;
|
|
13
|
+
}
|
|
14
|
+
else if (width !== undefined) {
|
|
15
|
+
const f = width / meta.width;
|
|
16
|
+
targetWidth = width;
|
|
17
|
+
targetHeight = Math.floor(meta.height * f);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
const f = height / meta.height;
|
|
21
|
+
targetHeight = height;
|
|
22
|
+
targetWidth = Math.floor(meta.width * f);
|
|
23
|
+
}
|
|
24
|
+
// Resize the image
|
|
25
|
+
const resizedImage = image.resize(targetWidth, targetHeight);
|
|
26
|
+
// Only finalize changes in the image pipeline if needed
|
|
27
|
+
if (finalizePipeline) {
|
|
28
|
+
// Use jpg format if possible for less memory usage
|
|
29
|
+
const formatPipe = meta.channels === 4 ? resizedImage.toFormat('png') : resizedImage.toFormat('jpg');
|
|
30
|
+
const buffer = await formatPipe.toBuffer();
|
|
31
|
+
return sharp(buffer);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
return resizedImage;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import sharp from 'sharp';
|
|
2
|
+
interface ScaleImagesOptions {
|
|
3
|
+
width?: number;
|
|
4
|
+
height?: number;
|
|
5
|
+
finalizePipeline?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const scaleImages: (images: sharp.Sharp[], { width, height, finalizePipeline }?: ScaleImagesOptions) => Promise<sharp.Sharp[]>;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import sharp from 'sharp';
|
|
2
|
+
export const scaleImages = async (images, { width, height, finalizePipeline = false } = {}) => {
|
|
3
|
+
// Ensure either width or height is provided
|
|
4
|
+
if (width == undefined && height === undefined) {
|
|
5
|
+
throw new Error('You must provide either width or height.');
|
|
6
|
+
}
|
|
7
|
+
// Return scaled images
|
|
8
|
+
const scaledImages = await Promise.all(images.map(async (image) => {
|
|
9
|
+
const meta = await image.metadata();
|
|
10
|
+
let targetWidth, targetHeight;
|
|
11
|
+
if (width !== undefined && height !== undefined) {
|
|
12
|
+
targetWidth = width;
|
|
13
|
+
targetHeight = height;
|
|
14
|
+
}
|
|
15
|
+
else if (width !== undefined) {
|
|
16
|
+
const f = width / meta.width;
|
|
17
|
+
targetWidth = width;
|
|
18
|
+
targetHeight = Math.floor(meta.height * f);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
const f = height / meta.height;
|
|
22
|
+
targetHeight = height;
|
|
23
|
+
targetWidth = Math.floor(meta.width * f);
|
|
24
|
+
}
|
|
25
|
+
const newImage = image.resize(targetWidth, targetHeight);
|
|
26
|
+
// Only finalize changes in the image pipeline if needed
|
|
27
|
+
if (finalizePipeline) {
|
|
28
|
+
// Use jpg format if possible for less memory usage
|
|
29
|
+
const formatPipe = meta.channels === 4 ? newImage.toFormat('png') : newImage.toFormat('jpg');
|
|
30
|
+
const buffer = await formatPipe.toBuffer();
|
|
31
|
+
return sharp(buffer);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
return newImage;
|
|
35
|
+
}
|
|
36
|
+
}));
|
|
37
|
+
return scaledImages;
|
|
38
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function median(values: readonly number[]): number | null;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function median(values) {
|
|
2
|
+
if (values.length === 0)
|
|
3
|
+
return null;
|
|
4
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
5
|
+
const mid = Math.floor(sorted.length / 2);
|
|
6
|
+
if (sorted.length % 2 === 1) {
|
|
7
|
+
return sorted[mid] ?? null;
|
|
8
|
+
}
|
|
9
|
+
const a = sorted[mid - 1];
|
|
10
|
+
const b = sorted[mid];
|
|
11
|
+
return a !== undefined && b !== undefined ? (a + b) / 2 : null;
|
|
12
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const randint = (lowOrValue, high) => {
|
|
2
|
+
if (high === undefined) {
|
|
3
|
+
return Math.round(Math.random() * lowOrValue);
|
|
4
|
+
}
|
|
5
|
+
let low = lowOrValue;
|
|
6
|
+
if (high > low) {
|
|
7
|
+
[low, high] = [high, low];
|
|
8
|
+
}
|
|
9
|
+
const range = high - low;
|
|
10
|
+
return Math.round(low + Math.random() * range);
|
|
11
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const trimmedMedian: (values: number[], trimRatio?: number) => number | null;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { median } from './median.js';
|
|
2
|
+
export const trimmedMedian = (values, trimRatio = 0.1) => {
|
|
3
|
+
if (values.length === 0)
|
|
4
|
+
return null;
|
|
5
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
6
|
+
const trim = Math.floor(sorted.length * trimRatio);
|
|
7
|
+
// Prevent trimming everything
|
|
8
|
+
if (trim * 2 >= sorted.length) {
|
|
9
|
+
return median(sorted);
|
|
10
|
+
}
|
|
11
|
+
return median(sorted.slice(trim, sorted.length - trim));
|
|
12
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface CreateSvgTextBufferOptions {
|
|
2
|
+
text: string;
|
|
3
|
+
maxWidth: number;
|
|
4
|
+
maxHeight: number;
|
|
5
|
+
fontSize: number;
|
|
6
|
+
fill?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const createSvgTextBuffer: ({ text, maxWidth, maxHeight, fontSize, fill }: CreateSvgTextBufferOptions) => Buffer<ArrayBuffer>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { escapeXML } from '../../helpers.js';
|
|
2
|
+
export const createSvgTextBuffer = ({ text, maxWidth, maxHeight, fontSize, fill = '#000000' }) => {
|
|
3
|
+
// Width and viewport are assigned to this svg
|
|
4
|
+
const svg = `
|
|
5
|
+
<svg xmlns="http://www.w3.org/2000/svg"
|
|
6
|
+
width="${maxWidth}" height="${maxHeight}"
|
|
7
|
+
viewBox="0 0 ${maxWidth} ${maxHeight}">
|
|
8
|
+
<text
|
|
9
|
+
x="${maxWidth / 2}"
|
|
10
|
+
y="${maxHeight / 2}"
|
|
11
|
+
font-size="${fontSize}"
|
|
12
|
+
font-family="sans-serif"
|
|
13
|
+
fill="${fill}"
|
|
14
|
+
text-anchor="middle"
|
|
15
|
+
dominant-baseline="middle">
|
|
16
|
+
${escapeXML(text)}
|
|
17
|
+
</text>
|
|
18
|
+
</svg>
|
|
19
|
+
`;
|
|
20
|
+
return Buffer.from(svg);
|
|
21
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
import { parseAspectRatio } from '../core/utils/images/parseAspectRatio.js';
|
|
3
|
+
export const aspectRatioValidator = z.coerce.string().transform((ratio, ctx) => {
|
|
4
|
+
const result = parseAspectRatio(ratio);
|
|
5
|
+
// Validate aspect ratio
|
|
6
|
+
if (!result) {
|
|
7
|
+
ctx.addIssue({
|
|
8
|
+
code: 'custom',
|
|
9
|
+
message: 'Invalid aspect ratio: Examples of valid ratios include 16/9, 2:3, 1x2, 1.77.',
|
|
10
|
+
input: ratio,
|
|
11
|
+
});
|
|
12
|
+
return z.NEVER;
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
export const useNumberCoercion = (schema) => {
|
|
3
|
+
return z.preprocess((val) => {
|
|
4
|
+
if (typeof val === 'number')
|
|
5
|
+
return val;
|
|
6
|
+
if (typeof val === 'string' && val.trim() !== '') {
|
|
7
|
+
const n = Number(val);
|
|
8
|
+
return Number.isNaN(n) ? val : n;
|
|
9
|
+
}
|
|
10
|
+
return val;
|
|
11
|
+
}, schema);
|
|
12
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
import { isSupportedOutputImage, SUPPORTED_OUTPUT_FORMATS } from '../core/helpers.js';
|
|
3
|
+
export const formatValidator = z.string().transform((extname, ctx) => {
|
|
4
|
+
if (isSupportedOutputImage(extname)) {
|
|
5
|
+
return extname;
|
|
6
|
+
}
|
|
7
|
+
else {
|
|
8
|
+
ctx.addIssue({
|
|
9
|
+
code: 'custom',
|
|
10
|
+
path: ['format'],
|
|
11
|
+
message: `Invalid format type. Valid output formats include: ${SUPPORTED_OUTPUT_FORMATS.join(', ')}`,
|
|
12
|
+
});
|
|
13
|
+
return z.NEVER;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
export declare const hexColorValidator: z.ZodUnion<readonly [z.ZodPipe<z.ZodString, z.ZodTransform<import("../core/utils/colors/types.js").RGBA, string>>, z.ZodObject<{
|
|
3
|
+
r: z.ZodNumber;
|
|
4
|
+
g: z.ZodNumber;
|
|
5
|
+
b: z.ZodNumber;
|
|
6
|
+
alpha: z.ZodNumber;
|
|
7
|
+
}, z.z.core.$strip>]>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
import { isValidHexColor } from '../core/helpers.js';
|
|
3
|
+
import { hexToRgba } from '../core/utils/colors/hexToRgba.js';
|
|
4
|
+
export const hexColorValidator = z.union([
|
|
5
|
+
z.string().transform((color, ctx) => {
|
|
6
|
+
// Handle transparency
|
|
7
|
+
if (color === 'transparent') {
|
|
8
|
+
return hexToRgba('#00000000');
|
|
9
|
+
}
|
|
10
|
+
// Handle hex values
|
|
11
|
+
if (!isValidHexColor(color)) {
|
|
12
|
+
ctx.addIssue({
|
|
13
|
+
code: 'custom',
|
|
14
|
+
message: "Invalid color: must be 'transparent', #rgb, #rrggbb, #rrggbbaa, or object of {r, g, b, a}.",
|
|
15
|
+
input: color,
|
|
16
|
+
});
|
|
17
|
+
return z.NEVER;
|
|
18
|
+
}
|
|
19
|
+
return hexToRgba(color);
|
|
20
|
+
}),
|
|
21
|
+
z.object({
|
|
22
|
+
r: z.number().int().min(0).max(255),
|
|
23
|
+
g: z.number().int().min(0).max(255),
|
|
24
|
+
b: z.number().int().min(0).max(255),
|
|
25
|
+
alpha: z.number().min(0).max(1),
|
|
26
|
+
}, "Invalid color: must be 'transparent', #rgb, #rrggbb, #rrggbbaa, or object of {r, g, b, a}."),
|
|
27
|
+
], "Invalid color: must be 'transparent', #rgb, #rrggbb, #rrggbbaa, or object of {r, g, b, a}.");
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
export declare const VALIDATORS: {
|
|
3
|
+
files: z.ZodArray<z.ZodString>;
|
|
4
|
+
dir: z.ZodString;
|
|
5
|
+
output: z.ZodString;
|
|
6
|
+
format: z.ZodPipe<z.ZodString, z.ZodTransform<"webp" | "gif" | "jpeg" | "jpg" | "png" | "tiff" | "avif", string>>;
|
|
7
|
+
cliTemplate: z.ZodString;
|
|
8
|
+
imageInputs: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>]>>;
|
|
9
|
+
captions: z.ZodArray<z.ZodString>;
|
|
10
|
+
caption: z.ZodBoolean;
|
|
11
|
+
recursive: z.ZodBoolean;
|
|
12
|
+
shuffle: z.ZodBoolean;
|
|
13
|
+
canvasColor: z.ZodUnion<readonly [z.ZodPipe<z.ZodString, z.ZodTransform<import("../core/utils/colors/types.js").RGBA, string>>, z.ZodObject<{
|
|
14
|
+
r: z.ZodNumber;
|
|
15
|
+
g: z.ZodNumber;
|
|
16
|
+
b: z.ZodNumber;
|
|
17
|
+
alpha: z.ZodNumber;
|
|
18
|
+
}, z.z.core.$strip>]>;
|
|
19
|
+
captionColor: z.ZodUnion<readonly [z.ZodPipe<z.ZodString, z.ZodTransform<import("../core/utils/colors/types.js").RGBA, string>>, z.ZodObject<{
|
|
20
|
+
r: z.ZodNumber;
|
|
21
|
+
g: z.ZodNumber;
|
|
22
|
+
b: z.ZodNumber;
|
|
23
|
+
alpha: z.ZodNumber;
|
|
24
|
+
}, z.z.core.$strip>]>;
|
|
25
|
+
borderColor: z.ZodUnion<readonly [z.ZodPipe<z.ZodString, z.ZodTransform<import("../core/utils/colors/types.js").RGBA, string>>, z.ZodObject<{
|
|
26
|
+
r: z.ZodNumber;
|
|
27
|
+
g: z.ZodNumber;
|
|
28
|
+
b: z.ZodNumber;
|
|
29
|
+
alpha: z.ZodNumber;
|
|
30
|
+
}, z.z.core.$strip>]>;
|
|
31
|
+
cornerRadius: z.ZodNumber;
|
|
32
|
+
gap: z.ZodNumber;
|
|
33
|
+
imageWidth: z.ZodNumber;
|
|
34
|
+
columns: z.ZodNumber;
|
|
35
|
+
maxCaptionSize: z.ZodNumber;
|
|
36
|
+
rowHeight: z.ZodNumber;
|
|
37
|
+
columnWidth: z.ZodNumber;
|
|
38
|
+
canvasWidth: z.ZodNumber;
|
|
39
|
+
canvasHeight: z.ZodNumber;
|
|
40
|
+
overlapPercentage: z.ZodNumber;
|
|
41
|
+
rotationRange: z.ZodNumber;
|
|
42
|
+
imageWidthVariance: z.ZodNumber;
|
|
43
|
+
borderWidth: z.ZodNumber;
|
|
44
|
+
cliCornerRadius: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>;
|
|
45
|
+
cliGap: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>;
|
|
46
|
+
cliImageWidth: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>;
|
|
47
|
+
cliColumns: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>;
|
|
48
|
+
cliMaxCaptionSize: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>;
|
|
49
|
+
cliRowHeight: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>;
|
|
50
|
+
cliColumnWidth: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>;
|
|
51
|
+
cliCanvasWidth: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>;
|
|
52
|
+
cliCanvasHeight: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>;
|
|
53
|
+
cliOverlapPercentage: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>;
|
|
54
|
+
cliRotationRange: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>;
|
|
55
|
+
cliImageWidthVariance: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>;
|
|
56
|
+
cliBorderWidth: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>;
|
|
57
|
+
flow: z.ZodEnum<{
|
|
58
|
+
horizontal: "horizontal";
|
|
59
|
+
vertical: "vertical";
|
|
60
|
+
}>;
|
|
61
|
+
hAlign: z.ZodEnum<{
|
|
62
|
+
left: "left";
|
|
63
|
+
center: "center";
|
|
64
|
+
right: "right";
|
|
65
|
+
justified: "justified";
|
|
66
|
+
}>;
|
|
67
|
+
vAlign: z.ZodEnum<{
|
|
68
|
+
justified: "justified";
|
|
69
|
+
top: "top";
|
|
70
|
+
middle: "middle";
|
|
71
|
+
bottom: "bottom";
|
|
72
|
+
}>;
|
|
73
|
+
preset: z.ZodEnum<{
|
|
74
|
+
"instagram-grid": "instagram-grid";
|
|
75
|
+
"dashboard-shot": "dashboard-shot";
|
|
76
|
+
"horizontal-book-spread": "horizontal-book-spread";
|
|
77
|
+
"vertical-book-spread": "vertical-book-spread";
|
|
78
|
+
"art-gallery": "art-gallery";
|
|
79
|
+
}>;
|
|
80
|
+
template: z.ZodObject<{
|
|
81
|
+
canvas: z.ZodObject<{
|
|
82
|
+
width: z.ZodNumber;
|
|
83
|
+
height: z.ZodNumber;
|
|
84
|
+
columns: z.ZodNumber;
|
|
85
|
+
rows: z.ZodNumber;
|
|
86
|
+
}, z.z.core.$strip>;
|
|
87
|
+
slots: z.ZodArray<z.ZodObject<{
|
|
88
|
+
col: z.ZodNumber;
|
|
89
|
+
row: z.ZodNumber;
|
|
90
|
+
colSpan: z.ZodNumber;
|
|
91
|
+
rowSpan: z.ZodNumber;
|
|
92
|
+
}, z.z.core.$strip>>;
|
|
93
|
+
}, z.z.core.$strip>;
|
|
94
|
+
aspectRatio: z.ZodPipe<z.z.ZodCoercedString<unknown>, z.ZodTransform<number, string>>;
|
|
95
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
import { hexColorValidator } from './hexColor.js';
|
|
3
|
+
import { aspectRatioValidator } from './aspectRatio.js';
|
|
4
|
+
import { sharpImageValidation } from './sharpImageInput.js';
|
|
5
|
+
import { dirPathValidator, filePathValidator } from './path.js';
|
|
6
|
+
import { outputFileValidator } from './outputFile.js';
|
|
7
|
+
import { useNumberCoercion } from './coercion.js';
|
|
8
|
+
import { formatValidator } from './format.js';
|
|
9
|
+
import { templateValidator } from './template.js';
|
|
10
|
+
export const VALIDATORS = {
|
|
11
|
+
// Inputs and outputs
|
|
12
|
+
files: z.array(filePathValidator),
|
|
13
|
+
dir: dirPathValidator,
|
|
14
|
+
output: outputFileValidator,
|
|
15
|
+
format: formatValidator,
|
|
16
|
+
cliTemplate: filePathValidator,
|
|
17
|
+
imageInputs: z.array(sharpImageValidation),
|
|
18
|
+
// Strings
|
|
19
|
+
captions: z.array(z.string()),
|
|
20
|
+
// Flags
|
|
21
|
+
caption: z.boolean(),
|
|
22
|
+
recursive: z.boolean(),
|
|
23
|
+
shuffle: z.boolean(),
|
|
24
|
+
// Colors
|
|
25
|
+
canvasColor: hexColorValidator,
|
|
26
|
+
captionColor: hexColorValidator,
|
|
27
|
+
borderColor: hexColorValidator,
|
|
28
|
+
// Numbers
|
|
29
|
+
cornerRadius: z.number().int().gte(0),
|
|
30
|
+
gap: z.number().gte(0).int(),
|
|
31
|
+
imageWidth: z.number().gt(0).int(),
|
|
32
|
+
columns: z.number().gt(0).int(),
|
|
33
|
+
maxCaptionSize: z.number().gt(0).int(),
|
|
34
|
+
rowHeight: z.number().gt(0).int(),
|
|
35
|
+
columnWidth: z.number().gt(0).int(),
|
|
36
|
+
canvasWidth: z.number().gt(0).int(),
|
|
37
|
+
canvasHeight: z.number().gt(0).int(),
|
|
38
|
+
overlapPercentage: z.number().gte(0).lte(100).int(),
|
|
39
|
+
rotationRange: z.number().gte(0).lte(360).int(),
|
|
40
|
+
imageWidthVariance: z.number().gte(0).int(),
|
|
41
|
+
borderWidth: z.number().gte(0).int(),
|
|
42
|
+
// Coerced Numbers
|
|
43
|
+
cliCornerRadius: useNumberCoercion(z.number().int().gte(0)),
|
|
44
|
+
cliGap: useNumberCoercion(z.number().gte(0).int()),
|
|
45
|
+
cliImageWidth: useNumberCoercion(z.number().gt(0).int()),
|
|
46
|
+
cliColumns: useNumberCoercion(z.number().gt(0).int()),
|
|
47
|
+
cliMaxCaptionSize: useNumberCoercion(z.number().gt(0).int()),
|
|
48
|
+
cliRowHeight: useNumberCoercion(z.number().gt(0).int()),
|
|
49
|
+
cliColumnWidth: useNumberCoercion(z.number().gt(0).int()),
|
|
50
|
+
cliCanvasWidth: useNumberCoercion(z.number().gt(0).int()),
|
|
51
|
+
cliCanvasHeight: useNumberCoercion(z.number().gt(0).int()),
|
|
52
|
+
cliOverlapPercentage: useNumberCoercion(z.number().gte(0).lte(100).int()),
|
|
53
|
+
cliRotationRange: useNumberCoercion(z.number().gte(0).lte(360).int()),
|
|
54
|
+
cliImageWidthVariance: useNumberCoercion(z.number().gte(0).int()),
|
|
55
|
+
cliBorderWidth: useNumberCoercion(z.number().gte(0).int()),
|
|
56
|
+
// Enumerations
|
|
57
|
+
flow: z.enum(['horizontal', 'vertical']),
|
|
58
|
+
hAlign: z.enum(['left', 'center', 'right', 'justified']),
|
|
59
|
+
vAlign: z.enum(['top', 'middle', 'bottom', 'justified']),
|
|
60
|
+
preset: z.enum(['instagram-grid', 'dashboard-shot', 'horizontal-book-spread', 'vertical-book-spread', 'art-gallery']),
|
|
61
|
+
// Misc
|
|
62
|
+
template: templateValidator,
|
|
63
|
+
aspectRatio: aspectRatioValidator,
|
|
64
|
+
};
|