@thi.ng/imago 0.3.1 → 0.4.1
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/CHANGELOG.md +13 -1
- package/README.md +12 -4
- package/api.d.ts +49 -0
- package/ops/output.js +21 -2
- package/package.json +7 -6
- package/proc.d.ts +2 -1
- package/proc.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2024-02-
|
|
3
|
+
- **Last updated**: 2024-02-28T14:23:30Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -9,6 +9,18 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
9
9
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
10
10
|
and/or version bumps of transitive dependencies.
|
|
11
11
|
|
|
12
|
+
### [0.4.1](https://github.com/thi-ng/umbrella/tree/@thi.ng/imago@0.4.1) (2024-02-28)
|
|
13
|
+
|
|
14
|
+
#### 🩹 Bug fixes
|
|
15
|
+
|
|
16
|
+
- fix typedarray input handling in processImage() ([075ecaa](https://github.com/thi-ng/umbrella/commit/075ecaa))
|
|
17
|
+
|
|
18
|
+
## [0.4.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/imago@0.4.0) (2024-02-27)
|
|
19
|
+
|
|
20
|
+
#### 🚀 Features
|
|
21
|
+
|
|
22
|
+
- add blurhash output option, update deps ([b7ffedd](https://github.com/thi-ng/umbrella/commit/b7ffedd))
|
|
23
|
+
|
|
12
24
|
## [0.3.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/imago@0.3.0) (2024-02-23)
|
|
13
25
|
|
|
14
26
|
#### 🚀 Features
|
package/README.md
CHANGED
|
@@ -76,9 +76,10 @@ The following pipeline performs these steps (in sequence):
|
|
|
76
76
|
- proportionally resize image to 1920px (longest side by default)
|
|
77
77
|
- overlay bitmap logo layer, positioned at 45% left / 5% bottom
|
|
78
78
|
- add custom EXIF metadata
|
|
79
|
-
- output this current stage as high quality AVIF (
|
|
79
|
+
- output this current stage as high quality AVIF (and record expanded output path)
|
|
80
80
|
- crop center square region
|
|
81
|
-
- output as JPEG thumbnail
|
|
81
|
+
- output as JPEG thumbnail (and record in outputs)
|
|
82
|
+
- compute [blurhash](https://github.com/thi-ng/umbrella/blob/develop/packages/blurhash) (and record in outputs)
|
|
82
83
|
|
|
83
84
|
```json tangle:export/readme-example1.json
|
|
84
85
|
[
|
|
@@ -113,7 +114,8 @@ The following pipeline performs these steps (in sequence):
|
|
|
113
114
|
"avif": { "quality": 80 }
|
|
114
115
|
},
|
|
115
116
|
{ "op": "crop", "size": [240, 240], "gravity": "c" },
|
|
116
|
-
{ "op": "output", "id": "thumb", "path": "{name}-thumb.jpg" }
|
|
117
|
+
{ "op": "output", "id": "thumb", "path": "{name}-thumb.jpg" },
|
|
118
|
+
{ "op": "output", "id": "hash", "path": "", blurhash: { detail: 4 } }
|
|
117
119
|
]
|
|
118
120
|
```
|
|
119
121
|
|
|
@@ -232,6 +234,11 @@ File output in any of these formats:
|
|
|
232
234
|
- tiff
|
|
233
235
|
- webp
|
|
234
236
|
|
|
237
|
+
Alternatively, a
|
|
238
|
+
[blurhash](https://github.com/thi-ng/umbrella/blob/develop/packages/blurhash) of
|
|
239
|
+
the image can be computed and stored in the outputs. In this case, no file will
|
|
240
|
+
be written.
|
|
241
|
+
|
|
235
242
|
#### Templated output paths
|
|
236
243
|
|
|
237
244
|
Output paths can contain `{id}`-templated parts which will be replaced/expanded.
|
|
@@ -302,12 +309,13 @@ For Node.js REPL:
|
|
|
302
309
|
const imago = await import("@thi.ng/imago");
|
|
303
310
|
```
|
|
304
311
|
|
|
305
|
-
Package sizes (brotli'd, pre-treeshake): ESM: 4.
|
|
312
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 4.15 KB
|
|
306
313
|
|
|
307
314
|
## Dependencies
|
|
308
315
|
|
|
309
316
|
- [@thi.ng/api](https://github.com/thi-ng/umbrella/tree/develop/packages/api)
|
|
310
317
|
- [@thi.ng/associative](https://github.com/thi-ng/umbrella/tree/develop/packages/associative)
|
|
318
|
+
- [@thi.ng/blurhash](https://github.com/thi-ng/umbrella/tree/develop/packages/blurhash)
|
|
311
319
|
- [@thi.ng/checks](https://github.com/thi-ng/umbrella/tree/develop/packages/checks)
|
|
312
320
|
- [@thi.ng/date](https://github.com/thi-ng/umbrella/tree/develop/packages/date)
|
|
313
321
|
- [@thi.ng/defmulti](https://github.com/thi-ng/umbrella/tree/develop/packages/defmulti)
|
package/api.d.ts
CHANGED
|
@@ -126,14 +126,54 @@ export interface OutputSpec extends ProcSpec {
|
|
|
126
126
|
id: string;
|
|
127
127
|
/**
|
|
128
128
|
* Possibly templated output path. See {@link formatPath} for details.
|
|
129
|
+
* Ignored if {@link OutputSpec.blurhash} is being used.
|
|
129
130
|
*/
|
|
130
131
|
path: string;
|
|
132
|
+
/**
|
|
133
|
+
* AVIF output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#avif)
|
|
134
|
+
*/
|
|
131
135
|
avif?: AvifOptions;
|
|
136
|
+
/**
|
|
137
|
+
* If given, ONLY the blurhash of the image will be computed and stored in
|
|
138
|
+
* the `outputs` object returned by {@link processImage}. The
|
|
139
|
+
* {@link OutputSpec.path} will be ignored and no file will be written.
|
|
140
|
+
*
|
|
141
|
+
* @remarks
|
|
142
|
+
* Important: Ensure the image has already been downsized to ~50-500 pixels.
|
|
143
|
+
* Larger images are causing unnecessary & long processing...
|
|
144
|
+
*/
|
|
145
|
+
blurhash?: {
|
|
146
|
+
/**
|
|
147
|
+
* Blurhash detail setting in 1-9 range, possibly given separately for
|
|
148
|
+
* X/Y axis.
|
|
149
|
+
*
|
|
150
|
+
* @defaultValue 4
|
|
151
|
+
*/
|
|
152
|
+
detail?: number | [number, number];
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* GIF output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#gif)
|
|
156
|
+
*/
|
|
132
157
|
gif?: GifOptions;
|
|
158
|
+
/**
|
|
159
|
+
* JPEG 2000 output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#jp2)
|
|
160
|
+
*/
|
|
133
161
|
jp2?: Jp2Options;
|
|
162
|
+
/**
|
|
163
|
+
* JPEG output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#jpeg)
|
|
164
|
+
*/
|
|
134
165
|
jpeg?: JpegOptions;
|
|
166
|
+
/**
|
|
167
|
+
* JPEG XL output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#jxl)
|
|
168
|
+
*/
|
|
135
169
|
jxl?: JxlOptions;
|
|
170
|
+
/**
|
|
171
|
+
* PNG output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#avif)
|
|
172
|
+
*/
|
|
136
173
|
png?: PngOptions;
|
|
174
|
+
/**
|
|
175
|
+
* Raw binary output options.
|
|
176
|
+
*/
|
|
137
177
|
raw?: boolean | {
|
|
138
178
|
/**
|
|
139
179
|
* If true, ensures the buffer has an alpha channel
|
|
@@ -145,8 +185,17 @@ export interface OutputSpec extends ProcSpec {
|
|
|
145
185
|
*/
|
|
146
186
|
meta?: boolean;
|
|
147
187
|
};
|
|
188
|
+
/**
|
|
189
|
+
* Tiled format output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#tile)
|
|
190
|
+
*/
|
|
148
191
|
tile?: TileOptions;
|
|
192
|
+
/**
|
|
193
|
+
* TIFF output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#tiff)
|
|
194
|
+
*/
|
|
149
195
|
tiff?: TiffOptions;
|
|
196
|
+
/**
|
|
197
|
+
* WebP output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#webp)
|
|
198
|
+
*/
|
|
150
199
|
webp?: WebpOptions;
|
|
151
200
|
}
|
|
152
201
|
export interface ResizeSpec extends ProcSpec {
|
package/ops/output.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
+
import { encode } from "@thi.ng/blurhash";
|
|
2
|
+
import { isNumber, isPlainObject } from "@thi.ng/checks";
|
|
1
3
|
import { writeFile, writeJSON } from "@thi.ng/file-io";
|
|
2
4
|
import { join, resolve } from "node:path";
|
|
3
5
|
import { formatPath } from "../path.js";
|
|
4
|
-
import { isPlainObject } from "@thi.ng/checks";
|
|
5
6
|
const outputProc = async (spec, input, ctx) => {
|
|
6
7
|
const opts = spec;
|
|
7
8
|
const outDir = resolve(ctx.opts.outDir || ".");
|
|
8
9
|
let output = input.clone();
|
|
10
|
+
if (opts.blurhash) {
|
|
11
|
+
await outputBlurHash(opts, output, ctx);
|
|
12
|
+
return [input, false];
|
|
13
|
+
}
|
|
9
14
|
if (opts.raw) {
|
|
10
15
|
await outputRaw(opts, output, ctx, outDir);
|
|
11
16
|
return [input, false];
|
|
@@ -76,7 +81,7 @@ const outputRaw = async (opts, output, ctx, outDir) => {
|
|
|
76
81
|
const { alpha = false, meta = false } = isPlainObject(opts.raw) ? opts.raw : {};
|
|
77
82
|
if (alpha)
|
|
78
83
|
output = output.ensureAlpha();
|
|
79
|
-
const { data, info } = await output.raw().toBuffer({ resolveWithObject: true });
|
|
84
|
+
const { data, info } = await output.ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
80
85
|
const path = join(outDir, formatPath(opts.path, ctx, opts, data));
|
|
81
86
|
writeFile(path, data, null, ctx.logger);
|
|
82
87
|
ctx.outputs[opts.id] = path;
|
|
@@ -90,6 +95,20 @@ const outputRaw = async (opts, output, ctx, outDir) => {
|
|
|
90
95
|
);
|
|
91
96
|
}
|
|
92
97
|
};
|
|
98
|
+
const outputBlurHash = async (opts, output, ctx) => {
|
|
99
|
+
const { data, info } = await output.ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
100
|
+
const detail = opts.blurhash.detail || 4;
|
|
101
|
+
const [dx, dy] = isNumber(detail) ? [detail, detail] : detail;
|
|
102
|
+
const hash = encode(
|
|
103
|
+
new Uint32Array(data.buffer),
|
|
104
|
+
info.width,
|
|
105
|
+
info.height,
|
|
106
|
+
dx,
|
|
107
|
+
dy
|
|
108
|
+
);
|
|
109
|
+
ctx.logger.debug("computed blurhash:", hash);
|
|
110
|
+
ctx.outputs[opts.id] = hash;
|
|
111
|
+
};
|
|
93
112
|
export {
|
|
94
113
|
outputProc
|
|
95
114
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/imago",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "JSON & API-based declarative and extensible image processing trees/pipelines",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -37,20 +37,21 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@thi.ng/api": "^8.9.26",
|
|
39
39
|
"@thi.ng/associative": "^6.3.43",
|
|
40
|
+
"@thi.ng/blurhash": "^0.1.11",
|
|
40
41
|
"@thi.ng/checks": "^3.5.0",
|
|
41
|
-
"@thi.ng/date": "^2.7.
|
|
42
|
+
"@thi.ng/date": "^2.7.2",
|
|
42
43
|
"@thi.ng/defmulti": "^3.0.26",
|
|
43
44
|
"@thi.ng/errors": "^2.4.18",
|
|
44
45
|
"@thi.ng/file-io": "^1.3.4",
|
|
45
46
|
"@thi.ng/logger": "^3.0.3",
|
|
46
|
-
"@thi.ng/pixel": "^6.1.
|
|
47
|
-
"@thi.ng/pixel-dither": "^1.1.
|
|
47
|
+
"@thi.ng/pixel": "^6.1.13",
|
|
48
|
+
"@thi.ng/pixel-dither": "^1.1.111",
|
|
48
49
|
"@thi.ng/prefixes": "^2.3.10",
|
|
49
50
|
"sharp": "^0.33.2"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
52
53
|
"@microsoft/api-extractor": "^7.40.1",
|
|
53
|
-
"@thi.ng/vectors": "^7.10.
|
|
54
|
+
"@thi.ng/vectors": "^7.10.13",
|
|
54
55
|
"esbuild": "^0.20.0",
|
|
55
56
|
"rimraf": "^5.0.5",
|
|
56
57
|
"typedoc": "^0.25.7",
|
|
@@ -125,5 +126,5 @@
|
|
|
125
126
|
"status": "alpha",
|
|
126
127
|
"year": 2024
|
|
127
128
|
},
|
|
128
|
-
"gitHead": "
|
|
129
|
+
"gitHead": "190d68e7f7524631b333cfdbf32c6a23be27c166\n"
|
|
129
130
|
}
|
package/proc.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
import type { TypedArray } from "@thi.ng/api";
|
|
2
3
|
import sharp, { type Sharp } from "sharp";
|
|
3
4
|
import type { ImgProcCtx, ImgProcOpts, ProcSpec } from "./api.js";
|
|
4
5
|
export declare const LOGGER: import("@thi.ng/logger").ProxyLogger;
|
|
@@ -17,7 +18,7 @@ export declare const LOGGER: import("@thi.ng/logger").ProxyLogger;
|
|
|
17
18
|
* @param opts
|
|
18
19
|
* @param parentCtx
|
|
19
20
|
*/
|
|
20
|
-
export declare const processImage: (src: string | Buffer | Sharp, specs: ProcSpec[], opts?: Partial<ImgProcOpts>, parentCtx?: ImgProcCtx) => Promise<{
|
|
21
|
+
export declare const processImage: (src: string | TypedArray | Buffer | ArrayBuffer | Sharp, specs: ProcSpec[], opts?: Partial<ImgProcOpts>, parentCtx?: ImgProcCtx) => Promise<{
|
|
21
22
|
img: sharp.Sharp;
|
|
22
23
|
meta: sharp.Metadata;
|
|
23
24
|
outputs: Record<string, string>;
|
package/proc.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isArrayBufferView, isString } from "@thi.ng/checks";
|
|
2
2
|
import { defmulti } from "@thi.ng/defmulti";
|
|
3
|
+
import { createTempFile, deleteFile } from "@thi.ng/file-io";
|
|
3
4
|
import { ROOT } from "@thi.ng/logger";
|
|
4
5
|
import sharp, {} from "sharp";
|
|
5
6
|
import { blurProc } from "./ops/blur.js";
|
|
@@ -16,10 +17,9 @@ import { outputProc } from "./ops/output.js";
|
|
|
16
17
|
import { resizeProc } from "./ops/resize.js";
|
|
17
18
|
import { rotateProc } from "./ops/rotate.js";
|
|
18
19
|
import { ensureSize } from "./units.js";
|
|
19
|
-
import { createTempFile, deleteFile } from "@thi.ng/file-io";
|
|
20
20
|
const LOGGER = ROOT.childLogger("imgproc");
|
|
21
21
|
const processImage = async (src, specs, opts = {}, parentCtx) => {
|
|
22
|
-
let img = isString(src) || isArrayBufferView(src
|
|
22
|
+
let img = isString(src) || isArrayBufferView(src) ? sharp(src) : src;
|
|
23
23
|
const meta = await img.metadata();
|
|
24
24
|
ensureSize(meta);
|
|
25
25
|
const ctx = {
|