zone5 1.6.3 → 1.6.5
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/dist/processor/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { SpanStatusCode, trace } from '@opentelemetry/api';
|
|
2
2
|
import { writeFile } from 'fs/promises';
|
|
3
3
|
import { join, parse, relative } from 'path';
|
|
4
|
-
import sharp from 'sharp';
|
|
5
4
|
import { generateBlurhash } from './blurhash.js';
|
|
6
5
|
import { getDominantColors } from './color.js';
|
|
7
6
|
import { configHash, ProcessorConfigSchema } from './config.js';
|
|
@@ -30,12 +29,12 @@ const processor = async (options) => {
|
|
|
30
29
|
'zone5.forceOverwrite': forceOverwrite,
|
|
31
30
|
});
|
|
32
31
|
if (!(await fileExists(featureFile)) || clear || forceOverwrite) {
|
|
33
|
-
|
|
32
|
+
// Note: generateImageVariants returns source dimensions to avoid redundant metadata reads
|
|
33
|
+
const [exifFeature, blurhash, averageColor, variantsResult] = await Promise.all([
|
|
34
34
|
exifFromFilePath(sourceFile),
|
|
35
35
|
generateBlurhash(sourceFile),
|
|
36
36
|
getDominantColors(sourceFile),
|
|
37
37
|
generateImageVariants({ sourceFile, processor: processorConfig, cacheDir, clear, forceOverwrite }),
|
|
38
|
-
sharp(sourceFile).metadata(),
|
|
39
38
|
]);
|
|
40
39
|
// Strip GPS data if configured (for privacy)
|
|
41
40
|
const geometry = processorConfig.strip_gps ? null : exifFeature.geometry;
|
|
@@ -45,17 +44,17 @@ const processor = async (options) => {
|
|
|
45
44
|
id: sourceHash,
|
|
46
45
|
properties: {
|
|
47
46
|
...exifFeature.properties,
|
|
48
|
-
aspectRatio:
|
|
47
|
+
aspectRatio: variantsResult.sourceWidth / variantsResult.sourceHeight,
|
|
49
48
|
blurhash,
|
|
50
49
|
averageColor,
|
|
51
50
|
},
|
|
52
|
-
assets: variants.map((variant) => ({
|
|
51
|
+
assets: variantsResult.variants.map((variant) => ({
|
|
53
52
|
href: relative(base.cache, variant.path),
|
|
54
53
|
width: variant.width,
|
|
55
54
|
})),
|
|
56
55
|
};
|
|
57
56
|
await writeFile(featureFile, JSON.stringify(feature));
|
|
58
|
-
span.setAttribute('zone5.variantsCount', variants.length);
|
|
57
|
+
span.setAttribute('zone5.variantsCount', variantsResult.variants.length);
|
|
59
58
|
}
|
|
60
59
|
else {
|
|
61
60
|
span.setAttribute('zone5.cached', true);
|
|
@@ -3,10 +3,15 @@ export interface GeneratedVariant {
|
|
|
3
3
|
width: number;
|
|
4
4
|
path: string;
|
|
5
5
|
}
|
|
6
|
+
export interface VariantsResult {
|
|
7
|
+
variants: GeneratedVariant[];
|
|
8
|
+
sourceWidth: number;
|
|
9
|
+
sourceHeight: number;
|
|
10
|
+
}
|
|
6
11
|
export declare function generateImageVariants(options: {
|
|
7
12
|
processor: ProcessorConfigInput;
|
|
8
13
|
sourceFile: string;
|
|
9
14
|
cacheDir: string;
|
|
10
15
|
clear?: boolean;
|
|
11
16
|
forceOverwrite?: boolean;
|
|
12
|
-
}): Promise<
|
|
17
|
+
}): Promise<VariantsResult>;
|
|
@@ -18,9 +18,9 @@ export async function generateImageVariants(options) {
|
|
|
18
18
|
const processor = ProcessorConfigSchema.parse(processorInput);
|
|
19
19
|
// Parse file path components
|
|
20
20
|
const { name: fileBasename, ext: fileExtension } = parse(sourceFile);
|
|
21
|
-
// Get source image metadata to check dimensions
|
|
21
|
+
// Get source image metadata to check dimensions (returned to caller to avoid redundant reads)
|
|
22
22
|
const sourceImage = sharp(sourceFile);
|
|
23
|
-
const { width: sourceWidth } = await sourceImage.metadata();
|
|
23
|
+
const { width: sourceWidth, height: sourceHeight } = await sourceImage.metadata();
|
|
24
24
|
// Filter out widths that would be wider than the source image
|
|
25
25
|
const validWidths = processor.variants.filter((width) => width <= sourceWidth);
|
|
26
26
|
span.setAttributes({
|
|
@@ -36,14 +36,13 @@ export async function generateImageVariants(options) {
|
|
|
36
36
|
await rm(cacheDir, { recursive: true, force: true });
|
|
37
37
|
}
|
|
38
38
|
await ensureDirectoryExists(cacheDir);
|
|
39
|
-
// Generate variants for each valid width
|
|
40
|
-
const
|
|
41
|
-
let generatedCount = 0;
|
|
42
|
-
for (const width of validWidths) {
|
|
39
|
+
// Generate variants for each valid width in parallel
|
|
40
|
+
const variantResults = await Promise.all(validWidths.map(async (width) => {
|
|
43
41
|
const variantFilename = `${fileBasename}-${width}${fileExtension}`;
|
|
44
42
|
const variantPath = join(cacheDir, variantFilename);
|
|
45
43
|
// Check if variant already exists and should be overwritten
|
|
46
44
|
const variantExists = await fileExists(variantPath);
|
|
45
|
+
let wasGenerated = false;
|
|
47
46
|
if (!variantExists || forceOverwrite) {
|
|
48
47
|
let img = sharp(sourceFile);
|
|
49
48
|
if (processor.resize_gamma) {
|
|
@@ -59,19 +58,21 @@ export async function generateImageVariants(options) {
|
|
|
59
58
|
img = await addDebugText(img, width, Math.ceil(h * scale));
|
|
60
59
|
}
|
|
61
60
|
await img.toFile(variantPath);
|
|
62
|
-
|
|
61
|
+
wasGenerated = true;
|
|
63
62
|
}
|
|
64
|
-
|
|
65
|
-
width,
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
}
|
|
63
|
+
return {
|
|
64
|
+
variant: { width, path: variantPath },
|
|
65
|
+
wasGenerated,
|
|
66
|
+
};
|
|
67
|
+
}));
|
|
68
|
+
const variants = variantResults.map((r) => r.variant);
|
|
69
|
+
const generatedCount = variantResults.filter((r) => r.wasGenerated).length;
|
|
69
70
|
span.setAttributes({
|
|
70
71
|
'zone5.variantsGenerated': generatedCount,
|
|
71
72
|
'zone5.variantsTotal': variants.length,
|
|
72
73
|
});
|
|
73
74
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
74
|
-
return variants;
|
|
75
|
+
return { variants, sourceWidth, sourceHeight };
|
|
75
76
|
}
|
|
76
77
|
catch (error) {
|
|
77
78
|
span.setStatus({
|