@computationalpathologygroup/openslide-js 1.0.0-beta.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/LICENSE +501 -0
- package/NOTICE +216 -0
- package/README.md +160 -0
- package/dist/cjs/deep-zoom.d.ts +66 -0
- package/dist/cjs/deep-zoom.d.ts.map +1 -0
- package/dist/cjs/deep-zoom.js +186 -0
- package/dist/cjs/deep-zoom.js.map +1 -0
- package/dist/cjs/errors.d.ts +9 -0
- package/dist/cjs/errors.d.ts.map +1 -0
- package/dist/cjs/errors.js +26 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/index.d.ts +18 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +27 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/openslide.d.ts +47 -0
- package/dist/cjs/openslide.d.ts.map +1 -0
- package/dist/cjs/openslide.js +191 -0
- package/dist/cjs/openslide.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/slide.d.ts +70 -0
- package/dist/cjs/slide.d.ts.map +1 -0
- package/dist/cjs/slide.js +139 -0
- package/dist/cjs/slide.js.map +1 -0
- package/dist/cjs/types.d.ts +150 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +3 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/wasm/openslide.js +2 -0
- package/dist/cjs/wasm/openslide.wasm +0 -0
- package/dist/cjs/worker-api.d.ts +55 -0
- package/dist/cjs/worker-api.d.ts.map +1 -0
- package/dist/cjs/worker-api.js +287 -0
- package/dist/cjs/worker-api.js.map +1 -0
- package/dist/esm/deep-zoom.d.ts +66 -0
- package/dist/esm/deep-zoom.d.ts.map +1 -0
- package/dist/esm/deep-zoom.js +182 -0
- package/dist/esm/deep-zoom.js.map +1 -0
- package/dist/esm/errors.d.ts +9 -0
- package/dist/esm/errors.d.ts.map +1 -0
- package/dist/esm/errors.js +21 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/index.d.ts +18 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +19 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/openslide.d.ts +47 -0
- package/dist/esm/openslide.d.ts.map +1 -0
- package/dist/esm/openslide.js +187 -0
- package/dist/esm/openslide.js.map +1 -0
- package/dist/esm/slide.d.ts +70 -0
- package/dist/esm/slide.d.ts.map +1 -0
- package/dist/esm/slide.js +135 -0
- package/dist/esm/slide.js.map +1 -0
- package/dist/esm/types.d.ts +150 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/wasm/openslide.js +2 -0
- package/dist/esm/wasm/openslide.wasm +0 -0
- package/dist/esm/worker-api.d.ts +55 -0
- package/dist/esm/worker-api.d.ts.map +1 -0
- package/dist/esm/worker-api.js +283 -0
- package/dist/esm/worker-api.js.map +1 -0
- package/dist/esm/worker.d.ts +8 -0
- package/dist/esm/worker.d.ts.map +1 -0
- package/dist/esm/worker.js +175 -0
- package/dist/esm/worker.js.map +1 -0
- package/package.json +74 -0
package/NOTICE
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
openslide-js
|
|
2
|
+
|
|
3
|
+
This product is distributed under the GNU Lesser General Public License,
|
|
4
|
+
version 2.1 only (LGPL-2.1-only). See the LICENSE file in the repository
|
|
5
|
+
root for the full license text.
|
|
6
|
+
|
|
7
|
+
This product bundles and is built from several third-party components,
|
|
8
|
+
each carrying its own license. The notices below identify those
|
|
9
|
+
components, their upstream sources, and the licenses under which they
|
|
10
|
+
are distributed.
|
|
11
|
+
|
|
12
|
+
================================================================================
|
|
13
|
+
1. Bundled into wasm/dist/openslide.wasm
|
|
14
|
+
================================================================================
|
|
15
|
+
|
|
16
|
+
The compiled WebAssembly artifact wasm/dist/openslide.wasm statically
|
|
17
|
+
links the following projects. Each retains its own license; the
|
|
18
|
+
combined binary is distributed under LGPL-2.1-only (the strongest
|
|
19
|
+
copyleft of any bundled component).
|
|
20
|
+
|
|
21
|
+
OpenSlide
|
|
22
|
+
Upstream: https://openslide.org
|
|
23
|
+
https://github.com/openslide/openslide
|
|
24
|
+
Pin: v4.0.0 tagged release (matches the official binary
|
|
25
|
+
distribution openslide-bin v4.0.0.13)
|
|
26
|
+
License: LGPL-2.1-only
|
|
27
|
+
Note: Modified via wasm/patches/openslide.patch — eight small
|
|
28
|
+
mechanical _with_data thunk wrappers for GLib sort
|
|
29
|
+
callbacks under Emscripten's strict call_indirect type
|
|
30
|
+
check. The complete corresponding source, including the
|
|
31
|
+
patch and the fetch script that pins the upstream tag,
|
|
32
|
+
is available in the wasm/ directory of this repository.
|
|
33
|
+
Also: wasm/dependencies/fetch-openslide.sh removes
|
|
34
|
+
subdir('tools') from upstream meson.build via sed
|
|
35
|
+
(Emscripten cannot link native helper executables).
|
|
36
|
+
|
|
37
|
+
GLib
|
|
38
|
+
Upstream: https://gitlab.gnome.org/GNOME/glib
|
|
39
|
+
Pin: 2.88.1
|
|
40
|
+
License: LGPL-2.1-or-later
|
|
41
|
+
Note: Modified via wasm/patches/glib.patch (10-patch mailbox
|
|
42
|
+
series from wasm-vips by Kleis Auke Wolthuizen, see
|
|
43
|
+
Section 3).
|
|
44
|
+
|
|
45
|
+
Cairo
|
|
46
|
+
Upstream: https://gitlab.freedesktop.org/cairo/cairo
|
|
47
|
+
Pin: 1.18.4
|
|
48
|
+
License: LGPL-2.1-only OR MPL-1.1
|
|
49
|
+
Note: Unmodified upstream source.
|
|
50
|
+
|
|
51
|
+
gdk-pixbuf
|
|
52
|
+
Upstream: https://gitlab.gnome.org/GNOME/gdk-pixbuf
|
|
53
|
+
Pin: 2.42.12
|
|
54
|
+
License: LGPL-2.1-or-later
|
|
55
|
+
Note: Modified via wasm/patches/gdk-pixbuf.patch — ~9 lines
|
|
56
|
+
wrapping the gdkpixbuf_bin executables foreach in
|
|
57
|
+
`if not meson.is_cross_build()`. Strategy informed by
|
|
58
|
+
discere-os/gdk-pixbuf.wasm (see Section 3).
|
|
59
|
+
|
|
60
|
+
fontconfig
|
|
61
|
+
Upstream: https://gitlab.freedesktop.org/fontconfig/fontconfig
|
|
62
|
+
Pin: 2.17.1
|
|
63
|
+
License: MIT (HPND-style)
|
|
64
|
+
Note: Unmodified upstream source. Upstream commit e3563fa2
|
|
65
|
+
(May 2023) migrated src/meson.build to meson's built-in
|
|
66
|
+
cc.preprocess(), making it Emscripten-buildable without
|
|
67
|
+
any compiler-detection patch.
|
|
68
|
+
|
|
69
|
+
pixman
|
|
70
|
+
Upstream: https://gitlab.freedesktop.org/pixman/pixman
|
|
71
|
+
License: MIT
|
|
72
|
+
|
|
73
|
+
FreeType
|
|
74
|
+
Upstream: https://freetype.org
|
|
75
|
+
License: FTL OR GPL-2.0-or-later
|
|
76
|
+
|
|
77
|
+
libtiff
|
|
78
|
+
Upstream: https://gitlab.com/libtiff/libtiff
|
|
79
|
+
License: libtiff (BSD-style)
|
|
80
|
+
|
|
81
|
+
libjpeg-turbo
|
|
82
|
+
Upstream: https://libjpeg-turbo.org
|
|
83
|
+
License: IJG AND BSD-3-Clause AND Zlib
|
|
84
|
+
|
|
85
|
+
OpenJPEG
|
|
86
|
+
Upstream: https://www.openjpeg.org
|
|
87
|
+
License: BSD-2-Clause
|
|
88
|
+
|
|
89
|
+
libpng
|
|
90
|
+
Upstream: http://www.libpng.org/pub/png/libpng.html
|
|
91
|
+
License: libpng-2.0
|
|
92
|
+
|
|
93
|
+
libxml2
|
|
94
|
+
Upstream: https://gitlab.gnome.org/GNOME/libxml2
|
|
95
|
+
License: MIT
|
|
96
|
+
|
|
97
|
+
Expat (libexpat)
|
|
98
|
+
Upstream: https://libexpat.github.io
|
|
99
|
+
License: MIT
|
|
100
|
+
|
|
101
|
+
zlib
|
|
102
|
+
Upstream: https://www.zlib.net
|
|
103
|
+
License: Zlib
|
|
104
|
+
|
|
105
|
+
zstd
|
|
106
|
+
Upstream: https://github.com/facebook/zstd
|
|
107
|
+
License: BSD-3-Clause OR GPL-2.0-only
|
|
108
|
+
|
|
109
|
+
libffi
|
|
110
|
+
Upstream: https://github.com/libffi/libffi
|
|
111
|
+
License: MIT
|
|
112
|
+
|
|
113
|
+
SQLite
|
|
114
|
+
Upstream: https://www.sqlite.org
|
|
115
|
+
License: blessing (public-domain dedication)
|
|
116
|
+
|
|
117
|
+
================================================================================
|
|
118
|
+
2. Source availability (LGPL-2.1 §6)
|
|
119
|
+
================================================================================
|
|
120
|
+
|
|
121
|
+
The LGPL-2.1-licensed components above (notably OpenSlide, GLib, Cairo,
|
|
122
|
+
and gdk-pixbuf) require that the complete corresponding source of the
|
|
123
|
+
combined work be available to recipients.
|
|
124
|
+
|
|
125
|
+
The complete corresponding source is the contents of the openslide-js
|
|
126
|
+
repository at https://github.com/computationalpathologygroup/openslide-js,
|
|
127
|
+
specifically the wasm/ directory, which contains:
|
|
128
|
+
|
|
129
|
+
- Dockerfile + build.sh — the deterministic build pipeline
|
|
130
|
+
- dependencies/fetch-*.sh — one fetch script per bundled project,
|
|
131
|
+
pinning the exact upstream commit/release used
|
|
132
|
+
- patches/*.patch — every modification applied to upstream sources
|
|
133
|
+
- openslide-api.c + emscripten-crossfile.meson — the linker glue
|
|
134
|
+
and Emscripten cross-compilation configuration
|
|
135
|
+
|
|
136
|
+
Reproducing the bundled wasm binary from these sources requires Docker
|
|
137
|
+
and is documented in README.md under "Building the WASM module".
|
|
138
|
+
|
|
139
|
+
================================================================================
|
|
140
|
+
3. Build infrastructure attribution
|
|
141
|
+
================================================================================
|
|
142
|
+
|
|
143
|
+
The WebAssembly build pipeline under wasm/ incorporates work from the
|
|
144
|
+
following upstream projects. Both are MIT-licensed and compatible with
|
|
145
|
+
openslide-js's LGPL-2.1-only distribution.
|
|
146
|
+
|
|
147
|
+
@conflux-xyz/openslide-wasm
|
|
148
|
+
Upstream: https://github.com/conflux-xyz/openslide-wasm
|
|
149
|
+
https://www.npmjs.com/package/@conflux-xyz/openslide-wasm
|
|
150
|
+
License: MIT (declared in the package's npm package.json; the
|
|
151
|
+
upstream GitHub repository does not currently carry an
|
|
152
|
+
explicit LICENSE file)
|
|
153
|
+
Used for: The overall WASM build pipeline — the Emscripten base
|
|
154
|
+
image and required packages, the meson and
|
|
155
|
+
cmake flag sets for each bundled native library, and
|
|
156
|
+
the emscripten meson cross-file. No source patches to
|
|
157
|
+
bundled libraries are derived from this project;
|
|
158
|
+
all four originally-imported patches (cairo,
|
|
159
|
+
fontconfig, gdk-pixbuf, openslide) have meson options,
|
|
160
|
+
upstream version upgrades, single-line sed transforms
|
|
161
|
+
in the fetch scripts, code informed by other projects
|
|
162
|
+
(see entries below).
|
|
163
|
+
|
|
164
|
+
wasm-vips (by Kleis Auke Wolthuizen)
|
|
165
|
+
Upstream: https://github.com/kleisauke/wasm-vips
|
|
166
|
+
License: MIT
|
|
167
|
+
Used for: The GLib WebAssembly patch series carried in
|
|
168
|
+
wasm/patches/glib.patch. Per-patch author lines are
|
|
169
|
+
preserved in the patch's mailbox-format headers.
|
|
170
|
+
|
|
171
|
+
VitoVan/pango-cairo-wasm (by Vito Van)
|
|
172
|
+
Upstream: https://github.com/VitoVan/pango-cairo-wasm
|
|
173
|
+
License: WTFPL (Do What The Fuck You Want To Public License)
|
|
174
|
+
Used for: The strategic insight that cairo can be cross-built for
|
|
175
|
+
WebAssembly with no source patches: cairo's util/
|
|
176
|
+
meson.build gates each helper executable
|
|
177
|
+
(cairo-gobject, cairo-script, cairo-trace, cairo-fdr) on
|
|
178
|
+
feature_conf flags, and the top-level executable loop
|
|
179
|
+
iterates an empty list when gtk_dep is not found. With
|
|
180
|
+
openslide-js's dependency set, none of those targets are
|
|
181
|
+
triggered, so the previous wasm/patches/cairo.patch
|
|
182
|
+
(which removed `subdir('util')`) is unnecessary.
|
|
183
|
+
|
|
184
|
+
discere-os/gdk-pixbuf.wasm and discere-os/fontconfig.wasm
|
|
185
|
+
(by Isaac Johnston / Superstruct Ltd)
|
|
186
|
+
Upstream: https://github.com/discere-os/gdk-pixbuf.wasm
|
|
187
|
+
https://github.com/discere-os/fontconfig.wasm
|
|
188
|
+
License: LGPL-2.1-or-later (gdk-pixbuf.wasm, matching upstream);
|
|
189
|
+
upstream fontconfig license + MIT build infrastructure
|
|
190
|
+
(fontconfig.wasm)
|
|
191
|
+
Used for: (1) For gdk-pixbuf — the strategy to cross-build cleanly
|
|
192
|
+
under Emscripten without source patches to the C loader
|
|
193
|
+
code: relying on the pre-existing upstream gating of
|
|
194
|
+
USE_GMODULE on GLib's pkg-config-advertised
|
|
195
|
+
`gmodule_supported` value, and the `builtin_loaders=all`
|
|
196
|
+
meson option for the loader-plugin loop. The thin patch
|
|
197
|
+
at wasm/patches/gdk-pixbuf.patch (only gating helper
|
|
198
|
+
executables on `meson.is_cross_build()`) is original
|
|
199
|
+
openslide-js code.
|
|
200
|
+
(2) For fontconfig — the strategy of pinning fontconfig
|
|
201
|
+
2.17.1 (which contains upstream commit e3563fa2,
|
|
202
|
+
May 2023, migrating src/meson.build to meson's built-in
|
|
203
|
+
cc.preprocess()), eliminating the conflux-xyz-derived
|
|
204
|
+
`cc.get_id() == 'clang' or ...emscripten` workaround
|
|
205
|
+
entirely. No patch is needed at fontconfig 2.17.1+.
|
|
206
|
+
|
|
207
|
+
The Emscripten C glue at wasm/openslide-api.c is distributed under
|
|
208
|
+
LGPL-2.1-only because it links directly against OpenSlide.
|
|
209
|
+
|
|
210
|
+
================================================================================
|
|
211
|
+
4. No warranty
|
|
212
|
+
================================================================================
|
|
213
|
+
|
|
214
|
+
This software is provided "as is", without warranty of any kind,
|
|
215
|
+
express or implied. See the LICENSE file for the full LGPL-2.1-only
|
|
216
|
+
disclaimer of warranty.
|
package/README.md
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# openslide-js
|
|
2
|
+
|
|
3
|
+
Client-side whole-slide image library powered by [OpenSlide](https://openslide.org) and WebAssembly.
|
|
4
|
+
|
|
5
|
+
Runs entirely in the browser — no server required.
|
|
6
|
+
|
|
7
|
+
> For native (Linux / Windows / macOS) usage, see [openslide-bin](https://github.com/openslide/openslide-bin) — the OpenSlide team's official binary distribution of the same C library used by openslide-python, openslide-java, and other native consumers. openslide-js is the WebAssembly sibling: same upstream OpenSlide and dependency pins (v4.0.0, GLib 2.88.1, Cairo 1.18.4, libdicom 1.0.5, etc.) compiled for the browser via Emscripten, with a TypeScript wrapper API on top.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @computationalpathologygroup/openslide-js
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { OpenSlide } from '@computationalpathologygroup/openslide-js';
|
|
19
|
+
|
|
20
|
+
const openslide = await OpenSlide.initialize();
|
|
21
|
+
const slide = await openslide.open(file); // File | File[] | URL | string
|
|
22
|
+
|
|
23
|
+
console.log(slide.levelCount);
|
|
24
|
+
console.log(slide.properties);
|
|
25
|
+
|
|
26
|
+
const imageData = await slide.readRegion(x, y, level, width, height);
|
|
27
|
+
slide.close();
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Multi-file formats (MIRAX, VMS)
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { OpenSlide, type VirtualFile } from '@computationalpathologygroup/openslide-js';
|
|
34
|
+
|
|
35
|
+
const entries: VirtualFile[] = [
|
|
36
|
+
{ path: 'slide.mrxs', file: mrxsFile },
|
|
37
|
+
{ path: 'slide/Slidedat.ini', file: datFile },
|
|
38
|
+
// ... remaining files
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
const slide = await openslide.open(entries);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Deep Zoom
|
|
45
|
+
|
|
46
|
+
Slides are read sparsely — only the byte ranges needed to decode the requested Deep Zoom tiles are accessed, via HTTP range requests for URLs (the origin must serve `Accept-Ranges: bytes`) or via the browser's File API for local files — so multi-gigabyte whole-slide images can be browsed in the viewport without ever loading the full file into memory.
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { DeepZoomGenerator } from '@computationalpathologygroup/openslide-js';
|
|
50
|
+
|
|
51
|
+
const dz = new DeepZoomGenerator(slide);
|
|
52
|
+
const tile = await dz.getTile(level, col, row); // returns ImageData
|
|
53
|
+
const xml = dz.getDzi('jpeg');
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Format Support
|
|
57
|
+
|
|
58
|
+
openslide-js supports the same whole-slide image formats as [OpenSlide](https://openslide.org), running entirely client-side via WebAssembly. Some formats have limitations in the browser environment.
|
|
59
|
+
|
|
60
|
+
### Single-File Formats
|
|
61
|
+
|
|
62
|
+
| Vendor | Format | Extension | Compression | Support level |
|
|
63
|
+
|:-------|:-------|:----------|:------------|:------:|
|
|
64
|
+
| Aperio | SVS | `.svs` | JPEG | :white_check_mark: Full |
|
|
65
|
+
| Aperio | SVS | `.svs` | JPEG 2000 | :white_check_mark: Full |
|
|
66
|
+
| Generic | Tiled TIFF | `.tiff` | Mixed | :white_check_mark: Full |
|
|
67
|
+
| Hamamatsu | NDPI | `.ndpi` | JPEG | :white_check_mark: Full |
|
|
68
|
+
| Leica | SCN (brightfield) | `.scn` | JPEG | :white_check_mark: Full |
|
|
69
|
+
| Philips | TIFF | `.tiff` | JPEG | :white_check_mark: Full |
|
|
70
|
+
|
|
71
|
+
### Multi-File Formats
|
|
72
|
+
|
|
73
|
+
| Vendor | Format | Extension | Support level | Notes |
|
|
74
|
+
|:-------|:-------|:----------|:------:|:------|
|
|
75
|
+
| DICOM | WSI | `.dcm` | :white_check_mark: Full | Opened via `VirtualFile[]` directory mounting |
|
|
76
|
+
| Hamamatsu | VMS | `.vms` | :white_check_mark: Full | Opened via `VirtualFile[]` directory mounting |
|
|
77
|
+
| Mirax | MRXS | `.mrxs` | :white_check_mark: Full | Opened via `VirtualFile[]` directory mounting |
|
|
78
|
+
| Trestle | TIF | `.tif` | :white_check_mark: Full | Opened via `VirtualFile[]` directory mounting |
|
|
79
|
+
|
|
80
|
+
### Unsupported
|
|
81
|
+
|
|
82
|
+
| Vendor | Format | Extension | Support level | Limitation |
|
|
83
|
+
|:-------|:-------|:----------|:------:|:-----------|
|
|
84
|
+
| Leica | SCN (fluorescence) | `.scn` | :x: No | No main brightfield image in fluorescence-only files |
|
|
85
|
+
| Olympus | VSI | `.vsi` | :x: No | VSI opener cannot find companion ETS directory via WORKERFS |
|
|
86
|
+
| Ventana | BIF | `.bif` | :x: No | `LEFT` direction attribute not supported |
|
|
87
|
+
| Zeiss | CZI | `.czi` | :x: No | Vendor detection not in OpenSlide v4.0.0 (added upstream post-release); JPEG XR codec also not compiled |
|
|
88
|
+
| Zeiss | ZVI | `.zvi` | :x: No | OLE2 compound documents cannot be read via HTTP |
|
|
89
|
+
|
|
90
|
+
### Not Yet Tested
|
|
91
|
+
|
|
92
|
+
| Vendor | Format | Extension | Support level | Notes |
|
|
93
|
+
|:-------|:-------|:----------|:------|
|
|
94
|
+
| Sakura | SVSLIDE | `.svslide` | SQLite-based, needs filesystem access |
|
|
95
|
+
|
|
96
|
+
> **Test coverage:** 292 integration tests across 15 formats (10 single-file + 5 multi-file), running in headless Chromium via Playwright.
|
|
97
|
+
> Run locally with `npm run test:integration` or containerized with `npm run test:integration:docker`.
|
|
98
|
+
|
|
99
|
+
## Requirements
|
|
100
|
+
|
|
101
|
+
The WASM module uses `SharedArrayBuffer` and requires the following HTTP headers:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
Cross-Origin-Opener-Policy: same-origin
|
|
105
|
+
Cross-Origin-Embedder-Policy: require-corp
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Building the WASM module
|
|
109
|
+
|
|
110
|
+
Requires Docker.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
docker build -t openslide-js ./wasm
|
|
114
|
+
mkdir -p wasm/dist
|
|
115
|
+
docker run --rm -v "$(pwd)/wasm/dist:/output" openslide-js
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Output: `wasm/dist/openslide.js` and `wasm/dist/openslide.wasm`.
|
|
119
|
+
|
|
120
|
+
## Building the TypeScript layer
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npm run build:ts
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Test Data
|
|
127
|
+
|
|
128
|
+
Integration tests require whole-slide image files that are not bundled in this repository (they are git-ignored). Download them with:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
npm run test:integration:fixtures
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
This runs `test/integration/download-fixtures.mjs`, which:
|
|
135
|
+
|
|
136
|
+
1. Fetches the [upstream index.json](https://openslide.cs.cmu.edu/download/openslide-testdata/index.json) and updates the local `test/data/index.json` if it has changed.
|
|
137
|
+
2. Downloads every file listed in the index into `test/data/`, preserving the subdirectory layout.
|
|
138
|
+
3. Verifies each file's SHA-256 hash. Files already present with a matching hash are skipped.
|
|
139
|
+
4. Extracts ZIP archives (multi-file formats) into sibling directories.
|
|
140
|
+
|
|
141
|
+
Re-running the script is safe and idempotent — only missing or stale files are re-downloaded. The total download size is roughly 20 GiB for the full index.
|
|
142
|
+
|
|
143
|
+
## Acknowledgements
|
|
144
|
+
|
|
145
|
+
The WASM build pipeline under `wasm/` incorporates work from two upstream projects, both MIT-licensed:
|
|
146
|
+
|
|
147
|
+
- [wasm-vips](https://github.com/kleisauke/wasm-vips) by Kleis Auke Wolthuizen (MIT) — the GLib WebAssembly patch series in `wasm/patches/glib.patch` (per-patch author lines preserved in the mailbox headers).
|
|
148
|
+
- [@conflux-xyz/openslide-wasm](https://github.com/conflux-xyz/openslide-wasm) (MIT, per its npm package) — informed the build strategy
|
|
149
|
+
- [discere-os/gdk-pixbuf.wasm](https://github.com/discere-os/gdk-pixbuf.wasm) and [discere-os/fontconfig.wasm](https://github.com/discere-os/fontconfig.wasm) by Isaac Johnston — informed (a) the patch-light gdk-pixbuf cross-build strategy (lean on upstream's conditional `USE_GMODULE` gating + `-Dbuiltin_loaders=all` rather than stripping C code) and (b) the choice to pin fontconfig at 2.17.1, where upstream's `cc.preprocess()` migration (May 2023) eliminates the need for any compiler-detection patch.
|
|
150
|
+
- [VitoVan/pango-cairo-wasm](https://github.com/VitoVan/pango-cairo-wasm) by Vito Van (WTFPL) — demonstrated that cairo cross-builds cleanly under Emscripten without any source patches; its meson invocation strategy informed dropping `wasm/patches/cairo.patch` entirely.
|
|
151
|
+
|
|
152
|
+
See [NOTICE](NOTICE) for the full third-party attribution, including every component statically linked into `wasm/dist/openslide.wasm` and LGPL-2.1 §6 source-availability information.
|
|
153
|
+
|
|
154
|
+
## Contributing
|
|
155
|
+
|
|
156
|
+
Patches welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) first — it documents how openslide-js handles third-party code, the preferred order of fixes (upstream meson option → sed transform → minimal patch), and the attribution rules that keep the project legally clean.
|
|
157
|
+
|
|
158
|
+
## License
|
|
159
|
+
|
|
160
|
+
LGPL-2.1-only — see [LICENSE](LICENSE) and [NOTICE](NOTICE).
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* deep-zoom.ts
|
|
3
|
+
*
|
|
4
|
+
* Deep Zoom Image (DZI) tile generator. Maps DZI tile coordinates to
|
|
5
|
+
* OpenSlide region reads. Compatible with viewers like OpenSeadragon.
|
|
6
|
+
*
|
|
7
|
+
* Pure TypeScript — no WASM dependency. Operates on a Slide instance.
|
|
8
|
+
*/
|
|
9
|
+
import type { Dimensions, DziInfo } from './types.js';
|
|
10
|
+
import type { Slide } from './slide.js';
|
|
11
|
+
export interface DeepZoomOptions {
|
|
12
|
+
/** Tile size in pixels (not counting overlap). Default: 254. */
|
|
13
|
+
tileSize?: number;
|
|
14
|
+
/** Overlap in pixels on each edge. Default: 1. */
|
|
15
|
+
overlap?: number;
|
|
16
|
+
/** Only render the non-empty region defined by bounds properties. Default: false. */
|
|
17
|
+
limitBounds?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare class DeepZoomGenerator {
|
|
20
|
+
private slide;
|
|
21
|
+
private _tileSize;
|
|
22
|
+
private _overlap;
|
|
23
|
+
private _levelCount;
|
|
24
|
+
private _levelDimensions;
|
|
25
|
+
private _levelTiles;
|
|
26
|
+
private _tileCount;
|
|
27
|
+
private _l0Offset;
|
|
28
|
+
private _l0Size;
|
|
29
|
+
constructor(slide: Slide, options?: DeepZoomOptions);
|
|
30
|
+
/** Number of Deep Zoom levels (0 = smallest, last = full resolution). */
|
|
31
|
+
get levelCount(): number;
|
|
32
|
+
/** Total number of tiles across all levels. */
|
|
33
|
+
get tileCount(): number;
|
|
34
|
+
/** Pixel dimensions at each DZI level. */
|
|
35
|
+
get levelDimensions(): readonly Dimensions[];
|
|
36
|
+
/** Tile grid dimensions at each DZI level. */
|
|
37
|
+
get levelTiles(): readonly {
|
|
38
|
+
columns: number;
|
|
39
|
+
rows: number;
|
|
40
|
+
}[];
|
|
41
|
+
/**
|
|
42
|
+
* Get a single tile as ImageData.
|
|
43
|
+
*
|
|
44
|
+
* @param level - DZI level (0 = smallest).
|
|
45
|
+
* @param col - Column index.
|
|
46
|
+
* @param row - Row index.
|
|
47
|
+
*/
|
|
48
|
+
getTile(level: number, col: number, row: number): Promise<ImageData>;
|
|
49
|
+
/**
|
|
50
|
+
* Generate the DZI XML descriptor string.
|
|
51
|
+
*/
|
|
52
|
+
getDzi(format?: 'jpeg' | 'png'): string;
|
|
53
|
+
/** Structured DZI info (alternative to XML). */
|
|
54
|
+
getDziInfo(format?: 'jpeg' | 'png'): DziInfo;
|
|
55
|
+
/**
|
|
56
|
+
* Compute tile bounds within the DZI level coordinate space.
|
|
57
|
+
*/
|
|
58
|
+
private getTileInfo;
|
|
59
|
+
/**
|
|
60
|
+
* Downsample a tile to the target dimensions using nearest-neighbor.
|
|
61
|
+
* This is a fallback; for better quality, users should use createImageBitmap
|
|
62
|
+
* in their viewer integration.
|
|
63
|
+
*/
|
|
64
|
+
private resampleTile;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=deep-zoom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deep-zoom.d.ts","sourceRoot":"","sources":["../../src/deep-zoom.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,WAAW,eAAe;IAC9B,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qFAAqF;IACrF,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAS;IAGzB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,gBAAgB,CAAe;IACvC,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,UAAU,CAAS;IAG3B,OAAO,CAAC,SAAS,CAA2B;IAC5C,OAAO,CAAC,OAAO,CAA2B;gBAE9B,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,eAAe;IA8CnD,yEAAyE;IACzE,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,+CAA+C;IAC/C,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,0CAA0C;IAC1C,IAAI,eAAe,IAAI,SAAS,UAAU,EAAE,CAE3C;IAED,8CAA8C;IAC9C,IAAI,UAAU,IAAI,SAAS;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAE7D;IAED;;;;;;OAMG;IACG,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IA2C1E;;OAEG;IACH,MAAM,CAAC,MAAM,GAAE,MAAM,GAAG,KAAc,GAAG,MAAM;IAa/C,gDAAgD;IAChD,UAAU,CAAC,MAAM,GAAE,MAAM,GAAG,KAAc,GAAG,OAAO;IAapD;;OAEG;IACH,OAAO,CAAC,WAAW;IAgBnB;;;;OAIG;IACH,OAAO,CAAC,YAAY;CAwBrB"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* deep-zoom.ts
|
|
4
|
+
*
|
|
5
|
+
* Deep Zoom Image (DZI) tile generator. Maps DZI tile coordinates to
|
|
6
|
+
* OpenSlide region reads. Compatible with viewers like OpenSeadragon.
|
|
7
|
+
*
|
|
8
|
+
* Pure TypeScript — no WASM dependency. Operates on a Slide instance.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.DeepZoomGenerator = void 0;
|
|
12
|
+
class DeepZoomGenerator {
|
|
13
|
+
slide;
|
|
14
|
+
_tileSize;
|
|
15
|
+
_overlap;
|
|
16
|
+
// Precomputed geometry
|
|
17
|
+
_levelCount;
|
|
18
|
+
_levelDimensions;
|
|
19
|
+
_levelTiles;
|
|
20
|
+
_tileCount;
|
|
21
|
+
// Slide region to render
|
|
22
|
+
_l0Offset;
|
|
23
|
+
_l0Size;
|
|
24
|
+
constructor(slide, options) {
|
|
25
|
+
this.slide = slide;
|
|
26
|
+
this._tileSize = options?.tileSize ?? 254;
|
|
27
|
+
this._overlap = options?.overlap ?? 1;
|
|
28
|
+
// Determine bounds
|
|
29
|
+
const props = slide.properties;
|
|
30
|
+
const limitBounds = options?.limitBounds ?? false;
|
|
31
|
+
if (limitBounds && props.has('openslide.bounds-x')) {
|
|
32
|
+
this._l0Offset = {
|
|
33
|
+
x: parseInt(props.get('openslide.bounds-x'), 10),
|
|
34
|
+
y: parseInt(props.get('openslide.bounds-y'), 10),
|
|
35
|
+
};
|
|
36
|
+
this._l0Size = {
|
|
37
|
+
w: parseInt(props.get('openslide.bounds-width'), 10),
|
|
38
|
+
h: parseInt(props.get('openslide.bounds-height'), 10),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
this._l0Offset = { x: 0, y: 0 };
|
|
43
|
+
this._l0Size = { w: slide.dimensions.width, h: slide.dimensions.height };
|
|
44
|
+
}
|
|
45
|
+
// Build the DZI level pyramid.
|
|
46
|
+
// DZI level 0 is the smallest (1x1), last level is full resolution.
|
|
47
|
+
const baseW = this._l0Size.w;
|
|
48
|
+
const baseH = this._l0Size.h;
|
|
49
|
+
this._levelCount = Math.ceil(Math.log2(Math.max(baseW, baseH))) + 1;
|
|
50
|
+
this._levelDimensions = [];
|
|
51
|
+
this._levelTiles = [];
|
|
52
|
+
this._tileCount = 0;
|
|
53
|
+
for (let i = 0; i < this._levelCount; i++) {
|
|
54
|
+
const scale = Math.pow(2, this._levelCount - 1 - i);
|
|
55
|
+
const w = Math.max(1, Math.ceil(baseW / scale));
|
|
56
|
+
const h = Math.max(1, Math.ceil(baseH / scale));
|
|
57
|
+
this._levelDimensions.push({ width: w, height: h });
|
|
58
|
+
const cols = Math.ceil(w / this._tileSize);
|
|
59
|
+
const rows = Math.ceil(h / this._tileSize);
|
|
60
|
+
this._levelTiles.push({ columns: cols, rows: rows });
|
|
61
|
+
this._tileCount += cols * rows;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** Number of Deep Zoom levels (0 = smallest, last = full resolution). */
|
|
65
|
+
get levelCount() {
|
|
66
|
+
return this._levelCount;
|
|
67
|
+
}
|
|
68
|
+
/** Total number of tiles across all levels. */
|
|
69
|
+
get tileCount() {
|
|
70
|
+
return this._tileCount;
|
|
71
|
+
}
|
|
72
|
+
/** Pixel dimensions at each DZI level. */
|
|
73
|
+
get levelDimensions() {
|
|
74
|
+
return this._levelDimensions;
|
|
75
|
+
}
|
|
76
|
+
/** Tile grid dimensions at each DZI level. */
|
|
77
|
+
get levelTiles() {
|
|
78
|
+
return this._levelTiles;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Get a single tile as ImageData.
|
|
82
|
+
*
|
|
83
|
+
* @param level - DZI level (0 = smallest).
|
|
84
|
+
* @param col - Column index.
|
|
85
|
+
* @param row - Row index.
|
|
86
|
+
*/
|
|
87
|
+
async getTile(level, col, row) {
|
|
88
|
+
if (level < 0 || level >= this._levelCount) {
|
|
89
|
+
throw new RangeError(`Level ${level} out of range [0, ${this._levelCount})`);
|
|
90
|
+
}
|
|
91
|
+
const grid = this._levelTiles[level];
|
|
92
|
+
if (col < 0 || col >= grid.columns || row < 0 || row >= grid.rows) {
|
|
93
|
+
throw new RangeError(`Tile (${col}, ${row}) out of range for level ${level}`);
|
|
94
|
+
}
|
|
95
|
+
const info = this.getTileInfo(level, col, row);
|
|
96
|
+
// Read from the slide at the best matching OpenSlide level
|
|
97
|
+
const dziDim = this._levelDimensions[level];
|
|
98
|
+
const downsample = this._l0Size.w / dziDim.width;
|
|
99
|
+
const slideLevel = this.slide.getBestLevelForDownsample(downsample);
|
|
100
|
+
const slideLevelDs = this.slide.levelDownsamples[slideLevel];
|
|
101
|
+
// Convert DZI tile coords to OpenSlide level-0 coords
|
|
102
|
+
const l0X = this._l0Offset.x + info.x * downsample;
|
|
103
|
+
const l0Y = this._l0Offset.y + info.y * downsample;
|
|
104
|
+
// Size to read at the slide level
|
|
105
|
+
const readW = Math.ceil(info.w * downsample / slideLevelDs);
|
|
106
|
+
const readH = Math.ceil(info.h * downsample / slideLevelDs);
|
|
107
|
+
const tile = await this.slide.readRegion(Math.round(l0X), Math.round(l0Y), slideLevel, readW, readH);
|
|
108
|
+
// If the read size matches the desired tile size, return directly
|
|
109
|
+
if (readW === info.w && readH === info.h) {
|
|
110
|
+
return tile;
|
|
111
|
+
}
|
|
112
|
+
// Otherwise, scale down to the exact tile dimensions using canvas
|
|
113
|
+
// (in a worker context, OffscreenCanvas; in main thread, regular canvas)
|
|
114
|
+
return this.resampleTile(tile, info.w, info.h);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Generate the DZI XML descriptor string.
|
|
118
|
+
*/
|
|
119
|
+
getDzi(format = 'jpeg') {
|
|
120
|
+
const dim = this._levelDimensions[this._levelCount - 1];
|
|
121
|
+
return [
|
|
122
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
123
|
+
`<Image xmlns="http://schemas.microsoft.com/deepzoom/2008"`,
|
|
124
|
+
` TileSize="${this._tileSize}"`,
|
|
125
|
+
` Overlap="${this._overlap}"`,
|
|
126
|
+
` Format="${format}">`,
|
|
127
|
+
` <Size Width="${dim.width}" Height="${dim.height}"/>`,
|
|
128
|
+
`</Image>`,
|
|
129
|
+
].join('\n');
|
|
130
|
+
}
|
|
131
|
+
/** Structured DZI info (alternative to XML). */
|
|
132
|
+
getDziInfo(format = 'jpeg') {
|
|
133
|
+
const dim = this._levelDimensions[this._levelCount - 1];
|
|
134
|
+
return {
|
|
135
|
+
tileSize: this._tileSize,
|
|
136
|
+
overlap: this._overlap,
|
|
137
|
+
format,
|
|
138
|
+
width: dim.width,
|
|
139
|
+
height: dim.height,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
// --- Internal ---
|
|
143
|
+
/**
|
|
144
|
+
* Compute tile bounds within the DZI level coordinate space.
|
|
145
|
+
*/
|
|
146
|
+
getTileInfo(level, col, row) {
|
|
147
|
+
const dim = this._levelDimensions[level];
|
|
148
|
+
const ts = this._tileSize;
|
|
149
|
+
const ol = this._overlap;
|
|
150
|
+
// Tile origin (accounting for overlap on non-edge tiles)
|
|
151
|
+
const x = col === 0 ? 0 : col * ts - ol;
|
|
152
|
+
const y = row === 0 ? 0 : row * ts - ol;
|
|
153
|
+
// Tile extent
|
|
154
|
+
const x2 = Math.min((col + 1) * ts + ol, dim.width);
|
|
155
|
+
const y2 = Math.min((row + 1) * ts + ol, dim.height);
|
|
156
|
+
return { x, y, w: x2 - x, h: y2 - y };
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Downsample a tile to the target dimensions using nearest-neighbor.
|
|
160
|
+
* This is a fallback; for better quality, users should use createImageBitmap
|
|
161
|
+
* in their viewer integration.
|
|
162
|
+
*/
|
|
163
|
+
resampleTile(source, dstW, dstH) {
|
|
164
|
+
const srcW = source.width;
|
|
165
|
+
const srcH = source.height;
|
|
166
|
+
const src = source.data;
|
|
167
|
+
const dst = new Uint8ClampedArray(dstW * dstH * 4);
|
|
168
|
+
const xRatio = srcW / dstW;
|
|
169
|
+
const yRatio = srcH / dstH;
|
|
170
|
+
for (let dy = 0; dy < dstH; dy++) {
|
|
171
|
+
const sy = Math.min(Math.floor(dy * yRatio), srcH - 1);
|
|
172
|
+
for (let dx = 0; dx < dstW; dx++) {
|
|
173
|
+
const sx = Math.min(Math.floor(dx * xRatio), srcW - 1);
|
|
174
|
+
const si = (sy * srcW + sx) * 4;
|
|
175
|
+
const di = (dy * dstW + dx) * 4;
|
|
176
|
+
dst[di] = src[si];
|
|
177
|
+
dst[di + 1] = src[si + 1];
|
|
178
|
+
dst[di + 2] = src[si + 2];
|
|
179
|
+
dst[di + 3] = src[si + 3];
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return new ImageData(dst, dstW, dstH);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
exports.DeepZoomGenerator = DeepZoomGenerator;
|
|
186
|
+
//# sourceMappingURL=deep-zoom.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deep-zoom.js","sourceRoot":"","sources":["../../src/deep-zoom.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Base error class for all OpenSlide errors. */
|
|
2
|
+
export declare class OpenSlideError extends Error {
|
|
3
|
+
constructor(message: unknown);
|
|
4
|
+
}
|
|
5
|
+
/** Thrown when the file format is not supported by OpenSlide. */
|
|
6
|
+
export declare class OpenSlideUnsupportedFormatError extends OpenSlideError {
|
|
7
|
+
constructor(message?: string);
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,OAAO;CAS7B;AAED,iEAAiE;AACjE,qBAAa,+BAAgC,SAAQ,cAAc;gBACrD,OAAO,CAAC,EAAE,MAAM;CAK7B"}
|