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.
@@ -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
- const [exifFeature, blurhash, averageColor, variants, metadata] = await Promise.all([
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: metadata.width / metadata.height,
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<GeneratedVariant[]>;
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 variants = [];
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
- generatedCount++;
61
+ wasGenerated = true;
63
62
  }
64
- variants.push({
65
- width,
66
- path: variantPath,
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({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zone5",
3
- "version": "1.6.3",
3
+ "version": "1.6.5",
4
4
  "repository": {
5
5
  "url": "https://github.com/cwygoda/zone5"
6
6
  },