@takazudo/zudo-image-tweaker 0.1.1 → 0.1.3
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 +27 -0
- package/dist/calibrate/index.d.ts +25 -15
- package/dist/calibrate/index.js +89 -120
- package/dist/heif/index.js +10 -273
- package/dist/index-DWJCvc5O.js +293 -0
- package/dist/index.js +14 -14
- package/dist/{presets-PTxNoMdy.js → presets-DyzR9as-.js} +42 -43
- package/dist/product-photo/index.js +103 -95
- package/dist/variants/index.js +1 -1
- package/package.json +1 -1
- package/dist/run-BIjGA2Fu.js +0 -22
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.3
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- b4push: queue heavy steps through the machine-wide heavy-guard (4b15f51)
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- product-photo: pass Buffer input to imgly as a MIME-typed Blob, so `removeBackground()` no longer fails with "Unsupported format" ([#126](https://github.com/zudolab/zudo-image-tweaker/pull/126), closes [#123](https://github.com/zudolab/zudo-image-tweaker/issues/123)) (140168c)
|
|
12
|
+
- deps: resolve root-workspace pnpm audit advisories ([#116](https://github.com/zudolab/zudo-image-tweaker/issues/116)) (993351d)
|
|
13
|
+
- deps: limit audit overrides to their current major/minor lines (87c3255)
|
|
14
|
+
|
|
15
|
+
### Other Changes
|
|
16
|
+
|
|
17
|
+
- ci: bump actions/checkout v7.0.1, actions/setup-node v7.1.0, pnpm/action-setup v6.1.0 (8998428)
|
|
18
|
+
- docs(doc): re-scaffold the doc site onto create-zudo-doc 8.1.0 / zfb 5.1.2 (f92c5d6, 7fde2a5, ff0c72d)
|
|
19
|
+
- ci: gate the doc build, links, wind audit and dependency audit; doc jobs move to Node 24 (4651d4e)
|
|
20
|
+
- build(doc): clear the high doc audit advisories (wrangler 4.152.0, zod 4.6.7, undici override) (aa5f7cf)
|
|
21
|
+
- chore: follow-ups from the code review (8bdd50e)
|
|
22
|
+
- chore(ci): record the NPM_TOKEN rotation on 2026-10-26 (760b1d1)
|
|
23
|
+
|
|
24
|
+
## 0.1.2
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- fix(calibrate): decode HEIC via /heif instead of hard-erroring off macOS (fec0285, [#103](https://github.com/zudolab/zudo-image-tweaker/pull/103))
|
|
29
|
+
|
|
3
30
|
## 0.1.1
|
|
4
31
|
|
|
5
32
|
### Other Changes
|
|
@@ -18,19 +18,27 @@
|
|
|
18
18
|
* non-default orientation tag are sampled and corrected in their
|
|
19
19
|
* upright, displayed orientation, not their as-stored one.
|
|
20
20
|
*
|
|
21
|
-
* HEIC/HEIF decoding is
|
|
22
|
-
* `
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
21
|
+
* HEIC/HEIF decoding is delegated wholesale to the sibling `/heif`
|
|
22
|
+
* module's `convertHeifToJpeg` (issue #102), which tries macOS `sips`
|
|
23
|
+
* first and falls back to its bundled Node/WASM decoder whenever `sips`
|
|
24
|
+
* is unavailable (Linux, Windows) OR fails on a given input. This module
|
|
25
|
+
* used to own a `sips`-only path and threw a capability-loss error
|
|
26
|
+
* everywhere else, telling callers to pre-convert via `/heif` — but
|
|
27
|
+
* `heic-decode` is a direct dependency of this package, so every consumer
|
|
28
|
+
* was reimplementing a dance the package could already do for itself.
|
|
29
|
+
* That mattered most for the HDR "gain map" HEICs modern phone cameras
|
|
30
|
+
* emit: their auxiliary-image references exceed the system libheif's
|
|
31
|
+
* limit, so `sips` AND sharp's bundled libheif both reject them while the
|
|
32
|
+
* WASM decoder handles them fine. Buffer input bypasses HEIC handling
|
|
33
|
+
* entirely; only a string path is checked for a `.heic`/`.heif`
|
|
34
|
+
* extension.
|
|
35
|
+
*
|
|
36
|
+
* TRUSTED-INPUT ONLY, inherited: routing through `/heif` means HEIC input
|
|
37
|
+
* to this module can reach `heic-decode` -> bundled `libheif-js` 1.19.8,
|
|
38
|
+
* which predates the libheif 1.22.0 fixes for CVE-2026-32740 (heap
|
|
39
|
+
* overflow) and CVE-2026-32739 (infinite-loop DoS). Only calibrate
|
|
40
|
+
* HEIC/HEIF files from sources you trust. See `/heif`'s module doc for
|
|
41
|
+
* the full statement of the exposure.
|
|
34
42
|
*
|
|
35
43
|
* ICC profile (issue #35): `normalizeBackgroundColor` samples and corrects
|
|
36
44
|
* pixels via a raw decode, which yields the source's literal device-space
|
|
@@ -67,7 +75,8 @@ export interface SampleBackgroundColorOptions {
|
|
|
67
75
|
patchSize?: number;
|
|
68
76
|
/**
|
|
69
77
|
* HEIC/HEIF input only: kill the `sips` conversion subprocess if it
|
|
70
|
-
* hasn't exited after this many ms
|
|
78
|
+
* hasn't exited after this many ms, falling back to `/heif`'s Node/WASM
|
|
79
|
+
* decoder. @default 60000
|
|
71
80
|
*/
|
|
72
81
|
sipsTimeoutMs?: number;
|
|
73
82
|
}
|
|
@@ -86,7 +95,8 @@ export interface NormalizeBackgroundColorOptions {
|
|
|
86
95
|
format?: 'jpeg' | 'png' | 'webp' | 'tiff';
|
|
87
96
|
/**
|
|
88
97
|
* HEIC/HEIF input only: kill the `sips` conversion subprocess if it
|
|
89
|
-
* hasn't exited after this many ms
|
|
98
|
+
* hasn't exited after this many ms, falling back to `/heif`'s Node/WASM
|
|
99
|
+
* decoder. @default 60000
|
|
90
100
|
*/
|
|
91
101
|
sipsTimeoutMs?: number;
|
|
92
102
|
}
|
package/dist/calibrate/index.js
CHANGED
|
@@ -1,58 +1,27 @@
|
|
|
1
|
-
import { randomUUID as
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
const
|
|
8
|
-
function
|
|
1
|
+
import { randomUUID as X } from "node:crypto";
|
|
2
|
+
import U from "node:fs/promises";
|
|
3
|
+
import Z from "node:os";
|
|
4
|
+
import B from "node:path";
|
|
5
|
+
import x from "sharp";
|
|
6
|
+
import { c as G } from "../index-DWJCvc5O.js";
|
|
7
|
+
const L = 6e4, O = 50, c = 5, Q = 60, V = { from: 0.08, to: 0.25 }, Y = [0.5, 2], z = 30;
|
|
8
|
+
function tt(t) {
|
|
9
9
|
return /\.hei[cf]$/i.test(t);
|
|
10
10
|
}
|
|
11
|
-
async function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
[
|
|
17
|
-
"-s",
|
|
18
|
-
"format",
|
|
19
|
-
"jpeg",
|
|
20
|
-
"-s",
|
|
21
|
-
"formatOptions",
|
|
22
|
-
"95",
|
|
23
|
-
z(t),
|
|
24
|
-
"--out",
|
|
25
|
-
e
|
|
26
|
-
],
|
|
27
|
-
{ timeoutMs: r }
|
|
28
|
-
);
|
|
29
|
-
} catch (n) {
|
|
30
|
-
if (await T.rm(e, { force: !0 }), Q(n))
|
|
31
|
-
return null;
|
|
32
|
-
throw new Error(
|
|
33
|
-
`HEIC/HEIF conversion via 'sips' failed for '${t}': ${n.message}. This can happen with HDR "gain map" HEIC files, which the system libheif that \`sips\` relies on may reject via a strict auxiliary-image-reference limit. Pre-convert '` + t + "' via the sibling /heif module (whose Node fallback does not carry that limit) before calling this function.",
|
|
34
|
-
{ cause: n }
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
return e;
|
|
38
|
-
}
|
|
39
|
-
async function L(t, r) {
|
|
40
|
-
if (typeof t == "string" && rt(t)) {
|
|
41
|
-
const e = await nt(t, r);
|
|
42
|
-
if (!e)
|
|
43
|
-
throw new Error(
|
|
44
|
-
`HEIC/HEIF decoding requires macOS 'sips', which is unavailable on this platform. Pre-convert '${t}' to JPEG/PNG (e.g. via the sibling /heif module) before calling this function.`
|
|
45
|
-
);
|
|
46
|
-
return { sharpInput: e, cleanup: () => T.rm(e, { force: !0 }) };
|
|
11
|
+
async function v(t, r) {
|
|
12
|
+
if (typeof t == "string" && tt(t)) {
|
|
13
|
+
const { buffer: e } = await G(t, { quality: 95, sipsTimeoutMs: r });
|
|
14
|
+
return { sharpInput: e, cleanup: async () => {
|
|
15
|
+
} };
|
|
47
16
|
}
|
|
48
17
|
return { sharpInput: t, cleanup: async () => {
|
|
49
18
|
} };
|
|
50
19
|
}
|
|
51
|
-
async function
|
|
52
|
-
const { width: r = 0, height: e = 0, orientation: n } = await
|
|
20
|
+
async function et(t) {
|
|
21
|
+
const { width: r = 0, height: e = 0, orientation: n } = await x(t).metadata();
|
|
53
22
|
return n !== void 0 && n >= 5 && n <= 8 ? { width: e, height: r } : { width: r, height: e };
|
|
54
23
|
}
|
|
55
|
-
function
|
|
24
|
+
function rt(t) {
|
|
56
25
|
let r = 0, e = 0, n = 0;
|
|
57
26
|
const o = t.length / 3;
|
|
58
27
|
for (let a = 0; a < t.length; a += 3)
|
|
@@ -63,7 +32,7 @@ function at(t) {
|
|
|
63
32
|
b: Math.round(n / o)
|
|
64
33
|
};
|
|
65
34
|
}
|
|
66
|
-
function
|
|
35
|
+
function _(t) {
|
|
67
36
|
const r = t.length;
|
|
68
37
|
return {
|
|
69
38
|
r: Math.round(t.reduce((e, n) => e + n.r, 0) / r),
|
|
@@ -71,67 +40,67 @@ function $(t) {
|
|
|
71
40
|
b: Math.round(t.reduce((e, n) => e + n.b, 0) / r)
|
|
72
41
|
};
|
|
73
42
|
}
|
|
74
|
-
async function
|
|
75
|
-
const e = r.patchSize ??
|
|
43
|
+
async function nt(t, r = {}) {
|
|
44
|
+
const e = r.patchSize ?? O, n = r.sipsTimeoutMs ?? L, o = e + c * 2, { sharpInput: a, cleanup: i } = await v(t, n);
|
|
76
45
|
try {
|
|
77
|
-
const { width:
|
|
78
|
-
if (!
|
|
46
|
+
const { width: h, height: f } = await et(a);
|
|
47
|
+
if (!h || !f || h < o || f < o)
|
|
79
48
|
throw new Error(
|
|
80
|
-
`Image too small (${
|
|
49
|
+
`Image too small (${h ?? 0}x${f ?? 0}). Minimum ${o}x${o} required.`
|
|
81
50
|
);
|
|
82
|
-
const
|
|
83
|
-
{ left:
|
|
84
|
-
{ left:
|
|
85
|
-
{ left:
|
|
86
|
-
{ left:
|
|
87
|
-
],
|
|
88
|
-
for (const m of
|
|
89
|
-
const { data:
|
|
90
|
-
|
|
51
|
+
const l = [
|
|
52
|
+
{ left: c, top: c },
|
|
53
|
+
{ left: h - e - c, top: c },
|
|
54
|
+
{ left: c, top: f - e - c },
|
|
55
|
+
{ left: h - e - c, top: f - e - c }
|
|
56
|
+
], s = [];
|
|
57
|
+
for (const m of l) {
|
|
58
|
+
const { data: u } = await x(a).rotate().extract({ left: m.left, top: m.top, width: e, height: e }).removeAlpha().raw().toBuffer({ resolveWithObject: !0 });
|
|
59
|
+
s.push(rt(u));
|
|
91
60
|
}
|
|
92
|
-
return
|
|
61
|
+
return _(s);
|
|
93
62
|
} finally {
|
|
94
63
|
await i();
|
|
95
64
|
}
|
|
96
65
|
}
|
|
97
|
-
async function
|
|
66
|
+
async function wt(t, r = {}) {
|
|
98
67
|
if (t.length === 0)
|
|
99
68
|
throw new Error("calibrateTargetFromSamples requires at least one reference image.");
|
|
100
|
-
const e = await Promise.all(t.map((n) =>
|
|
101
|
-
return
|
|
69
|
+
const e = await Promise.all(t.map((n) => nt(n, r)));
|
|
70
|
+
return _(e);
|
|
102
71
|
}
|
|
103
|
-
function
|
|
72
|
+
function q(t, r, e) {
|
|
104
73
|
return Math.min(Math.max(t, r), e);
|
|
105
74
|
}
|
|
106
|
-
function
|
|
75
|
+
function C(t) {
|
|
107
76
|
return t < 0 ? 0 : t > 255 ? 255 : Math.round(t);
|
|
108
77
|
}
|
|
109
|
-
function
|
|
78
|
+
function H(t, r, e) {
|
|
110
79
|
const n = Math.max(t, r, e), o = Math.min(t, r, e), a = n - o;
|
|
111
80
|
if (a === 0) return 0;
|
|
112
81
|
let i;
|
|
113
82
|
return n === t ? i = (r - e) / a % 6 : n === r ? i = (e - t) / a + 2 : i = (t - r) / a + 4, i *= 60, i < 0 && (i += 360), i;
|
|
114
83
|
}
|
|
115
|
-
function
|
|
84
|
+
function j(t, r, e) {
|
|
116
85
|
const n = Math.max(t, r, e), o = Math.min(t, r, e);
|
|
117
86
|
return n === 0 ? 0 : (n - o) / n;
|
|
118
87
|
}
|
|
119
|
-
function
|
|
120
|
-
if (Math.max(t, r, e) <
|
|
121
|
-
const f =
|
|
88
|
+
function ot(t, r, e, n, o, a, i) {
|
|
89
|
+
if (Math.max(t, r, e) < z || o < i.from) return 0;
|
|
90
|
+
const f = j(t, r, e);
|
|
122
91
|
if (f < i.from) return 0;
|
|
123
|
-
const
|
|
124
|
-
let
|
|
125
|
-
|
|
126
|
-
const m =
|
|
127
|
-
return (
|
|
92
|
+
const l = H(t, r, e);
|
|
93
|
+
let s = Math.abs(l - n);
|
|
94
|
+
s > 180 && (s = 360 - s);
|
|
95
|
+
const m = s < a ? 1 - s / a : 0, u = i.to - i.from;
|
|
96
|
+
return (u > 0 ? q((f - i.from) / u, 0, 1) : f >= i.from ? 1 : 0) * m;
|
|
128
97
|
}
|
|
129
|
-
function
|
|
98
|
+
function at(t) {
|
|
130
99
|
if (typeof t != "string") return "jpeg";
|
|
131
|
-
const r =
|
|
100
|
+
const r = B.extname(t).toLowerCase();
|
|
132
101
|
return r === ".png" ? "png" : r === ".webp" ? "webp" : r === ".tiff" || r === ".tif" ? "tiff" : "jpeg";
|
|
133
102
|
}
|
|
134
|
-
function
|
|
103
|
+
function it(t, r) {
|
|
135
104
|
switch (r) {
|
|
136
105
|
case "png":
|
|
137
106
|
return t.png();
|
|
@@ -143,64 +112,64 @@ function ft(t, r) {
|
|
|
143
112
|
return t.jpeg({ quality: 95 });
|
|
144
113
|
}
|
|
145
114
|
}
|
|
146
|
-
function
|
|
147
|
-
let i = 0,
|
|
148
|
-
for (let
|
|
149
|
-
let m = ((o +
|
|
150
|
-
for (let
|
|
151
|
-
i += t[m],
|
|
115
|
+
function ct(t, r, e, n, o, a) {
|
|
116
|
+
let i = 0, h = 0, f = 0;
|
|
117
|
+
for (let s = 0; s < a; s++) {
|
|
118
|
+
let m = ((o + s) * r + n) * e;
|
|
119
|
+
for (let u = 0; u < a; u++)
|
|
120
|
+
i += t[m], h += t[m + 1], f += t[m + 2], m += e;
|
|
152
121
|
}
|
|
153
|
-
const
|
|
122
|
+
const l = a * a;
|
|
154
123
|
return {
|
|
155
|
-
r: Math.round(i /
|
|
156
|
-
g: Math.round(
|
|
157
|
-
b: Math.round(f /
|
|
124
|
+
r: Math.round(i / l),
|
|
125
|
+
g: Math.round(h / l),
|
|
126
|
+
b: Math.round(f / l)
|
|
158
127
|
};
|
|
159
128
|
}
|
|
160
|
-
function
|
|
129
|
+
function st(t, r, e, n, o) {
|
|
161
130
|
const a = [
|
|
162
|
-
{ left:
|
|
163
|
-
{ left: r - o -
|
|
164
|
-
{ left:
|
|
165
|
-
{ left: r - o -
|
|
131
|
+
{ left: c, top: c },
|
|
132
|
+
{ left: r - o - c, top: c },
|
|
133
|
+
{ left: c, top: e - o - c },
|
|
134
|
+
{ left: r - o - c, top: e - o - c }
|
|
166
135
|
];
|
|
167
|
-
return
|
|
168
|
-
a.map((i) =>
|
|
136
|
+
return _(
|
|
137
|
+
a.map((i) => ct(t, r, n, i.left, i.top, o))
|
|
169
138
|
);
|
|
170
139
|
}
|
|
171
|
-
async function
|
|
140
|
+
async function dt(t, r) {
|
|
172
141
|
const {
|
|
173
142
|
target: e,
|
|
174
|
-
patchSize: n =
|
|
175
|
-
hueRadiusDeg: o =
|
|
176
|
-
saturationGate: a =
|
|
177
|
-
channelClamp: i =
|
|
178
|
-
format:
|
|
179
|
-
sipsTimeoutMs: f =
|
|
143
|
+
patchSize: n = O,
|
|
144
|
+
hueRadiusDeg: o = Q,
|
|
145
|
+
saturationGate: a = V,
|
|
146
|
+
channelClamp: i = Y,
|
|
147
|
+
format: h,
|
|
148
|
+
sipsTimeoutMs: f = L
|
|
180
149
|
} = r;
|
|
181
150
|
if (!Number.isInteger(n) || n <= 0)
|
|
182
151
|
throw new Error(`patchSize must be a positive integer, got ${n}`);
|
|
183
|
-
const
|
|
184
|
-
let
|
|
152
|
+
const l = n + c * 2, { sharpInput: s, cleanup: m } = await v(t, f);
|
|
153
|
+
let u = null;
|
|
185
154
|
try {
|
|
186
|
-
const { hasAlpha: D, icc:
|
|
187
|
-
if (!p.width || !p.height || p.width <
|
|
155
|
+
const { hasAlpha: D, icc: S } = await x(s).metadata(), F = x(s).rotate(), { data: N, info: p } = await (D ? F.ensureAlpha() : F.removeAlpha()).raw().toBuffer({ resolveWithObject: !0 }), E = p.channels, w = Buffer.from(N);
|
|
156
|
+
if (!p.width || !p.height || p.width < l || p.height < l)
|
|
188
157
|
throw new Error(
|
|
189
|
-
`Image too small (${p.width ?? 0}x${p.height ?? 0}). Minimum ${
|
|
158
|
+
`Image too small (${p.width ?? 0}x${p.height ?? 0}). Minimum ${l}x${l} required.`
|
|
190
159
|
);
|
|
191
|
-
const d =
|
|
192
|
-
for (let g = 0; g < w.length; g +=
|
|
193
|
-
const M = w[g],
|
|
194
|
-
|
|
160
|
+
const d = st(w, p.width, p.height, E, n), [W, k] = i, I = (g, M) => M === 0 ? 1 : q(g / M, W, k), P = I(e.r, d.r), $ = I(e.g, d.g), R = I(e.b, d.b), J = H(d.r, d.g, d.b), K = j(d.r, d.g, d.b);
|
|
161
|
+
for (let g = 0; g < w.length; g += E) {
|
|
162
|
+
const M = w[g], A = w[g + 1], y = w[g + 2], T = ot(M, A, y, J, K, o, a);
|
|
163
|
+
T > 0.01 && (w[g] = C(M + T * (M * P - M)), w[g + 1] = C(A + T * (A * $ - A)), w[g + 2] = C(y + T * (y * R - y)));
|
|
195
164
|
}
|
|
196
|
-
let b =
|
|
197
|
-
return
|
|
165
|
+
let b = x(w, { raw: { width: p.width, height: p.height, channels: E } });
|
|
166
|
+
return S && (u = B.join(Z.tmpdir(), `zit-calibrate-icc-${process.pid}-${X()}.icc`), await U.writeFile(u, S), b = b.withIccProfile(u)), b = it(b, h ?? at(t)), { buffer: await b.toBuffer(), applied: { scaleR: P, scaleG: $, scaleB: R } };
|
|
198
167
|
} finally {
|
|
199
|
-
|
|
168
|
+
u && await U.rm(u, { force: !0 }), await m();
|
|
200
169
|
}
|
|
201
170
|
}
|
|
202
171
|
export {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
172
|
+
wt as calibrateTargetFromSamples,
|
|
173
|
+
dt as normalizeBackgroundColor,
|
|
174
|
+
nt as sampleBackgroundColor
|
|
206
175
|
};
|
package/dist/heif/index.js
CHANGED
|
@@ -1,275 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
const T = 90, D = 256 * 1024 * 1024, N = 6e4, F = 16383 * 16383;
|
|
8
|
-
async function J(t) {
|
|
9
|
-
return typeof t == "string" ? (await S.stat(t)).size : t.length;
|
|
10
|
-
}
|
|
11
|
-
async function L(t, r) {
|
|
12
|
-
const a = await J(t);
|
|
13
|
-
if (a > r)
|
|
14
|
-
throw new Error(`HEIF input of ${a} bytes exceeds maxInputBytes (${r})`);
|
|
15
|
-
}
|
|
16
|
-
async function at(t, r = {}) {
|
|
17
|
-
const a = r.quality ?? T, n = r.maxInputBytes ?? D, o = r.maxDecodePixels ?? F, s = r.sipsTimeoutMs ?? N;
|
|
18
|
-
await L(t, n);
|
|
19
|
-
let e = null;
|
|
20
|
-
if (typeof t == "string") {
|
|
21
|
-
const i = await R(t, a, s);
|
|
22
|
-
if (i.result) return i.result;
|
|
23
|
-
e = i.error;
|
|
24
|
-
}
|
|
25
|
-
try {
|
|
26
|
-
return await X(t, { quality: a, maxInputBytes: n, maxDecodePixels: o });
|
|
27
|
-
} catch (i) {
|
|
28
|
-
const d = [typeof t == "string" ? e ? `'sips' failed (${e.message})` : "'sips' is unavailable (non-macOS)" : null, `the Node fallback also failed: ${i.message}`].filter(Boolean).join(" and ");
|
|
29
|
-
throw new Error(`HEIF conversion failed: ${d}.`);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
async function R(t, r, a) {
|
|
33
|
-
const n = v.join(k.tmpdir(), `heif-sips-${process.pid}-${O()}.jpg`);
|
|
34
|
-
try {
|
|
35
|
-
await $(
|
|
36
|
-
"sips",
|
|
37
|
-
[
|
|
38
|
-
"-s",
|
|
39
|
-
"format",
|
|
40
|
-
"jpeg",
|
|
41
|
-
"-s",
|
|
42
|
-
"formatOptions",
|
|
43
|
-
String(r),
|
|
44
|
-
z(t),
|
|
45
|
-
"--out",
|
|
46
|
-
n
|
|
47
|
-
],
|
|
48
|
-
{ timeoutMs: a }
|
|
49
|
-
);
|
|
50
|
-
} catch (o) {
|
|
51
|
-
return await S.rm(n, { force: !0 }), H(o) ? { result: null, error: null } : { result: null, error: o };
|
|
52
|
-
}
|
|
53
|
-
try {
|
|
54
|
-
const o = await S.readFile(n), s = await P(o).metadata();
|
|
55
|
-
return {
|
|
56
|
-
result: {
|
|
57
|
-
buffer: o,
|
|
58
|
-
width: s.width ?? 0,
|
|
59
|
-
height: s.height ?? 0,
|
|
60
|
-
iccApplied: !!s.icc,
|
|
61
|
-
converter: "sips"
|
|
62
|
-
},
|
|
63
|
-
error: null
|
|
64
|
-
};
|
|
65
|
-
} finally {
|
|
66
|
-
await S.rm(n, { force: !0 });
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
async function X(t, r = {}) {
|
|
70
|
-
const a = r.quality ?? T, n = r.maxInputBytes ?? D, o = r.maxDecodePixels ?? F;
|
|
71
|
-
await L(t, n);
|
|
72
|
-
const s = typeof t == "string" ? await S.readFile(t) : t;
|
|
73
|
-
V(s, o);
|
|
74
|
-
const { default: e } = await import("heic-decode"), { width: i, height: l, data: d } = await e({ buffer: s }), y = Z(s), h = y !== null && y.length <= q ? y : null, c = G(s);
|
|
75
|
-
let f = await P(Buffer.from(d.buffer, d.byteOffset, d.byteLength), {
|
|
76
|
-
raw: { width: i, height: l, channels: 4 }
|
|
77
|
-
}).removeAlpha().jpeg({ quality: a }).toBuffer();
|
|
78
|
-
return h && (f = Y(f, h)), c && (f = W(f, c)), {
|
|
79
|
-
buffer: f,
|
|
80
|
-
width: i,
|
|
81
|
-
height: l,
|
|
82
|
-
iccApplied: h !== null,
|
|
83
|
-
converter: "node"
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
function V(t, r) {
|
|
87
|
-
let a = null;
|
|
88
|
-
try {
|
|
89
|
-
const n = E(t, 0, t.length, "meta");
|
|
90
|
-
if (!n) return;
|
|
91
|
-
const o = E(t, n.bodyStart + 4, n.bodyEnd, "iprp");
|
|
92
|
-
if (!o) return;
|
|
93
|
-
const s = E(t, o.bodyStart, o.bodyEnd, "ipco");
|
|
94
|
-
if (!s) return;
|
|
95
|
-
for (const e of b(t, s.bodyStart, s.bodyEnd)) {
|
|
96
|
-
if (e.type !== "ispe" || e.bodyEnd - e.bodyStart < 12) continue;
|
|
97
|
-
const i = t.readUInt32BE(e.bodyStart + 4), l = t.readUInt32BE(e.bodyStart + 8);
|
|
98
|
-
if (i * l > r) {
|
|
99
|
-
a = { width: i, height: l };
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
} catch {
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
if (a)
|
|
107
|
-
throw new Error(
|
|
108
|
-
`HEIF declares an image of ${a.width}x${a.height} pixels, exceeding the ${r}-pixel decode limit (maxDecodePixels)`
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
const U = Buffer.from("ICC_PROFILE\0", "latin1"), x = 65533 - U.length - 1 - 1, q = 255 * x;
|
|
112
|
-
function Y(t, r) {
|
|
113
|
-
if (t.length < 2 || t[0] !== 255 || t[1] !== 216)
|
|
114
|
-
throw new Error("Expected a JPEG buffer starting with the SOI marker");
|
|
115
|
-
const a = Math.max(1, Math.ceil(r.length / x)), n = [];
|
|
116
|
-
for (let o = 0; o < a; o++) {
|
|
117
|
-
const s = r.subarray(o * x, (o + 1) * x), e = 2 + U.length + 1 + 1 + s.length, i = Buffer.alloc(4 + U.length + 2);
|
|
118
|
-
i.writeUInt8(255, 0), i.writeUInt8(226, 1), i.writeUInt16BE(e, 2), U.copy(i, 4), i.writeUInt8(o + 1, 4 + U.length), i.writeUInt8(a, 4 + U.length + 1), n.push(i, s);
|
|
119
|
-
}
|
|
120
|
-
return Buffer.concat([t.subarray(0, 2), ...n, t.subarray(2)]);
|
|
121
|
-
}
|
|
122
|
-
const C = Buffer.from("Exif\0\0", "latin1");
|
|
123
|
-
function W(t, r) {
|
|
124
|
-
if (t.length < 2 || t[0] !== 255 || t[1] !== 216)
|
|
125
|
-
throw new Error("Expected a JPEG buffer starting with the SOI marker");
|
|
126
|
-
const a = 2 + C.length + r.length;
|
|
127
|
-
if (a > 65535) return t;
|
|
128
|
-
const n = Buffer.alloc(4 + C.length);
|
|
129
|
-
return n.writeUInt8(255, 0), n.writeUInt8(225, 1), n.writeUInt16BE(a, 2), C.copy(n, 4), Buffer.concat([t.subarray(0, 2), n, r, t.subarray(2)]);
|
|
130
|
-
}
|
|
131
|
-
function G(t) {
|
|
132
|
-
try {
|
|
133
|
-
const r = E(t, 0, t.length, "meta");
|
|
134
|
-
if (!r) return null;
|
|
135
|
-
const a = r.bodyStart + 4, n = K(t, a, r.bodyEnd);
|
|
136
|
-
if (n === null) return null;
|
|
137
|
-
const o = Q(t, a, r.bodyEnd, n);
|
|
138
|
-
if (!o || o.length < 12 || o.offset + o.length > t.length) return null;
|
|
139
|
-
const s = t.subarray(o.offset, o.offset + o.length), e = 4 + s.readUInt32BE(0);
|
|
140
|
-
if (e >= s.length - 8) return null;
|
|
141
|
-
const i = s.toString("latin1", e, e + 2);
|
|
142
|
-
return i !== "II" && i !== "MM" ? null : j(s.subarray(e));
|
|
143
|
-
} catch {
|
|
144
|
-
return null;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
function K(t, r, a) {
|
|
148
|
-
const n = E(t, r, a, "iinf");
|
|
149
|
-
if (!n) return null;
|
|
150
|
-
const o = t.readUInt8(n.bodyStart), s = n.bodyStart + 4 + (o === 0 ? 2 : 4);
|
|
151
|
-
for (const e of b(t, s, n.bodyEnd)) {
|
|
152
|
-
if (e.type !== "infe") continue;
|
|
153
|
-
const i = t.readUInt8(e.bodyStart);
|
|
154
|
-
if (i < 2) continue;
|
|
155
|
-
const l = i === 2 ? 2 : 4, d = i === 2 ? t.readUInt16BE(e.bodyStart + 4) : t.readUInt32BE(e.bodyStart + 4), y = e.bodyStart + 4 + l + 2;
|
|
156
|
-
if (t.toString("latin1", y, y + 4) === "Exif") return d;
|
|
157
|
-
}
|
|
158
|
-
return null;
|
|
159
|
-
}
|
|
160
|
-
function Q(t, r, a, n) {
|
|
161
|
-
const o = E(t, r, a, "iloc");
|
|
162
|
-
if (!o) return null;
|
|
163
|
-
const s = t.readUInt8(o.bodyStart);
|
|
164
|
-
let e = o.bodyStart + 4;
|
|
165
|
-
const i = t.readUInt16BE(e);
|
|
166
|
-
e += 2;
|
|
167
|
-
const l = i >> 12 & 15, d = i >> 8 & 15, y = i >> 4 & 15, h = s >= 1 ? i & 15 : 0, c = (f) => {
|
|
168
|
-
let u;
|
|
169
|
-
return f === 0 ? u = 0 : f === 8 ? u = Number(t.readBigUInt64BE(e)) : u = t.readUIntBE(e, f), e += f, u;
|
|
170
|
-
};
|
|
171
|
-
let m;
|
|
172
|
-
s < 2 ? (m = t.readUInt16BE(e), e += 2) : (m = t.readUInt32BE(e), e += 4);
|
|
173
|
-
for (let f = 0; f < m; f++) {
|
|
174
|
-
let u;
|
|
175
|
-
s < 2 ? (u = t.readUInt16BE(e), e += 2) : (u = t.readUInt32BE(e), e += 4);
|
|
176
|
-
let I = 0;
|
|
177
|
-
s >= 1 && (I = t.readUInt16BE(e) & 15, e += 2);
|
|
178
|
-
const p = t.readUInt16BE(e);
|
|
179
|
-
e += 2;
|
|
180
|
-
const w = c(y), g = t.readUInt16BE(e);
|
|
181
|
-
e += 2;
|
|
182
|
-
let B = null;
|
|
183
|
-
for (let _ = 0; _ < g; _++) {
|
|
184
|
-
h > 0 && c(h);
|
|
185
|
-
const A = c(l), M = c(d);
|
|
186
|
-
_ === 0 && (B = { offset: w + A, length: M });
|
|
187
|
-
}
|
|
188
|
-
if (u === n)
|
|
189
|
-
return I !== 0 || p !== 0 || g !== 1 ? null : B;
|
|
190
|
-
}
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
|
-
function j(t) {
|
|
194
|
-
const r = Buffer.from(t);
|
|
195
|
-
try {
|
|
196
|
-
const a = r.toString("latin1", 0, 2) === "II", n = (i) => a ? r.readUInt16LE(i) : r.readUInt16BE(i), s = ((i) => a ? r.readUInt32LE(i) : r.readUInt32BE(i))(4), e = n(s);
|
|
197
|
-
for (let i = 0; i < e; i++) {
|
|
198
|
-
const l = s + 2 + i * 12;
|
|
199
|
-
if (n(l) === 274) {
|
|
200
|
-
a ? r.writeUInt16LE(1, l + 8) : r.writeUInt16BE(1, l + 8);
|
|
201
|
-
break;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
} catch {
|
|
205
|
-
}
|
|
206
|
-
return r;
|
|
207
|
-
}
|
|
208
|
-
function* b(t, r, a) {
|
|
209
|
-
let n = r;
|
|
210
|
-
for (; n + 8 <= a; ) {
|
|
211
|
-
let o = t.readUInt32BE(n);
|
|
212
|
-
const s = t.toString("latin1", n + 4, n + 8);
|
|
213
|
-
let e = 8;
|
|
214
|
-
if (o === 1) {
|
|
215
|
-
if (n + 16 > a) break;
|
|
216
|
-
o = Number(t.readBigUInt64BE(n + 8)), e = 16;
|
|
217
|
-
} else o === 0 && (o = a - n);
|
|
218
|
-
if (o < e || n + o > a) break;
|
|
219
|
-
yield { type: s, start: n, header: e, size: o, bodyStart: n + e, bodyEnd: n + o }, n += o;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
function E(t, r, a, n) {
|
|
223
|
-
for (const o of b(t, r, a))
|
|
224
|
-
if (o.type === n) return o;
|
|
225
|
-
return null;
|
|
226
|
-
}
|
|
227
|
-
function Z(t) {
|
|
228
|
-
try {
|
|
229
|
-
const r = E(t, 0, t.length, "meta");
|
|
230
|
-
if (!r) return null;
|
|
231
|
-
const a = r.bodyStart + 4, n = E(t, a, r.bodyEnd, "pitm");
|
|
232
|
-
if (!n) return null;
|
|
233
|
-
const s = t.readUInt8(n.bodyStart) === 0 ? t.readUInt16BE(n.bodyStart + 4) : t.readUInt32BE(n.bodyStart + 4), e = E(t, a, r.bodyEnd, "iprp");
|
|
234
|
-
if (!e) return null;
|
|
235
|
-
const i = E(t, e.bodyStart, e.bodyEnd, "ipco");
|
|
236
|
-
if (!i) return null;
|
|
237
|
-
const l = [...b(t, i.bodyStart, i.bodyEnd)], d = E(t, e.bodyStart, e.bodyEnd, "ipma");
|
|
238
|
-
if (!d) return null;
|
|
239
|
-
const y = t.readUInt8(d.bodyStart), h = t.readUIntBE(d.bodyStart + 1, 3);
|
|
240
|
-
let c = d.bodyStart + 4;
|
|
241
|
-
const m = t.readUInt32BE(c);
|
|
242
|
-
c += 4;
|
|
243
|
-
let f = null;
|
|
244
|
-
for (let u = 0; u < m; u++) {
|
|
245
|
-
const I = y < 1 ? t.readUInt16BE(c) : t.readUInt32BE(c);
|
|
246
|
-
c += y < 1 ? 2 : 4;
|
|
247
|
-
const p = t.readUInt8(c);
|
|
248
|
-
c += 1;
|
|
249
|
-
const w = [];
|
|
250
|
-
for (let g = 0; g < p; g++) {
|
|
251
|
-
let B;
|
|
252
|
-
h & 1 ? (B = t.readUInt16BE(c) & 32767, c += 2) : (B = t.readUInt8(c) & 127, c += 1), w.push(B);
|
|
253
|
-
}
|
|
254
|
-
I === s && (f = w);
|
|
255
|
-
}
|
|
256
|
-
if (!f) return null;
|
|
257
|
-
for (const u of f) {
|
|
258
|
-
const I = l[u - 1];
|
|
259
|
-
if (I && I.type === "colr") {
|
|
260
|
-
const p = t.toString("latin1", I.bodyStart, I.bodyStart + 4);
|
|
261
|
-
if (p === "prof" || p === "rICC")
|
|
262
|
-
return t.subarray(I.bodyStart + 4, I.bodyEnd);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
return null;
|
|
266
|
-
} catch {
|
|
267
|
-
return null;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
1
|
+
import "node:crypto";
|
|
2
|
+
import "node:fs/promises";
|
|
3
|
+
import "node:os";
|
|
4
|
+
import "node:path";
|
|
5
|
+
import "sharp";
|
|
6
|
+
import { c as a, a as c, e as f, b as s } from "../index-DWJCvc5O.js";
|
|
270
7
|
export {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
8
|
+
a as convertHeifToJpeg,
|
|
9
|
+
c as convertHeifToJpegNode,
|
|
10
|
+
f as extractExifFromHeif,
|
|
11
|
+
s as extractIccFromHeif
|
|
275
12
|
};
|