@travetto/image 5.0.13 → 5.0.15
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 +1 -1
- package/package.json +1 -1
- package/src/util.ts +49 -54
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ import { ImageUtil } from '@travetto/image';
|
|
|
27
27
|
|
|
28
28
|
export class ResizeService {
|
|
29
29
|
async resizeImage(imgPath: string, width: number, height: number): Promise<string> {
|
|
30
|
-
const stream = await ImageUtil.
|
|
30
|
+
const stream = await ImageUtil.convert(createReadStream(imgPath), { w: width, h: height });
|
|
31
31
|
const out = imgPath.replace(/[.][^.]+$/, (ext) => `.resized${ext}`);
|
|
32
32
|
await pipeline(stream, createWriteStream(out));
|
|
33
33
|
return out;
|
package/package.json
CHANGED
package/src/util.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
+
import { createReadStream } from 'node:fs';
|
|
1
2
|
import { Readable } from 'node:stream';
|
|
2
3
|
import { ReadableStream } from 'node:stream/web';
|
|
3
4
|
import { pipeline } from 'node:stream/promises';
|
|
4
|
-
|
|
5
|
-
import type { Sharp } from 'sharp';
|
|
5
|
+
import { Metadata } from 'sharp';
|
|
6
6
|
|
|
7
7
|
import { castTo } from '@travetto/runtime';
|
|
8
8
|
|
|
9
9
|
type ImageFormat = 'jpeg' | 'png' | 'avif' | 'webp';
|
|
10
|
+
type Input = Buffer | string | ReadableStream | Readable;
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
|
-
* Image
|
|
13
|
+
* Image convert options
|
|
13
14
|
*/
|
|
14
|
-
export interface
|
|
15
|
+
export interface ConvertOptions {
|
|
15
16
|
/**
|
|
16
17
|
* New height
|
|
17
18
|
*/
|
|
@@ -30,74 +31,68 @@ export interface ResizeOptions {
|
|
|
30
31
|
format?: ImageFormat;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
/**
|
|
34
|
-
* Image optimize options
|
|
35
|
-
*/
|
|
36
|
-
export interface OptimizeOptions {
|
|
37
|
-
format?: ImageFormat;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
type ImageType = Readable | Buffer | ReadableStream;
|
|
42
|
-
|
|
43
34
|
/**
|
|
44
35
|
* Simple support for image manipulation.
|
|
45
36
|
*/
|
|
46
37
|
export class ImageUtil {
|
|
47
38
|
|
|
48
|
-
static async #sharpReturn<T extends ImageType>(output: Sharp, input: T, optimize?: boolean, format?: ImageFormat): Promise<T> {
|
|
49
|
-
output = output
|
|
50
|
-
.jpeg({ ...(optimize ? { quality: 80, progressive: true } : {}), force: format === 'jpeg' })
|
|
51
|
-
.png({ ...(optimize ? { compressionLevel: 9, quality: 80, adaptiveFiltering: true } : {}), force: format === 'png' })
|
|
52
|
-
.avif({ ...(optimize ? { quality: 70 } : {}), force: format === 'avif' })
|
|
53
|
-
.webp({ ...(optimize ? { quality: 80 } : {}), force: format === 'webp' });
|
|
54
|
-
const stream = Buffer.isBuffer(input) ? Readable.from(input) : input;
|
|
55
|
-
pipeline(stream, output);
|
|
56
|
-
return castTo('pipeThrough' in input ? ReadableStream.from(output) : Buffer.isBuffer(input) ? output.toBuffer() : output);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
39
|
/**
|
|
60
|
-
*
|
|
40
|
+
* Convert image
|
|
61
41
|
*/
|
|
62
|
-
static async
|
|
63
|
-
const dims = [options.w, options.h].map(x => x ? Math.trunc(x) : undefined);
|
|
64
|
-
const fluid = dims.some(x => !x);
|
|
65
|
-
|
|
42
|
+
static async convert<T extends Input>(image: T, { format, optimize, ...opts }: ConvertOptions): Promise<T extends string ? Readable : T> {
|
|
66
43
|
const { default: sharp } = await import('sharp');
|
|
67
44
|
|
|
68
|
-
|
|
69
|
-
|
|
45
|
+
let builder = sharp();
|
|
46
|
+
if (opts.w || opts.h) {
|
|
47
|
+
const dims = [opts.w, opts.h].map(x => x ? Math.trunc(x) : undefined);
|
|
48
|
+
const fluid = dims.some(x => !x);
|
|
49
|
+
builder = builder.resize({
|
|
70
50
|
width: dims[0],
|
|
71
51
|
height: dims[1],
|
|
72
52
|
fit: fluid ? 'inside' : 'fill'
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
options.optimize,
|
|
76
|
-
options.format
|
|
77
|
-
);
|
|
78
|
-
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
79
55
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
return this.#sharpReturn(sharp(), image, true, options.format);
|
|
86
|
-
}
|
|
56
|
+
builder = builder
|
|
57
|
+
.avif({ force: format === 'avif', ...optimize ? { quality: 70 } : {} })
|
|
58
|
+
.webp({ force: format === 'webp', ...optimize ? { quality: 80 } : {} })
|
|
59
|
+
.png({ force: format === 'png', ...optimize ? { compressionLevel: 9, quality: 80, adaptiveFiltering: true } : {} })
|
|
60
|
+
.jpeg({ force: format === 'jpeg', ...optimize ? { quality: 80, progressive: true } : {} });
|
|
87
61
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return
|
|
62
|
+
const stream = Buffer.isBuffer(image) ?
|
|
63
|
+
Readable.from(image) :
|
|
64
|
+
(typeof image === 'string' ? createReadStream(image) : image);
|
|
65
|
+
|
|
66
|
+
pipeline(stream, builder);
|
|
67
|
+
return castTo(
|
|
68
|
+
typeof image === 'string' ?
|
|
69
|
+
builder : Buffer.isBuffer(image) ?
|
|
70
|
+
builder.toBuffer() :
|
|
71
|
+
(image instanceof ReadableStream) ?
|
|
72
|
+
ReadableStream.from(builder) : builder
|
|
73
|
+
);
|
|
94
74
|
}
|
|
95
75
|
|
|
96
76
|
/**
|
|
97
|
-
* Get
|
|
77
|
+
* Get Image metadata
|
|
98
78
|
*/
|
|
99
|
-
static async
|
|
79
|
+
static async getMetadata(image: Input): Promise<{
|
|
80
|
+
width: number;
|
|
81
|
+
height: number;
|
|
82
|
+
aspect: number;
|
|
83
|
+
format: ImageFormat;
|
|
84
|
+
}> {
|
|
100
85
|
const { default: sharp } = await import('sharp');
|
|
101
|
-
|
|
86
|
+
const out = await ((Buffer.isBuffer(image) || typeof image === 'string') ?
|
|
87
|
+
sharp(image).metadata() :
|
|
88
|
+
new Promise<Metadata>((resolve, reject) =>
|
|
89
|
+
pipeline(image, sharp().metadata((err, metadata) => err ? reject(err) : resolve(metadata)))
|
|
90
|
+
));
|
|
91
|
+
return {
|
|
92
|
+
width: out.width!,
|
|
93
|
+
height: out.height!,
|
|
94
|
+
format: castTo(out.format?.replace('heif', 'avif')!),
|
|
95
|
+
aspect: out.width! / out.height!
|
|
96
|
+
};
|
|
102
97
|
}
|
|
103
98
|
}
|