@ohos-ports/cornerstone-core 2.6.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +230 -0
- package/dist/cornerstone-node-bootstrap.js +264 -0
- package/dist/cornerstone.js +9084 -0
- package/dist/cornerstone.js.map +1 -0
- package/dist/cornerstone.min.js +3 -0
- package/dist/cornerstone.min.js.map +1 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014 Chris Hafey (chafey@gmail.com)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>cornerstone-core</h1>
|
|
3
|
+
|
|
4
|
+
<p>Cornerstone.js delivers a complete web based medical imaging platform. This repository contains the Cornerstone.js "Core" component which is a lightweight JavaScript library for displaying medical images in modern web browsers that support the HTML5 canvas element.</p>
|
|
5
|
+
|
|
6
|
+
[**Read The Docs**](https://docs.cornerstonejs.org/) | [Edit the docs](https://github.com/cornerstonejs/cornerstone/tree/master/docs)
|
|
7
|
+
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<hr />
|
|
11
|
+
|
|
12
|
+
<!-- prettier-ignore-start -->
|
|
13
|
+
[![Coverage Status][coverage-image]][coverage-url]
|
|
14
|
+
[](#contributors)
|
|
15
|
+
|
|
16
|
+
[![NPM version][npm-version-image]][npm-url]
|
|
17
|
+
[![NPM downloads][npm-downloads-image]][npm-url]
|
|
18
|
+
[![MIT License][license-image]][license-url]
|
|
19
|
+
<!-- prettier-ignore-end -->
|
|
20
|
+
|
|
21
|
+
Cornerstone Core is not meant to be a complete application itself, but instead a component that can be used as part of larger more complex applications. See the
|
|
22
|
+
[OHIF Viewer](http://viewer.ohif.org/) for an example of using the various Cornerstone
|
|
23
|
+
libraries to build a simple study viewer.
|
|
24
|
+
|
|
25
|
+
Cornerstone Core is agnostic to the actual container used to store image pixels as well as the transport mechanism used to get the image data. In fact, Cornerstone Core itself has no ability to read/parse or load images and instead depends on one or more [ImageLoaders](https://github.com/cornerstonejs/cornerstone/wiki/ImageLoader) to function.
|
|
26
|
+
|
|
27
|
+
The goal here is to avoid constraining developers to work within a single container and transport (e.g. DICOM) since images are stored in a variety of formats (including proprietary). By providing flexibility with respect to the container and transport, the highest performance image display may be obtained as no conversion to an alternate container or transport is required. It is hoped that developers feel empowered to load images from any type of image container using any kind of transport. See the [CornerstoneWADOImageLoader](https://github.com/cornerstonejs/cornerstoneWADOImageLoader) project for an example
|
|
28
|
+
of a DICOM WADO based Image Loader.
|
|
29
|
+
|
|
30
|
+
Cornerstone Core is agnostic to the exact interaction paradigm being used. It does not include any mouse, touch or keyboard bindings to manipulate the various image properties such as scale, translation or ww/wc. The goal here is to avoid constraining developers using this library to fit into a given ui paradigm. It is hoped that developers are empowered to create new paradigms possibly using new input mechanisms to interact with medical images (e.g. [Kinect](http://en.wikipedia.org/wiki/Kinect) or [Accelerometer](http://en.wikipedia.org/wiki/Accelerometer)).
|
|
31
|
+
Cornerstone does provide a set of API's allowing manipulation of the image properties via javascript. See the [CornerstoneTools](https://github.com/cornerstonejs/cornerstoneTools) library for an example of common tools built on top of Cornerstone.
|
|
32
|
+
|
|
33
|
+
Community
|
|
34
|
+
---------
|
|
35
|
+
|
|
36
|
+
Have questions? Try posting on our [google groups forum](https://groups.google.com/forum/#!forum/cornerstone-platform).
|
|
37
|
+
|
|
38
|
+
Live Examples
|
|
39
|
+
---------------
|
|
40
|
+
The best way to see the power of this library is to actually see it in use.
|
|
41
|
+
|
|
42
|
+
[Click here for a list of examples of using the Cornerstone library.](https://rawgit.com/cornerstonejs/cornerstone/master/example/index.html)
|
|
43
|
+
|
|
44
|
+
Install
|
|
45
|
+
-------
|
|
46
|
+
|
|
47
|
+
Get a packaged source file:
|
|
48
|
+
|
|
49
|
+
* [cornerstone.js](https://unpkg.com/cornerstone-core/dist/cornerstone.js)
|
|
50
|
+
* `https://unpkg.com/cornerstone-core/dist/cornerstone.js`
|
|
51
|
+
* [cornerstone.min.js](https://unpkg.com/cornerstone-core/dist/cornerstone.min.js)
|
|
52
|
+
* `https://unpkg.com/cornerstone-core/dist/cornerstone.min.js`
|
|
53
|
+
|
|
54
|
+
Or install via [NPM](https://www.npmjs.com/):
|
|
55
|
+
|
|
56
|
+
**Latest stable release:**
|
|
57
|
+
|
|
58
|
+
> npm install cornerstone-core
|
|
59
|
+
|
|
60
|
+
**Pre-release, unstable, mostly for contributors:**
|
|
61
|
+
|
|
62
|
+
> npm install cornerstone-core@next
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
Key Features
|
|
66
|
+
------------
|
|
67
|
+
|
|
68
|
+
* HTML5/Javascript based library to easily add interactive medical images to web applications
|
|
69
|
+
* Serves as a foundation to build more complex medical imaging applications from - enterprise viewer, report viewer, etc.
|
|
70
|
+
* Supports all HTML5 based browsers including mobile, tablet and desktop
|
|
71
|
+
* Displays all common medical image formats (e.g. 8 bit grayscale, 16 bit grayscale, RGB color)
|
|
72
|
+
* High performance image display
|
|
73
|
+
* Retrieval of images from different systems with different protocols via Image Loader plugin design
|
|
74
|
+
* API support for changing viewport properties (e.g. ww/wc, zoom, pan, invert)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
Links
|
|
78
|
+
=====
|
|
79
|
+
|
|
80
|
+
[Development Process](docs/developmentProcess.md)
|
|
81
|
+
|
|
82
|
+
[Installation](docs/installation.md)
|
|
83
|
+
|
|
84
|
+
[Developer Guide](docs/developer-guide.md)
|
|
85
|
+
|
|
86
|
+
[View the wiki for documentation on the concepts and APIs](https://github.com/cornerstonejs/cornerstone/wiki)
|
|
87
|
+
|
|
88
|
+
[View Roadmap](docs/roadmap.md)
|
|
89
|
+
|
|
90
|
+
[View Backlog](docs/backlog.md)
|
|
91
|
+
|
|
92
|
+
[2014 comp.protocols.dicom thread that started this project](https://groups.google.com/forum/#!topic/comp.protocols.dicom/_2fMh69GdAM)
|
|
93
|
+
|
|
94
|
+
[CornerstoneTools](https://github.com/cornerstonejs/cornerstoneTools) - A library of common tools that can be used with Cornerstone
|
|
95
|
+
|
|
96
|
+
[CornerstoneWADOImageLoader](https://github.com/cornerstonejs/cornerstoneWADOImageLoader) - A Cornerstone Image Loader that works with WADO-URI, WADO-RS and DICOM P10 files
|
|
97
|
+
|
|
98
|
+
[CornerstoneWebImageLoader](https://github.com/cornerstonejs/cornerstoneWebImageLoader) - A Cornerstone Image Loader that works with PNG and JPEG files
|
|
99
|
+
|
|
100
|
+
[dicomParser](https://github.com/cornerstonejs/dicomParser) - A JavaScript library designed to parse DICOM for web browsers
|
|
101
|
+
|
|
102
|
+
Code Contributors
|
|
103
|
+
=================
|
|
104
|
+
|
|
105
|
+
I welcome pull requests, please see FAQ below for guidance on this.
|
|
106
|
+
|
|
107
|
+
* @simonmd - CSS improvements in the cornerstoneDemo application
|
|
108
|
+
* @doncharkowsky - The angle tool in cornerstoneTools
|
|
109
|
+
* @prasath-rasterimages - Touch event bindings in cornerstoneTools
|
|
110
|
+
* @jpamburn - Performance optimizations for signed data, fixes for image caching
|
|
111
|
+
* @jmhmd - for getPixels() implementation
|
|
112
|
+
* @devishree-raster - for flip and rotate implementation
|
|
113
|
+
|
|
114
|
+
FAQ
|
|
115
|
+
===
|
|
116
|
+
|
|
117
|
+
_Why did you decide to license this library using the open source MIT license?_
|
|
118
|
+
|
|
119
|
+
The main reason this library is released as [open source](http://en.wikipedia.org/wiki/Open_source) is
|
|
120
|
+
that I believe that medical imaging in particular can do a lot more to improve patient outcomes
|
|
121
|
+
but the cost of doing so is prohibitive. Making this library open source removes the cost barrier and will
|
|
122
|
+
hopefully usher in a new set of medical imaging based applications.
|
|
123
|
+
|
|
124
|
+
The old adage [a picture is worth a thousand words](http://en.wikipedia.org/wiki/A_picture_is_worth_a_thousand_words)
|
|
125
|
+
is very true in medical imaging. When a patient is going through a disease process, they often face fear
|
|
126
|
+
and confusion. Medical terminology amplifies these issues as it is hard to understand and therefore
|
|
127
|
+
disempowering. Medical imaging allows a mysterious health issue to be visualized and therefore brings a
|
|
128
|
+
level of understanding that just can't be accomplished via textual information found in lab or radiology
|
|
129
|
+
reports. By helping a patient (and its supporting friends/family) connect with the disease visually through images, it is believed that fear, anxiety and confusion will all be reduced which
|
|
130
|
+
will increase optimism and therefore patient outcomes.
|
|
131
|
+
|
|
132
|
+
It is my hope that this library be used to build a variety of applications and experiences
|
|
133
|
+
to deliver on this vision. The MIT license allows this library to be used in any type of application - personal, open source and commercial and is therefore appropriate to support this vision. If you are reading this, I hope you can join me in this mission as there is still a lot to be done.
|
|
134
|
+
|
|
135
|
+
_Why doesn't Cornerstone natively support the display of DICOM images?_
|
|
136
|
+
|
|
137
|
+
While DICOM has support for just about every type of medical image, there are many cases where medical images
|
|
138
|
+
are not stored in DICOM format. In many cases, a PACS may receive DICOM images but store them in a proprietary
|
|
139
|
+
format on disk. In this case, it can be faster to access images by having an image loader that works with
|
|
140
|
+
a proprietary PACS interface that would not require conversion from the proprietary format into a standard format
|
|
141
|
+
like DICOM. Another example of this is is dermatology where images are often taken using standard
|
|
142
|
+
digital cameras and are stored as JPEG not DICOM.
|
|
143
|
+
|
|
144
|
+
The main reason this library is not based around DICOM is that it wants to reach the widest possible adoption
|
|
145
|
+
and that will be accomplished by supporting as many types of image containers and transports possible.
|
|
146
|
+
Another side effect of this approach is that the code base is smaller and easier to understand since
|
|
147
|
+
it is focused on doing exactly one thing. That being said, it is is expected that the majority of images
|
|
148
|
+
displayed using this library will have originated as DICOM images. It is therefore important to make sure
|
|
149
|
+
that there are no limitations with respect to displaying the different types of DICOM images and have robust supporting libraries for DICOM. Separate libraries to add DICOM specific support already exist, check out the [CornerstoneWADOImageLoader](https://github.com/cornerstonejs/cornerstoneWADOImageLoader) library and the [dicomParser](https://github.com/cornerstonejs/dicomParser) library.
|
|
150
|
+
|
|
151
|
+
_Why doesn't Cornerstone include basic tools like ww/wc using the mouse?_
|
|
152
|
+
|
|
153
|
+
There is no standard for user interaction in medical imaging and a wide variety of interaction paradigms exist.
|
|
154
|
+
For example, one medical imaging application may use the left mouse button to adjust ww/wc and another may use the right mouse button. The main reason this library does not include tools is that it wants to reach the widest possible adoption and that will only be accomplished by making any interaction paradigm possible. No tools are therefore provided with this library allowing users of the library to choose
|
|
155
|
+
whatever interaction paradigm they like. It is also hoped that this approach will make it easier for developers to experiment with new user input mechanisms like [Kinect](http://en.wikipedia.org/wiki/Kinect) or [Accelerometer](http://en.wikipedia.org/wiki/Accelerometer). Another side effect of this
|
|
156
|
+
approach is that the code base is smaller and easier to understand since it is focused on doing exactly one
|
|
157
|
+
thing. Tools are provided using the separate [CornerstoneTools](https://github.com/cornerstonejs/cornerstoneTools) if desired.
|
|
158
|
+
|
|
159
|
+
_Why doesn't this library support older browsers like IE8?_
|
|
160
|
+
|
|
161
|
+
Much of the performance in this library is possible due to utilizing modern web features such as HTML5 canvas,
|
|
162
|
+
high performance javascript engines and WebGL. These feature are not avaialble in IE8 and there are no suitable
|
|
163
|
+
polyfills available. Sorry, upgrade your browser.
|
|
164
|
+
|
|
165
|
+
_Why doesn't this library support stacks of images?_
|
|
166
|
+
|
|
167
|
+
Images stack functionality such as a CT series or MRI series can actually be quite complex. Regardless of
|
|
168
|
+
what stack functionality is desired, all stacks ultimately need to be able to display a single image and that is what this library is focused on doing. Stack functionality is therefore pushed up to a higher layer. The [CornerstoneTools](https://github.com/cornerstonejs/cornerstoneTools) contains stack functionality and is a good place to look to see how various stack related functionality is implemented.
|
|
169
|
+
|
|
170
|
+
_How do you envision this library supporting 3D functionality such as MPR, MIP and VR?_
|
|
171
|
+
|
|
172
|
+
This library would be responsible for displaying the rendered image to the user. The rendering of the 3D image would be done by some other library - perhaps on the server side. This library is purely 2D and has no knowledge of 3D image space. It will probably make sense to have several layers on top of this library to provide 3D functionality. For example, one layer that has a 3D viewport with properties such as transformation matrix, slice thickness, transfer function/LUT, segmentation masks, etc. And another 3D tools layer that provides various tools on top of the 3d viewport (rotate, zoom, segment, scroll, etc).
|
|
173
|
+
|
|
174
|
+
OHIF/Cornerstone is working with the 3DSlicer project to integrate the two. I also expect to implement
|
|
175
|
+
client side MPR at some point as the browsers seem to be handling large memory much better.
|
|
176
|
+
|
|
177
|
+
_I would like to contribute code - how do I do this?_
|
|
178
|
+
|
|
179
|
+
Fork the repository, make your change and submit a pull request.
|
|
180
|
+
|
|
181
|
+
_Any guidance on submitting changes?_
|
|
182
|
+
|
|
183
|
+
While I do appreciate code contributions, I will not merge it unless it meets the following criteria:
|
|
184
|
+
|
|
185
|
+
* Functionality is appropriate for the repository. Consider posting on the forum if you are not sure
|
|
186
|
+
* Code quality is acceptable. I don't have coding standards defined, but make sure it passes ESLint and looks like the rest of the code in the repository.
|
|
187
|
+
* Quality of design is acceptable. This is a bit subjective so you should consider posting on the forum for specific guidance
|
|
188
|
+
|
|
189
|
+
I will provide feedback on your pull request if it fails to meet any of the above.
|
|
190
|
+
|
|
191
|
+
Please consider separate pull requests for each feature as big pull requests are very time consuming to understand.
|
|
192
|
+
It is highly probably that I will reject a large pull request due to the time it would take to comprehend.
|
|
193
|
+
|
|
194
|
+
_Will you add feature XYZ for me?_
|
|
195
|
+
|
|
196
|
+
If it is in the roadmap, I intend to implement it some day - probably when I actually need it. If you really need something now and are willing to pay for it, try posting on the cornerstone platform google group
|
|
197
|
+
|
|
198
|
+
Research notice
|
|
199
|
+
~~~~~~~~~~~~~~~
|
|
200
|
+
|
|
201
|
+
Please note that this repository is participating in a study into
|
|
202
|
+
sustainability of open source projects. Data will be gathered about this
|
|
203
|
+
repository for approximately the next 12 months, starting from June
|
|
204
|
+
2021.
|
|
205
|
+
|
|
206
|
+
Data collected will include number of contributors, number of PRs, time
|
|
207
|
+
taken to close/merge these PRs, and issues closed.
|
|
208
|
+
|
|
209
|
+
For more information, please visit `the informational
|
|
210
|
+
page <https://sustainable-open-science-and-software.github.io/>`__ or
|
|
211
|
+
download the `participant information
|
|
212
|
+
sheet <https://sustainable-open-science-and-software.github.io/assets/PIS_sustainable_software.pdf>`__.
|
|
213
|
+
|
|
214
|
+
Copyright
|
|
215
|
+
=========
|
|
216
|
+
|
|
217
|
+
Copyright 2017 Chris Hafey [chafey@gmail.com](mailto:chafey@gmail.com)
|
|
218
|
+
|
|
219
|
+
[license-image]: http://img.shields.io/badge/license-MIT-blue.svg?style=flat
|
|
220
|
+
[license-url]: LICENSE
|
|
221
|
+
|
|
222
|
+
[npm-url]: https://npmjs.org/package/cornerstone-core
|
|
223
|
+
[npm-version-image]: http://img.shields.io/npm/v/cornerstone-core.svg?style=flat
|
|
224
|
+
[npm-downloads-image]: http://img.shields.io/npm/dm/cornerstone-core.svg?style=flat
|
|
225
|
+
|
|
226
|
+
[travis-url]: http://travis-ci.org/cornerstonejs/cornerstone
|
|
227
|
+
[travis-image]: https://travis-ci.org/cornerstonejs/cornerstone.svg?branch=master
|
|
228
|
+
|
|
229
|
+
[coverage-url]: https://coveralls.io/github/cornerstonejs/cornerstone?branch=master
|
|
230
|
+
[coverage-image]: https://coveralls.io/repos/github/cornerstonejs/cornerstone/badge.svg?branch=master
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js / HarmonyOS bootstrap shim for cornerstone-core.
|
|
3
|
+
*
|
|
4
|
+
* cornerstone-core is a browser-only UMD library: its UMD wrapper evaluates
|
|
5
|
+
* `window` at load time, and its rendering pipeline needs DOM + canvas.
|
|
6
|
+
*
|
|
7
|
+
* This shim bootstraps a jsdom DOM environment (with real canvas 2D support
|
|
8
|
+
* provided by the `canvas` package, aliased to the HarmonyOS prebuilt
|
|
9
|
+
* `@ohos-ports/canvas`) so that the UMD bundle can be required from Node.js
|
|
10
|
+
* on HarmonyOS and canvas-based APIs can operate for real.
|
|
11
|
+
*
|
|
12
|
+
* WebGL IS available: since round 2 the optional native dependency
|
|
13
|
+
* `@ohos-ports/gl` (headless-gl HarmonyOS port, natively compiled via
|
|
14
|
+
* node-gyp against the OHOS EGL/GLES stack) provides real WebGL 1 contexts
|
|
15
|
+
* in Node.js. jsdom's HTMLCanvasElement#getContext is hooked so that
|
|
16
|
+
* 'webgl' / 'experimental-webgl' requests return a real headless-gl context,
|
|
17
|
+
* and each frame's framebuffer is copied back into the canvas backing
|
|
18
|
+
* surface so ctx2d.drawImage(webglCanvas) composites real pixels.
|
|
19
|
+
*/
|
|
20
|
+
"use strict";
|
|
21
|
+
|
|
22
|
+
if (typeof window !== "undefined") {
|
|
23
|
+
// Already in a browser-like environment; nothing to do.
|
|
24
|
+
module.exports = window;
|
|
25
|
+
} else {
|
|
26
|
+
const { JSDOM } = require("jsdom");
|
|
27
|
+
|
|
28
|
+
const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>", {
|
|
29
|
+
pretendToBeVisual: true,
|
|
30
|
+
url: "http://localhost/",
|
|
31
|
+
});
|
|
32
|
+
const win = dom.window;
|
|
33
|
+
|
|
34
|
+
// Expose the DOM environment as globals so that the UMD bundle's bare
|
|
35
|
+
// `window` / `document` / `navigator` references resolve inside Node.js.
|
|
36
|
+
// Some globals (e.g. navigator in Node >= 21) are getter-only, so use
|
|
37
|
+
// defineProperty and ignore failures for those already provided by Node.
|
|
38
|
+
const defineGlobal = (name, value) => {
|
|
39
|
+
try {
|
|
40
|
+
Object.defineProperty(globalThis, name, {
|
|
41
|
+
value,
|
|
42
|
+
writable: true,
|
|
43
|
+
configurable: true,
|
|
44
|
+
enumerable: false,
|
|
45
|
+
});
|
|
46
|
+
} catch (e) {
|
|
47
|
+
// Keep the Node-provided global if it cannot be redefined.
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
defineGlobal("window", win);
|
|
52
|
+
defineGlobal("document", win.document);
|
|
53
|
+
defineGlobal("navigator", win.navigator);
|
|
54
|
+
defineGlobal("location", win.location);
|
|
55
|
+
defineGlobal("Image", win.Image);
|
|
56
|
+
defineGlobal("HTMLElement", win.HTMLElement);
|
|
57
|
+
defineGlobal("HTMLCanvasElement", win.HTMLCanvasElement);
|
|
58
|
+
defineGlobal("XMLHttpRequest", win.XMLHttpRequest);
|
|
59
|
+
// Event classes must come from the jsdom realm: cornerstone creates events
|
|
60
|
+
// with `new CustomEvent(...)` and dispatches them on jsdom elements, which
|
|
61
|
+
// reject cross-realm (Node-built) events.
|
|
62
|
+
defineGlobal("CustomEvent", win.CustomEvent);
|
|
63
|
+
defineGlobal("Event", win.Event);
|
|
64
|
+
defineGlobal("getComputedStyle", win.getComputedStyle.bind(win));
|
|
65
|
+
defineGlobal("requestAnimationFrame", win.requestAnimationFrame.bind(win));
|
|
66
|
+
defineGlobal("cancelAnimationFrame", win.cancelAnimationFrame.bind(win));
|
|
67
|
+
|
|
68
|
+
// --- WebGL support via @ohos-ports/gl (headless-gl HarmonyOS port) ---
|
|
69
|
+
// headless-gl creates a REAL, natively compiled WebGL 1 context without a
|
|
70
|
+
// window (EGL/GLES on HarmonyOS). We hook jsdom's HTMLCanvasElement so
|
|
71
|
+
// canvas.getContext('webgl' / 'experimental-webgl') returns a headless-gl
|
|
72
|
+
// context sized to the canvas. Because a headless-gl context has no browser
|
|
73
|
+
// compositing step, the GL framebuffer is copied back into the jsdom
|
|
74
|
+
// canvas' 2D backing surface after every drawArrays() call, so
|
|
75
|
+
// ctx2d.drawImage(webglCanvas) composites real pixels (equivalent to
|
|
76
|
+
// preserveDrawingBuffer behaviour in a browser).
|
|
77
|
+
try {
|
|
78
|
+
const createGL = require("@ohos-ports/gl");
|
|
79
|
+
const idlUtils = require("jsdom/lib/generated/idl/utils");
|
|
80
|
+
|
|
81
|
+
const glStates = new WeakMap();
|
|
82
|
+
|
|
83
|
+
function syncFramebufferToCanvas(state) {
|
|
84
|
+
try {
|
|
85
|
+
const { gl, w, h, impl } = state;
|
|
86
|
+
if (!gl || !w || !h) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const buf = new Uint8Array(w * h * 4);
|
|
90
|
+
gl.readPixels(0, 0, w, h, gl.RGBA, gl.UNSIGNED_BYTE, buf);
|
|
91
|
+
// GL framebuffers are bottom-up; flip rows for the 2D surface and
|
|
92
|
+
// force opaque alpha so drawImage compositing is not transparent.
|
|
93
|
+
const flipped = new Uint8Array(w * h * 4);
|
|
94
|
+
const row = w * 4;
|
|
95
|
+
for (let y = 0; y < h; y++) {
|
|
96
|
+
flipped.set(buf.subarray((h - 1 - y) * row, (h - y) * row), y * row);
|
|
97
|
+
for (let x = 3; x < row; x += 4) {
|
|
98
|
+
flipped[y * row + x] = 255;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const c2d = impl._getCanvas().getContext("2d");
|
|
102
|
+
const img = c2d.createImageData(w, h);
|
|
103
|
+
img.data.set(flipped);
|
|
104
|
+
c2d.putImageData(img, 0, 0);
|
|
105
|
+
} catch (e) {
|
|
106
|
+
// Never break the GL draw loop because of a copy-back failure.
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function makeHandler(state) {
|
|
111
|
+
return {
|
|
112
|
+
get(target, prop) {
|
|
113
|
+
if (prop === "canvas") {
|
|
114
|
+
return state.canvas;
|
|
115
|
+
}
|
|
116
|
+
if (prop === "drawingBufferWidth") {
|
|
117
|
+
return state.w;
|
|
118
|
+
}
|
|
119
|
+
if (prop === "drawingBufferHeight") {
|
|
120
|
+
return state.h;
|
|
121
|
+
}
|
|
122
|
+
if (prop === "__cornerstoneGLState") {
|
|
123
|
+
return state;
|
|
124
|
+
}
|
|
125
|
+
// After each real GL draw, copy the framebuffer into the jsdom
|
|
126
|
+
// canvas backing surface so drawImage() composites real pixels.
|
|
127
|
+
if (prop === "drawArrays") {
|
|
128
|
+
return function (mode, first, count) {
|
|
129
|
+
const r = state.gl.drawArrays(mode, first, count);
|
|
130
|
+
syncFramebufferToCanvas(state);
|
|
131
|
+
return r;
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
// OHOS ANGLE GLES driver: 'precision mediump float' is broken for
|
|
135
|
+
// the 65536-scale arithmetic cornerstone's int16/uint16 shaders
|
|
136
|
+
// rely on (decoded values collapse). Upgrade fragment shaders to
|
|
137
|
+
// highp, which works on this driver.
|
|
138
|
+
if (prop === "shaderSource") {
|
|
139
|
+
return function (shader, src) {
|
|
140
|
+
if (typeof src === "string") {
|
|
141
|
+
src = src.replace(
|
|
142
|
+
/^precision\s+mediump\s+float\s*;/,
|
|
143
|
+
"precision highp float;"
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
return state.gl.shaderSource(shader, src);
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const v = state.gl[prop];
|
|
150
|
+
return typeof v === "function" ? v.bind(state.gl) : v;
|
|
151
|
+
},
|
|
152
|
+
has(target, prop) {
|
|
153
|
+
return prop in state.gl || prop === "canvas";
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function resizeIfNeeded(state) {
|
|
159
|
+
const canvas = state.canvas;
|
|
160
|
+
const w = canvas.width;
|
|
161
|
+
const h = canvas.height;
|
|
162
|
+
if (!w || !h || (w === state.w && h === state.h)) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
state.w = w;
|
|
166
|
+
state.h = h;
|
|
167
|
+
let newGl = null;
|
|
168
|
+
try {
|
|
169
|
+
newGl = createGL(w, h);
|
|
170
|
+
} catch (e) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (!newGl) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
state.gl = newGl;
|
|
177
|
+
// Mimic the browser context-lost/restored cycle so cornerstone purges
|
|
178
|
+
// its texture/program caches and re-initializes on the new GL context.
|
|
179
|
+
state.canvas.dispatchEvent(
|
|
180
|
+
new win.Event("webglcontextlost", { cancelable: true })
|
|
181
|
+
);
|
|
182
|
+
state.canvas.dispatchEvent(new win.Event("webglcontextrestored"));
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function watchResize(state) {
|
|
186
|
+
const canvas = state.canvas;
|
|
187
|
+
const proto = Object.getPrototypeOf(canvas);
|
|
188
|
+
for (const dim of ["width", "height"]) {
|
|
189
|
+
const d = Object.getOwnPropertyDescriptor(proto, dim);
|
|
190
|
+
if (!d || typeof d.set !== "function") {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
Object.defineProperty(canvas, dim, {
|
|
194
|
+
get() {
|
|
195
|
+
return d.get.call(canvas);
|
|
196
|
+
},
|
|
197
|
+
set(v) {
|
|
198
|
+
d.set.call(canvas, v);
|
|
199
|
+
try {
|
|
200
|
+
resizeIfNeeded(state);
|
|
201
|
+
} catch (e) {
|
|
202
|
+
// ignore resize handling errors
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
configurable: true,
|
|
206
|
+
enumerable: d.enumerable,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function getOrCreateWebGLContext(canvasWrapper, options) {
|
|
212
|
+
let state = glStates.get(canvasWrapper);
|
|
213
|
+
if (state) {
|
|
214
|
+
return state.wrapper;
|
|
215
|
+
}
|
|
216
|
+
const impl = idlUtils.implForWrapper(canvasWrapper);
|
|
217
|
+
if (!impl || !impl._getCanvas()) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
const w = canvasWrapper.width || 300;
|
|
221
|
+
const h = canvasWrapper.height || 150;
|
|
222
|
+
let gl = null;
|
|
223
|
+
try {
|
|
224
|
+
gl = createGL(w, h);
|
|
225
|
+
} catch (e) {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
if (!gl) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
state = { gl, w, h, impl, canvas: canvasWrapper };
|
|
232
|
+
state.wrapper = new Proxy({}, makeHandler(state));
|
|
233
|
+
glStates.set(canvasWrapper, state);
|
|
234
|
+
watchResize(state);
|
|
235
|
+
return state.wrapper;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const origGetContext = win.HTMLCanvasElement.prototype.getContext;
|
|
239
|
+
win.HTMLCanvasElement.prototype.getContext = function (contextId) {
|
|
240
|
+
const t = String(contextId).toLowerCase();
|
|
241
|
+
if (t === "webgl" || t === "experimental-webgl") {
|
|
242
|
+
return getOrCreateWebGLContext(this, arguments[1]);
|
|
243
|
+
}
|
|
244
|
+
return origGetContext.apply(this, arguments);
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
// Expose on both the Node global (bare `WebGLRenderingContext`
|
|
248
|
+
// references) and the jsdom window (cornerstone checks
|
|
249
|
+
// `window.WebGLRenderingContext` in isWebGLAvailable()).
|
|
250
|
+
defineGlobal("WebGLRenderingContext", createGL.WebGLRenderingContext);
|
|
251
|
+
try {
|
|
252
|
+
win.WebGLRenderingContext = createGL.WebGLRenderingContext;
|
|
253
|
+
} catch (e2) {
|
|
254
|
+
// ignore
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
win.__cornerstoneWebGLSource = "@ohos-ports/gl";
|
|
258
|
+
} catch (e) {
|
|
259
|
+
// @ohos-ports/gl unavailable or failed to load: WebGL stays unavailable
|
|
260
|
+
// and canvas2D rendering continues to work.
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
module.exports = win;
|
|
264
|
+
}
|