@takazudo/zudo-image-tweaker 0.1.1 → 0.1.2

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.2
4
+
5
+ ### Fixed
6
+
7
+ - fix(calibrate): decode HEIC via /heif instead of hard-erroring off macOS (fec0285, [#103](https://github.com/zudolab/zudo-image-tweaker/pull/103))
8
+
3
9
  ## 0.1.1
4
10
 
5
11
  ### 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 feature-detected via macOS `sips` (invoked with
22
- * `execFile` argument arrays, never a shell string) because this module
23
- * carries no Node-native HEIC decoder. `sampleBackgroundColor` and
24
- * `normalizeBackgroundColor` throw a descriptive error for `.heic`/`.heif`
25
- * input on any platform where `sips` is unavailable (Linux, Windows) —
26
- * pre-convert such inputs to JPEG/PNG (e.g. via the sibling `/heif`
27
- * module, which does carry a Node-native fallback) before calling into
28
- * this module. Buffer input bypasses HEIC handling entirely; only a
29
- * string path is checked for a `.heic`/`.heif` extension. A `sips` failure
30
- * for any reason other than being absent (e.g. an HDR "gain map" HEIC
31
- * whose auxiliary-image references exceed the system libheif's limit —
32
- * see `/heif`'s module doc for the full explanation) is rethrown wrapped
33
- * with the same pre-convert-via-`/heif` guidance (issue #34).
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. @default 60000
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. @default 60000
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
  }
@@ -1,58 +1,27 @@
1
- import { randomUUID as O } from "node:crypto";
2
- import T from "node:fs/promises";
3
- import R from "node:os";
4
- import P from "node:path";
5
- import y from "sharp";
6
- import { r as Z, a as z, i as Q } from "../run-BIjGA2Fu.js";
7
- const U = 6e4, j = 50, s = 5, V = 60, Y = { from: 0.08, to: 0.25 }, tt = [0.5, 2], et = 30;
8
- function rt(t) {
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 nt(t, r) {
12
- const e = P.join(R.tmpdir(), `zit-calibrate-${process.pid}-${O()}.jpg`);
13
- try {
14
- await Z(
15
- "sips",
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 ot(t) {
52
- const { width: r = 0, height: e = 0, orientation: n } = await y(t).metadata();
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 at(t) {
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 $(t) {
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 it(t, r = {}) {
75
- const e = r.patchSize ?? j, n = r.sipsTimeoutMs ?? U, o = e + s * 2, { sharpInput: a, cleanup: i } = await L(t, n);
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: u, height: f } = await ot(a);
78
- if (!u || !f || u < o || f < o)
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 (${u ?? 0}x${f ?? 0}). Minimum ${o}x${o} required.`
49
+ `Image too small (${h ?? 0}x${f ?? 0}). Minimum ${o}x${o} required.`
81
50
  );
82
- const h = [
83
- { left: s, top: s },
84
- { left: u - e - s, top: s },
85
- { left: s, top: f - e - s },
86
- { left: u - e - s, top: f - e - s }
87
- ], c = [];
88
- for (const m of h) {
89
- const { data: l } = await y(a).rotate().extract({ left: m.left, top: m.top, width: e, height: e }).removeAlpha().raw().toBuffer({ resolveWithObject: !0 });
90
- c.push(at(l));
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 $(c);
61
+ return _(s);
93
62
  } finally {
94
63
  await i();
95
64
  }
96
65
  }
97
- async function bt(t, r = {}) {
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) => it(n, r)));
101
- return $(e);
69
+ const e = await Promise.all(t.map((n) => nt(n, r)));
70
+ return _(e);
102
71
  }
103
- function N(t, r, e) {
72
+ function q(t, r, e) {
104
73
  return Math.min(Math.max(t, r), e);
105
74
  }
106
- function v(t) {
75
+ function C(t) {
107
76
  return t < 0 ? 0 : t > 255 ? 255 : Math.round(t);
108
77
  }
109
- function q(t, r, e) {
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 k(t, r, e) {
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 st(t, r, e, n, o, a, i) {
120
- if (Math.max(t, r, e) < et || o < i.from) return 0;
121
- const f = k(t, r, e);
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 h = q(t, r, e);
124
- let c = Math.abs(h - n);
125
- c > 180 && (c = 360 - c);
126
- const m = c < a ? 1 - c / a : 0, l = i.to - i.from;
127
- return (l > 0 ? N((f - i.from) / l, 0, 1) : f >= i.from ? 1 : 0) * m;
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 ct(t) {
98
+ function at(t) {
130
99
  if (typeof t != "string") return "jpeg";
131
- const r = P.extname(t).toLowerCase();
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 ft(t, r) {
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 lt(t, r, e, n, o, a) {
147
- let i = 0, u = 0, f = 0;
148
- for (let c = 0; c < a; c++) {
149
- let m = ((o + c) * r + n) * e;
150
- for (let l = 0; l < a; l++)
151
- i += t[m], u += t[m + 1], f += t[m + 2], m += e;
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 h = a * a;
122
+ const l = a * a;
154
123
  return {
155
- r: Math.round(i / h),
156
- g: Math.round(u / h),
157
- b: Math.round(f / h)
124
+ r: Math.round(i / l),
125
+ g: Math.round(h / l),
126
+ b: Math.round(f / l)
158
127
  };
159
128
  }
160
- function ht(t, r, e, n, o) {
129
+ function st(t, r, e, n, o) {
161
130
  const a = [
162
- { left: s, top: s },
163
- { left: r - o - s, top: s },
164
- { left: s, top: e - o - s },
165
- { left: r - o - s, top: e - o - s }
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) => lt(t, r, n, i.left, i.top, o))
136
+ return _(
137
+ a.map((i) => ct(t, r, n, i.left, i.top, o))
169
138
  );
170
139
  }
171
- async function yt(t, r) {
140
+ async function dt(t, r) {
172
141
  const {
173
142
  target: e,
174
- patchSize: n = j,
175
- hueRadiusDeg: o = V,
176
- saturationGate: a = Y,
177
- channelClamp: i = tt,
178
- format: u,
179
- sipsTimeoutMs: f = U
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 h = n + s * 2, { sharpInput: c, cleanup: m } = await L(t, f);
184
- let l = null;
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: _ } = await y(c).metadata(), F = y(c).rotate(), { data: W, info: p } = await (D ? F.ensureAlpha() : F.removeAlpha()).raw().toBuffer({ resolveWithObject: !0 }), A = p.channels, w = Buffer.from(W);
187
- if (!p.width || !p.height || p.width < h || p.height < h)
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 ${h}x${h} required.`
158
+ `Image too small (${p.width ?? 0}x${p.height ?? 0}). Minimum ${l}x${l} required.`
190
159
  );
191
- const d = ht(w, p.width, p.height, A, n), [G, J] = i, C = (g, M) => M === 0 ? 1 : N(g / M, G, J), S = C(e.r, d.r), H = C(e.g, d.g), B = C(e.b, d.b), K = q(d.r, d.g, d.b), X = k(d.r, d.g, d.b);
192
- for (let g = 0; g < w.length; g += A) {
193
- const M = w[g], E = w[g + 1], x = w[g + 2], I = st(M, E, x, K, X, o, a);
194
- I > 0.01 && (w[g] = v(M + I * (M * S - M)), w[g + 1] = v(E + I * (E * H - E)), w[g + 2] = v(x + I * (x * B - x)));
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 = y(w, { raw: { width: p.width, height: p.height, channels: A } });
197
- return _ && (l = P.join(R.tmpdir(), `zit-calibrate-icc-${process.pid}-${O()}.icc`), await T.writeFile(l, _), b = b.withIccProfile(l)), b = ft(b, u ?? ct(t)), { buffer: await b.toBuffer(), applied: { scaleR: S, scaleG: H, scaleB: B } };
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
- l && await T.rm(l, { force: !0 }), await m();
168
+ u && await U.rm(u, { force: !0 }), await m();
200
169
  }
201
170
  }
202
171
  export {
203
- bt as calibrateTargetFromSamples,
204
- yt as normalizeBackgroundColor,
205
- it as sampleBackgroundColor
172
+ wt as calibrateTargetFromSamples,
173
+ dt as normalizeBackgroundColor,
174
+ nt as sampleBackgroundColor
206
175
  };
@@ -1,275 +1,12 @@
1
- import { randomUUID as O } from "node:crypto";
2
- import S from "node:fs/promises";
3
- import k from "node:os";
4
- import v from "node:path";
5
- import P from "sharp";
6
- import { r as $, a as z, i as H } from "../run-BIjGA2Fu.js";
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
- at as convertHeifToJpeg,
272
- X as convertHeifToJpegNode,
273
- G as extractExifFromHeif,
274
- Z as extractIccFromHeif
8
+ a as convertHeifToJpeg,
9
+ c as convertHeifToJpegNode,
10
+ f as extractExifFromHeif,
11
+ s as extractIccFromHeif
275
12
  };
@@ -0,0 +1,293 @@
1
+ import { randomUUID as k } from "node:crypto";
2
+ import g from "node:fs/promises";
3
+ import v from "node:os";
4
+ import F from "node:path";
5
+ import L from "sharp";
6
+ import { execFile as N } from "node:child_process";
7
+ import { promisify as $ } from "node:util";
8
+ const z = $(N), H = 6e4;
9
+ async function J(t, r, a = {}) {
10
+ const { timeoutMs: n = H, killSignal: o = "SIGKILL" } = a, { stdout: s, stderr: e } = await z(t, r, {
11
+ timeout: n,
12
+ killSignal: o
13
+ });
14
+ return { stdout: s, stderr: e };
15
+ }
16
+ function R(t) {
17
+ return F.resolve(t);
18
+ }
19
+ function X(t) {
20
+ return t?.code === "ENOENT";
21
+ }
22
+ const C = 90, P = 256 * 1024 * 1024, V = 6e4, D = 16383 * 16383;
23
+ async function q(t) {
24
+ return typeof t == "string" ? (await g.stat(t)).size : t.length;
25
+ }
26
+ async function M(t, r) {
27
+ const a = await q(t);
28
+ if (a > r)
29
+ throw new Error(`HEIF input of ${a} bytes exceeds maxInputBytes (${r})`);
30
+ }
31
+ async function dt(t, r = {}) {
32
+ const a = r.quality ?? C, n = r.maxInputBytes ?? P, o = r.maxDecodePixels ?? D, s = r.sipsTimeoutMs ?? V;
33
+ await M(t, n);
34
+ let e = null;
35
+ if (typeof t == "string") {
36
+ const i = await Y(t, a, s);
37
+ if (i.result) return i.result;
38
+ e = i.error;
39
+ }
40
+ try {
41
+ return await G(t, { quality: a, maxInputBytes: n, maxDecodePixels: o });
42
+ } catch (i) {
43
+ 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 ");
44
+ throw new Error(`HEIF conversion failed: ${d}.`);
45
+ }
46
+ }
47
+ async function Y(t, r, a) {
48
+ const n = F.join(v.tmpdir(), `heif-sips-${process.pid}-${k()}.jpg`);
49
+ try {
50
+ await J(
51
+ "sips",
52
+ [
53
+ "-s",
54
+ "format",
55
+ "jpeg",
56
+ "-s",
57
+ "formatOptions",
58
+ String(r),
59
+ R(t),
60
+ "--out",
61
+ n
62
+ ],
63
+ { timeoutMs: a }
64
+ );
65
+ } catch (o) {
66
+ return await g.rm(n, { force: !0 }), X(o) ? { result: null, error: null } : { result: null, error: o };
67
+ }
68
+ try {
69
+ const o = await g.readFile(n), s = await L(o).metadata();
70
+ return {
71
+ result: {
72
+ buffer: o,
73
+ width: s.width ?? 0,
74
+ height: s.height ?? 0,
75
+ iccApplied: !!s.icc,
76
+ converter: "sips"
77
+ },
78
+ error: null
79
+ };
80
+ } finally {
81
+ await g.rm(n, { force: !0 });
82
+ }
83
+ }
84
+ async function G(t, r = {}) {
85
+ const a = r.quality ?? C, n = r.maxInputBytes ?? P, o = r.maxDecodePixels ?? D;
86
+ await M(t, n);
87
+ const s = typeof t == "string" ? await g.readFile(t) : t;
88
+ W(s, o);
89
+ const { default: e } = await import("heic-decode"), { width: i, height: l, data: d } = await e({ buffer: s }), y = rt(s), m = y !== null && y.length <= K ? y : null, c = Z(s);
90
+ let f = await L(Buffer.from(d.buffer, d.byteOffset, d.byteLength), {
91
+ raw: { width: i, height: l, channels: 4 }
92
+ }).removeAlpha().jpeg({ quality: a }).toBuffer();
93
+ return m && (f = Q(f, m)), c && (f = j(f, c)), {
94
+ buffer: f,
95
+ width: i,
96
+ height: l,
97
+ iccApplied: m !== null,
98
+ converter: "node"
99
+ };
100
+ }
101
+ function W(t, r) {
102
+ let a = null;
103
+ try {
104
+ const n = E(t, 0, t.length, "meta");
105
+ if (!n) return;
106
+ const o = E(t, n.bodyStart + 4, n.bodyEnd, "iprp");
107
+ if (!o) return;
108
+ const s = E(t, o.bodyStart, o.bodyEnd, "ipco");
109
+ if (!s) return;
110
+ for (const e of b(t, s.bodyStart, s.bodyEnd)) {
111
+ if (e.type !== "ispe" || e.bodyEnd - e.bodyStart < 12) continue;
112
+ const i = t.readUInt32BE(e.bodyStart + 4), l = t.readUInt32BE(e.bodyStart + 8);
113
+ if (i * l > r) {
114
+ a = { width: i, height: l };
115
+ break;
116
+ }
117
+ }
118
+ } catch {
119
+ return;
120
+ }
121
+ if (a)
122
+ throw new Error(
123
+ `HEIF declares an image of ${a.width}x${a.height} pixels, exceeding the ${r}-pixel decode limit (maxDecodePixels)`
124
+ );
125
+ }
126
+ const U = Buffer.from("ICC_PROFILE\0", "latin1"), x = 65533 - U.length - 1 - 1, K = 255 * x;
127
+ function Q(t, r) {
128
+ if (t.length < 2 || t[0] !== 255 || t[1] !== 216)
129
+ throw new Error("Expected a JPEG buffer starting with the SOI marker");
130
+ const a = Math.max(1, Math.ceil(r.length / x)), n = [];
131
+ for (let o = 0; o < a; o++) {
132
+ const s = r.subarray(o * x, (o + 1) * x), e = 2 + U.length + 1 + 1 + s.length, i = Buffer.alloc(4 + U.length + 2);
133
+ 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);
134
+ }
135
+ return Buffer.concat([t.subarray(0, 2), ...n, t.subarray(2)]);
136
+ }
137
+ const _ = Buffer.from("Exif\0\0", "latin1");
138
+ function j(t, r) {
139
+ if (t.length < 2 || t[0] !== 255 || t[1] !== 216)
140
+ throw new Error("Expected a JPEG buffer starting with the SOI marker");
141
+ const a = 2 + _.length + r.length;
142
+ if (a > 65535) return t;
143
+ const n = Buffer.alloc(4 + _.length);
144
+ return n.writeUInt8(255, 0), n.writeUInt8(225, 1), n.writeUInt16BE(a, 2), _.copy(n, 4), Buffer.concat([t.subarray(0, 2), n, r, t.subarray(2)]);
145
+ }
146
+ function Z(t) {
147
+ try {
148
+ const r = E(t, 0, t.length, "meta");
149
+ if (!r) return null;
150
+ const a = r.bodyStart + 4, n = tt(t, a, r.bodyEnd);
151
+ if (n === null) return null;
152
+ const o = et(t, a, r.bodyEnd, n);
153
+ if (!o || o.length < 12 || o.offset + o.length > t.length) return null;
154
+ const s = t.subarray(o.offset, o.offset + o.length), e = 4 + s.readUInt32BE(0);
155
+ if (e >= s.length - 8) return null;
156
+ const i = s.toString("latin1", e, e + 2);
157
+ return i !== "II" && i !== "MM" ? null : nt(s.subarray(e));
158
+ } catch {
159
+ return null;
160
+ }
161
+ }
162
+ function tt(t, r, a) {
163
+ const n = E(t, r, a, "iinf");
164
+ if (!n) return null;
165
+ const o = t.readUInt8(n.bodyStart), s = n.bodyStart + 4 + (o === 0 ? 2 : 4);
166
+ for (const e of b(t, s, n.bodyEnd)) {
167
+ if (e.type !== "infe") continue;
168
+ const i = t.readUInt8(e.bodyStart);
169
+ if (i < 2) continue;
170
+ 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;
171
+ if (t.toString("latin1", y, y + 4) === "Exif") return d;
172
+ }
173
+ return null;
174
+ }
175
+ function et(t, r, a, n) {
176
+ const o = E(t, r, a, "iloc");
177
+ if (!o) return null;
178
+ const s = t.readUInt8(o.bodyStart);
179
+ let e = o.bodyStart + 4;
180
+ const i = t.readUInt16BE(e);
181
+ e += 2;
182
+ const l = i >> 12 & 15, d = i >> 8 & 15, y = i >> 4 & 15, m = s >= 1 ? i & 15 : 0, c = (f) => {
183
+ let u;
184
+ return f === 0 ? u = 0 : f === 8 ? u = Number(t.readBigUInt64BE(e)) : u = t.readUIntBE(e, f), e += f, u;
185
+ };
186
+ let h;
187
+ s < 2 ? (h = t.readUInt16BE(e), e += 2) : (h = t.readUInt32BE(e), e += 4);
188
+ for (let f = 0; f < h; f++) {
189
+ let u;
190
+ s < 2 ? (u = t.readUInt16BE(e), e += 2) : (u = t.readUInt32BE(e), e += 4);
191
+ let I = 0;
192
+ s >= 1 && (I = t.readUInt16BE(e) & 15, e += 2);
193
+ const p = t.readUInt16BE(e);
194
+ e += 2;
195
+ const w = c(y), S = t.readUInt16BE(e);
196
+ e += 2;
197
+ let B = null;
198
+ for (let T = 0; T < S; T++) {
199
+ m > 0 && c(m);
200
+ const A = c(l), O = c(d);
201
+ T === 0 && (B = { offset: w + A, length: O });
202
+ }
203
+ if (u === n)
204
+ return I !== 0 || p !== 0 || S !== 1 ? null : B;
205
+ }
206
+ return null;
207
+ }
208
+ function nt(t) {
209
+ const r = Buffer.from(t);
210
+ try {
211
+ 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);
212
+ for (let i = 0; i < e; i++) {
213
+ const l = s + 2 + i * 12;
214
+ if (n(l) === 274) {
215
+ a ? r.writeUInt16LE(1, l + 8) : r.writeUInt16BE(1, l + 8);
216
+ break;
217
+ }
218
+ }
219
+ } catch {
220
+ }
221
+ return r;
222
+ }
223
+ function* b(t, r, a) {
224
+ let n = r;
225
+ for (; n + 8 <= a; ) {
226
+ let o = t.readUInt32BE(n);
227
+ const s = t.toString("latin1", n + 4, n + 8);
228
+ let e = 8;
229
+ if (o === 1) {
230
+ if (n + 16 > a) break;
231
+ o = Number(t.readBigUInt64BE(n + 8)), e = 16;
232
+ } else o === 0 && (o = a - n);
233
+ if (o < e || n + o > a) break;
234
+ yield { type: s, start: n, header: e, size: o, bodyStart: n + e, bodyEnd: n + o }, n += o;
235
+ }
236
+ }
237
+ function E(t, r, a, n) {
238
+ for (const o of b(t, r, a))
239
+ if (o.type === n) return o;
240
+ return null;
241
+ }
242
+ function rt(t) {
243
+ try {
244
+ const r = E(t, 0, t.length, "meta");
245
+ if (!r) return null;
246
+ const a = r.bodyStart + 4, n = E(t, a, r.bodyEnd, "pitm");
247
+ if (!n) return null;
248
+ const s = t.readUInt8(n.bodyStart) === 0 ? t.readUInt16BE(n.bodyStart + 4) : t.readUInt32BE(n.bodyStart + 4), e = E(t, a, r.bodyEnd, "iprp");
249
+ if (!e) return null;
250
+ const i = E(t, e.bodyStart, e.bodyEnd, "ipco");
251
+ if (!i) return null;
252
+ const l = [...b(t, i.bodyStart, i.bodyEnd)], d = E(t, e.bodyStart, e.bodyEnd, "ipma");
253
+ if (!d) return null;
254
+ const y = t.readUInt8(d.bodyStart), m = t.readUIntBE(d.bodyStart + 1, 3);
255
+ let c = d.bodyStart + 4;
256
+ const h = t.readUInt32BE(c);
257
+ c += 4;
258
+ let f = null;
259
+ for (let u = 0; u < h; u++) {
260
+ const I = y < 1 ? t.readUInt16BE(c) : t.readUInt32BE(c);
261
+ c += y < 1 ? 2 : 4;
262
+ const p = t.readUInt8(c);
263
+ c += 1;
264
+ const w = [];
265
+ for (let S = 0; S < p; S++) {
266
+ let B;
267
+ m & 1 ? (B = t.readUInt16BE(c) & 32767, c += 2) : (B = t.readUInt8(c) & 127, c += 1), w.push(B);
268
+ }
269
+ I === s && (f = w);
270
+ }
271
+ if (!f) return null;
272
+ for (const u of f) {
273
+ const I = l[u - 1];
274
+ if (I && I.type === "colr") {
275
+ const p = t.toString("latin1", I.bodyStart, I.bodyStart + 4);
276
+ if (p === "prof" || p === "rICC")
277
+ return t.subarray(I.bodyStart + 4, I.bodyEnd);
278
+ }
279
+ }
280
+ return null;
281
+ } catch {
282
+ return null;
283
+ }
284
+ }
285
+ export {
286
+ G as a,
287
+ rt as b,
288
+ dt as c,
289
+ R as d,
290
+ Z as e,
291
+ X as i,
292
+ J as r
293
+ };
package/dist/index.js CHANGED
@@ -1,16 +1,16 @@
1
- import { D as a, a as o, b as t, c as s, d as E, e as p, I as i, P as n, S as A, V as m, f as T, n as S, p as I, g as _, h as c, s as d } from "./presets-PTxNoMdy.js";
2
- import { convertHeifToJpeg as f, convertHeifToJpegNode as O, extractExifFromHeif as F, extractIccFromHeif as D } from "./heif/index.js";
1
+ import { D as r, a as o, b as t, c as s, d as E, e as p, I as i, P as n, S as A, V as m, f as T, n as S, p as c, g as I, h as _, s as d } from "./presets-DyzR9as-.js";
2
+ import { c as f, a as O, e as F, b as D } from "./index-DWJCvc5O.js";
3
3
  import { generateOgpFromLandscape as N, generateOgpImage as h, generateSmartOgp as u } from "./ogp/index.js";
4
4
  import { encodeUnderByteBudget as L } from "./budget/index.js";
5
5
  import { cropToSquare as P, insetOnSquare as C, padToSquare as M, padToSquareCentered as G, trimPadSquare as R } from "./square/index.js";
6
- import { alphaTrim as H, composeProductPhoto as V, generateShadowLayers as k, removeBackground as v } from "./product-photo/index.js";
7
- import { calibrateTargetFromSamples as b, normalizeBackgroundColor as q, sampleBackgroundColor as y } from "./calibrate/index.js";
6
+ import { alphaTrim as H, composeProductPhoto as V, generateShadowLayers as b, removeBackground as k } from "./product-photo/index.js";
7
+ import { calibrateTargetFromSamples as X, normalizeBackgroundColor as q, sampleBackgroundColor as y } from "./calibrate/index.js";
8
8
  import { compositeBatch as Y, compositeOverlay as J } from "./composite/index.js";
9
9
  import { batchBlurhashToDataUri as z, blurhashToDataUri as K, encodeImageToBlurhash as Q } from "./blurhash/index.js";
10
- import { bakeOrientation as Z, deriveOrientation as $, parseExifDate as ee, pickVariantWidths as re, stripExif as ae } from "./exif/index.js";
10
+ import { bakeOrientation as Z, deriveOrientation as $, parseExifDate as ee, pickVariantWidths as ae, stripExif as re } from "./exif/index.js";
11
11
  import { DEFAULT_MAX_CANVAS_AREA as te, HEIC_DECODE_FAILED_MESSAGE as se, MISSING_EXIFR_MESSAGE as Ee, MISSING_HEIC2ANY_MESSAGE as pe, ORIENTATION_BAKE_FAILED_MESSAGE_PREFIX as ie, deriveGeometry as ne, needsOrientationBake as Ae, prepareImageForUpload as me, roundAspectRatio as Te } from "./browser/index.js";
12
12
  export {
13
- a as DEFAULT_CACHE_FILENAME,
13
+ r as DEFAULT_CACHE_FILENAME,
14
14
  o as DEFAULT_CONCURRENCY,
15
15
  t as DEFAULT_FORMATS,
16
16
  te as DEFAULT_MAX_CANVAS_AREA,
@@ -29,7 +29,7 @@ export {
29
29
  Z as bakeOrientation,
30
30
  z as batchBlurhashToDataUri,
31
31
  K as blurhashToDataUri,
32
- b as calibrateTargetFromSamples,
32
+ X as calibrateTargetFromSamples,
33
33
  V as composeProductPhoto,
34
34
  Y as compositeBatch,
35
35
  J as compositeOverlay,
@@ -45,7 +45,7 @@ export {
45
45
  D as extractIccFromHeif,
46
46
  N as generateOgpFromLandscape,
47
47
  h as generateOgpImage,
48
- k as generateShadowLayers,
48
+ b as generateShadowLayers,
49
49
  u as generateSmartOgp,
50
50
  C as insetOnSquare,
51
51
  Ae as needsOrientationBake,
@@ -54,15 +54,15 @@ export {
54
54
  M as padToSquare,
55
55
  G as padToSquareCentered,
56
56
  ee as parseExifDate,
57
- I as photoVariantsPreset,
58
- re as pickVariantWidths,
57
+ c as photoVariantsPreset,
58
+ ae as pickVariantWidths,
59
59
  me as prepareImageForUpload,
60
- _ as processImages,
61
- c as processOne,
62
- v as removeBackground,
60
+ I as processImages,
61
+ _ as processOne,
62
+ k as removeBackground,
63
63
  Te as roundAspectRatio,
64
64
  y as sampleBackgroundColor,
65
65
  d as selectVariantWidths,
66
- ae as stripExif,
66
+ re as stripExif,
67
67
  R as trimPadSquare
68
68
  };
@@ -3,27 +3,26 @@ import u from "node:path";
3
3
  import j from "sharp";
4
4
  import { encodeImageToBlurhash as it } from "./blurhash/index.js";
5
5
  import { pickVariantWidths as st } from "./exif/index.js";
6
- import { convertHeifToJpeg as ct } from "./heif/index.js";
6
+ import { r as R, i as Y, d as J, c as ct } from "./index-DWJCvc5O.js";
7
7
  import { generateSmartOgp as ut } from "./ogp/index.js";
8
- import { randomUUID as Y } from "node:crypto";
8
+ import { randomUUID as Q } from "node:crypto";
9
9
  import pt from "xxhash-wasm";
10
- import { r as R, i as J, a as Q } from "./run-BIjGA2Fu.js";
11
10
  import { constants as lt } from "node:fs";
12
- import ft from "node:os";
11
+ import ht from "node:os";
13
12
  let v = null;
14
- function ht() {
13
+ function ft() {
15
14
  return v || (v = pt(), v.catch(() => {
16
15
  v = null;
17
16
  })), v;
18
17
  }
19
18
  async function mt(t) {
20
- const [a, e] = await Promise.all([ht(), m.readFile(t)]);
19
+ const [a, e] = await Promise.all([ft(), m.readFile(t)]);
21
20
  return a.h64Raw(e).toString(16);
22
21
  }
23
22
  async function L(t, a) {
24
23
  const e = u.join(
25
24
  u.dirname(t),
26
- `.${u.basename(t)}.${Y()}.tmp`
25
+ `.${u.basename(t)}.${Q()}.tmp`
27
26
  );
28
27
  try {
29
28
  const r = await a(e);
@@ -57,7 +56,7 @@ async function gt(t, a) {
57
56
  try {
58
57
  return await R(t, a), !0;
59
58
  } catch (e) {
60
- return !J(e);
59
+ return !Y(e);
61
60
  }
62
61
  }
63
62
  async function U(t, a) {
@@ -96,10 +95,10 @@ function Nt(t) {
96
95
  async function K(t) {
97
96
  if (!await yt()) return null;
98
97
  try {
99
- const { stdout: a } = await R("file", ["-b", "--mime-type", Q(t)]);
98
+ const { stdout: a } = await R("file", ["-b", "--mime-type", J(t)]);
100
99
  return a.trim();
101
100
  } catch (a) {
102
- return J(a), null;
101
+ return Y(a), null;
103
102
  }
104
103
  }
105
104
  async function Ot(t) {
@@ -131,9 +130,9 @@ async function Pt(t) {
131
130
  }
132
131
  }
133
132
  async function $(t, a, e, r = "jpg") {
134
- const n = u.join(ft.tmpdir(), `zit-repair-${process.pid}-${Y()}.${r}`);
133
+ const n = u.join(ht.tmpdir(), `zit-repair-${process.pid}-${Q()}.${r}`);
135
134
  try {
136
- await R(t, a(Q(e), n));
135
+ await R(t, a(J(e), n));
137
136
  const o = await m.readFile(n);
138
137
  return o.length > 0 && await Pt(o) ? o : null;
139
138
  } catch {
@@ -207,7 +206,7 @@ const jt = (t) => {
207
206
  mode: "full",
208
207
  slug: et(t)
209
208
  }), At = [600, 900, 1200, 1600, 2e3], Ct = 85, kt = ["webp"], Mt = 4, $t = "ogp.jpg", Dt = ".cache.json", Rt = ["jpg", "jpeg", "png", "webp", "heic", "heif", "gif", "avif"], Lt = new RegExp(`\\.(${Rt.join("|")})$`, "i"), Ut = (t, a) => `${t}w.${a}`;
210
- class f extends Error {
209
+ class h extends Error {
211
210
  stage;
212
211
  constructor(a, e) {
213
212
  super(e instanceof Error ? e.message : String(e), { cause: e }), this.name = "VariantProcessingError", this.stage = a;
@@ -318,7 +317,7 @@ async function Jt(t, a, e, r) {
318
317
  r.stripMetadata || w.keepIccProfile();
319
318
  const { size: d } = await L(
320
319
  y,
321
- (h) => qt(w, s, r.quality).toFile(h)
320
+ (f) => qt(w, s, r.quality).toFile(f)
322
321
  );
323
322
  n.push({ width: o, format: s, filename: l, path: y, size: d });
324
323
  }
@@ -367,7 +366,7 @@ async function Kt(t, a, e) {
367
366
  async function Zt(t, a) {
368
367
  const e = at(a), { inputPath: r } = t, { mode: n, slug: o } = t.tag ?? e.tagParser(u.basename(r));
369
368
  if (!Vt(o))
370
- throw new f(
369
+ throw new h(
371
370
  "slug",
372
371
  new Error(`unsafe output slug "${o}" derived from "${u.basename(r)}"`)
373
372
  );
@@ -376,20 +375,20 @@ async function Zt(t, a) {
376
375
  try {
377
376
  d = await mt(r);
378
377
  } catch (i) {
379
- throw new f("io", i);
378
+ throw new h("io", i);
380
379
  }
381
- const h = await dt(y);
382
- if (h && h.hash === d && h.configHash === w && h.mode === n) {
383
- const i = Qt(n, h, r, e);
384
- if (i && Array.isArray(h.outputs) && Xt(i, h.outputs) && await Kt(s, i, h.outputSizes))
385
- return h.metadata && await e.onMetadata?.(h.metadata), {
380
+ const f = await dt(y);
381
+ if (f && f.hash === d && f.configHash === w && f.mode === n) {
382
+ const i = Qt(n, f, r, e);
383
+ if (i && Array.isArray(f.outputs) && Xt(i, f.outputs) && await Kt(s, i, f.outputSizes))
384
+ return f.metadata && await e.onMetadata?.(f.metadata), {
386
385
  ...l,
387
386
  status: "skipped",
388
387
  reason: "cache-hit",
389
- animated: h.animated,
388
+ animated: f.animated,
390
389
  variants: [],
391
390
  ogp: null,
392
- metadata: h.metadata
391
+ metadata: f.metadata
393
392
  };
394
393
  }
395
394
  if (await vt(r))
@@ -397,32 +396,32 @@ async function Zt(t, a) {
397
396
  try {
398
397
  await m.mkdir(s, { recursive: !0 });
399
398
  } catch (i) {
400
- throw new f("io", i);
399
+ throw new h("io", i);
401
400
  }
402
401
  let c = r;
403
402
  if (await Ot(r))
404
403
  try {
405
404
  c = (await ct(r, { quality: 90 })).buffer;
406
405
  } catch (i) {
407
- throw new f("heic", i);
406
+ throw new h("heic", i);
408
407
  }
409
408
  let p;
410
409
  try {
411
410
  const i = await Yt(c, e.autoRepair, e.backupCorrupted);
412
411
  p = i.metadata, c = i.input;
413
412
  } catch (i) {
414
- throw new f("probe", i);
413
+ throw new h("probe", i);
415
414
  }
416
415
  const F = p.autoOrient?.width || p.width || 0, x = p.autoOrient?.height || p.height || 0;
417
416
  if (!F || !x)
418
- throw new f("probe", new Error(`could not determine dimensions for "${o}"`));
417
+ throw new h("probe", new Error(`could not determine dimensions for "${o}"`));
419
418
  const E = Ht(p);
420
419
  if (n === "ogonly") {
421
420
  let i;
422
421
  try {
423
422
  i = await D(c, s, e);
424
423
  } catch (S) {
425
- throw new f("ogp", S);
424
+ throw new h("ogp", S);
426
425
  }
427
426
  return await z(y, {
428
427
  hash: d,
@@ -441,13 +440,13 @@ async function Zt(t, a) {
441
440
  const i = u.join(s, I(r));
442
441
  await L(i, (S) => m.copyFile(r, S)), C = (await m.stat(i)).size;
443
442
  } catch (i) {
444
- throw new f("passthrough", i);
443
+ throw new h("passthrough", i);
445
444
  }
446
445
  if (n === "og")
447
446
  try {
448
447
  b = await D(c, s, e);
449
448
  } catch (i) {
450
- throw new f("ogp", i);
449
+ throw new h("ogp", i);
451
450
  }
452
451
  } else {
453
452
  const i = async (g) => {
@@ -457,7 +456,7 @@ async function Zt(t, a) {
457
456
  try {
458
457
  N = await D(g, s, e);
459
458
  } catch (ot) {
460
- throw new f("ogp", ot);
459
+ throw new h("ogp", ot);
461
460
  }
462
461
  return { blurhash: M, variants: T, ogp: N };
463
462
  };
@@ -465,13 +464,13 @@ async function Zt(t, a) {
465
464
  try {
466
465
  S = await i(c);
467
466
  } catch (g) {
468
- const M = g instanceof f ? g.cause : g, T = e.autoRepair && typeof c == "string" && Z(M) ? await tt(c, { backupCorrupted: e.backupCorrupted }) : null;
467
+ const M = g instanceof h ? g.cause : g, T = e.autoRepair && typeof c == "string" && Z(M) ? await tt(c, { backupCorrupted: e.backupCorrupted }) : null;
469
468
  if (!T)
470
- throw g instanceof f ? g : new f("variants", g);
469
+ throw g instanceof h ? g : new h("variants", g);
471
470
  try {
472
471
  S = await i(T);
473
472
  } catch (N) {
474
- throw N instanceof f ? N : new f("variants", N);
473
+ throw N instanceof h ? N : new h("variants", N);
475
474
  }
476
475
  }
477
476
  ({ blurhash: A, variants: O, ogp: b } = S);
@@ -497,7 +496,7 @@ async function Zt(t, a) {
497
496
  try {
498
497
  await z(y, { hash: d, configHash: w, mode: n, animated: E, outputs: nt, outputSizes: _, metadata: P });
499
498
  } catch (i) {
500
- throw new f("cache", i);
499
+ throw new h("cache", i);
501
500
  }
502
501
  return await e.onMetadata?.(P), { ...l, status: "processed", animated: E, variants: O, ogp: b, metadata: P };
503
502
  }
@@ -549,7 +548,7 @@ async function ae(t, a) {
549
548
  }
550
549
  return e;
551
550
  }
552
- async function de(t) {
551
+ async function we(t) {
553
552
  const a = at(t), e = t.concurrency ?? Mt;
554
553
  if (!Number.isFinite(e) || e < 1)
555
554
  throw new Error(
@@ -596,15 +595,15 @@ async function de(t) {
596
595
  await s({
597
596
  inputPath: c.inputPath,
598
597
  slug: c.tag?.slug ?? u.basename(c.inputPath),
599
- stage: p instanceof f ? p.stage : "unknown",
598
+ stage: p instanceof h ? p.stage : "unknown",
600
599
  error: p instanceof Error ? p.message : String(p)
601
600
  });
602
601
  }
603
602
  });
604
- const h = t.cleanupOrphans && !y ? await ae(a.outputDir, new Set(l.map((c) => c.tag.slug))) : [];
605
- return { results: n, failed: o, removed: h };
603
+ const f = t.cleanupOrphans && !y ? await ae(a.outputDir, new Set(l.map((c) => c.tag.slug))) : [];
604
+ return { results: n, failed: o, removed: f };
606
605
  }
607
- const re = [400, 800, 1600], ge = {
606
+ const re = [400, 800, 1600], de = {
608
607
  widths: re,
609
608
  bakeExifOrientation: !0,
610
609
  stripMetadata: !0,
@@ -615,16 +614,16 @@ export {
615
614
  Lt as I,
616
615
  re as P,
617
616
  Rt as S,
618
- f as V,
617
+ h as V,
619
618
  Mt as a,
620
619
  kt as b,
621
620
  $t as c,
622
621
  Ct as d,
623
622
  At as e,
624
623
  jt as f,
625
- de as g,
624
+ we as g,
626
625
  Zt as h,
627
626
  xt as n,
628
- ge as p,
627
+ de as p,
629
628
  rt as s
630
629
  };
@@ -1,4 +1,4 @@
1
- import { D as E, a as T, b as r, c as A, d as e, e as _, I, P as D, S as o, V as t, f as F, n as L, p as N, g as O, h as P, s as U } from "../presets-PTxNoMdy.js";
1
+ import { D as E, a as T, b as r, c as A, d as e, e as _, I, P as D, S as o, V as t, f as F, n as L, p as N, g as O, h as P, s as U } from "../presets-DyzR9as-.js";
2
2
  export {
3
3
  E as DEFAULT_CACHE_FILENAME,
4
4
  T as DEFAULT_CONCURRENCY,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takazudo/zudo-image-tweaker",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "sharp-based image-tweaking toolkit: variants, HEIF conversion, OGP cards, byte-budget encoding, square crops, product-photo background removal, calibration, compositing, blurhash, EXIF, and browser upload prep.",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -1,22 +0,0 @@
1
- import { execFile as a } from "node:child_process";
2
- import c from "node:path";
3
- import { promisify as u } from "node:util";
4
- const m = u(a), f = 6e4;
5
- async function E(r, t, o = {}) {
6
- const { timeoutMs: i = f, killSignal: n = "SIGKILL" } = o, { stdout: e, stderr: s } = await m(r, t, {
7
- timeout: i,
8
- killSignal: n
9
- });
10
- return { stdout: e, stderr: s };
11
- }
12
- function M(r) {
13
- return c.resolve(r);
14
- }
15
- function T(r) {
16
- return r?.code === "ENOENT";
17
- }
18
- export {
19
- M as a,
20
- T as i,
21
- E as r
22
- };