@thi.ng/imago 0.4.0 → 0.5.0
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 +40 -1
- package/README.md +147 -11
- package/api.d.ts +231 -34
- package/index.d.ts +18 -0
- package/index.js +18 -0
- package/layers/color.d.ts +3 -0
- package/layers/color.js +31 -0
- package/layers/image.d.ts +1 -1
- package/layers/image.js +18 -6
- package/layers/raw.d.ts +3 -0
- package/layers/raw.js +28 -0
- package/layers/svg.d.ts +1 -1
- package/layers/svg.js +17 -4
- package/layers/text.d.ts +1 -1
- package/layers/text.js +16 -14
- package/ops/composite.js +10 -6
- package/ops/crop.js +12 -3
- package/ops/extend.js +1 -1
- package/ops/output.js +7 -4
- package/ops/resize.js +9 -2
- package/ops/rotate.js +4 -1
- package/ops.d.ts +68 -1
- package/ops.js +13 -1
- package/package.json +60 -6
- package/path.d.ts +1 -0
- package/path.js +4 -0
- package/proc.d.ts +2 -3
- package/proc.js +2 -2
- package/units.d.ts +22 -5
- package/units.js +77 -26
package/proc.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
import sharp, { type Sharp } from "sharp";
|
|
3
|
-
import type { ImgProcCtx, ImgProcOpts, ProcSpec } from "./api.js";
|
|
2
|
+
import type { BufferLike, ImgProcCtx, ImgProcOpts, ProcSpec } from "./api.js";
|
|
4
3
|
export declare const LOGGER: import("@thi.ng/logger").ProxyLogger;
|
|
5
4
|
/**
|
|
6
5
|
* Main API function. Takes an image input (file path, buffer or existing Sharp
|
|
@@ -17,7 +16,7 @@ export declare const LOGGER: import("@thi.ng/logger").ProxyLogger;
|
|
|
17
16
|
* @param opts
|
|
18
17
|
* @param parentCtx
|
|
19
18
|
*/
|
|
20
|
-
export declare const processImage: (src: string |
|
|
19
|
+
export declare const processImage: (src: string | BufferLike | ArrayBuffer | Sharp, specs: ProcSpec[], opts?: Partial<ImgProcOpts>, parentCtx?: ImgProcCtx) => Promise<{
|
|
21
20
|
img: sharp.Sharp;
|
|
22
21
|
meta: sharp.Metadata;
|
|
23
22
|
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 = {
|
package/units.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { Nullable } from "@thi.ng/api";
|
|
2
1
|
import type { Metadata } from "sharp";
|
|
3
|
-
import { type Color, type
|
|
2
|
+
import { type Color, type Dim, type Gravity, type Position, type Sides, type Size, type SizeRef, type SizeUnit } from "./api.js";
|
|
4
3
|
export declare const ensureSize: (meta: Metadata) => false;
|
|
5
4
|
export declare const coerceColor: (col: Color) => string | {
|
|
6
5
|
r: number;
|
|
@@ -8,7 +7,23 @@ export declare const coerceColor: (col: Color) => string | {
|
|
|
8
7
|
b: number;
|
|
9
8
|
alpha?: number | undefined;
|
|
10
9
|
};
|
|
11
|
-
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* The given `size` MUST already be resolved (in pixels), e.g. via an earlier
|
|
14
|
+
* call to {@link computeSize}. `parentSize` is also in pixels.
|
|
15
|
+
*
|
|
16
|
+
* @param size
|
|
17
|
+
* @param parentSize
|
|
18
|
+
* @param opts
|
|
19
|
+
*/
|
|
20
|
+
export declare const positionOrGravity: ([w, h]: Dim, parentSize: Dim, { pos, gravity, origin, ref, unit, }: {
|
|
21
|
+
pos?: Position | undefined;
|
|
22
|
+
gravity?: Gravity | undefined;
|
|
23
|
+
origin?: Gravity | undefined;
|
|
24
|
+
ref?: SizeRef | undefined;
|
|
25
|
+
unit?: SizeUnit | undefined;
|
|
26
|
+
}) => {
|
|
12
27
|
gravity: string;
|
|
13
28
|
left?: undefined;
|
|
14
29
|
top?: undefined;
|
|
@@ -17,8 +32,10 @@ export declare const positionOrGravity: (pos: CompLayer["pos"], gravity: Nullabl
|
|
|
17
32
|
top: number | undefined;
|
|
18
33
|
gravity?: undefined;
|
|
19
34
|
} | undefined;
|
|
35
|
+
export declare const gravityFlags: (gravity: Gravity) => boolean[];
|
|
20
36
|
export declare const gravityPosition: (gravity: Gravity, [w, h]: Dim, [parentW, parentH]: Dim) => number[];
|
|
21
|
-
export declare const refSize: ([w, h]: Dim, ref?: SizeRef) =>
|
|
22
|
-
export declare const computeSize: (size: Size, curr: Dim, unit?: SizeUnit) => Dim;
|
|
37
|
+
export declare const refSize: ([w, h]: Dim, ref?: SizeRef) => Dim;
|
|
38
|
+
export declare const computeSize: (size: Size, curr: Dim, ref?: SizeRef, unit?: SizeUnit) => Dim;
|
|
39
|
+
export declare const computeSizeWithAspect: (size: number, [w, h]: Dim, aspect: number, unit?: SizeUnit, clamp?: boolean) => Dim;
|
|
23
40
|
export declare const computeMargins: (size: Size | Sides, curr: Dim, ref?: SizeRef, unit?: SizeUnit) => Sides;
|
|
24
41
|
//# sourceMappingURL=units.d.ts.map
|
package/units.js
CHANGED
|
@@ -6,70 +6,119 @@ import {
|
|
|
6
6
|
const round = Math.round;
|
|
7
7
|
const ensureSize = (meta) => !(isNumber(meta.width) && isNumber(meta.height)) && illegalArgs("can't determine image size");
|
|
8
8
|
const coerceColor = (col) => isString(col) ? col : isArrayLike(col) ? { r: col[0], g: col[1], b: col[2], alpha: col[3] ?? 1 } : col;
|
|
9
|
-
const positionOrGravity = (
|
|
9
|
+
const positionOrGravity = ([w, h], parentSize, {
|
|
10
|
+
pos,
|
|
11
|
+
gravity,
|
|
12
|
+
origin,
|
|
13
|
+
ref,
|
|
14
|
+
unit = "px"
|
|
15
|
+
}) => {
|
|
10
16
|
if (!pos)
|
|
11
17
|
return gravity ? { gravity: GRAVITY_MAP[gravity] } : void 0;
|
|
12
|
-
const
|
|
18
|
+
const [parentW, parentH] = parentSize;
|
|
13
19
|
let { l, r, t, b } = pos;
|
|
14
|
-
|
|
15
|
-
l
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
[l, r, t, b] = computeMargins(
|
|
21
|
+
[l || 0, r || 0, t || 0, b || 0],
|
|
22
|
+
parentSize,
|
|
23
|
+
ref,
|
|
24
|
+
unit
|
|
25
|
+
);
|
|
26
|
+
let left, top;
|
|
27
|
+
const [isE, isW, isN, isS] = origin ? gravityFlags(origin) : [];
|
|
28
|
+
const w2 = w >> 1;
|
|
29
|
+
const h2 = h >> 1;
|
|
30
|
+
if (pos.l != null)
|
|
31
|
+
left = round(l) + (origin ? isW ? 0 : isE ? -w : -w2 : 0);
|
|
32
|
+
if (pos.r != null)
|
|
33
|
+
left = round(parentW - r) + (origin ? isW ? 0 : isE ? -w : -w2 : -w);
|
|
34
|
+
if (pos.t != null)
|
|
35
|
+
top = round(t) + (origin ? isN ? 0 : isS ? -h : -h2 : 0);
|
|
36
|
+
if (pos.b != null)
|
|
37
|
+
top = round(parentH - b) + (origin ? isN ? 0 : isS ? -h : -h2 : -h);
|
|
38
|
+
return { left, top };
|
|
23
39
|
};
|
|
40
|
+
const gravityFlags = (gravity) => ["e", "w", "n", "s"].map((x) => gravity.includes(x));
|
|
24
41
|
const gravityPosition = (gravity, [w, h], [parentW, parentH]) => [
|
|
25
42
|
gravity.includes("w") ? 0 : gravity.includes("e") ? parentW - w : parentW - w >> 1,
|
|
26
43
|
gravity.includes("n") ? 0 : gravity.includes("s") ? parentH - h : parentH - h >> 1
|
|
27
44
|
];
|
|
28
45
|
const refSize = ([w, h], ref) => {
|
|
46
|
+
let v;
|
|
29
47
|
switch (ref) {
|
|
30
48
|
case "w":
|
|
31
|
-
return w;
|
|
49
|
+
return [w, w];
|
|
32
50
|
case "h":
|
|
33
|
-
return h;
|
|
51
|
+
return [h, h];
|
|
34
52
|
case "max":
|
|
35
|
-
|
|
53
|
+
v = Math.max(w, h);
|
|
54
|
+
return [v, v];
|
|
36
55
|
case "min":
|
|
56
|
+
v = Math.min(w, h);
|
|
57
|
+
return [v, v];
|
|
58
|
+
case "both":
|
|
37
59
|
default:
|
|
38
|
-
return
|
|
60
|
+
return [w, h];
|
|
39
61
|
}
|
|
40
62
|
};
|
|
41
|
-
const computeSize = (size, curr, unit = "px") => {
|
|
63
|
+
const computeSize = (size, curr, ref, unit = "px") => {
|
|
42
64
|
const aspect = curr[0] / curr[1];
|
|
43
65
|
let res;
|
|
44
66
|
if (isNumber(size)) {
|
|
45
|
-
|
|
67
|
+
if (unit === "%") {
|
|
68
|
+
res = refSize(curr, ref);
|
|
69
|
+
res = [res[0] * size / 100, res[1] * size / 100];
|
|
70
|
+
} else {
|
|
71
|
+
res = [size, size];
|
|
72
|
+
}
|
|
46
73
|
} else {
|
|
47
|
-
|
|
48
|
-
|
|
74
|
+
let [w, h] = size;
|
|
75
|
+
if (unit === "%") {
|
|
76
|
+
const [rw, rh] = refSize(curr, ref);
|
|
77
|
+
w *= rw / 100;
|
|
78
|
+
h *= rh / 100;
|
|
79
|
+
size = [w, h];
|
|
80
|
+
}
|
|
81
|
+
res = w >= 0 ? h >= 0 ? size : [w, w / aspect] : h >= 0 ? [h * aspect, h] : illegalArgs(
|
|
49
82
|
`require at least width or height, but got: ${JSON.stringify(
|
|
50
83
|
size
|
|
51
84
|
)}`
|
|
52
85
|
);
|
|
53
86
|
}
|
|
87
|
+
res[0] = round(res[0]);
|
|
88
|
+
res[1] = round(res[1]);
|
|
89
|
+
return res;
|
|
90
|
+
};
|
|
91
|
+
const computeSizeWithAspect = (size, [w, h], aspect, unit = "px", clamp = true) => {
|
|
92
|
+
const origAspect = w / h;
|
|
93
|
+
const min = Math.min(w, h);
|
|
94
|
+
const max = Math.max(w, h);
|
|
95
|
+
let res;
|
|
54
96
|
if (unit === "%") {
|
|
55
|
-
|
|
56
|
-
res[1] *= curr[1] / 100;
|
|
97
|
+
size = size / 100 * max;
|
|
57
98
|
}
|
|
99
|
+
if (clamp) {
|
|
100
|
+
size = Math.min(size, max);
|
|
101
|
+
if (size / aspect > min)
|
|
102
|
+
size = min * aspect;
|
|
103
|
+
}
|
|
104
|
+
res = origAspect > 1 ? [size, size / aspect] : [size / aspect, size];
|
|
58
105
|
res[0] = round(res[0]);
|
|
59
106
|
res[1] = round(res[1]);
|
|
60
107
|
return res;
|
|
61
108
|
};
|
|
62
|
-
const computeMargins = (size, curr, ref
|
|
109
|
+
const computeMargins = (size, curr, ref, unit = "px") => {
|
|
63
110
|
let res;
|
|
64
111
|
const refSide = refSize(curr, ref);
|
|
65
112
|
const isPC = unit === "%";
|
|
66
113
|
if (isArray(size) && size.length === 4) {
|
|
67
|
-
res = isPC ? size.map((x) => round(x * refSide / 100)) : size.map(round);
|
|
114
|
+
res = isPC ? size.map((x, i) => round(x * refSide[i >> 1] / 100)) : size.map(round);
|
|
68
115
|
} else if (isNumber(size)) {
|
|
69
|
-
const w = round(isPC ? refSide * size / 100 : size);
|
|
70
|
-
|
|
116
|
+
const w = round(isPC ? refSide[0] * size / 100 : size);
|
|
117
|
+
const h = round(isPC ? refSide[1] * size / 100 : size);
|
|
118
|
+
res = [w, w, h, h];
|
|
71
119
|
} else {
|
|
72
|
-
const
|
|
120
|
+
const w = round(isPC ? refSide[0] * size[0] / 100 : size[0]);
|
|
121
|
+
const h = round(isPC ? refSide[1] * size[1] / 100 : size[1]);
|
|
73
122
|
res = [w, w, h, h];
|
|
74
123
|
}
|
|
75
124
|
return res;
|
|
@@ -78,7 +127,9 @@ export {
|
|
|
78
127
|
coerceColor,
|
|
79
128
|
computeMargins,
|
|
80
129
|
computeSize,
|
|
130
|
+
computeSizeWithAspect,
|
|
81
131
|
ensureSize,
|
|
132
|
+
gravityFlags,
|
|
82
133
|
gravityPosition,
|
|
83
134
|
positionOrGravity,
|
|
84
135
|
refSize
|