spatialdata-js-util 0.1.0__py3-none-any.whl
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.
- spatialdata_js_util/__init__.py +107 -0
- spatialdata_js_util/cli.py +803 -0
- spatialdata_js_util/codecs/__init__.py +67 -0
- spatialdata_js_util/codecs/backends.py +250 -0
- spatialdata_js_util/codecs/chunks.py +40 -0
- spatialdata_js_util/codecs/encoding.py +154 -0
- spatialdata_js_util/codecs/htj2k_wasm.py +266 -0
- spatialdata_js_util/codecs/names.py +26 -0
- spatialdata_js_util/codecs/probe/multicomponent.j2c +0 -0
- spatialdata_js_util/codecs/probe/multicomponent.json +3 -0
- spatialdata_js_util/codecs/probe/multicomponent.npy +0 -0
- spatialdata_js_util/codecs/vendor/__init__.py +1 -0
- spatialdata_js_util/codecs/vendor/encode-plane.mjs +164 -0
- spatialdata_js_util/codecs/vendor/openjph/index.mjs +131 -0
- spatialdata_js_util/codecs/vendor/openjph/wasm/libopenjph.mjs +2 -0
- spatialdata_js_util/codecs/vendor/openjph/wasm/libopenjph.wasm +0 -0
- spatialdata_js_util/codecs/vendor/openjph/wasm/libopenjph_simd.mjs +2 -0
- spatialdata_js_util/codecs/vendor/openjph/wasm/libopenjph_simd.wasm +0 -0
- spatialdata_js_util/codecs/zarr_codec.py +149 -0
- spatialdata_js_util/errors.py +5 -0
- spatialdata_js_util/images.py +849 -0
- spatialdata_js_util/index_permutations.py +311 -0
- spatialdata_js_util/points.py +445 -0
- spatialdata_js_util/points_zarr.py +799 -0
- spatialdata_js_util/provenance.py +17 -0
- spatialdata_js_util/pyramids.py +318 -0
- spatialdata_js_util/runners.py +458 -0
- spatialdata_js_util/store.py +305 -0
- spatialdata_js_util/tables.py +310 -0
- spatialdata_js_util/tui/__init__.py +0 -0
- spatialdata_js_util/tui/app.py +112 -0
- spatialdata_js_util/tui/models.py +45 -0
- spatialdata_js_util/tui/screens.py +1255 -0
- spatialdata_js_util/tui/widgets.py +50 -0
- spatialdata_js_util/verify.py +338 -0
- spatialdata_js_util-0.1.0.dist-info/METADATA +412 -0
- spatialdata_js_util-0.1.0.dist-info/RECORD +40 -0
- spatialdata_js_util-0.1.0.dist-info/WHEEL +5 -0
- spatialdata_js_util-0.1.0.dist-info/entry_points.txt +7 -0
- spatialdata_js_util-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"""The openjph-wasm HTJ2K backend: vendored WASM driven by Node.js workers.
|
|
2
|
+
|
|
3
|
+
This is the same WASM build the JS reader uses, which makes it the reference for
|
|
4
|
+
encode/decode agreement with the browser. Prefer the `backends` module over
|
|
5
|
+
calling this directly — it selects between this and the Node-free `imagecodecs`
|
|
6
|
+
backend.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import atexit
|
|
12
|
+
import base64
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import shutil
|
|
16
|
+
import struct
|
|
17
|
+
import subprocess
|
|
18
|
+
import threading
|
|
19
|
+
from functools import lru_cache
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
import numpy as np
|
|
24
|
+
|
|
25
|
+
_VENDOR_DIR = Path(__file__).resolve().parent / "vendor"
|
|
26
|
+
_ENCODE_SCRIPT = _VENDOR_DIR / "encode-plane.mjs"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def encode_script_path() -> Path:
|
|
30
|
+
return _ENCODE_SCRIPT
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def openjph_vendor_dir() -> Path:
|
|
34
|
+
return _VENDOR_DIR / "openjph"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def openjph_encode_options(encode_options: dict[str, Any]) -> tuple[bool, float]:
|
|
38
|
+
"""Map encode options to OpenJPH WASM setQuality(reversible, quality)."""
|
|
39
|
+
reversible = bool(encode_options.get("reversible", True))
|
|
40
|
+
if reversible:
|
|
41
|
+
return True, 0.0
|
|
42
|
+
quality = encode_options.get("quality", encode_options.get("level", 0.0002))
|
|
43
|
+
return False, float(quality)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _encode_request_payload(
|
|
47
|
+
volume: np.ndarray, *, reversible: bool, quality: float
|
|
48
|
+
) -> dict[str, Any]:
|
|
49
|
+
"""Build an encode request for a 2D plane or a 3D (components, y, x) volume.
|
|
50
|
+
|
|
51
|
+
The samples are sent planar / component-major (C-order of the array), which
|
|
52
|
+
is exactly the layout openjph-wasm expects for multi-component codestreams.
|
|
53
|
+
"""
|
|
54
|
+
array = np.ascontiguousarray(np.asarray(volume))
|
|
55
|
+
if array.ndim == 2:
|
|
56
|
+
components, (height, width) = 1, (int(array.shape[0]), int(array.shape[1]))
|
|
57
|
+
elif array.ndim == 3:
|
|
58
|
+
components, height, width = (int(value) for value in array.shape)
|
|
59
|
+
else:
|
|
60
|
+
raise ValueError(
|
|
61
|
+
f"HTJ2K encode expects a 2D plane or 3D (components, y, x) volume, got shape {array.shape}."
|
|
62
|
+
)
|
|
63
|
+
return {
|
|
64
|
+
"width": width,
|
|
65
|
+
"height": height,
|
|
66
|
+
"components": components,
|
|
67
|
+
"dtype": array.dtype.name,
|
|
68
|
+
"reversible": reversible,
|
|
69
|
+
"quality": quality,
|
|
70
|
+
"plane": base64.b64encode(array.tobytes(order="C")).decode("ascii"),
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# Decode response header (see vendor/encode-plane.mjs): little-endian
|
|
75
|
+
# u32 components, u32 height, u32 width, u8 bytesPerSample, u8 isSigned.
|
|
76
|
+
_DECODE_HEADER = struct.Struct("<IIIBB")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _decode_response_to_array(resp: bytes) -> np.ndarray:
|
|
80
|
+
components, height, width, bytes_per_sample, is_signed = _DECODE_HEADER.unpack_from(resp, 0)
|
|
81
|
+
body = resp[_DECODE_HEADER.size :]
|
|
82
|
+
dtype = np.dtype(f"{'i' if is_signed else 'u'}{bytes_per_sample}")
|
|
83
|
+
return np.frombuffer(body, dtype=dtype).reshape(components, height, width)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class OpenJphEncoderWorker:
|
|
87
|
+
"""Long-lived Node subprocess that loads OpenJPH WASM once."""
|
|
88
|
+
|
|
89
|
+
def __init__(self) -> None:
|
|
90
|
+
node = shutil.which("node")
|
|
91
|
+
if node is None:
|
|
92
|
+
raise RuntimeError("Node.js is required for HTJ2K encode but was not found on PATH.")
|
|
93
|
+
if not _ENCODE_SCRIPT.is_file():
|
|
94
|
+
raise RuntimeError(f"HTJ2K encode script not found: {_ENCODE_SCRIPT}")
|
|
95
|
+
vendor_dir = openjph_vendor_dir()
|
|
96
|
+
missing = [
|
|
97
|
+
str(path.relative_to(vendor_dir))
|
|
98
|
+
for path in (vendor_dir / "index.mjs", vendor_dir / "wasm" / "libopenjph.wasm")
|
|
99
|
+
if not path.is_file()
|
|
100
|
+
]
|
|
101
|
+
if missing:
|
|
102
|
+
raise RuntimeError(
|
|
103
|
+
f"Vendored openjph-wasm assets missing under {vendor_dir}: {', '.join(missing)}. "
|
|
104
|
+
"Both index.mjs and wasm/libopenjph.wasm are required; "
|
|
105
|
+
"run scripts/vendor-openjph-for-python.mjs before building the package."
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
self._lock = threading.Lock()
|
|
109
|
+
self._proc = subprocess.Popen(
|
|
110
|
+
[node, str(_ENCODE_SCRIPT), "--worker"],
|
|
111
|
+
stdin=subprocess.PIPE,
|
|
112
|
+
stdout=subprocess.PIPE,
|
|
113
|
+
stderr=subprocess.DEVNULL,
|
|
114
|
+
bufsize=0,
|
|
115
|
+
)
|
|
116
|
+
if self._proc.stdin is None or self._proc.stdout is None:
|
|
117
|
+
raise RuntimeError("Failed to open pipes for HTJ2K encoder worker.")
|
|
118
|
+
|
|
119
|
+
def close(self) -> None:
|
|
120
|
+
with self._lock:
|
|
121
|
+
assert(self._proc)
|
|
122
|
+
if self._proc.stdin is not None:
|
|
123
|
+
self._proc.stdin.close()
|
|
124
|
+
if self._proc.poll() is None:
|
|
125
|
+
self._proc.wait(timeout=5)
|
|
126
|
+
if self._proc.poll() is None:
|
|
127
|
+
self._proc.terminate()
|
|
128
|
+
self._proc.wait(timeout=5)
|
|
129
|
+
if self._proc.poll() is None:
|
|
130
|
+
self._proc.kill()
|
|
131
|
+
self._proc = None # type: ignore[assignment]
|
|
132
|
+
|
|
133
|
+
def _request(self, payload: dict[str, Any]) -> bytes:
|
|
134
|
+
with self._lock:
|
|
135
|
+
if self._proc is None or self._proc.poll() is not None:
|
|
136
|
+
raise RuntimeError("HTJ2K worker is not running.")
|
|
137
|
+
body = json.dumps(payload).encode("utf-8")
|
|
138
|
+
assert self._proc.stdin is not None
|
|
139
|
+
assert self._proc.stdout is not None
|
|
140
|
+
self._proc.stdin.write(struct.pack(">I", len(body)))
|
|
141
|
+
self._proc.stdin.write(body)
|
|
142
|
+
self._proc.stdin.flush()
|
|
143
|
+
|
|
144
|
+
header = self._read_exact(self._proc.stdout, 5)
|
|
145
|
+
status = header[0]
|
|
146
|
+
length = struct.unpack(">I", header[1:5])[0]
|
|
147
|
+
resp = self._read_exact(self._proc.stdout, length)
|
|
148
|
+
if status != 0:
|
|
149
|
+
message = resp.decode("utf-8", errors="replace")
|
|
150
|
+
raise RuntimeError(message or "HTJ2K worker failed.")
|
|
151
|
+
return bytes(resp)
|
|
152
|
+
|
|
153
|
+
def encode(self, volume: np.ndarray, *, reversible: bool = True, quality: float = 0.0) -> bytes:
|
|
154
|
+
return self._request(
|
|
155
|
+
_encode_request_payload(volume, reversible=reversible, quality=quality)
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
def decode(self, codestream: bytes | bytearray) -> np.ndarray:
|
|
159
|
+
payload = {
|
|
160
|
+
"op": "decode",
|
|
161
|
+
"codestream": base64.b64encode(bytes(codestream)).decode("ascii"),
|
|
162
|
+
}
|
|
163
|
+
return _decode_response_to_array(self._request(payload))
|
|
164
|
+
|
|
165
|
+
@staticmethod
|
|
166
|
+
def _read_exact(stream: Any, length: int) -> bytes:
|
|
167
|
+
chunks: list[bytes] = []
|
|
168
|
+
received = 0
|
|
169
|
+
while received < length:
|
|
170
|
+
chunk = stream.read(length - received)
|
|
171
|
+
if not chunk:
|
|
172
|
+
raise RuntimeError("HTJ2K encoder worker closed stdout unexpectedly.")
|
|
173
|
+
chunks.append(chunk)
|
|
174
|
+
received += len(chunk)
|
|
175
|
+
return b"".join(chunks)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class EncoderPool:
|
|
179
|
+
"""Pool of persistent OpenJPH encoder workers."""
|
|
180
|
+
|
|
181
|
+
def __init__(self, workers: int | None = None) -> None:
|
|
182
|
+
count = workers if workers is not None else (os.cpu_count() or 1)
|
|
183
|
+
self._workers = [OpenJphEncoderWorker() for _ in range(max(1, count))]
|
|
184
|
+
self._next = 0
|
|
185
|
+
self._lock = threading.Lock()
|
|
186
|
+
|
|
187
|
+
def _next_worker(self) -> OpenJphEncoderWorker:
|
|
188
|
+
with self._lock:
|
|
189
|
+
worker = self._workers[self._next]
|
|
190
|
+
self._next = (self._next + 1) % len(self._workers)
|
|
191
|
+
return worker
|
|
192
|
+
|
|
193
|
+
def encode(self, volume: np.ndarray, *, reversible: bool = True, quality: float = 0.0) -> bytes:
|
|
194
|
+
return self._next_worker().encode(volume, reversible=reversible, quality=quality)
|
|
195
|
+
|
|
196
|
+
def decode(self, codestream: bytes | bytearray) -> np.ndarray:
|
|
197
|
+
return self._next_worker().decode(codestream)
|
|
198
|
+
|
|
199
|
+
def close(self) -> None:
|
|
200
|
+
for worker in self._workers:
|
|
201
|
+
worker.close()
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
_pool: EncoderPool | None = None
|
|
205
|
+
_pool_lock = threading.Lock()
|
|
206
|
+
_pool_workers: int | None = None
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def configure_encoder_pool(workers: int | None = None) -> None:
|
|
210
|
+
"""Configure or replace the global HTJ2K encoder worker pool."""
|
|
211
|
+
global _pool, _pool_workers
|
|
212
|
+
with _pool_lock:
|
|
213
|
+
if _pool is not None:
|
|
214
|
+
_pool.close()
|
|
215
|
+
_pool = None
|
|
216
|
+
_pool_workers = workers
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def get_encoder_pool(workers: int | None = None) -> EncoderPool:
|
|
220
|
+
global _pool, _pool_workers
|
|
221
|
+
with _pool_lock:
|
|
222
|
+
effective_workers = workers if workers is not None else _pool_workers
|
|
223
|
+
if _pool is None or (workers is not None and workers != _pool_workers):
|
|
224
|
+
if _pool is not None:
|
|
225
|
+
_pool.close()
|
|
226
|
+
_pool_workers = effective_workers
|
|
227
|
+
_pool = EncoderPool(workers=effective_workers)
|
|
228
|
+
return _pool
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def shutdown_encoder_pool() -> None:
|
|
232
|
+
global _pool, _pool_workers
|
|
233
|
+
with _pool_lock:
|
|
234
|
+
if _pool is not None:
|
|
235
|
+
_pool.close()
|
|
236
|
+
_pool = None
|
|
237
|
+
_pool_workers = None
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
atexit.register(shutdown_encoder_pool)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
@lru_cache(maxsize=1)
|
|
244
|
+
def wasm_encode_available() -> bool:
|
|
245
|
+
"""Return whether the vendored OpenJPH WASM helper (and Node.js) is usable."""
|
|
246
|
+
try:
|
|
247
|
+
plane = np.zeros((4, 4), dtype=np.uint16)
|
|
248
|
+
encode_htj2k_wasm(plane, reversible=True, quality=0.0)
|
|
249
|
+
except Exception:
|
|
250
|
+
return False
|
|
251
|
+
return True
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def encode_htj2k_wasm(
|
|
255
|
+
volume: np.ndarray,
|
|
256
|
+
*,
|
|
257
|
+
reversible: bool = True,
|
|
258
|
+
quality: float = 0.0,
|
|
259
|
+
) -> bytes:
|
|
260
|
+
"""Encode a 2D plane or 3D (components, y, x) volume to an HTJ2K codestream."""
|
|
261
|
+
return get_encoder_pool().encode(volume, reversible=reversible, quality=quality)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def decode_htj2k_wasm(codestream: bytes | bytearray) -> np.ndarray:
|
|
265
|
+
"""Decode an HTJ2K codestream to a (components, y, x) array via openjph-wasm."""
|
|
266
|
+
return get_encoder_pool().decode(codestream)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Codec identifiers shared by the writer, the reader shim, and the JS runtime.
|
|
2
|
+
|
|
3
|
+
These strings are the `name` field of the zarr v3 array metadata `codecs` entry,
|
|
4
|
+
so they are part of the on-disk contract. They must stay in sync with
|
|
5
|
+
`packages/zarrextra/src/codecs.ts`.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Literal
|
|
11
|
+
|
|
12
|
+
CODEC_JPEG2K = "imagecodecs_jpeg2k"
|
|
13
|
+
CODEC_HTJ2K_OPENJPH = "experimental.openjph_htj2k"
|
|
14
|
+
# Legacy label for stores written before OpenJPH became the supported encoder.
|
|
15
|
+
CODEC_HTJ2K_LEGACY = "experimental.imagecodecs_htj2k"
|
|
16
|
+
|
|
17
|
+
HTJ2K_CODECS = frozenset({CODEC_HTJ2K_OPENJPH, CODEC_HTJ2K_LEGACY})
|
|
18
|
+
SUPPORTED_IMAGE_CODECS = frozenset({CODEC_JPEG2K, CODEC_HTJ2K_OPENJPH})
|
|
19
|
+
|
|
20
|
+
HTJ2K_ENCODER = "openjph"
|
|
21
|
+
|
|
22
|
+
CodecName = Literal["imagecodecs_jpeg2k", "experimental.openjph_htj2k"]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def is_htj2k_codec(codec: str) -> bool:
|
|
26
|
+
return codec in HTJ2K_CODECS
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Vendored OpenJPH WASM assets and Node encode driver."""
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Encode/decode HTJ2K chunks via vendored openjph-wasm.
|
|
5
|
+
*
|
|
6
|
+
* A chunk is one or more planar, component-major planes (e.g. z-planes of a
|
|
7
|
+
* volumetric chunk) encoded as a single multi-component codestream.
|
|
8
|
+
*
|
|
9
|
+
* One-shot mode (default): encode only.
|
|
10
|
+
* stdin: JSON { width, height, components?, dtype, reversible?, quality?, plane: base64 }
|
|
11
|
+
* stdout: raw HTJ2K bytes
|
|
12
|
+
*
|
|
13
|
+
* Worker mode (--worker):
|
|
14
|
+
* Repeated length-prefixed requests on stdin; length-prefixed responses on stdout.
|
|
15
|
+
* Request: [u32 BE length][JSON utf8]
|
|
16
|
+
* encode (default): { width, height, components?, dtype, reversible?, quality?, plane: base64 }
|
|
17
|
+
* decode: { op: "decode", codestream: base64 }
|
|
18
|
+
* Response: [u8 status][u32 BE length][payload]
|
|
19
|
+
* status 0 = payload (encode: HTJ2K bytes; decode: 14-byte header + planar samples)
|
|
20
|
+
* status 1 = UTF-8 error message
|
|
21
|
+
*
|
|
22
|
+
* Decode header (little-endian): u32 components, u32 height, u32 width,
|
|
23
|
+
* u8 bytesPerSample, u8 isSigned — followed by the raw component-major samples.
|
|
24
|
+
*/
|
|
25
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
26
|
+
|
|
27
|
+
const vendorDir = dirname(fileURLToPath(import.meta.url));
|
|
28
|
+
const openjphIndex = join(vendorDir, 'openjph', 'index.mjs');
|
|
29
|
+
const workerMode = process.argv.includes('--worker');
|
|
30
|
+
|
|
31
|
+
async function readStdin() {
|
|
32
|
+
const chunks = [];
|
|
33
|
+
for await (const chunk of process.stdin) {
|
|
34
|
+
chunks.push(chunk);
|
|
35
|
+
}
|
|
36
|
+
return Buffer.concat(chunks);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function planeArrayForDtype(dtype, bytes) {
|
|
40
|
+
switch (dtype) {
|
|
41
|
+
case 'uint8':
|
|
42
|
+
return new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
43
|
+
case 'int8':
|
|
44
|
+
return new Int8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
45
|
+
case 'uint16':
|
|
46
|
+
return new Uint16Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 2);
|
|
47
|
+
case 'int16':
|
|
48
|
+
return new Int16Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 2);
|
|
49
|
+
default:
|
|
50
|
+
throw new Error(`Unsupported plane dtype '${dtype}'.`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function loadRuntime() {
|
|
55
|
+
const mod = await import(pathToFileURL(openjphIndex).href);
|
|
56
|
+
if (typeof mod.encode !== 'function' || typeof mod.decode !== 'function') {
|
|
57
|
+
throw new Error('Vendored openjph-wasm does not expose encode()/decode().');
|
|
58
|
+
}
|
|
59
|
+
return mod;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function encodeChunk(runtime, request) {
|
|
63
|
+
const { width, height, dtype } = request;
|
|
64
|
+
const components = request.components ?? 1;
|
|
65
|
+
const reversible = request.reversible ?? true;
|
|
66
|
+
const quality = request.quality ?? 0;
|
|
67
|
+
const planeBytes = Buffer.from(request.plane, 'base64');
|
|
68
|
+
const data = planeArrayForDtype(dtype, planeBytes);
|
|
69
|
+
const expectedValues = width * height * components;
|
|
70
|
+
if (data.length !== expectedValues) {
|
|
71
|
+
throw new Error(`Chunk has ${data.length} samples, expected ${expectedValues}.`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// bitDepth / isSigned are inferred from the typed array by openjph-wasm.
|
|
75
|
+
const input = { data, width, height, components, reversible };
|
|
76
|
+
if (!reversible) {
|
|
77
|
+
input.quality = quality;
|
|
78
|
+
}
|
|
79
|
+
return await runtime.encode(input);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function decodeChunk(runtime, request) {
|
|
83
|
+
const codestream = Buffer.from(request.codestream, 'base64');
|
|
84
|
+
const result = await runtime.decode(new Uint8Array(codestream));
|
|
85
|
+
const samples = result.data;
|
|
86
|
+
const bytesPerSample = samples.BYTES_PER_ELEMENT;
|
|
87
|
+
const header = Buffer.alloc(14);
|
|
88
|
+
header.writeUInt32LE(result.components, 0);
|
|
89
|
+
header.writeUInt32LE(result.height, 4);
|
|
90
|
+
header.writeUInt32LE(result.width, 8);
|
|
91
|
+
header.writeUInt8(bytesPerSample, 12);
|
|
92
|
+
header.writeUInt8(result.isSigned ? 1 : 0, 13);
|
|
93
|
+
const body = Buffer.from(samples.buffer, samples.byteOffset, samples.byteLength);
|
|
94
|
+
return Buffer.concat([header, body]);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function handleRequest(runtime, request) {
|
|
98
|
+
return request.op === 'decode'
|
|
99
|
+
? await decodeChunk(runtime, request)
|
|
100
|
+
: await encodeChunk(runtime, request);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function writeResponse(status, payload) {
|
|
104
|
+
const header = Buffer.alloc(5);
|
|
105
|
+
header.writeUInt8(status, 0);
|
|
106
|
+
header.writeUInt32BE(payload.length, 1);
|
|
107
|
+
process.stdout.write(header);
|
|
108
|
+
if (payload.length > 0) {
|
|
109
|
+
process.stdout.write(payload);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function* readLengthPrefixedJson(stream) {
|
|
114
|
+
let buffer = Buffer.alloc(0);
|
|
115
|
+
for await (const chunk of stream) {
|
|
116
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
117
|
+
while (buffer.length >= 4) {
|
|
118
|
+
const length = buffer.readUInt32BE(0);
|
|
119
|
+
if (buffer.length < 4 + length) {
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
const body = buffer.subarray(4, 4 + length);
|
|
123
|
+
buffer = buffer.subarray(4 + length);
|
|
124
|
+
yield JSON.parse(body.toString('utf8'));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function runWorker(runtime) {
|
|
130
|
+
for await (const request of readLengthPrefixedJson(process.stdin)) {
|
|
131
|
+
try {
|
|
132
|
+
const payload = await handleRequest(runtime, request);
|
|
133
|
+
writeResponse(0, Buffer.from(payload));
|
|
134
|
+
} catch (error) {
|
|
135
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
136
|
+
writeResponse(1, Buffer.from(message, 'utf8'));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function runOnce(runtime) {
|
|
142
|
+
const request = JSON.parse((await readStdin()).toString('utf8'));
|
|
143
|
+
const encoded = await encodeChunk(runtime, request);
|
|
144
|
+
process.stdout.write(Buffer.from(encoded));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function main() {
|
|
148
|
+
const runtime = await loadRuntime();
|
|
149
|
+
if (workerMode) {
|
|
150
|
+
await runWorker(runtime);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
await runOnce(runtime);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
main().catch((error) => {
|
|
157
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
158
|
+
if (workerMode) {
|
|
159
|
+
writeResponse(1, Buffer.from(message, 'utf8'));
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
process.stderr.write(`${message}\n`);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// openjph-wasm: typed wrapper around the OpenJPH Emscripten module.
|
|
2
|
+
// Provides multi-component HTJ2K (JPEG 2000 Part 15) encode + decode.
|
|
3
|
+
let modPromise;
|
|
4
|
+
async function loadModule(options = {}) {
|
|
5
|
+
if (options.moduleFactory)
|
|
6
|
+
return options.moduleFactory();
|
|
7
|
+
const url = new URL("./wasm/libopenjph.mjs", import.meta.url).href;
|
|
8
|
+
const imported = await import(/* @vite-ignore */ url);
|
|
9
|
+
const factory = imported.default ?? imported;
|
|
10
|
+
return factory(options.locateFile ? { locateFile: options.locateFile } : {});
|
|
11
|
+
}
|
|
12
|
+
/** Initialise (and cache) the underlying WASM module. */
|
|
13
|
+
export function init(options) {
|
|
14
|
+
modPromise ??= loadModule(options);
|
|
15
|
+
return modPromise;
|
|
16
|
+
}
|
|
17
|
+
function dtypeOf(view) {
|
|
18
|
+
if (view instanceof Uint8Array || view instanceof Uint8ClampedArray)
|
|
19
|
+
return { bitDepth: 8, isSigned: false };
|
|
20
|
+
if (view instanceof Int8Array)
|
|
21
|
+
return { bitDepth: 8, isSigned: true };
|
|
22
|
+
if (view instanceof Uint16Array)
|
|
23
|
+
return { bitDepth: 16, isSigned: false };
|
|
24
|
+
if (view instanceof Int16Array)
|
|
25
|
+
return { bitDepth: 16, isSigned: true };
|
|
26
|
+
if (view instanceof Int32Array)
|
|
27
|
+
return { bitDepth: 32, isSigned: true };
|
|
28
|
+
throw new Error("openjph-wasm: unsupported typed array for encode input");
|
|
29
|
+
}
|
|
30
|
+
function outputArray(bitDepth, isSigned, n) {
|
|
31
|
+
if (bitDepth <= 8)
|
|
32
|
+
return isSigned ? new Int8Array(n) : new Uint8Array(n);
|
|
33
|
+
if (bitDepth <= 16)
|
|
34
|
+
return isSigned ? new Int16Array(n) : new Uint16Array(n);
|
|
35
|
+
return new Int32Array(n);
|
|
36
|
+
}
|
|
37
|
+
/** Decode a J2K/HTJ2K codestream into planar, component-major samples. */
|
|
38
|
+
export async function decode(codestream, options) {
|
|
39
|
+
const mod = await init(options);
|
|
40
|
+
const create = mod.cwrap("create_j2c_data", "number", []);
|
|
41
|
+
const initData = mod.cwrap("init_j2c_data", null, ["number", "number", "number"]);
|
|
42
|
+
const numComps = mod.cwrap("get_j2c_num_components", "number", ["number"]);
|
|
43
|
+
const getW = mod.cwrap("get_j2c_width", "number", ["number", "number"]);
|
|
44
|
+
const getH = mod.cwrap("get_j2c_height", "number", ["number", "number"]);
|
|
45
|
+
const getBD = mod.cwrap("get_j2c_bit_depth", "number", ["number", "number"]);
|
|
46
|
+
const getSigned = mod.cwrap("get_j2c_is_signed", "number", ["number", "number"]);
|
|
47
|
+
const parse = mod.cwrap("parse_j2c_data", null, ["number"]);
|
|
48
|
+
const pull = mod.cwrap("pull_j2c_line", "number", ["number"]);
|
|
49
|
+
const currComp = mod.cwrap("get_curr_comp", "number", ["number"]);
|
|
50
|
+
const release = mod.cwrap("release_j2c_data", null, ["number"]);
|
|
51
|
+
const inPtr = mod._malloc(codestream.length);
|
|
52
|
+
mod.HEAPU8.set(codestream, inPtr);
|
|
53
|
+
const j2c = create();
|
|
54
|
+
try {
|
|
55
|
+
initData(j2c, inPtr, codestream.length);
|
|
56
|
+
const components = numComps(j2c);
|
|
57
|
+
if (components <= 0)
|
|
58
|
+
throw new Error("openjph-wasm: failed to parse codestream headers");
|
|
59
|
+
const width = getW(j2c, 0);
|
|
60
|
+
const height = getH(j2c, 0);
|
|
61
|
+
const bitDepth = getBD(j2c, 0);
|
|
62
|
+
const isSigned = getSigned(j2c, 0) === 1;
|
|
63
|
+
parse(j2c);
|
|
64
|
+
const out = outputArray(bitDepth, isSigned, components * width * height);
|
|
65
|
+
const rowPerComp = new Int32Array(components);
|
|
66
|
+
const totalLines = components * height;
|
|
67
|
+
for (let i = 0; i < totalLines; i++) {
|
|
68
|
+
const linePtr = pull(j2c);
|
|
69
|
+
const c = currComp(j2c);
|
|
70
|
+
const row = rowPerComp[c]++;
|
|
71
|
+
const base = (linePtr >> 2); // i32 index into HEAP32
|
|
72
|
+
const dst = (c * height + row) * width;
|
|
73
|
+
for (let x = 0; x < width; x++)
|
|
74
|
+
out[dst + x] = mod.HEAP32[base + x];
|
|
75
|
+
}
|
|
76
|
+
return { width, height, components, bitDepth, isSigned, data: out };
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
release(j2c);
|
|
80
|
+
mod._free(inPtr);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** Encode planar, component-major samples into a J2K/HTJ2K codestream. */
|
|
84
|
+
export async function encode(input, options) {
|
|
85
|
+
const mod = await init(options);
|
|
86
|
+
const { width, height } = input;
|
|
87
|
+
const components = input.components ?? input.data.length / (width * height);
|
|
88
|
+
if (!Number.isInteger(components) || components < 1)
|
|
89
|
+
throw new Error("openjph-wasm: data length is not a multiple of width*height");
|
|
90
|
+
const inferred = dtypeOf(input.data);
|
|
91
|
+
const bitDepth = input.bitDepth ?? inferred.bitDepth;
|
|
92
|
+
const isSigned = input.isSigned ?? inferred.isSigned;
|
|
93
|
+
const reversible = input.reversible ?? true;
|
|
94
|
+
const quality = input.quality ?? 0;
|
|
95
|
+
const decompositions = input.decompositions ?? 5;
|
|
96
|
+
const [bw, bh] = input.blockSize ?? [64, 64];
|
|
97
|
+
const encCreate = mod.cwrap("enc_create", "number", []);
|
|
98
|
+
const encEncode = mod.cwrap("enc_encode", "number", ["number", "number", "number", "number", "number", "number", "number", "number", "number", "number", "number", "number"]);
|
|
99
|
+
const encGetData = mod.cwrap("enc_get_data", "number", ["number"]);
|
|
100
|
+
const encGetSize = mod.cwrap("enc_get_size", "number", ["number"]);
|
|
101
|
+
const encDestroy = mod.cwrap("enc_destroy", null, ["number"]);
|
|
102
|
+
const n = components * width * height;
|
|
103
|
+
// Convert samples to int32 (planar comp-major) for the line buffers.
|
|
104
|
+
const i32 = new Int32Array(n);
|
|
105
|
+
const src = input.data;
|
|
106
|
+
for (let i = 0; i < n; i++)
|
|
107
|
+
i32[i] = src[i] | 0;
|
|
108
|
+
const dataPtr = mod._malloc(n * 4);
|
|
109
|
+
mod.HEAP32.set(i32, dataPtr >> 2);
|
|
110
|
+
const bdPtr = mod._malloc(components * 4);
|
|
111
|
+
const sgPtr = mod._malloc(components * 4);
|
|
112
|
+
for (let c = 0; c < components; c++) {
|
|
113
|
+
mod.HEAP32[(bdPtr >> 2) + c] = bitDepth;
|
|
114
|
+
mod.HEAP32[(sgPtr >> 2) + c] = isSigned ? 1 : 0;
|
|
115
|
+
}
|
|
116
|
+
const enc = encCreate();
|
|
117
|
+
try {
|
|
118
|
+
const size = encEncode(enc, dataPtr, width, height, components, bdPtr, sgPtr, reversible ? 1 : 0, quality, decompositions, bw, bh);
|
|
119
|
+
if (size < 0)
|
|
120
|
+
throw new Error("openjph-wasm: encode failed");
|
|
121
|
+
const dataAddr = encGetData(enc);
|
|
122
|
+
const sz = encGetSize(enc);
|
|
123
|
+
return mod.HEAPU8.slice(dataAddr, dataAddr + sz);
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
encDestroy(enc);
|
|
127
|
+
mod._free(dataPtr);
|
|
128
|
+
mod._free(bdPtr);
|
|
129
|
+
mod._free(sgPtr);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
async function Module(moduleArg={}){var Module=moduleArg;var ENVIRONMENT_IS_WEB=!!globalThis.window;var ENVIRONMENT_IS_WORKER=!!globalThis.WorkerGlobalScope;var ENVIRONMENT_IS_NODE=globalThis.process?.versions?.node&&globalThis.process?.type!="renderer";if(ENVIRONMENT_IS_NODE){const{createRequire}=await import("node:module");var require=createRequire(import.meta.url)}var programArgs=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var _scriptName=import.meta.url;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("node:fs");if(_scriptName.startsWith("file:")){scriptDirectory=require("node:path").dirname(require("node:url").fileURLToPath(_scriptName))+"/"}readBinary=filename=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename);return ret};readAsync=async(filename,binary=true)=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename,binary?undefined:"utf8");return ret};if(process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}programArgs=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){try{scriptDirectory=new URL(".",_scriptName).href}catch{}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=async url=>{var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=console.log.bind(console);var err=console.error.bind(console);var wasmBinary;var ABORT=false;var isFileURI=filename=>filename.startsWith("file://");class EmscriptenEH{}class EmscriptenSjLj extends EmscriptenEH{}class CppException extends EmscriptenEH{constructor(excPtr){super();this.excPtr=excPtr}}var runtimeInitialized=false;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);HEAPF32=new Float32Array(b);HEAPF64=new Float64Array(b);HEAP64=new BigInt64Array(b);HEAPU64=new BigUint64Array(b)}function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(onPreRuns)}function initRuntime(){runtimeInitialized=true;wasmExports["w"]()}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(onPostRuns)}function abort(what){Module["onAbort"]?.(what);what=`Aborted(${what})`;err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);throw e}var wasmBinaryFile;function findWasmBinary(){if(Module["locateFile"]){return locateFile("libopenjph.wasm")}return new URL("libopenjph.wasm",import.meta.url).href}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}async function getWasmBinary(binaryFile){if(!wasmBinary){try{var response=await readAsync(binaryFile);return new Uint8Array(response)}catch{}}return getBinarySync(binaryFile)}async function instantiateArrayBuffer(binaryFile,imports){try{var binary=await getWasmBinary(binaryFile);var instance=await WebAssembly.instantiate(binary,imports);return instance}catch(reason){err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)}}async function instantiateAsync(binary,binaryFile,imports){if(!binary&&!ENVIRONMENT_IS_NODE){try{var response=fetch(binaryFile,{credentials:"same-origin"});var instantiationResult=await WebAssembly.instantiateStreaming(response,imports);return instantiationResult}catch(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation")}}return instantiateArrayBuffer(binaryFile,imports)}function getWasmImports(){var imports={a:wasmImports};return imports}async function createWasm(){function receiveInstance(instance,module){wasmExports=instance.exports;assignWasmExports(wasmExports);updateMemoryViews();return wasmExports}function receiveInstantiationResult(result){return receiveInstance(result["instance"])}var info=getWasmImports();if(Module["instantiateWasm"]){return new Promise((resolve,reject)=>{Module["instantiateWasm"](info,(inst,mod)=>{resolve(receiveInstance(inst,mod))})})}wasmBinaryFile??=findWasmBinary();var result=await instantiateAsync(wasmBinary,wasmBinaryFile,info);var exports=receiveInstantiationResult(result);return exports}class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var HEAP16;var HEAP32;var HEAP64;var HEAP8;var HEAPF32;var HEAPF64;var HEAPU16;var HEAPU32;var HEAPU64;var HEAPU8;var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var onPostRuns=[];var addOnPostRun=cb=>onPostRuns.push(cb);var onPreRuns=[];var addOnPreRun=cb=>onPreRuns.push(cb);function getValue(ptr,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":return HEAP8[ptr];case"i8":return HEAP8[ptr];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":return HEAP64[ptr>>3];case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];case"*":return HEAPU32[ptr>>2];default:abort(`invalid type for getValue: ${type}`)}}var noExitRuntime=true;function setValue(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":HEAP8[ptr]=value;break;case"i8":HEAP8[ptr]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":HEAP64[ptr>>3]=BigInt(value);break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;case"*":HEAPU32[ptr>>2]=value;break;default:abort(`invalid type for setValue: ${type}`)}}var stackRestore=val=>__emscripten_stack_restore(val);var stackSave=()=>_emscripten_stack_get_current();var exceptionCaught=[];var uncaughtExceptionCount=0;var ___cxa_begin_catch=ptr=>{var info=new ExceptionInfo(ptr);if(!info.get_caught()){info.set_caught(true);uncaughtExceptionCount--}info.set_rethrown(false);exceptionCaught.push(info);return ___cxa_get_exception_ptr(ptr)};var exceptionLast=null;var ___cxa_end_catch=()=>{_setThrew(0,0);var info=exceptionCaught.pop();___cxa_decrement_exception_refcount(info.excPtr);exceptionLast=null};class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){HEAPU32[this.ptr+4>>2]=type}get_type(){return HEAPU32[this.ptr+4>>2]}set_destructor(destructor){HEAPU32[this.ptr+8>>2]=destructor}get_destructor(){return HEAPU32[this.ptr+8>>2]}set_caught(caught){caught=caught?1:0;HEAP8[this.ptr+12]=caught}get_caught(){return HEAP8[this.ptr+12]!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13]=rethrown}get_rethrown(){return HEAP8[this.ptr+13]!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){HEAPU32[this.ptr+16>>2]=adjustedPtr}get_adjusted_ptr(){return HEAPU32[this.ptr+16>>2]}}var setTempRet0=val=>__emscripten_tempret_set(val);var findMatchingCatch=args=>{var thrown=exceptionLast?.excPtr;if(!thrown){setTempRet0(0);return 0}var info=new ExceptionInfo(thrown);info.set_adjusted_ptr(thrown);var thrownType=info.get_type();if(!thrownType){setTempRet0(0);return thrown}for(var caughtType of args){if(caughtType===0||caughtType===thrownType){break}var adjusted_ptr_addr=info.ptr+16;if(___cxa_can_catch(caughtType,thrownType,adjusted_ptr_addr)){setTempRet0(caughtType);return thrown}}setTempRet0(thrownType);return thrown};var ___cxa_find_matching_catch_2=()=>findMatchingCatch([]);var ___cxa_find_matching_catch_3=arg0=>findMatchingCatch([arg0]);var ___cxa_throw=(ptr,type,destructor)=>{var info=new ExceptionInfo(ptr);info.init(type,destructor);___cxa_increment_exception_refcount(ptr);exceptionLast=new CppException(ptr);uncaughtExceptionCount++;throw exceptionLast};var ___resumeException=ptr=>{if(!exceptionLast){exceptionLast=new CppException(ptr)}throw exceptionLast};var __abort_js=()=>abort("");var getHeapMax=()=>2147483648;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var growMemory=size=>{var oldHeapSize=wasmMemory.buffer.byteLength;var pages=(size-oldHeapSize+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var _fd_close=fd=>52;var INT53_MAX=9007199254740992;var INT53_MIN=-9007199254740992;var bigintToI53Checked=num=>num<INT53_MIN||num>INT53_MAX?NaN:Number(num);function _fd_seek(fd,offset,whence,newOffset){offset=bigintToI53Checked(offset);return 70}var printCharBuffers=[null,[],[]];var UTF8Decoder=globalThis.TextDecoder&&new TextDecoder;var findStringEnd=(heapOrArray,idx,maxBytesToRead,ignoreNul)=>{var maxIdx=idx+maxBytesToRead;if(ignoreNul)return maxIdx;while(heapOrArray[idx]&&!(idx>=maxIdx))++idx;return idx};var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead,ignoreNul)=>{var endPtr=findStringEnd(heapOrArray,idx,maxBytesToRead,ignoreNul);if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx<endPtr){var u0=heapOrArray[idx++];if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=heapOrArray[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=heapOrArray[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|heapOrArray[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}return str};var printChar=(stream,curr)=>{var buffer=printCharBuffers[stream];if(curr===0||curr===10){(stream===1?out:err)(UTF8ArrayToString(buffer));buffer.length=0}else{buffer.push(curr)}};var UTF8ToString=(ptr,maxBytesToRead,ignoreNul)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead,ignoreNul):"";var _fd_write=(fd,iov,iovcnt,pnum)=>{var num=0;for(var i=0;i<iovcnt;i++){var ptr=HEAPU32[iov>>2];var len=HEAPU32[iov+4>>2];iov+=8;for(var j=0;j<len;j++){printChar(fd,HEAPU8[ptr+j])}num+=len}HEAPU32[pnum>>2]=num;return 0};var _llvm_eh_typeid_for=type=>type;var wasmTableMirror=[];var getWasmTableEntry=funcPtr=>{var func=wasmTableMirror[funcPtr];if(!func){wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func};var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer)};var lengthBytesUTF8=str=>{var len=0;for(var i=0;i<str.length;++i){var c=str.charCodeAt(i);if(c<=127){len++}else if(c<=2047){len+=2}else if(c>=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.codePointAt(i);if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;i++}}heap[outIdx]=0;return outIdx-startIdx};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i<args.length;i++){var converter=toC[argTypes[i]];if(converter){if(stack===0)stack=stackSave();cArgs[i]=converter(args[i])}else{cArgs[i]=args[i]}}}var ret=func(...cArgs);function onDone(ret){if(stack!==0)stackRestore(stack);return convertReturnValue(ret)}ret=onDone(ret);return ret};var cwrap=(ident,returnType,argTypes,opts)=>{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};{if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(Module["print"])out=Module["print"];if(Module["printErr"])err=Module["printErr"];if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];if(Module["arguments"])programArgs=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].shift()()}}}Module["ccall"]=ccall;Module["cwrap"]=cwrap;Module["setValue"]=setValue;Module["getValue"]=getValue;Module["writeArrayToMemory"]=writeArrayToMemory;var _create_j2c_data,_init_j2c_data,_get_j2c_num_components,_get_j2c_width,_get_j2c_height,_get_j2c_bit_depth,_get_j2c_is_signed,_get_j2c_downsampling_x,_get_j2c_downsampling_y,_parse_j2c_data,_pull_j2c_line,_get_curr_comp,_restrict_input_resolution,_enable_resilience,_release_j2c_data,_enc_create,_enc_destroy,_enc_encode,_enc_get_data,_enc_get_size,_free,_malloc,_setThrew,__emscripten_tempret_set,__emscripten_stack_restore,__emscripten_stack_alloc,_emscripten_stack_get_current,___cxa_increment_exception_refcount,___cxa_decrement_exception_refcount,___cxa_can_catch,___cxa_get_exception_ptr,memory,__indirect_function_table,wasmMemory,wasmTable;function assignWasmExports(wasmExports){_create_j2c_data=Module["_create_j2c_data"]=wasmExports["x"];_init_j2c_data=Module["_init_j2c_data"]=wasmExports["z"];_get_j2c_num_components=Module["_get_j2c_num_components"]=wasmExports["A"];_get_j2c_width=Module["_get_j2c_width"]=wasmExports["B"];_get_j2c_height=Module["_get_j2c_height"]=wasmExports["C"];_get_j2c_bit_depth=Module["_get_j2c_bit_depth"]=wasmExports["D"];_get_j2c_is_signed=Module["_get_j2c_is_signed"]=wasmExports["E"];_get_j2c_downsampling_x=Module["_get_j2c_downsampling_x"]=wasmExports["F"];_get_j2c_downsampling_y=Module["_get_j2c_downsampling_y"]=wasmExports["G"];_parse_j2c_data=Module["_parse_j2c_data"]=wasmExports["H"];_pull_j2c_line=Module["_pull_j2c_line"]=wasmExports["I"];_get_curr_comp=Module["_get_curr_comp"]=wasmExports["J"];_restrict_input_resolution=Module["_restrict_input_resolution"]=wasmExports["K"];_enable_resilience=Module["_enable_resilience"]=wasmExports["L"];_release_j2c_data=Module["_release_j2c_data"]=wasmExports["M"];_enc_create=Module["_enc_create"]=wasmExports["N"];_enc_destroy=Module["_enc_destroy"]=wasmExports["O"];_enc_encode=Module["_enc_encode"]=wasmExports["P"];_enc_get_data=Module["_enc_get_data"]=wasmExports["Q"];_enc_get_size=Module["_enc_get_size"]=wasmExports["R"];_free=Module["_free"]=wasmExports["S"];_malloc=Module["_malloc"]=wasmExports["T"];_setThrew=wasmExports["U"];__emscripten_tempret_set=wasmExports["V"];__emscripten_stack_restore=wasmExports["W"];__emscripten_stack_alloc=wasmExports["X"];_emscripten_stack_get_current=wasmExports["Y"];___cxa_increment_exception_refcount=wasmExports["Z"];___cxa_decrement_exception_refcount=wasmExports["_"];___cxa_can_catch=wasmExports["$"];___cxa_get_exception_ptr=wasmExports["aa"];memory=wasmMemory=wasmExports["v"];__indirect_function_table=wasmTable=wasmExports["y"]}var wasmImports={g:___cxa_begin_catch,n:___cxa_end_catch,c:___cxa_find_matching_catch_2,a:___cxa_find_matching_catch_3,d:___cxa_throw,b:___resumeException,r:__abort_js,q:_emscripten_resize_heap,t:_fd_close,s:_fd_seek,l:_fd_write,o:invoke_i,e:invoke_ii,m:invoke_iii,h:invoke_iiii,j:invoke_v,i:invoke_vi,k:invoke_vii,f:invoke_viiii,u:invoke_viiiiii,p:_llvm_eh_typeid_for};function invoke_ii(index,a1){var sp=stackSave();try{return getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(!(e instanceof EmscriptenEH))throw e;_setThrew(1,0)}}function invoke_v(index){var sp=stackSave();try{getWasmTableEntry(index)()}catch(e){stackRestore(sp);if(!(e instanceof EmscriptenEH))throw e;_setThrew(1,0)}}function invoke_vi(index,a1){var sp=stackSave();try{getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(!(e instanceof EmscriptenEH))throw e;_setThrew(1,0)}}function invoke_iiii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(!(e instanceof EmscriptenEH))throw e;_setThrew(1,0)}}function invoke_viiii(index,a1,a2,a3,a4){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(!(e instanceof EmscriptenEH))throw e;_setThrew(1,0)}}function invoke_i(index){var sp=stackSave();try{return getWasmTableEntry(index)()}catch(e){stackRestore(sp);if(!(e instanceof EmscriptenEH))throw e;_setThrew(1,0)}}function invoke_viiiiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(!(e instanceof EmscriptenEH))throw e;_setThrew(1,0)}}function invoke_iii(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(!(e instanceof EmscriptenEH))throw e;_setThrew(1,0)}}function invoke_vii(index,a1,a2){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(!(e instanceof EmscriptenEH))throw e;_setThrew(1,0)}}async function run(){preRun();var setStatus=Module["setStatus"];if(setStatus){setStatus("Running...");await new Promise(resolve=>setTimeout(resolve,1));setTimeout(setStatus,1,"")}if(ABORT)return;initRuntime();Module["onRuntimeInitialized"]?.();postRun()}var wasmExports;wasmExports=await createWasm();await run();
|
|
2
|
+
;return Module}export default Module;
|
|
Binary file
|