Initial project import
This commit is contained in:
186
node_modules/@monogrid/gainmap-js/CHANGELOG.md
generated
vendored
Normal file
186
node_modules/@monogrid/gainmap-js/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
# [3.4.0](https://github.com/MONOGRID/gainmap-js/compare/v3.3.0...v3.4.0) (2025-11-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adds AgXToneMapping and NeutralToneMapping to encoding SDR Material shader ([8c163da](https://github.com/MONOGRID/gainmap-js/commit/8c163da5c208412814d3f4ee9e3647d0ad3bba12))
|
||||
|
||||
# [3.3.0](https://github.com/MONOGRID/gainmap-js/compare/v3.2.0...v3.3.0) (2025-11-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* removes wasm dependency and implements pure-js JPG encoder ([#73](https://github.com/MONOGRID/gainmap-js/issues/73)) ([00b6e43](https://github.com/MONOGRID/gainmap-js/commit/00b6e43f2ada89e39d76491017ff173574a20873))
|
||||
|
||||
# [3.2.0](https://github.com/MONOGRID/gainmap-js/compare/v3.1.0...v3.2.0) (2025-11-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* WebGPU support ([#72](https://github.com/MONOGRID/gainmap-js/issues/72)) ([0d85bec](https://github.com/MONOGRID/gainmap-js/commit/0d85becd0e8b79fc5adfb5bbd757e35e032ee77e))
|
||||
|
||||
# [3.1.0](https://github.com/MONOGRID/gainmap-js/compare/v3.0.6...v3.1.0) (2024-12-05)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **decode:** removes `DOMParser`, decode is now compatible with Web Workers ([b6a607d](https://github.com/MONOGRID/gainmap-js/commit/b6a607d1be3e7e86524e059c9eb61c8ee2a9e6f7))
|
||||
|
||||
## [3.0.6](https://github.com/MONOGRID/gainmap-js/compare/v3.0.5...v3.0.6) (2024-09-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove LogLuv following threejs removal https://github.com/mrdoob/three.js/pull/29144 ([1df2154](https://github.com/MONOGRID/gainmap-js/commit/1df2154dce59aff39439eb4974c42b55eddc862b))
|
||||
|
||||
## [3.0.5](https://github.com/MONOGRID/gainmap-js/compare/v3.0.4...v3.0.5) (2024-04-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **package.json:** publint fixes so that package is correctly imported in next.js ([#36](https://github.com/MONOGRID/gainmap-js/issues/36)) ([490df10](https://github.com/MONOGRID/gainmap-js/commit/490df10f401a82267595dd9e161cc6a0bbce3d94))
|
||||
|
||||
## [3.0.4](https://github.com/MONOGRID/gainmap-js/compare/v3.0.3...v3.0.4) (2024-04-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* adds setRenderer on LoaderBase ([#34](https://github.com/MONOGRID/gainmap-js/issues/34)) ([18ad0ec](https://github.com/MONOGRID/gainmap-js/commit/18ad0eca49d95685b7f78fc4137f4aaf1338e782))
|
||||
|
||||
## [3.0.3](https://github.com/MONOGRID/gainmap-js/compare/v3.0.2...v3.0.3) (2024-02-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **libultrahdr-wasm:** encoding of odd sized images ([#31](https://github.com/MONOGRID/gainmap-js/issues/31)) ([efd52c3](https://github.com/MONOGRID/gainmap-js/commit/efd52c385387d2575c161e243b07369100e8e349))
|
||||
|
||||
## [3.0.2](https://github.com/MONOGRID/gainmap-js/compare/v3.0.1...v3.0.2) (2024-01-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **encode:** encodes a valid image when an invalid tonemapping value was provided as input ([94cec23](https://github.com/MONOGRID/gainmap-js/commit/94cec2363aa0dcb3cc46fca048c68ed7e555ebd0))
|
||||
|
||||
## [3.0.1](https://github.com/MONOGRID/gainmap-js/compare/v3.0.0...v3.0.1) (2023-12-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **encode:** hdrCapacityMax correctly computed in output metadata ([f5f2215](https://github.com/MONOGRID/gainmap-js/commit/f5f22152eb236831cb9f23646445e6459be18285))
|
||||
* **encode:** findTextureMinMax correctly finds min values in textures ([fd94680](https://github.com/MONOGRID/gainmap-js/commit/fd94680a76fdb04b5aa85b4210f3aec21b45a727))
|
||||
|
||||
# [3.0.0](https://github.com/MONOGRID/gainmap-js/compare/v2.0.7...v3.0.0) (2023-11-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **loaders:** properly catches render errors and calls onError callback ([b9bcdd1](https://github.com/MONOGRID/gainmap-js/commit/b9bcdd127576fa61c6ee92c876f4845cd80b4d34)), closes [#16](https://github.com/MONOGRID/gainmap-js/issues/16)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **core:** disables default mipmap generation, enables user to specify renderTarget (and toDataTexture) options ([147d278](https://github.com/MONOGRID/gainmap-js/commit/147d2783224cb0a2039d762abf4e4b972b0e86da)), closes [#14](https://github.com/MONOGRID/gainmap-js/issues/14) [#15](https://github.com/MONOGRID/gainmap-js/issues/15)
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* **core:** `generateMipmaps` is no longer `true` by default, both `minFilter` is no longer `LinearMipMapLinearFilter` by default but `LinearFilter`, `wrapS` and `warpT` are no longer `RepeatWrapping` by default but `ClampToEdgeWrapping`
|
||||
|
||||
## [2.0.7](https://github.com/MONOGRID/gainmap-js/compare/v2.0.6...v2.0.7) (2023-11-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** QuadRenderer dispose method now properly disposes of its internal resources ([#13](https://github.com/MONOGRID/gainmap-js/issues/13)) ([8e4473d](https://github.com/MONOGRID/gainmap-js/commit/8e4473da77732080de24f98dd271fecda06f9e53))
|
||||
* **HDRJPGLoader:** renders (and returns) an SDR image when provided with a normal jpeg file ([#12](https://github.com/MONOGRID/gainmap-js/issues/12)) ([5222151](https://github.com/MONOGRID/gainmap-js/commit/5222151e6b5c95df79f1c4085cf36f30bd9c2dc4))
|
||||
|
||||
## [2.0.6](https://github.com/MONOGRID/gainmap-js/compare/v2.0.5...v2.0.6) (2023-11-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **decode:** changes usage of `NoColorSpace` to `LinearSRGBColorSpace` ([587dc03](https://github.com/MONOGRID/gainmap-js/commit/587dc0377876533b18b506516d8757e04e830c62))
|
||||
* **loaders:** fixes LoadingManager `onLoad` actually waiting for gainmaps to be generated ([77170f5](https://github.com/MONOGRID/gainmap-js/commit/77170f57c5ad277d3e97d1236ab93a29106c4a99))
|
||||
|
||||
## [2.0.5](https://github.com/MONOGRID/gainmap-js/compare/v2.0.4...v2.0.5) (2023-11-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **jpegrloader:** rename JPEGRLoader to HDRJPEGLoader, old name kept for compatibility ([ac6e386](https://github.com/MONOGRID/gainmap-js/commit/ac6e38610886b7adec5806a7ad301bff1ec00d62))
|
||||
|
||||
## [2.0.4](https://github.com/MONOGRID/gainmap-js/compare/v2.0.3...v2.0.4) (2023-11-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **decode:** clamp max values in the decode shader to min/max half float ([96986be](https://github.com/MONOGRID/gainmap-js/commit/96986be23dd95825d19fac3b3de520d59d8ad936))
|
||||
|
||||
## [2.0.3](https://github.com/MONOGRID/gainmap-js/compare/v2.0.2...v2.0.3) (2023-11-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **gainmaploader:** fix GainMapLoader progress handler not being calculated correctly ([a8e556a](https://github.com/MONOGRID/gainmap-js/commit/a8e556ab1d465a9bd705960d175464cf8d434ea1))
|
||||
|
||||
## [2.0.2](https://github.com/MONOGRID/gainmap-js/compare/v2.0.1...v2.0.2) (2023-11-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **decode:** improves compatibility with browsers with no createImageBitmap ([12c7609](https://github.com/MONOGRID/gainmap-js/commit/12c7609ee815a460f95419aab328b412e759f012))
|
||||
* **decoder:** fix bug when using decodeResult.renderTarget.texture as source for PMREMGenerator ([4ebb983](https://github.com/MONOGRID/gainmap-js/commit/4ebb983d5bbc7f524e4b1231f630e3714cf1f870))
|
||||
|
||||
## [2.0.1](https://github.com/MONOGRID/gainmap-js/compare/v2.0.0...v2.0.1) (2023-11-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **decode:** implements proper feature testing for QuadRenderer.toArray ([20109ad](https://github.com/MONOGRID/gainmap-js/commit/20109ad31977124c1169f096e8ccd36628599f89))
|
||||
|
||||
# [2.0.0](https://github.com/MONOGRID/gainmap-js/compare/v1.1.1...v2.0.0) (2023-11-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* removes libultrahdr wasm from the decoding part of the library, allows users to load JPEGR files using pure js ([#9](https://github.com/MONOGRID/gainmap-js/issues/9)) ([3ad16f9](https://github.com/MONOGRID/gainmap-js/commit/3ad16f97fec6040fdfdfb4cd5e71b1ac8e504e28))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* The encoder portion of the library has been separated and moved to `@monogrid/gainmap-js/encode`, in order to save file size on user's bundles, all encoding functions must now be imported with that path.
|
||||
|
||||
`JPEGRLoader` has been moved from `@monogrid/gainmap-js/libultrahdr` to `@monogrid/gainmap-js` because it now uses a pure js approach
|
||||
|
||||
## [1.1.1](https://github.com/MONOGRID/gainmap-js/compare/v1.1.0...v1.1.1) (2023-11-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fixes Firefox Compatibility ([1cec657](https://github.com/MONOGRID/gainmap-js/commit/1cec65708127b6fd064277f4f923fc0f65610fa2))
|
||||
* **libultrahdr:** fixes circular dependency between JPEGRLoader and libultrahdr ([f30f786](https://github.com/MONOGRID/gainmap-js/commit/f30f7865fb27a601635168b8a104a9935653e758))
|
||||
|
||||
# [1.1.0](https://github.com/MONOGRID/gainmap-js/compare/v1.0.2...v1.1.0) (2023-11-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **decode:** adds threejs loaders ([b32f02a](https://github.com/MONOGRID/gainmap-js/commit/b32f02a09d20fbd9d17b35c65cf4dba8aafc9ed5))
|
||||
|
||||
## [1.0.2](https://github.com/MONOGRID/gainmap-js/compare/v1.0.1...v1.0.2) (2023-11-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **release:** add publishConfig to package.json ([cffff0b](https://github.com/MONOGRID/gainmap-js/commit/cffff0b31050ab54040922748b82d97e6aa820a3))
|
||||
|
||||
## [1.0.1](https://github.com/MONOGRID/gainmap-js/compare/v1.0.0...v1.0.1) (2023-11-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **release:** scoped package for NPM publishing ([0e30758](https://github.com/MONOGRID/gainmap-js/commit/0e307589e51dd05e160062f2ae78fc746cbdf5aa))
|
||||
|
||||
# 1.0.0 (2023-11-03)
|
||||
|
||||
First Release
|
||||
128
node_modules/@monogrid/gainmap-js/CODE_OF_CONDUCT.md
generated
vendored
Normal file
128
node_modules/@monogrid/gainmap-js/CODE_OF_CONDUCT.md
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
gainmap@monogrid.com.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
130
node_modules/@monogrid/gainmap-js/CONTRIBUTING.md
generated
vendored
Normal file
130
node_modules/@monogrid/gainmap-js/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
<!-- omit in toc -->
|
||||
# Contributing to gainmap-js
|
||||
|
||||
First off, thanks for taking the time to contribute! ❤️
|
||||
|
||||
All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉
|
||||
|
||||
> And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about:
|
||||
> - Star the project
|
||||
> - Tweet about it
|
||||
> - Refer this project in your project's readme
|
||||
> - Mention the project at local meetups and tell your friends/colleagues
|
||||
|
||||
<!-- omit in toc -->
|
||||
## Table of Contents
|
||||
|
||||
- [I Have a Question](#i-have-a-question)
|
||||
- [I Want To Contribute](#i-want-to-contribute)
|
||||
- [Reporting Bugs](#reporting-bugs)
|
||||
- [Suggesting Enhancements](#suggesting-enhancements)
|
||||
- [Your First Code Contribution](#your-first-code-contribution)
|
||||
- [Improving The Documentation](#improving-the-documentation)
|
||||
- [Styleguides](#styleguides)
|
||||
- [Commit Messages](#commit-messages)
|
||||
- [Join The Project Team](#join-the-project-team)
|
||||
|
||||
|
||||
|
||||
## I Have a Question
|
||||
|
||||
> If you want to ask a question, we assume that you have read the available [Documentation](https://github.com/MONOGRID/gainmap-js/wiki).
|
||||
|
||||
Before you ask a question, it is best to search for existing [Issues](https://github.com/MONOGRID/gainmap-js/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.
|
||||
|
||||
If you then still feel the need to ask a question and need clarification, we recommend the following:
|
||||
|
||||
- Open an [Issue](https://github.com/MONOGRID/gainmap-js/issues/new).
|
||||
- Provide as much context as you can about what you're running into.
|
||||
- Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant.
|
||||
|
||||
We will then take care of the issue as soon as possible.
|
||||
|
||||
<!--
|
||||
You might want to create a separate issue tag for questions and include it in this description. People should then tag their issues accordingly.
|
||||
|
||||
Depending on how large the project is, you may want to outsource the questioning, e.g. to Stack Overflow or Gitter. You may add additional contact and information possibilities:
|
||||
- IRC
|
||||
- Slack
|
||||
- Gitter
|
||||
- Stack Overflow tag
|
||||
- Blog
|
||||
- FAQ
|
||||
- Roadmap
|
||||
- E-Mail List
|
||||
- Forum
|
||||
-->
|
||||
|
||||
## I Want To Contribute
|
||||
|
||||
> ### Legal Notice <!-- omit in toc -->
|
||||
> When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license.
|
||||
|
||||
### Reporting Bugs
|
||||
|
||||
<!-- omit in toc -->
|
||||
#### Before Submitting a Bug Report
|
||||
|
||||
A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.
|
||||
|
||||
- Make sure that you are using the latest version.
|
||||
- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](https://github.com/MONOGRID/gainmap-js/wiki). If you are looking for support, you might want to check [this section](#i-have-a-question)).
|
||||
- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/MONOGRID/gainmap-jsissues?q=label%3Abug).
|
||||
- Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.
|
||||
- Collect information about the bug:
|
||||
- Stack trace (Traceback)
|
||||
- OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
|
||||
- Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
|
||||
- Possibly your input and the output
|
||||
- Can you reliably reproduce the issue? And can you also reproduce it with older versions?
|
||||
|
||||
<!-- omit in toc -->
|
||||
#### How Do I Submit a Good Bug Report?
|
||||
|
||||
> You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to <gainmap@monogrid.com>.
|
||||
<!-- You may add a PGP key to allow the messages to be sent encrypted as well. -->
|
||||
|
||||
We use GitHub issues to track bugs and errors. If you run into an issue with the project:
|
||||
|
||||
- Open an [Issue](https://github.com/MONOGRID/gainmap-js/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
|
||||
- Explain the behavior you would expect and the actual behavior.
|
||||
- Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
|
||||
- Provide the information you collected in the previous section.
|
||||
|
||||
Once it's filed:
|
||||
|
||||
- The project team will label the issue accordingly.
|
||||
- A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as `needs-repro`. Bugs with the `needs-repro` tag will not be addressed until they are reproduced.
|
||||
- If the team is able to reproduce the issue, it will be marked `needs-fix`, as well as possibly other tags (such as `critical`), and the issue will be left to be [implemented by someone](#your-first-code-contribution).
|
||||
|
||||
<!-- You might want to create an issue template for bugs and errors that can be used as a guide and that defines the structure of the information to be included. If you do so, reference it here in the description. -->
|
||||
|
||||
|
||||
### Suggesting Enhancements
|
||||
|
||||
This section guides you through submitting an enhancement suggestion for gainmap-js, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.
|
||||
|
||||
<!-- omit in toc -->
|
||||
#### Before Submitting an Enhancement
|
||||
|
||||
- Make sure that you are using the latest version.
|
||||
- Read the [documentation](https://github.com/MONOGRID/gainmap-js/wiki) carefully and find out if the functionality is already covered, maybe by an individual configuration.
|
||||
- Perform a [search](https://github.com/MONOGRID/gainmap-js/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
|
||||
- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
|
||||
|
||||
<!-- omit in toc -->
|
||||
#### How Do I Submit a Good Enhancement Suggestion?
|
||||
|
||||
Enhancement suggestions are tracked as [GitHub issues](https://github.com/MONOGRID/gainmap-js/issues).
|
||||
|
||||
- Use a **clear and descriptive title** for the issue to identify the suggestion.
|
||||
- Provide a **step-by-step description of the suggested enhancement** in as many details as possible.
|
||||
- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you.
|
||||
- You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to. You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux. <!-- this should only be included if the project has a GUI -->
|
||||
- **Explain why this enhancement would be useful** to most gainmap-js users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
|
||||
|
||||
|
||||
|
||||
<!-- omit in toc -->
|
||||
## Attribution
|
||||
This guide is based on the **contributing-gen**. [Make your own](https://github.com/bttger/contributing-gen)!
|
||||
21
node_modules/@monogrid/gainmap-js/LICENSE
generated
vendored
Normal file
21
node_modules/@monogrid/gainmap-js/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 MONOGRID
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
371
node_modules/@monogrid/gainmap-js/README.md
generated
vendored
Normal file
371
node_modules/@monogrid/gainmap-js/README.md
generated
vendored
Normal file
@@ -0,0 +1,371 @@
|
||||
# gainmap-js
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2FMONOGRID%2Fgainmap-js?ref=badge_shield)
|
||||
|
||||
A Javascript (TypeScript) Encoder/Decoder Implementation of Adobe's Gain Map Technology for storing HDR Images using an SDR Image + a "Gain map"
|
||||
|
||||
> :warning: This library is intended for encoding and decoding gain map images for the [three.js](https://github.com/mrdoob/three.js/) 3D Library
|
||||
>
|
||||
> It can be used for general encode/decode of gain maps but it depends on the three.js library which, in itself, is quite heavy if you only use it to encode/decode gain maps.
|
||||
|
||||
## Share Your Project!
|
||||
Have you built something awesome using this library? We’d love to see what you’ve created!
|
||||
Whether it’s a small demo or a full-scale application, your project can inspire others and help improve the library. Please share your work in one of these ways:
|
||||
* GitHub Issues: [Open a new issue](https://github.com/MONOGRID/gainmap-js/issues/new) in this repository with a brief description, screenshots, and links to your project.
|
||||
* Email: Send us an email at gainmap@monogrid.com with your project details.
|
||||
Your contributions and creative ideas make our community stronger. We can’t wait to see what you build!
|
||||
|
||||
## Live Demo
|
||||
|
||||
* [WebGPU Version](https://monogrid.github.io/gainmap-js/webgpu.html)
|
||||
* [Legacy WebGL Version](https://monogrid.github.io/gainmap-js/)
|
||||
|
||||
Both compares loading:
|
||||
1. a `JPEG` file with embedded gain map data
|
||||
2. a `webp` sdr file + a `webp` gain map + metadata JSON
|
||||
3. a comparable size `.hdr` file for comparison
|
||||
|
||||
## [Free online encoder](https://gainmap-creator.monogrid.com)
|
||||
|
||||
Use it to convert `.hdr` and `.exr` files into gain maps. It's free and the whole process happens in your browser.
|
||||
|
||||
## Installing
|
||||
```bash
|
||||
$ npm install @monogrid/gainmap-js three
|
||||
```
|
||||
|
||||
## What is a Gain map?
|
||||
|
||||
[See here](https://gregbenzphotography.com/hdr-images/jpg-hdr-gain-maps-in-adobe-camera-raw/) for a detailed explanation, here are some relevant parts:
|
||||
|
||||
> A gain map is a single file with a second pseudo-image embedded in it to create an optimized result for a specific monitor. It can be used to generate the HDR version (which looks dramatically better where supported), the SDR version (without tone mapping to ensures great quality), or anything in between (to better support less capable HDR displays).
|
||||
|
||||
> Gain maps are not a new type of file, but rather a technology which can be embedded into a variety of image formats. There are reference specs already for the JPG, AVIF, JXL, and HEIF file formats. JPG is especially notable as it could not properly support HDR without gain maps and it offers a very useful bridge to the future (i.e. highly compatible with today’s software).
|
||||
|
||||
> A gain map includes:
|
||||
>
|
||||
> * A **base (default) image**. This can be an SDR or an HDR image (JPG gain maps are always encoded with SDR as the base). If the browser or viewing software does not understand gain maps, it will just the treat file as if it were just the base image.
|
||||
> * The **gain map**. This is a secondary “image” embedded in the file. It is not a real image, but rather contains data to convert each pixel from the base image into the other (SDR or HDR) version of the image.
|
||||
>* Gain map **metadata**. This tells the browser how the gain map is encoded as well as critical information to optimize rendering on any display.
|
||||
|
||||
Please note that Google [is adopting the gain map technology in Android 14](https://support.google.com/photos/answer/14159275) but its naming of the technology refers to it as **Ultra HDR Image Format** and a JPEG file with embedded gain map is [apparently called JPEGR](https://github.com/google/libultrahdr/blob/3a3a752a5da0b2304b1b6de0ef383bbe41256a67/lib/jpegr.h#L28C16-L28C21) in their terminology, we call it `HDRJPEG` for the moment.
|
||||
|
||||
## API
|
||||
|
||||
Refer to the [WIKI](https://github.com/MONOGRID/gainmap-js/wiki) for detailed documentation about the API.
|
||||
|
||||
## Examples
|
||||
|
||||
### Decoding
|
||||
|
||||
The main use case of this library is to decode a JPEG file that contains gain map data
|
||||
and use it instead of a traditional `.exr` or `.hdr` image.
|
||||
|
||||
> NOTE: Starting from v3.1.0 Decoding also works in a WebWorker, thanks to [Alejandro Romano](https://github.com/Arecsu) for the [contribution](https://github.com/MONOGRID/gainmap-js/pull/59)
|
||||
|
||||
### Using a single JPEG with embedded Gain map Metadata
|
||||
|
||||
This approach lets you load a single file with an embedded Gain Map.
|
||||
|
||||
The advantage is to have a single file to load.
|
||||
|
||||
The disadvantages are:
|
||||
* No WEBP compression
|
||||
* The JPEG cannot be manipulated in Photoshop, GIMP, or any other software that does not support the gain map technology (no photo editing software supports it at the time of writing 06-11-2023).
|
||||
* Photo sharing websites and/or services (i.e. sharing with Slack) will likely strip the Gain map metadata and the HDR information will be lost, leaving you with only the SDR Representation.
|
||||
|
||||
```ts
|
||||
import { HDRJPGLoader } from '@monogrid/gainmap-js'
|
||||
import {
|
||||
EquirectangularReflectionMapping,
|
||||
Mesh,
|
||||
MeshBasicMaterial,
|
||||
PerspectiveCamera,
|
||||
PlaneGeometry,
|
||||
Scene,
|
||||
WebGLRenderer
|
||||
} from 'three'
|
||||
|
||||
const renderer = new WebGLRenderer()
|
||||
|
||||
const loader = new HDRJPGLoader(renderer)
|
||||
.setRenderTargetOptions({ mapping: EquirectangularReflectionMapping })
|
||||
|
||||
const result = await loader.loadAsync('gainmap.jpeg')
|
||||
// `result` can be used to populate a Texture
|
||||
|
||||
const scene = new Scene()
|
||||
const mesh = new Mesh(
|
||||
new PlaneGeometry(),
|
||||
new MeshBasicMaterial({ map: result.renderTarget.texture })
|
||||
)
|
||||
scene.add(mesh)
|
||||
renderer.render(scene, new PerspectiveCamera())
|
||||
|
||||
// Starting from three.js r159
|
||||
// `result.renderTarget.texture` can
|
||||
// also be used as Equirectangular scene background
|
||||
//
|
||||
// it was previously needed to convert it
|
||||
// to a DataTexture with `result.toDataTexture()`
|
||||
scene.background = result.renderTarget.texture
|
||||
|
||||
// result must be manually disposed
|
||||
// when you are done using it
|
||||
result.dispose()
|
||||
```
|
||||
|
||||
### Using separate files
|
||||
|
||||
Using separate files will get rid of the limitations of using a single JPEG file but it will force to use three separate files
|
||||
|
||||
1. An SDR Representation file
|
||||
2. A Gainmap file
|
||||
3. A JSON containing the gainmap metadata used for decoding
|
||||
|
||||
|
||||
```ts
|
||||
import { GainMapLoader } from '@monogrid/gainmap-js'
|
||||
import {
|
||||
EquirectangularReflectionMapping,
|
||||
Mesh,
|
||||
MeshBasicMaterial,
|
||||
PerspectiveCamera,
|
||||
PlaneGeometry,
|
||||
Scene,
|
||||
WebGLRenderer
|
||||
} from 'three'
|
||||
|
||||
const renderer = new WebGLRenderer()
|
||||
|
||||
const loader = new GainMapLoader(renderer)
|
||||
.setRenderTargetOptions({ mapping: EquirectangularReflectionMapping })
|
||||
|
||||
const result = await loader.loadAsync(['sdr.jpeg', 'gainmap.jpeg', 'metadata.json'])
|
||||
// `result` can be used to populate a Texture
|
||||
|
||||
const scene = new Scene()
|
||||
const mesh = new Mesh(
|
||||
new PlaneGeometry(),
|
||||
new MeshBasicMaterial({ map: result.renderTarget.texture })
|
||||
)
|
||||
scene.add(mesh)
|
||||
renderer.render(scene, new PerspectiveCamera())
|
||||
|
||||
// Starting from three.js r159
|
||||
// `result.renderTarget.texture` can
|
||||
// also be used as Equirectangular scene background
|
||||
//
|
||||
// it was previously needed to convert it
|
||||
// to a DataTexture with `result.toDataTexture()`
|
||||
scene.background = result.renderTarget.texture
|
||||
|
||||
// result must be manually disposed
|
||||
// when you are done using it
|
||||
result.dispose()
|
||||
```
|
||||
|
||||
### Decoding with WebGPU
|
||||
|
||||
> NOTE: WebGPU decoding requires three.js r163 or higher and a browser that supports WebGPU
|
||||
|
||||
The library provides WebGPU-accelerated decoding through the `@monogrid/gainmap-js/webgpu` entry point. WebGPU decoding uses Three.js Shading Language (TSL) and offers improved performance and modern GPU architecture support.
|
||||
|
||||
#### Using a single JPEG with embedded Gain map Metadata (WebGPU)
|
||||
|
||||
```ts
|
||||
import { HDRJPGLoader } from '@monogrid/gainmap-js/webgpu'
|
||||
import {
|
||||
EquirectangularReflectionMapping,
|
||||
Mesh,
|
||||
MeshBasicMaterial,
|
||||
PerspectiveCamera,
|
||||
PlaneGeometry,
|
||||
Scene,
|
||||
WebGPURenderer
|
||||
} from 'three/webgpu'
|
||||
|
||||
const renderer = new WebGPURenderer()
|
||||
await renderer.init()
|
||||
|
||||
const loader = new HDRJPGLoader(renderer)
|
||||
.setRenderTargetOptions({ mapping: EquirectangularReflectionMapping })
|
||||
|
||||
const result = await loader.loadAsync('gainmap.jpeg')
|
||||
// `result` can be used to populate a Texture
|
||||
|
||||
const scene = new Scene()
|
||||
const mesh = new Mesh(
|
||||
new PlaneGeometry(),
|
||||
new MeshBasicMaterial({ map: result.renderTarget.texture })
|
||||
)
|
||||
scene.add(mesh)
|
||||
renderer.render(scene, new PerspectiveCamera())
|
||||
|
||||
// Starting from three.js r159
|
||||
// `result.renderTarget.texture` can
|
||||
// also be used as Equirectangular scene background
|
||||
scene.background = result.renderTarget.texture
|
||||
|
||||
// result must be manually disposed
|
||||
// when you are done using it
|
||||
result.dispose()
|
||||
```
|
||||
|
||||
#### Using separate files (WebGPU)
|
||||
|
||||
```ts
|
||||
import { GainMapLoader } from '@monogrid/gainmap-js/webgpu'
|
||||
import {
|
||||
EquirectangularReflectionMapping,
|
||||
Mesh,
|
||||
MeshBasicMaterial,
|
||||
PerspectiveCamera,
|
||||
PlaneGeometry,
|
||||
Scene,
|
||||
WebGPURenderer
|
||||
} from 'three/webgpu'
|
||||
|
||||
const renderer = new WebGPURenderer()
|
||||
await renderer.init()
|
||||
|
||||
const loader = new GainMapLoader(renderer)
|
||||
.setRenderTargetOptions({ mapping: EquirectangularReflectionMapping })
|
||||
|
||||
const result = await loader.loadAsync(['sdr.jpeg', 'gainmap.jpeg', 'metadata.json'])
|
||||
// `result` can be used to populate a Texture
|
||||
|
||||
const scene = new Scene()
|
||||
const mesh = new Mesh(
|
||||
new PlaneGeometry(),
|
||||
new MeshBasicMaterial({ map: result.renderTarget.texture })
|
||||
)
|
||||
scene.add(mesh)
|
||||
renderer.render(scene, new PerspectiveCamera())
|
||||
|
||||
// Starting from three.js r159
|
||||
// `result.renderTarget.texture` can
|
||||
// also be used as Equirectangular scene background
|
||||
scene.background = result.renderTarget.texture
|
||||
|
||||
// result must be manually disposed
|
||||
// when you are done using it
|
||||
result.dispose()
|
||||
```
|
||||
|
||||
#### Key differences between WebGL and WebGPU
|
||||
|
||||
1. **Import path**: Use `@monogrid/gainmap-js/webgpu` instead of `@monogrid/gainmap-js`
|
||||
2. **Three.js imports**: Use `three/webgpu` instead of `three`
|
||||
3. **Renderer**: Use `WebGPURenderer` instead of `WebGLRenderer`
|
||||
4. **Renderer initialization**: Call `await renderer.init()` before using WebGPU renderer
|
||||
5. **Async decoding**: The `decode()` function is async in WebGPU
|
||||
|
||||
### Encoding
|
||||
|
||||
Encoding a Gain map starting from an EXR file.
|
||||
|
||||
This is generally not useful in a `three.js` site but this library exposes methods
|
||||
that allow to encode an `.exr` or `hdr` file into a `jpeg` with an embedded gain map.
|
||||
|
||||
```ts
|
||||
import { compress, encode, findTextureMinMax } from '@monogrid/gainmap-js/encode'
|
||||
import { encodeJPEGMetadata } from '@monogrid/gainmap-js/libultrahdr'
|
||||
import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js'
|
||||
|
||||
// load an HDR file
|
||||
const loader = new EXRLoader()
|
||||
const image = await loader.loadAsync('image.exr')
|
||||
|
||||
// find RAW RGB Max value of a texture
|
||||
const textureMax = findTextureMinMax(image)
|
||||
|
||||
// Encode the gainmap
|
||||
const encodingResult = encode({
|
||||
image,
|
||||
// this will encode the full HDR range
|
||||
maxContentBoost: Math.max.apply(this, textureMax)
|
||||
})
|
||||
|
||||
// obtain the RAW RGBA SDR buffer and create an ImageData
|
||||
const sdrImageData = new ImageData(encodingResult.sdr.toArray(), encodingResult.sdr.width, encodingResult.sdr.height)
|
||||
// obtain the RAW RGBA Gain map buffer and create an ImageData
|
||||
const gainMapImageData = new ImageData(encodingResult.gainMap.toArray(), encodingResult.gainMap.width, encodingResult.gainMap.height)
|
||||
|
||||
// parallel compress the RAW buffers into the specified mimeType
|
||||
const mimeType = 'image/jpeg'
|
||||
const quality = 0.9
|
||||
|
||||
const [sdr, gainMap] = await Promise.all([
|
||||
compress({
|
||||
source: sdrImageData,
|
||||
mimeType,
|
||||
quality,
|
||||
flipY: true // output needs to be flipped
|
||||
}),
|
||||
compress({
|
||||
source: gainMapImageData,
|
||||
mimeType,
|
||||
quality,
|
||||
flipY: true // output needs to be flipped
|
||||
})
|
||||
])
|
||||
|
||||
// obtain the metadata which will be embedded into
|
||||
// and XMP tag inside the final JPEG file
|
||||
const metadata = encodingResult.getMetadata()
|
||||
|
||||
// embed the compressed images + metadata into a single
|
||||
// JPEG file
|
||||
const jpeg = encodeJPEGMetadata({
|
||||
...encodingResult,
|
||||
...metadata,
|
||||
sdr,
|
||||
gainMap
|
||||
})
|
||||
|
||||
// `jpeg` will be an `Uint8Array` which can be saved somewhere
|
||||
|
||||
// encoder must be manually disposed
|
||||
// when no longer needed
|
||||
encodingResult.gainMap.dispose()
|
||||
encodingResult.sdr.dispose()
|
||||
|
||||
```
|
||||
|
||||
## Libultrahdr in Vite
|
||||
|
||||
If you import `@monogrid/gainmap-js/libultrahdr`
|
||||
You will need to exclude it from Vite optimizations.
|
||||
|
||||
```js
|
||||
// vite.config.js
|
||||
|
||||
module.exports = defineConfig({
|
||||
...
|
||||
optimizeDeps: {
|
||||
exclude: ['@monogrid/gainmap-js/libultrahdr']
|
||||
},
|
||||
...
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
## Building
|
||||
|
||||
Clone the repository:
|
||||
```bash
|
||||
$ git clone git@github.com:MONOGRID/gainmap-js.git
|
||||
$ cd gainmap-js
|
||||
$ npm i
|
||||
$ npm run build
|
||||
```
|
||||
|
||||
|
||||
## References
|
||||
|
||||
* [Adobe Gainmap Specification](https://helpx.adobe.com/camera-raw/using/gain-map.html)
|
||||
* [Ultra HDR Image Format v1.0](https://developer.android.com/guide/topics/media/platform/hdr-image-format)
|
||||
|
||||
|
||||
## License
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2FMONOGRID%2Fgainmap-js?ref=badge_large)
|
||||
5
node_modules/@monogrid/gainmap-js/dist/Loader-CKVwvejH.js
generated
vendored
Normal file
5
node_modules/@monogrid/gainmap-js/dist/Loader-CKVwvejH.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
424
node_modules/@monogrid/gainmap-js/dist/Loader-DLI-_JDP.js
generated
vendored
Normal file
424
node_modules/@monogrid/gainmap-js/dist/Loader-DLI-_JDP.js
generated
vendored
Normal file
@@ -0,0 +1,424 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
|
||||
import { SRGBColorSpace, LinearSRGBColorSpace, HalfFloatType, Loader, LoadingManager, Texture, UVMapping, ClampToEdgeWrapping, LinearFilter, LinearMipMapLinearFilter, RGBAFormat, UnsignedByteType } from 'three';
|
||||
|
||||
/**
|
||||
* Shared decode implementation factory
|
||||
* Creates a decode function that prepares a QuadRenderer with the given parameters
|
||||
*/
|
||||
function createDecodeFunction(config) {
|
||||
return (params) => {
|
||||
const { sdr, gainMap, renderer } = params;
|
||||
if (sdr.colorSpace !== SRGBColorSpace) {
|
||||
console.warn('SDR Colorspace needs to be *SRGBColorSpace*, setting it automatically');
|
||||
sdr.colorSpace = SRGBColorSpace;
|
||||
}
|
||||
sdr.needsUpdate = true;
|
||||
if (gainMap.colorSpace !== LinearSRGBColorSpace) {
|
||||
console.warn('Gainmap Colorspace needs to be *LinearSRGBColorSpace*, setting it automatically');
|
||||
gainMap.colorSpace = LinearSRGBColorSpace;
|
||||
}
|
||||
gainMap.needsUpdate = true;
|
||||
const material = config.createMaterial({
|
||||
...params,
|
||||
sdr,
|
||||
gainMap
|
||||
});
|
||||
const quadRenderer = config.createQuadRenderer({
|
||||
width: sdr.image.width,
|
||||
height: sdr.image.height,
|
||||
type: HalfFloatType,
|
||||
colorSpace: LinearSRGBColorSpace,
|
||||
material,
|
||||
renderer,
|
||||
renderTargetOptions: params.renderTargetOptions
|
||||
});
|
||||
return quadRenderer;
|
||||
};
|
||||
}
|
||||
|
||||
class GainMapNotFoundError extends Error {
|
||||
}
|
||||
|
||||
class XMPMetadataNotFoundError extends Error {
|
||||
}
|
||||
|
||||
const getXMLValue = (xml, tag, defaultValue) => {
|
||||
// Check for attribute format first: tag="value"
|
||||
const attributeMatch = new RegExp(`${tag}="([^"]*)"`, 'i').exec(xml);
|
||||
if (attributeMatch)
|
||||
return attributeMatch[1];
|
||||
// Check for tag format: <tag>value</tag> or <tag><rdf:li>value</rdf:li>...</tag>
|
||||
const tagMatch = new RegExp(`<${tag}[^>]*>([\\s\\S]*?)</${tag}>`, 'i').exec(xml);
|
||||
if (tagMatch) {
|
||||
// Check if it contains rdf:li elements
|
||||
const liValues = tagMatch[1].match(/<rdf:li>([^<]*)<\/rdf:li>/g);
|
||||
if (liValues && liValues.length === 3) {
|
||||
return liValues.map(v => v.replace(/<\/?rdf:li>/g, ''));
|
||||
}
|
||||
return tagMatch[1].trim();
|
||||
}
|
||||
if (defaultValue !== undefined)
|
||||
return defaultValue;
|
||||
throw new Error(`Can't find ${tag} in gainmap metadata`);
|
||||
};
|
||||
const extractXMP = (input) => {
|
||||
let str;
|
||||
// support node test environment
|
||||
if (typeof TextDecoder !== 'undefined')
|
||||
str = new TextDecoder().decode(input);
|
||||
else
|
||||
str = input.toString();
|
||||
let start = str.indexOf('<x:xmpmeta');
|
||||
while (start !== -1) {
|
||||
const end = str.indexOf('x:xmpmeta>', start);
|
||||
const xmpBlock = str.slice(start, end + 10);
|
||||
try {
|
||||
const gainMapMin = getXMLValue(xmpBlock, 'hdrgm:GainMapMin', '0');
|
||||
const gainMapMax = getXMLValue(xmpBlock, 'hdrgm:GainMapMax');
|
||||
const gamma = getXMLValue(xmpBlock, 'hdrgm:Gamma', '1');
|
||||
const offsetSDR = getXMLValue(xmpBlock, 'hdrgm:OffsetSDR', '0.015625');
|
||||
const offsetHDR = getXMLValue(xmpBlock, 'hdrgm:OffsetHDR', '0.015625');
|
||||
// These are always attributes, so we can use a simpler regex
|
||||
const hdrCapacityMinMatch = /hdrgm:HDRCapacityMin="([^"]*)"/.exec(xmpBlock);
|
||||
const hdrCapacityMin = hdrCapacityMinMatch ? hdrCapacityMinMatch[1] : '0';
|
||||
const hdrCapacityMaxMatch = /hdrgm:HDRCapacityMax="([^"]*)"/.exec(xmpBlock);
|
||||
if (!hdrCapacityMaxMatch)
|
||||
throw new Error('Incomplete gainmap metadata');
|
||||
const hdrCapacityMax = hdrCapacityMaxMatch[1];
|
||||
return {
|
||||
gainMapMin: Array.isArray(gainMapMin) ? gainMapMin.map(v => parseFloat(v)) : [parseFloat(gainMapMin), parseFloat(gainMapMin), parseFloat(gainMapMin)],
|
||||
gainMapMax: Array.isArray(gainMapMax) ? gainMapMax.map(v => parseFloat(v)) : [parseFloat(gainMapMax), parseFloat(gainMapMax), parseFloat(gainMapMax)],
|
||||
gamma: Array.isArray(gamma) ? gamma.map(v => parseFloat(v)) : [parseFloat(gamma), parseFloat(gamma), parseFloat(gamma)],
|
||||
offsetSdr: Array.isArray(offsetSDR) ? offsetSDR.map(v => parseFloat(v)) : [parseFloat(offsetSDR), parseFloat(offsetSDR), parseFloat(offsetSDR)],
|
||||
offsetHdr: Array.isArray(offsetHDR) ? offsetHDR.map(v => parseFloat(v)) : [parseFloat(offsetHDR), parseFloat(offsetHDR), parseFloat(offsetHDR)],
|
||||
hdrCapacityMin: parseFloat(hdrCapacityMin),
|
||||
hdrCapacityMax: parseFloat(hdrCapacityMax)
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
// Continue searching for another xmpmeta block if this one fails
|
||||
}
|
||||
start = str.indexOf('<x:xmpmeta', end);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* MPF Extractor (Multi Picture Format Extractor)
|
||||
* By Henrik S Nilsson 2019
|
||||
*
|
||||
* Extracts images stored in images based on the MPF format (found here: https://www.cipa.jp/e/std/std-sec.html
|
||||
* under "CIPA DC-007-Translation-2021 Multi-Picture Format"
|
||||
*
|
||||
* Overly commented, and without intention of being complete or production ready.
|
||||
* Created to extract depth maps from iPhone images, and to learn about image metadata.
|
||||
* Kudos to: Phil Harvey (exiftool), Jaume Sanchez (android-lens-blur-depth-extractor)
|
||||
*/
|
||||
class MPFExtractor {
|
||||
options;
|
||||
constructor(options) {
|
||||
this.options = {
|
||||
debug: options && options.debug !== undefined ? options.debug : false,
|
||||
extractFII: options && options.extractFII !== undefined ? options.extractFII : true,
|
||||
extractNonFII: options && options.extractNonFII !== undefined ? options.extractNonFII : true
|
||||
};
|
||||
}
|
||||
extract(imageArrayBuffer) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const debug = this.options.debug;
|
||||
const dataView = new DataView(imageArrayBuffer.buffer);
|
||||
// If you're executing this line on a big endian machine, it'll be reversed.
|
||||
// bigEnd further down though, refers to the endianness of the image itself.
|
||||
if (dataView.getUint16(0) !== 0xffd8) {
|
||||
reject(new Error('Not a valid jpeg'));
|
||||
return;
|
||||
}
|
||||
const length = dataView.byteLength;
|
||||
let offset = 2;
|
||||
let loops = 0;
|
||||
let marker; // APP# marker
|
||||
while (offset < length) {
|
||||
if (++loops > 250) {
|
||||
reject(new Error(`Found no marker after ${loops} loops 😵`));
|
||||
return;
|
||||
}
|
||||
if (dataView.getUint8(offset) !== 0xff) {
|
||||
reject(new Error(`Not a valid marker at offset 0x${offset.toString(16)}, found: 0x${dataView.getUint8(offset).toString(16)}`));
|
||||
return;
|
||||
}
|
||||
marker = dataView.getUint8(offset + 1);
|
||||
if (debug)
|
||||
console.log(`Marker: ${marker.toString(16)}`);
|
||||
if (marker === 0xe2) {
|
||||
if (debug)
|
||||
console.log('Found APP2 marker (0xffe2)');
|
||||
// Works for iPhone 8 Plus, X, and XSMax. Or any photos of MPF format.
|
||||
// Great way to visualize image information in html is using Exiftool. E.g.:
|
||||
// ./exiftool.exe -htmldump -wantTrailer photo.jpg > photo.html
|
||||
const formatPt = offset + 4;
|
||||
/*
|
||||
* Structure of the MP Format Identifier
|
||||
*
|
||||
* Offset Addr. | Code (Hex) | Description
|
||||
* +00 ff Marker Prefix <-- offset
|
||||
* +01 e2 APP2
|
||||
* +02 #n APP2 Field Length
|
||||
* +03 #n APP2 Field Length
|
||||
* +04 4d 'M' <-- formatPt
|
||||
* +05 50 'P'
|
||||
* +06 46 'F'
|
||||
* +07 00 NULL
|
||||
* <-- tiffOffset
|
||||
*/
|
||||
if (dataView.getUint32(formatPt) === 0x4d504600) {
|
||||
// Found MPF tag, so we start dig out sub images
|
||||
const tiffOffset = formatPt + 4;
|
||||
let bigEnd; // Endianness from TIFF header
|
||||
// Test for TIFF validity and endianness
|
||||
// 0x4949 and 0x4D4D ('II' and 'MM') marks Little Endian and Big Endian
|
||||
if (dataView.getUint16(tiffOffset) === 0x4949) {
|
||||
bigEnd = false;
|
||||
}
|
||||
else if (dataView.getUint16(tiffOffset) === 0x4d4d) {
|
||||
bigEnd = true;
|
||||
}
|
||||
else {
|
||||
reject(new Error('No valid endianness marker found in TIFF header'));
|
||||
return;
|
||||
}
|
||||
if (dataView.getUint16(tiffOffset + 2, !bigEnd) !== 0x002a) {
|
||||
reject(new Error('Not valid TIFF data! (no 0x002A marker)'));
|
||||
return;
|
||||
}
|
||||
// 32 bit number stating the offset from the start of the 8 Byte MP Header
|
||||
// to MP Index IFD Least possible value is thus 8 (means 0 offset)
|
||||
const firstIFDOffset = dataView.getUint32(tiffOffset + 4, !bigEnd);
|
||||
if (firstIFDOffset < 0x00000008) {
|
||||
reject(new Error('Not valid TIFF data! (First offset less than 8)'));
|
||||
return;
|
||||
}
|
||||
// Move ahead to MP Index IFD
|
||||
// Assume we're at the first IFD, so firstIFDOffset points to
|
||||
// MP Index IFD and not MP Attributes IFD. (If we try extract from a sub image,
|
||||
// we fail silently here due to this assumption)
|
||||
// Count (2 Byte) | MP Index Fields a.k.a. MP Entries (count * 12 Byte) | Offset of Next IFD (4 Byte)
|
||||
const dirStart = tiffOffset + firstIFDOffset; // Start of IFD (Image File Directory)
|
||||
const count = dataView.getUint16(dirStart, !bigEnd); // Count of MPEntries (2 Byte)
|
||||
// Extract info from MPEntries (starting after Count)
|
||||
const entriesStart = dirStart + 2;
|
||||
let numberOfImages = 0;
|
||||
for (let i = entriesStart; i < entriesStart + 12 * count; i += 12) {
|
||||
// Each entry is 12 Bytes long
|
||||
// Check MP Index IFD tags, here we only take tag 0xb001 = Number of images
|
||||
if (dataView.getUint16(i, !bigEnd) === 0xb001) {
|
||||
// stored in Last 4 bytes of its 12 Byte entry.
|
||||
numberOfImages = dataView.getUint32(i + 8, !bigEnd);
|
||||
}
|
||||
}
|
||||
const nextIFDOffsetLen = 4; // 4 Byte offset field that appears after MP Index IFD tags
|
||||
const MPImageListValPt = dirStart + 2 + count * 12 + nextIFDOffsetLen;
|
||||
const images = [];
|
||||
for (let i = MPImageListValPt; i < MPImageListValPt + numberOfImages * 16; i += 16) {
|
||||
const image = {
|
||||
MPType: dataView.getUint32(i, !bigEnd),
|
||||
size: dataView.getUint32(i + 4, !bigEnd),
|
||||
// This offset is specified relative to the address of the MP Endian
|
||||
// field in the MP Header, unless the image is a First Individual Image,
|
||||
// in which case the value of the offset shall be NULL (0x00000000).
|
||||
dataOffset: dataView.getUint32(i + 8, !bigEnd),
|
||||
dependantImages: dataView.getUint32(i + 12, !bigEnd),
|
||||
start: -1,
|
||||
end: -1,
|
||||
isFII: false
|
||||
};
|
||||
if (!image.dataOffset) {
|
||||
// dataOffset is 0x00000000 for First Individual Image
|
||||
image.start = 0;
|
||||
image.isFII = true;
|
||||
}
|
||||
else {
|
||||
image.start = tiffOffset + image.dataOffset;
|
||||
image.isFII = false;
|
||||
}
|
||||
image.end = image.start + image.size;
|
||||
images.push(image);
|
||||
}
|
||||
if (this.options.extractNonFII && images.length) {
|
||||
const bufferBlob = new Blob([dataView]);
|
||||
const imgs = [];
|
||||
for (const image of images) {
|
||||
if (image.isFII && !this.options.extractFII) {
|
||||
continue; // Skip FII
|
||||
}
|
||||
const imageBlob = bufferBlob.slice(image.start, image.end + 1, 'image/jpeg');
|
||||
// we don't need this
|
||||
// const imageUrl = URL.createObjectURL(imageBlob)
|
||||
// image.img = document.createElement('img')
|
||||
// image.img.src = imageUrl
|
||||
imgs.push(imageBlob);
|
||||
}
|
||||
resolve(imgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
offset += 2 + dataView.getUint16(offset + 2);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts XMP Metadata and the gain map recovery image
|
||||
* from a single JPEG file.
|
||||
*
|
||||
* @category Decoding Functions
|
||||
* @group Decoding Functions
|
||||
* @param jpegFile an `Uint8Array` containing and encoded JPEG file
|
||||
* @returns an sdr `Uint8Array` compressed in JPEG, a gainMap `Uint8Array` compressed in JPEG and the XMP parsed XMP metadata
|
||||
* @throws Error if XMP Metadata is not found
|
||||
* @throws Error if Gain map image is not found
|
||||
* @example
|
||||
* import { FileLoader } from 'three'
|
||||
* import { extractGainmapFromJPEG } from '@monogrid/gainmap-js'
|
||||
*
|
||||
* const jpegFile = await new FileLoader()
|
||||
* .setResponseType('arraybuffer')
|
||||
* .loadAsync('image.jpg')
|
||||
*
|
||||
* const { sdr, gainMap, metadata } = extractGainmapFromJPEG(jpegFile)
|
||||
*/
|
||||
const extractGainmapFromJPEG = async (jpegFile) => {
|
||||
const metadata = extractXMP(jpegFile);
|
||||
if (!metadata)
|
||||
throw new XMPMetadataNotFoundError('Gain map XMP metadata not found');
|
||||
const mpfExtractor = new MPFExtractor({ extractFII: true, extractNonFII: true });
|
||||
const images = await mpfExtractor.extract(jpegFile);
|
||||
if (images.length !== 2)
|
||||
throw new GainMapNotFoundError('Gain map recovery image not found');
|
||||
return {
|
||||
sdr: new Uint8Array(await images[0].arrayBuffer()),
|
||||
gainMap: new Uint8Array(await images[1].arrayBuffer()),
|
||||
metadata
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* private function, async get image from blob
|
||||
*
|
||||
* @param blob
|
||||
* @returns
|
||||
*/
|
||||
const getHTMLImageFromBlob = (blob) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = document.createElement('img');
|
||||
img.onload = () => { resolve(img); };
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
|
||||
img.onerror = (e) => { reject(e); };
|
||||
img.src = URL.createObjectURL(blob);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Shared base class for loaders that extracts common logic
|
||||
*/
|
||||
class LoaderBaseShared extends Loader {
|
||||
_renderer;
|
||||
_renderTargetOptions;
|
||||
_internalLoadingManager;
|
||||
_config;
|
||||
constructor(config, manager) {
|
||||
super(manager);
|
||||
this._config = config;
|
||||
if (config.renderer)
|
||||
this._renderer = config.renderer;
|
||||
this._internalLoadingManager = new LoadingManager();
|
||||
}
|
||||
setRenderer(renderer) {
|
||||
this._renderer = renderer;
|
||||
return this;
|
||||
}
|
||||
setRenderTargetOptions(options) {
|
||||
this._renderTargetOptions = options;
|
||||
return this;
|
||||
}
|
||||
prepareQuadRenderer() {
|
||||
if (!this._renderer) {
|
||||
console.warn('WARNING: A Renderer was not passed to this Loader constructor or in setRenderer, the result of this Loader will need to be converted to a Data Texture with toDataTexture() before you can use it in your renderer.');
|
||||
}
|
||||
const material = this._config.createMaterial({
|
||||
gainMapMax: [1, 1, 1],
|
||||
gainMapMin: [0, 0, 0],
|
||||
gamma: [1, 1, 1],
|
||||
offsetHdr: [1, 1, 1],
|
||||
offsetSdr: [1, 1, 1],
|
||||
hdrCapacityMax: 1,
|
||||
hdrCapacityMin: 0,
|
||||
maxDisplayBoost: 1,
|
||||
gainMap: new Texture(),
|
||||
sdr: new Texture()
|
||||
});
|
||||
return this._config.createQuadRenderer({
|
||||
width: 16,
|
||||
height: 16,
|
||||
type: HalfFloatType,
|
||||
colorSpace: LinearSRGBColorSpace,
|
||||
material,
|
||||
renderer: this._renderer,
|
||||
renderTargetOptions: this._renderTargetOptions
|
||||
});
|
||||
}
|
||||
async processImages(sdrBuffer, gainMapBuffer, imageOrientation) {
|
||||
const gainMapBlob = gainMapBuffer ? new Blob([gainMapBuffer], { type: 'image/jpeg' }) : undefined;
|
||||
const sdrBlob = new Blob([sdrBuffer], { type: 'image/jpeg' });
|
||||
let sdrImage;
|
||||
let gainMapImage;
|
||||
let needsFlip = false;
|
||||
if (typeof createImageBitmap === 'undefined') {
|
||||
const res = await Promise.all([
|
||||
gainMapBlob ? getHTMLImageFromBlob(gainMapBlob) : Promise.resolve(undefined),
|
||||
getHTMLImageFromBlob(sdrBlob)
|
||||
]);
|
||||
gainMapImage = res[0];
|
||||
sdrImage = res[1];
|
||||
needsFlip = imageOrientation === 'flipY';
|
||||
}
|
||||
else {
|
||||
const res = await Promise.all([
|
||||
gainMapBlob ? createImageBitmap(gainMapBlob, { imageOrientation: imageOrientation || 'flipY' }) : Promise.resolve(undefined),
|
||||
createImageBitmap(sdrBlob, { imageOrientation: imageOrientation || 'flipY' })
|
||||
]);
|
||||
gainMapImage = res[0];
|
||||
sdrImage = res[1];
|
||||
}
|
||||
return { sdrImage, gainMapImage, needsFlip };
|
||||
}
|
||||
createTextures(sdrImage, gainMapImage, needsFlip) {
|
||||
const gainMap = new Texture(gainMapImage || new ImageData(2, 2), UVMapping, ClampToEdgeWrapping, ClampToEdgeWrapping, LinearFilter, LinearMipMapLinearFilter, RGBAFormat, UnsignedByteType, 1, LinearSRGBColorSpace);
|
||||
gainMap.flipY = needsFlip;
|
||||
gainMap.needsUpdate = true;
|
||||
const sdr = new Texture(sdrImage, UVMapping, ClampToEdgeWrapping, ClampToEdgeWrapping, LinearFilter, LinearMipMapLinearFilter, RGBAFormat, UnsignedByteType, 1, SRGBColorSpace);
|
||||
sdr.flipY = needsFlip;
|
||||
sdr.needsUpdate = true;
|
||||
return { gainMap, sdr };
|
||||
}
|
||||
updateQuadRenderer(quadRenderer, sdrImage, gainMap, sdr, metadata) {
|
||||
quadRenderer.width = sdrImage.width;
|
||||
quadRenderer.height = sdrImage.height;
|
||||
quadRenderer.material.gainMap = gainMap;
|
||||
quadRenderer.material.sdr = sdr;
|
||||
quadRenderer.material.gainMapMin = metadata.gainMapMin;
|
||||
quadRenderer.material.gainMapMax = metadata.gainMapMax;
|
||||
quadRenderer.material.offsetHdr = metadata.offsetHdr;
|
||||
quadRenderer.material.offsetSdr = metadata.offsetSdr;
|
||||
quadRenderer.material.gamma = metadata.gamma;
|
||||
quadRenderer.material.hdrCapacityMin = metadata.hdrCapacityMin;
|
||||
quadRenderer.material.hdrCapacityMax = metadata.hdrCapacityMax;
|
||||
quadRenderer.material.maxDisplayBoost = Math.pow(2, metadata.hdrCapacityMax);
|
||||
quadRenderer.material.needsUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
export { GainMapNotFoundError as G, LoaderBaseShared as L, MPFExtractor as M, XMPMetadataNotFoundError as X, extractXMP as a, createDecodeFunction as c, extractGainmapFromJPEG as e };
|
||||
310
node_modules/@monogrid/gainmap-js/dist/QuadRenderer-Bj1xl_EK.js
generated
vendored
Normal file
310
node_modules/@monogrid/gainmap-js/dist/QuadRenderer-Bj1xl_EK.js
generated
vendored
Normal file
@@ -0,0 +1,310 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
|
||||
import { ClampToEdgeWrapping, LinearFilter, Scene, OrthographicCamera, HalfFloatType, FloatType, Mesh, PlaneGeometry, WebGLRenderTarget, RGBAFormat, UVMapping, WebGLRenderer, DataTexture, LinearSRGBColorSpace, ShaderMaterial, Texture, MeshBasicMaterial, IntType, ShortType, ByteType, UnsignedIntType, UnsignedByteType } from 'three';
|
||||
|
||||
const getBufferForType = (type, width, height) => {
|
||||
let out;
|
||||
switch (type) {
|
||||
case UnsignedByteType:
|
||||
out = new Uint8ClampedArray(width * height * 4);
|
||||
break;
|
||||
case HalfFloatType:
|
||||
out = new Uint16Array(width * height * 4);
|
||||
break;
|
||||
case UnsignedIntType:
|
||||
out = new Uint32Array(width * height * 4);
|
||||
break;
|
||||
case ByteType:
|
||||
out = new Int8Array(width * height * 4);
|
||||
break;
|
||||
case ShortType:
|
||||
out = new Int16Array(width * height * 4);
|
||||
break;
|
||||
case IntType:
|
||||
out = new Int32Array(width * height * 4);
|
||||
break;
|
||||
case FloatType:
|
||||
out = new Float32Array(width * height * 4);
|
||||
break;
|
||||
default:
|
||||
throw new Error('Unsupported data type');
|
||||
}
|
||||
return out;
|
||||
};
|
||||
let _canReadPixelsResult;
|
||||
/**
|
||||
* Test if this browser implementation can correctly read pixels from the specified
|
||||
* Render target type.
|
||||
*
|
||||
* Runs only once
|
||||
*
|
||||
* @param type
|
||||
* @param renderer
|
||||
* @param camera
|
||||
* @param renderTargetOptions
|
||||
* @returns
|
||||
*/
|
||||
const canReadPixels = (type, renderer, camera, renderTargetOptions) => {
|
||||
if (_canReadPixelsResult !== undefined)
|
||||
return _canReadPixelsResult;
|
||||
const testRT = new WebGLRenderTarget(1, 1, renderTargetOptions);
|
||||
renderer.setRenderTarget(testRT);
|
||||
const mesh = new Mesh(new PlaneGeometry(), new MeshBasicMaterial({ color: 0xffffff }));
|
||||
renderer.render(mesh, camera);
|
||||
renderer.setRenderTarget(null);
|
||||
const out = getBufferForType(type, testRT.width, testRT.height);
|
||||
renderer.readRenderTargetPixels(testRT, 0, 0, testRT.width, testRT.height, out);
|
||||
testRT.dispose();
|
||||
mesh.geometry.dispose();
|
||||
mesh.material.dispose();
|
||||
_canReadPixelsResult = out[0] !== 0;
|
||||
return _canReadPixelsResult;
|
||||
};
|
||||
/**
|
||||
* Utility class used for rendering a texture with a material
|
||||
*
|
||||
* @category Core
|
||||
* @group Core
|
||||
*/
|
||||
class QuadRenderer {
|
||||
_renderer;
|
||||
_rendererIsDisposable = false;
|
||||
_material;
|
||||
_scene;
|
||||
_camera;
|
||||
_quad;
|
||||
_renderTarget;
|
||||
_width;
|
||||
_height;
|
||||
_type;
|
||||
_colorSpace;
|
||||
_supportsReadPixels = true;
|
||||
/**
|
||||
* Constructs a new QuadRenderer
|
||||
*
|
||||
* @param options Parameters for this QuadRenderer
|
||||
*/
|
||||
constructor(options) {
|
||||
this._width = options.width;
|
||||
this._height = options.height;
|
||||
this._type = options.type;
|
||||
this._colorSpace = options.colorSpace;
|
||||
const rtOptions = {
|
||||
// fixed options
|
||||
format: RGBAFormat,
|
||||
depthBuffer: false,
|
||||
stencilBuffer: false,
|
||||
// user options
|
||||
type: this._type, // set in class property
|
||||
colorSpace: this._colorSpace, // set in class property
|
||||
anisotropy: options.renderTargetOptions?.anisotropy !== undefined ? options.renderTargetOptions?.anisotropy : 1,
|
||||
generateMipmaps: options.renderTargetOptions?.generateMipmaps !== undefined ? options.renderTargetOptions?.generateMipmaps : false,
|
||||
magFilter: options.renderTargetOptions?.magFilter !== undefined ? options.renderTargetOptions?.magFilter : LinearFilter,
|
||||
minFilter: options.renderTargetOptions?.minFilter !== undefined ? options.renderTargetOptions?.minFilter : LinearFilter,
|
||||
samples: options.renderTargetOptions?.samples !== undefined ? options.renderTargetOptions?.samples : undefined,
|
||||
wrapS: options.renderTargetOptions?.wrapS !== undefined ? options.renderTargetOptions?.wrapS : ClampToEdgeWrapping,
|
||||
wrapT: options.renderTargetOptions?.wrapT !== undefined ? options.renderTargetOptions?.wrapT : ClampToEdgeWrapping
|
||||
};
|
||||
this._material = options.material;
|
||||
if (options.renderer) {
|
||||
this._renderer = options.renderer;
|
||||
}
|
||||
else {
|
||||
this._renderer = QuadRenderer.instantiateRenderer();
|
||||
this._rendererIsDisposable = true;
|
||||
}
|
||||
this._scene = new Scene();
|
||||
this._camera = new OrthographicCamera();
|
||||
this._camera.position.set(0, 0, 10);
|
||||
this._camera.left = -0.5;
|
||||
this._camera.right = 0.5;
|
||||
this._camera.top = 0.5;
|
||||
this._camera.bottom = -0.5;
|
||||
this._camera.updateProjectionMatrix();
|
||||
if (!canReadPixels(this._type, this._renderer, this._camera, rtOptions)) {
|
||||
let alternativeType;
|
||||
switch (this._type) {
|
||||
case HalfFloatType:
|
||||
alternativeType = this._renderer.extensions.has('EXT_color_buffer_float') ? FloatType : undefined;
|
||||
break;
|
||||
}
|
||||
if (alternativeType !== undefined) {
|
||||
console.warn(`This browser does not support reading pixels from ${this._type} RenderTargets, switching to ${FloatType}`);
|
||||
this._type = alternativeType;
|
||||
}
|
||||
else {
|
||||
this._supportsReadPixels = false;
|
||||
console.warn('This browser dos not support toArray or toDataTexture, calls to those methods will result in an error thrown');
|
||||
}
|
||||
}
|
||||
this._quad = new Mesh(new PlaneGeometry(), this._material);
|
||||
this._quad.geometry.computeBoundingBox();
|
||||
this._scene.add(this._quad);
|
||||
this._renderTarget = new WebGLRenderTarget(this.width, this.height, rtOptions);
|
||||
this._renderTarget.texture.mapping = options.renderTargetOptions?.mapping !== undefined ? options.renderTargetOptions?.mapping : UVMapping;
|
||||
}
|
||||
/**
|
||||
* Instantiates a temporary renderer
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
static instantiateRenderer() {
|
||||
const renderer = new WebGLRenderer();
|
||||
renderer.setSize(128, 128);
|
||||
// renderer.outputColorSpace = SRGBColorSpace
|
||||
// renderer.toneMapping = LinearToneMapping
|
||||
// renderer.debug.checkShaderErrors = false
|
||||
// this._rendererIsDisposable = true
|
||||
return renderer;
|
||||
}
|
||||
/**
|
||||
* Renders the input texture using the specified material
|
||||
*/
|
||||
render = () => {
|
||||
this._renderer.setRenderTarget(this._renderTarget);
|
||||
try {
|
||||
this._renderer.render(this._scene, this._camera);
|
||||
}
|
||||
catch (e) {
|
||||
this._renderer.setRenderTarget(null);
|
||||
throw e;
|
||||
}
|
||||
this._renderer.setRenderTarget(null);
|
||||
};
|
||||
/**
|
||||
* Obtains a Buffer containing the rendered texture.
|
||||
*
|
||||
* @throws Error if the browser cannot read pixels from this RenderTarget type.
|
||||
* @returns a TypedArray containing RGBA values from this renderer
|
||||
*/
|
||||
toArray() {
|
||||
if (!this._supportsReadPixels)
|
||||
throw new Error('Can\'t read pixels in this browser');
|
||||
const out = getBufferForType(this._type, this._width, this._height);
|
||||
this._renderer.readRenderTargetPixels(this._renderTarget, 0, 0, this._width, this._height, out);
|
||||
return out;
|
||||
}
|
||||
/**
|
||||
* Performs a readPixel operation in the renderTarget
|
||||
* and returns a DataTexture containing the read data
|
||||
*
|
||||
* @param options options
|
||||
* @returns
|
||||
*/
|
||||
toDataTexture(options) {
|
||||
const returnValue = new DataTexture(
|
||||
// fixed values
|
||||
this.toArray(), this.width, this.height, RGBAFormat, this._type,
|
||||
// user values
|
||||
options?.mapping || UVMapping, options?.wrapS || ClampToEdgeWrapping, options?.wrapT || ClampToEdgeWrapping, options?.magFilter || LinearFilter, options?.minFilter || LinearFilter, options?.anisotropy || 1,
|
||||
// fixed value
|
||||
LinearSRGBColorSpace);
|
||||
// set this afterwards, we can't set it in constructor
|
||||
returnValue.generateMipmaps = options?.generateMipmaps !== undefined ? options?.generateMipmaps : false;
|
||||
return returnValue;
|
||||
}
|
||||
/**
|
||||
* If using a disposable renderer, it will dispose it.
|
||||
*/
|
||||
disposeOnDemandRenderer() {
|
||||
this._renderer.setRenderTarget(null);
|
||||
if (this._rendererIsDisposable) {
|
||||
this._renderer.dispose();
|
||||
this._renderer.forceContextLoss();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Will dispose of **all** assets used by this renderer.
|
||||
*
|
||||
*
|
||||
* @param disposeRenderTarget will dispose of the renderTarget which will not be usable later
|
||||
* set this to true if you passed the `renderTarget.texture` to a `PMREMGenerator`
|
||||
* or are otherwise done with it.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* const loader = new HDRJPGLoader(renderer)
|
||||
* const result = await loader.loadAsync('gainmap.jpeg')
|
||||
* const mesh = new Mesh(geometry, new MeshBasicMaterial({ map: result.renderTarget.texture }) )
|
||||
* // DO NOT dispose the renderTarget here,
|
||||
* // it is used directly in the material
|
||||
* result.dispose()
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* const loader = new HDRJPGLoader(renderer)
|
||||
* const pmremGenerator = new PMREMGenerator( renderer );
|
||||
* const result = await loader.loadAsync('gainmap.jpeg')
|
||||
* const envMap = pmremGenerator.fromEquirectangular(result.renderTarget.texture)
|
||||
* const mesh = new Mesh(geometry, new MeshStandardMaterial({ envMap }) )
|
||||
* // renderTarget can be disposed here
|
||||
* // because it was used to generate a PMREM texture
|
||||
* result.dispose(true)
|
||||
* ```
|
||||
*/
|
||||
dispose(disposeRenderTarget) {
|
||||
this.disposeOnDemandRenderer();
|
||||
if (disposeRenderTarget) {
|
||||
this.renderTarget.dispose();
|
||||
}
|
||||
// dispose shader material texture uniforms
|
||||
if (this.material instanceof ShaderMaterial) {
|
||||
Object.values(this.material.uniforms).forEach(v => {
|
||||
if (v.value instanceof Texture)
|
||||
v.value.dispose();
|
||||
});
|
||||
}
|
||||
// dispose other material properties
|
||||
Object.values(this.material).forEach(value => {
|
||||
if (value instanceof Texture)
|
||||
value.dispose();
|
||||
});
|
||||
this.material.dispose();
|
||||
this._quad.geometry.dispose();
|
||||
}
|
||||
/**
|
||||
* Width of the texture
|
||||
*/
|
||||
get width() { return this._width; }
|
||||
set width(value) {
|
||||
this._width = value;
|
||||
this._renderTarget.setSize(this._width, this._height);
|
||||
}
|
||||
/**
|
||||
* Height of the texture
|
||||
*/
|
||||
get height() { return this._height; }
|
||||
set height(value) {
|
||||
this._height = value;
|
||||
this._renderTarget.setSize(this._width, this._height);
|
||||
}
|
||||
/**
|
||||
* The renderer used
|
||||
*/
|
||||
get renderer() { return this._renderer; }
|
||||
/**
|
||||
* The `WebGLRenderTarget` used.
|
||||
*/
|
||||
get renderTarget() { return this._renderTarget; }
|
||||
set renderTarget(value) {
|
||||
this._renderTarget = value;
|
||||
this._width = value.width;
|
||||
this._height = value.height;
|
||||
// this._type = value.texture.type
|
||||
}
|
||||
/**
|
||||
* The `Material` used.
|
||||
*/
|
||||
get material() { return this._material; }
|
||||
/**
|
||||
*
|
||||
*/
|
||||
get type() { return this._type; }
|
||||
get colorSpace() { return this._colorSpace; }
|
||||
}
|
||||
|
||||
export { QuadRenderer as Q };
|
||||
5
node_modules/@monogrid/gainmap-js/dist/QuadRenderer-BoQMkXLf.js
generated
vendored
Normal file
5
node_modules/@monogrid/gainmap-js/dist/QuadRenderer-BoQMkXLf.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
import{ClampToEdgeWrapping as e,LinearFilter as r,Scene as t,OrthographicCamera as i,HalfFloatType as s,FloatType as a,Mesh as n,PlaneGeometry as h,WebGLRenderTarget as o,RGBAFormat as d,UVMapping as p,WebGLRenderer as _,DataTexture as g,LinearSRGBColorSpace as l,ShaderMaterial as c,Texture as w,MeshBasicMaterial as m,IntType as T,ShortType as u,ByteType as y,UnsignedIntType as f,UnsignedByteType as O}from"three";const b=(e,r,t)=>{let i;switch(e){case O:i=new Uint8ClampedArray(r*t*4);break;case s:i=new Uint16Array(r*t*4);break;case f:i=new Uint32Array(r*t*4);break;case y:i=new Int8Array(r*t*4);break;case u:i=new Int16Array(r*t*4);break;case T:i=new Int32Array(r*t*4);break;case a:i=new Float32Array(r*t*4);break;default:throw new Error("Unsupported data type")}return i};let v;class R{_renderer;_rendererIsDisposable=!1;_material;_scene;_camera;_quad;_renderTarget;_width;_height;_type;_colorSpace;_supportsReadPixels=!0;constructor(_){this._width=_.width,this._height=_.height,this._type=_.type,this._colorSpace=_.colorSpace;const g={format:d,depthBuffer:!1,stencilBuffer:!1,type:this._type,colorSpace:this._colorSpace,anisotropy:void 0!==_.renderTargetOptions?.anisotropy?_.renderTargetOptions?.anisotropy:1,generateMipmaps:void 0!==_.renderTargetOptions?.generateMipmaps&&_.renderTargetOptions?.generateMipmaps,magFilter:void 0!==_.renderTargetOptions?.magFilter?_.renderTargetOptions?.magFilter:r,minFilter:void 0!==_.renderTargetOptions?.minFilter?_.renderTargetOptions?.minFilter:r,samples:void 0!==_.renderTargetOptions?.samples?_.renderTargetOptions?.samples:void 0,wrapS:void 0!==_.renderTargetOptions?.wrapS?_.renderTargetOptions?.wrapS:e,wrapT:void 0!==_.renderTargetOptions?.wrapT?_.renderTargetOptions?.wrapT:e};if(this._material=_.material,_.renderer?this._renderer=_.renderer:(this._renderer=R.instantiateRenderer(),this._rendererIsDisposable=!0),this._scene=new t,this._camera=new i,this._camera.position.set(0,0,10),this._camera.left=-.5,this._camera.right=.5,this._camera.top=.5,this._camera.bottom=-.5,this._camera.updateProjectionMatrix(),!((e,r,t,i)=>{if(void 0!==v)return v;const s=new o(1,1,i);r.setRenderTarget(s);const a=new n(new h,new m({color:16777215}));r.render(a,t),r.setRenderTarget(null);const d=b(e,s.width,s.height);return r.readRenderTargetPixels(s,0,0,s.width,s.height,d),s.dispose(),a.geometry.dispose(),a.material.dispose(),v=0!==d[0],v})(this._type,this._renderer,this._camera,g)){let e;if(this._type===s)e=this._renderer.extensions.has("EXT_color_buffer_float")?a:void 0;void 0!==e?(console.warn(`This browser does not support reading pixels from ${this._type} RenderTargets, switching to ${a}`),this._type=e):(this._supportsReadPixels=!1,console.warn("This browser dos not support toArray or toDataTexture, calls to those methods will result in an error thrown"))}this._quad=new n(new h,this._material),this._quad.geometry.computeBoundingBox(),this._scene.add(this._quad),this._renderTarget=new o(this.width,this.height,g),this._renderTarget.texture.mapping=void 0!==_.renderTargetOptions?.mapping?_.renderTargetOptions?.mapping:p}static instantiateRenderer(){const e=new _;return e.setSize(128,128),e}render=()=>{this._renderer.setRenderTarget(this._renderTarget);try{this._renderer.render(this._scene,this._camera)}catch(e){throw this._renderer.setRenderTarget(null),e}this._renderer.setRenderTarget(null)};toArray(){if(!this._supportsReadPixels)throw new Error("Can't read pixels in this browser");const e=b(this._type,this._width,this._height);return this._renderer.readRenderTargetPixels(this._renderTarget,0,0,this._width,this._height,e),e}toDataTexture(t){const i=new g(this.toArray(),this.width,this.height,d,this._type,t?.mapping||p,t?.wrapS||e,t?.wrapT||e,t?.magFilter||r,t?.minFilter||r,t?.anisotropy||1,l);return i.generateMipmaps=void 0!==t?.generateMipmaps&&t?.generateMipmaps,i}disposeOnDemandRenderer(){this._renderer.setRenderTarget(null),this._rendererIsDisposable&&(this._renderer.dispose(),this._renderer.forceContextLoss())}dispose(e){this.disposeOnDemandRenderer(),e&&this.renderTarget.dispose(),this.material instanceof c&&Object.values(this.material.uniforms).forEach(e=>{e.value instanceof w&&e.value.dispose()}),Object.values(this.material).forEach(e=>{e instanceof w&&e.dispose()}),this.material.dispose(),this._quad.geometry.dispose()}get width(){return this._width}set width(e){this._width=e,this._renderTarget.setSize(this._width,this._height)}get height(){return this._height}set height(e){this._height=e,this._renderTarget.setSize(this._width,this._height)}get renderer(){return this._renderer}get renderTarget(){return this._renderTarget}set renderTarget(e){this._renderTarget=e,this._width=e.width,this._height=e.height}get material(){return this._material}get type(){return this._type}get colorSpace(){return this._colorSpace}}export{R as Q};
|
||||
5
node_modules/@monogrid/gainmap-js/dist/_commonjsHelpers-CDmClQiF.js
generated
vendored
Normal file
5
node_modules/@monogrid/gainmap-js/dist/_commonjsHelpers-CDmClQiF.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function o(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}export{e as c,o as g};
|
||||
12
node_modules/@monogrid/gainmap-js/dist/_commonjsHelpers-v3qvwW2J.js
generated
vendored
Normal file
12
node_modules/@monogrid/gainmap-js/dist/_commonjsHelpers-v3qvwW2J.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
|
||||
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
||||
|
||||
function getDefaultExportFromCjs (x) {
|
||||
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
||||
}
|
||||
|
||||
export { commonjsGlobal as c, getDefaultExportFromCjs as g };
|
||||
92
node_modules/@monogrid/gainmap-js/dist/compress-C-X439Jm.js
generated
vendored
Normal file
92
node_modules/@monogrid/gainmap-js/dist/compress-C-X439Jm.js
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Used internally
|
||||
*
|
||||
* @internal
|
||||
* @param canvas
|
||||
* @param mimeType
|
||||
* @param quality
|
||||
* @returns
|
||||
*/
|
||||
const canvasToBlob = async (canvas, mimeType, quality) => {
|
||||
if (typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas) {
|
||||
return canvas.convertToBlob({ type: mimeType, quality: quality || 0.9 });
|
||||
}
|
||||
else if (canvas instanceof HTMLCanvasElement) {
|
||||
return new Promise((resolve, reject) => {
|
||||
canvas.toBlob((res) => {
|
||||
if (res)
|
||||
resolve(res);
|
||||
else
|
||||
reject(new Error('Failed to convert canvas to blob'));
|
||||
}, mimeType, quality || 0.9);
|
||||
});
|
||||
}
|
||||
/* istanbul ignore next
|
||||
as long as this function is not exported this is only here
|
||||
to satisfy TS strict mode internally
|
||||
*/
|
||||
throw new Error('Unsupported canvas element');
|
||||
};
|
||||
/**
|
||||
* Converts a RAW RGBA image buffer into the provided `mimeType` using the provided `quality`
|
||||
*
|
||||
* @category Compression
|
||||
* @group Compression
|
||||
* @param params
|
||||
* @throws {Error} if the browser does not support [createImageBitmap](https://caniuse.com/createimagebitmap)
|
||||
* @throws {Error} if the provided source image cannot be decoded
|
||||
* @throws {Error} if the function fails to create a canvas context
|
||||
*/
|
||||
const compress = async (params) => {
|
||||
if (typeof createImageBitmap === 'undefined')
|
||||
throw new Error('createImageBitmap() not supported.');
|
||||
const { source, mimeType, quality, flipY } = params;
|
||||
let imageBitmapSource;
|
||||
if ((source instanceof Uint8Array || source instanceof Uint8ClampedArray) && 'sourceMimeType' in params) {
|
||||
imageBitmapSource = new Blob([source], { type: params.sourceMimeType });
|
||||
}
|
||||
else if (source instanceof ImageData) {
|
||||
imageBitmapSource = source;
|
||||
}
|
||||
else {
|
||||
throw new Error('Invalid source image');
|
||||
}
|
||||
const img = await createImageBitmap(imageBitmapSource);
|
||||
const width = img.width;
|
||||
const height = img.height;
|
||||
let canvas;
|
||||
if (typeof OffscreenCanvas !== 'undefined') {
|
||||
canvas = new OffscreenCanvas(width, height);
|
||||
}
|
||||
else {
|
||||
canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
}
|
||||
// apparently we do need to assert the type here for npx tsc to be happy
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx)
|
||||
throw new Error('Failed to create canvas Context');
|
||||
// flip Y
|
||||
if (flipY === true) {
|
||||
ctx.translate(0, height);
|
||||
ctx.scale(1, -1);
|
||||
}
|
||||
ctx.drawImage(img, 0, 0, width, height);
|
||||
const blob = await canvasToBlob(canvas, mimeType, quality || 0.9);
|
||||
const data = new Uint8Array(await blob.arrayBuffer());
|
||||
return {
|
||||
data,
|
||||
mimeType,
|
||||
width,
|
||||
height
|
||||
};
|
||||
};
|
||||
|
||||
export { compress as c };
|
||||
5
node_modules/@monogrid/gainmap-js/dist/compress-DY-CSunh.js
generated
vendored
Normal file
5
node_modules/@monogrid/gainmap-js/dist/compress-DY-CSunh.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
const e=async e=>{if("undefined"==typeof createImageBitmap)throw new Error("createImageBitmap() not supported.");const{source:t,mimeType:a,quality:n,flipY:r}=e;let o;if((t instanceof Uint8Array||t instanceof Uint8ClampedArray)&&"sourceMimeType"in e)o=new Blob([t],{type:e.sourceMimeType});else{if(!(t instanceof ImageData))throw new Error("Invalid source image");o=t}const i=await createImageBitmap(o),s=i.width,c=i.height;let f;"undefined"!=typeof OffscreenCanvas?f=new OffscreenCanvas(s,c):(f=document.createElement("canvas"),f.width=s,f.height=c);const m=f.getContext("2d");if(!m)throw new Error("Failed to create canvas Context");!0===r&&(m.translate(0,c),m.scale(1,-1)),m.drawImage(i,0,0,s,c);const w=await(async(e,t,a)=>{if("undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)return e.convertToBlob({type:t,quality:a||.9});if(e instanceof HTMLCanvasElement)return new Promise((n,r)=>{e.toBlob(e=>{e?n(e):r(new Error("Failed to convert canvas to blob"))},t,a||.9)});throw new Error("Unsupported canvas element")})(f,a,n||.9);return{data:new Uint8Array(await w.arrayBuffer()),mimeType:a,width:s,height:c}};export{e as c};
|
||||
153
node_modules/@monogrid/gainmap-js/dist/core/QuadRenderer.d.ts
generated
vendored
Normal file
153
node_modules/@monogrid/gainmap-js/dist/core/QuadRenderer.d.ts
generated
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
import { ByteType, ColorSpace, DataTexture, FloatType, HalfFloatType, IntType, Material, ShortType, Texture, TextureDataType, UnsignedByteType, UnsignedInt248Type, UnsignedInt5999Type, UnsignedInt101111Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, WebGLRenderer, WebGLRenderTarget } from 'three';
|
||||
import { QuadRendererTextureOptions, TextureImageFormat } from './types';
|
||||
/**
|
||||
* Utility Type that translates `three` texture types to their TypedArray counterparts.
|
||||
*
|
||||
* @category Utility
|
||||
* @group Utility
|
||||
*/
|
||||
export type TextureDataTypeToBufferType<TType extends TextureDataType> = TType extends typeof UnsignedByteType ? Uint8ClampedArray<ArrayBuffer> : TType extends typeof ByteType ? Int8Array<ArrayBuffer> : TType extends typeof ShortType ? Int16Array<ArrayBuffer> : TType extends typeof UnsignedShortType ? Uint16Array<ArrayBuffer> : TType extends typeof IntType ? Int32Array<ArrayBuffer> : TType extends typeof UnsignedIntType ? Uint32Array<ArrayBuffer> : TType extends typeof FloatType ? Float32Array<ArrayBuffer> : TType extends typeof HalfFloatType ? Uint16Array<ArrayBuffer> : TType extends typeof UnsignedShort4444Type ? Uint16Array<ArrayBuffer> : TType extends typeof UnsignedShort5551Type ? Uint16Array<ArrayBuffer> : TType extends typeof UnsignedInt248Type ? Uint32Array<ArrayBuffer> : TType extends typeof UnsignedInt5999Type ? Uint32Array<ArrayBuffer> : TType extends typeof UnsignedInt101111Type ? Uint32Array<ArrayBuffer> : never;
|
||||
export type QuadRendererOptions<TType extends TextureDataType, TMaterial extends Material> = {
|
||||
/**
|
||||
* Width of the render target
|
||||
*/
|
||||
width: number;
|
||||
/**
|
||||
* height of the renderTarget
|
||||
*/
|
||||
height: number;
|
||||
/**
|
||||
* TextureDataType of the renderTarget
|
||||
*/
|
||||
type: TType;
|
||||
/**
|
||||
* ColorSpace of the renderTarget
|
||||
*/
|
||||
colorSpace: ColorSpace;
|
||||
/**
|
||||
* material to use for rendering
|
||||
*/
|
||||
material: TMaterial;
|
||||
/**
|
||||
* Renderer instance to use
|
||||
*/
|
||||
renderer?: WebGLRenderer;
|
||||
/**
|
||||
* Additional renderTarget options
|
||||
*/
|
||||
renderTargetOptions?: QuadRendererTextureOptions;
|
||||
};
|
||||
/**
|
||||
* Utility class used for rendering a texture with a material
|
||||
*
|
||||
* @category Core
|
||||
* @group Core
|
||||
*/
|
||||
export declare class QuadRenderer<TType extends TextureDataType, TMaterial extends Material> {
|
||||
private _renderer;
|
||||
private _rendererIsDisposable;
|
||||
private _material;
|
||||
private _scene;
|
||||
private _camera;
|
||||
private _quad;
|
||||
private _renderTarget;
|
||||
private _width;
|
||||
private _height;
|
||||
private _type;
|
||||
private _colorSpace;
|
||||
private _supportsReadPixels;
|
||||
/**
|
||||
* Constructs a new QuadRenderer
|
||||
*
|
||||
* @param options Parameters for this QuadRenderer
|
||||
*/
|
||||
constructor(options: QuadRendererOptions<TType, TMaterial>);
|
||||
/**
|
||||
* Instantiates a temporary renderer
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
static instantiateRenderer(): WebGLRenderer;
|
||||
/**
|
||||
* Renders the input texture using the specified material
|
||||
*/
|
||||
render: () => void;
|
||||
/**
|
||||
* Obtains a Buffer containing the rendered texture.
|
||||
*
|
||||
* @throws Error if the browser cannot read pixels from this RenderTarget type.
|
||||
* @returns a TypedArray containing RGBA values from this renderer
|
||||
*/
|
||||
toArray(): TextureDataTypeToBufferType<TType>;
|
||||
/**
|
||||
* Performs a readPixel operation in the renderTarget
|
||||
* and returns a DataTexture containing the read data
|
||||
*
|
||||
* @param options options
|
||||
* @returns
|
||||
*/
|
||||
toDataTexture(options?: QuadRendererTextureOptions): DataTexture;
|
||||
/**
|
||||
* If using a disposable renderer, it will dispose it.
|
||||
*/
|
||||
disposeOnDemandRenderer(): void;
|
||||
/**
|
||||
* Will dispose of **all** assets used by this renderer.
|
||||
*
|
||||
*
|
||||
* @param disposeRenderTarget will dispose of the renderTarget which will not be usable later
|
||||
* set this to true if you passed the `renderTarget.texture` to a `PMREMGenerator`
|
||||
* or are otherwise done with it.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* const loader = new HDRJPGLoader(renderer)
|
||||
* const result = await loader.loadAsync('gainmap.jpeg')
|
||||
* const mesh = new Mesh(geometry, new MeshBasicMaterial({ map: result.renderTarget.texture }) )
|
||||
* // DO NOT dispose the renderTarget here,
|
||||
* // it is used directly in the material
|
||||
* result.dispose()
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* const loader = new HDRJPGLoader(renderer)
|
||||
* const pmremGenerator = new PMREMGenerator( renderer );
|
||||
* const result = await loader.loadAsync('gainmap.jpeg')
|
||||
* const envMap = pmremGenerator.fromEquirectangular(result.renderTarget.texture)
|
||||
* const mesh = new Mesh(geometry, new MeshStandardMaterial({ envMap }) )
|
||||
* // renderTarget can be disposed here
|
||||
* // because it was used to generate a PMREM texture
|
||||
* result.dispose(true)
|
||||
* ```
|
||||
*/
|
||||
dispose(disposeRenderTarget?: boolean): void;
|
||||
/**
|
||||
* Width of the texture
|
||||
*/
|
||||
get width(): number;
|
||||
set width(value: number);
|
||||
/**
|
||||
* Height of the texture
|
||||
*/
|
||||
get height(): number;
|
||||
set height(value: number);
|
||||
/**
|
||||
* The renderer used
|
||||
*/
|
||||
get renderer(): WebGLRenderer;
|
||||
/**
|
||||
* The `WebGLRenderTarget` used.
|
||||
*/
|
||||
get renderTarget(): WebGLRenderTarget<Texture<TextureImageFormat>>;
|
||||
set renderTarget(value: WebGLRenderTarget<Texture<TextureImageFormat>>);
|
||||
/**
|
||||
* The `Material` used.
|
||||
*/
|
||||
get material(): TMaterial;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
get type(): TType;
|
||||
get colorSpace(): ColorSpace;
|
||||
}
|
||||
14
node_modules/@monogrid/gainmap-js/dist/core/get-data-texture.d.ts
generated
vendored
Normal file
14
node_modules/@monogrid/gainmap-js/dist/core/get-data-texture.d.ts
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import { DataTexture } from 'three';
|
||||
import { EXR } from 'three/examples/jsm/loaders/EXRLoader.js';
|
||||
import { HDR } from 'three/examples/jsm/loaders/HDRLoader.js';
|
||||
import { RGBE } from 'three/examples/jsm/loaders/RGBELoader.js';
|
||||
/**
|
||||
* Utility function to obtain a `DataTexture` from various input formats
|
||||
*
|
||||
* @category Utility
|
||||
* @group Utility
|
||||
*
|
||||
* @param image
|
||||
* @returns
|
||||
*/
|
||||
export declare const getDataTexture: (image: EXR | RGBE | HDR | DataTexture) => DataTexture;
|
||||
3
node_modules/@monogrid/gainmap-js/dist/core/index.d.ts
generated
vendored
Normal file
3
node_modules/@monogrid/gainmap-js/dist/core/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './get-data-texture';
|
||||
export * from './QuadRenderer';
|
||||
export * from './types';
|
||||
93
node_modules/@monogrid/gainmap-js/dist/core/types.d.ts
generated
vendored
Normal file
93
node_modules/@monogrid/gainmap-js/dist/core/types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
import { Mapping, RenderTargetOptions } from 'three';
|
||||
export type Constructor = new (...args: any[]) => any;
|
||||
/**
|
||||
* This is the Metadata stored in an encoded Gainmap which is used
|
||||
* to decode it and return an HDR image
|
||||
*
|
||||
* @category Specs
|
||||
* @group Specs
|
||||
*/
|
||||
export type GainMapMetadata = {
|
||||
/**
|
||||
* This is the gamma to apply to the stored map values.
|
||||
* @defaultValue [1, 1, 1]
|
||||
* @remarks
|
||||
* * Typically you can use a gamma of 1.0.
|
||||
* * You can use a different value if your gain map has a very uneven distribution of log_recovery(x, y) values.
|
||||
*
|
||||
* For example, this might apply if a gain map has a lot of detail just above SDR range (represented as small log_recovery(x, y) values),
|
||||
* and a very large map_max_log2 for the top end of the HDR rendition's desired brightness (represented by large log_recovery(x, y) values).
|
||||
* In this case, you can use a map_gamma higher than 1.0 so that recovery(x, y) can precisely encode the detail in both the low end and high end of log_recovery(x, y).
|
||||
*/
|
||||
gamma: [number, number, number];
|
||||
/**
|
||||
* This is log2 of the minimum display boost value for which the map is applied at all.
|
||||
*
|
||||
* @remarks
|
||||
* * This value also affects how much to apply the gain map based on the display boost.
|
||||
* * Must be 0.0 or greater.
|
||||
*
|
||||
* Logarithmic space
|
||||
*/
|
||||
hdrCapacityMin: number;
|
||||
/**
|
||||
* Stores the value of hdr_capacity_max. This is log2 of the maximum display boost value for which the map is applied completely.
|
||||
*
|
||||
* @remarks
|
||||
* * This value also affects how much to apply the gain map based on the display boost.
|
||||
* * Must be greater than hdrCapacityMin.
|
||||
* * Required.
|
||||
*
|
||||
* Logarithmic space
|
||||
*/
|
||||
hdrCapacityMax: number;
|
||||
/**
|
||||
* This is the offset to apply to the SDR pixel values during gain map generation and application
|
||||
* @defaultValue [1/64, 1/64, 1/64]
|
||||
*/
|
||||
offsetSdr: [number, number, number];
|
||||
/**
|
||||
* This is the offset to apply to the HDR pixel values during gain map generation and application.
|
||||
* @defaultValue [1/64, 1/64, 1/64]
|
||||
*/
|
||||
offsetHdr: [number, number, number];
|
||||
/**
|
||||
* This is log2 of min content boost, which is the minimum allowed ratio of
|
||||
* the linear luminance for the target HDR rendition relative to
|
||||
* (divided by) that of the SDR image, at a given pixel.
|
||||
*/
|
||||
gainMapMin: [number, number, number];
|
||||
/**
|
||||
* This is log2 of max content boost, which is the maximum allowed ratio of
|
||||
* the linear luminance for the Target HDR rendition relative to
|
||||
* (divided by) that of the SDR image, at a given pixel.
|
||||
*/
|
||||
gainMapMax: [number, number, number];
|
||||
};
|
||||
export type GainMapMetadataExtended = GainMapMetadata & {
|
||||
version: string;
|
||||
maxContentBoost: number;
|
||||
minContentBoost: number;
|
||||
};
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export type QuadRendererTextureOptions = Omit<RenderTargetOptions, 'type' | 'format' | 'colorSpace' | 'encoding' | 'depthTexture' | 'stencilBuffer' | 'depthBuffer' | 'internalFormat'> & {
|
||||
/**
|
||||
* @defaultValue 300
|
||||
*/
|
||||
mapping?: Mapping;
|
||||
/**
|
||||
* @defaultValue 1
|
||||
*/
|
||||
anisotropy?: number;
|
||||
};
|
||||
/**
|
||||
* Accepted image format for textures.
|
||||
* For many operations we need a texture based on an image with width & height.
|
||||
* It could also be a canvas, the only thing we actually need is a width and a height
|
||||
*/
|
||||
export type TextureImageFormat = {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
1
node_modules/@monogrid/gainmap-js/dist/decode.d.ts
generated
vendored
Normal file
1
node_modules/@monogrid/gainmap-js/dist/decode.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './decode/index';
|
||||
574
node_modules/@monogrid/gainmap-js/dist/decode.js
generated
vendored
Normal file
574
node_modules/@monogrid/gainmap-js/dist/decode.js
generated
vendored
Normal file
@@ -0,0 +1,574 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
|
||||
import { Q as QuadRenderer } from './QuadRenderer-Bj1xl_EK.js';
|
||||
import { c as createDecodeFunction, L as LoaderBaseShared, e as extractGainmapFromJPEG, X as XMPMetadataNotFoundError, G as GainMapNotFoundError } from './Loader-DLI-_JDP.js';
|
||||
export { M as MPFExtractor, a as extractXMP } from './Loader-DLI-_JDP.js';
|
||||
import { ShaderMaterial, NoBlending, Vector3, WebGLRenderer, FileLoader } from 'three';
|
||||
|
||||
const vertexShader = /* glsl */ `
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`;
|
||||
const fragmentShader = /* glsl */ `
|
||||
// min half float value
|
||||
#define HALF_FLOAT_MIN vec3( -65504, -65504, -65504 )
|
||||
// max half float value
|
||||
#define HALF_FLOAT_MAX vec3( 65504, 65504, 65504 )
|
||||
|
||||
uniform sampler2D sdr;
|
||||
uniform sampler2D gainMap;
|
||||
uniform vec3 gamma;
|
||||
uniform vec3 offsetHdr;
|
||||
uniform vec3 offsetSdr;
|
||||
uniform vec3 gainMapMin;
|
||||
uniform vec3 gainMapMax;
|
||||
uniform float weightFactor;
|
||||
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vec3 rgb = texture2D( sdr, vUv ).rgb;
|
||||
vec3 recovery = texture2D( gainMap, vUv ).rgb;
|
||||
vec3 logRecovery = pow( recovery, gamma );
|
||||
vec3 logBoost = gainMapMin * ( 1.0 - logRecovery ) + gainMapMax * logRecovery;
|
||||
vec3 hdrColor = (rgb + offsetSdr) * exp2( logBoost * weightFactor ) - offsetHdr;
|
||||
vec3 clampedHdrColor = max( HALF_FLOAT_MIN, min( HALF_FLOAT_MAX, hdrColor ));
|
||||
gl_FragColor = vec4( clampedHdrColor , 1.0 );
|
||||
}
|
||||
`;
|
||||
/**
|
||||
* A Material which is able to decode the Gainmap into a full HDR Representation
|
||||
*
|
||||
* @category Materials
|
||||
* @group Materials
|
||||
*/
|
||||
class GainMapDecoderMaterial extends ShaderMaterial {
|
||||
_maxDisplayBoost;
|
||||
_hdrCapacityMin;
|
||||
_hdrCapacityMax;
|
||||
/**
|
||||
*
|
||||
* @param params
|
||||
*/
|
||||
constructor({ gamma, offsetHdr, offsetSdr, gainMapMin, gainMapMax, maxDisplayBoost, hdrCapacityMin, hdrCapacityMax, sdr, gainMap }) {
|
||||
super({
|
||||
name: 'GainMapDecoderMaterial',
|
||||
vertexShader,
|
||||
fragmentShader,
|
||||
uniforms: {
|
||||
sdr: { value: sdr },
|
||||
gainMap: { value: gainMap },
|
||||
gamma: { value: new Vector3(1.0 / gamma[0], 1.0 / gamma[1], 1.0 / gamma[2]) },
|
||||
offsetHdr: { value: new Vector3().fromArray(offsetHdr) },
|
||||
offsetSdr: { value: new Vector3().fromArray(offsetSdr) },
|
||||
gainMapMin: { value: new Vector3().fromArray(gainMapMin) },
|
||||
gainMapMax: { value: new Vector3().fromArray(gainMapMax) },
|
||||
weightFactor: {
|
||||
value: (Math.log2(maxDisplayBoost) - hdrCapacityMin) / (hdrCapacityMax - hdrCapacityMin)
|
||||
}
|
||||
},
|
||||
blending: NoBlending,
|
||||
depthTest: false,
|
||||
depthWrite: false
|
||||
});
|
||||
this._maxDisplayBoost = maxDisplayBoost;
|
||||
this._hdrCapacityMin = hdrCapacityMin;
|
||||
this._hdrCapacityMax = hdrCapacityMax;
|
||||
this.needsUpdate = true;
|
||||
this.uniformsNeedUpdate = true;
|
||||
}
|
||||
get sdr() { return this.uniforms.sdr.value; }
|
||||
set sdr(value) { this.uniforms.sdr.value = value; }
|
||||
get gainMap() { return this.uniforms.gainMap.value; }
|
||||
set gainMap(value) { this.uniforms.gainMap.value = value; }
|
||||
/**
|
||||
* @see {@link GainMapMetadata.offsetHdr}
|
||||
*/
|
||||
get offsetHdr() { return this.uniforms.offsetHdr.value.toArray(); }
|
||||
set offsetHdr(value) { this.uniforms.offsetHdr.value.fromArray(value); }
|
||||
/**
|
||||
* @see {@link GainMapMetadata.offsetSdr}
|
||||
*/
|
||||
get offsetSdr() { return this.uniforms.offsetSdr.value.toArray(); }
|
||||
set offsetSdr(value) { this.uniforms.offsetSdr.value.fromArray(value); }
|
||||
/**
|
||||
* @see {@link GainMapMetadata.gainMapMin}
|
||||
*/
|
||||
get gainMapMin() { return this.uniforms.gainMapMin.value.toArray(); }
|
||||
set gainMapMin(value) { this.uniforms.gainMapMin.value.fromArray(value); }
|
||||
/**
|
||||
* @see {@link GainMapMetadata.gainMapMax}
|
||||
*/
|
||||
get gainMapMax() { return this.uniforms.gainMapMax.value.toArray(); }
|
||||
set gainMapMax(value) { this.uniforms.gainMapMax.value.fromArray(value); }
|
||||
/**
|
||||
* @see {@link GainMapMetadata.gamma}
|
||||
*/
|
||||
get gamma() {
|
||||
const g = this.uniforms.gamma.value;
|
||||
return [1 / g.x, 1 / g.y, 1 / g.z];
|
||||
}
|
||||
set gamma(value) {
|
||||
const g = this.uniforms.gamma.value;
|
||||
g.x = 1.0 / value[0];
|
||||
g.y = 1.0 / value[1];
|
||||
g.z = 1.0 / value[2];
|
||||
}
|
||||
/**
|
||||
* @see {@link GainMapMetadata.hdrCapacityMin}
|
||||
* @remarks Logarithmic space
|
||||
*/
|
||||
get hdrCapacityMin() { return this._hdrCapacityMin; }
|
||||
set hdrCapacityMin(value) {
|
||||
this._hdrCapacityMin = value;
|
||||
this.calculateWeight();
|
||||
}
|
||||
/**
|
||||
* @see {@link GainMapMetadata.hdrCapacityMin}
|
||||
* @remarks Logarithmic space
|
||||
*/
|
||||
get hdrCapacityMax() { return this._hdrCapacityMax; }
|
||||
set hdrCapacityMax(value) {
|
||||
this._hdrCapacityMax = value;
|
||||
this.calculateWeight();
|
||||
}
|
||||
/**
|
||||
* @see {@link GainmapDecodingParameters.maxDisplayBoost}
|
||||
* @remarks Non Logarithmic space
|
||||
*/
|
||||
get maxDisplayBoost() { return this._maxDisplayBoost; }
|
||||
set maxDisplayBoost(value) {
|
||||
this._maxDisplayBoost = Math.max(1, Math.min(65504, value));
|
||||
this.calculateWeight();
|
||||
}
|
||||
calculateWeight() {
|
||||
const val = (Math.log2(this._maxDisplayBoost) - this._hdrCapacityMin) / (this._hdrCapacityMax - this._hdrCapacityMin);
|
||||
this.uniforms.weightFactor.value = Math.max(0, Math.min(1, val));
|
||||
}
|
||||
}
|
||||
|
||||
const decodeImpl = createDecodeFunction({
|
||||
renderer: WebGLRenderer,
|
||||
createMaterial: (params) => new GainMapDecoderMaterial(params),
|
||||
createQuadRenderer: (params) => new QuadRenderer(params)
|
||||
});
|
||||
/**
|
||||
* Decodes a gain map using a WebGL RenderTarget
|
||||
*
|
||||
* @category Decoding Functions
|
||||
* @group Decoding Functions
|
||||
* @example
|
||||
* import { decode } from '@monogrid/gainmap-js'
|
||||
* import {
|
||||
* Mesh,
|
||||
* MeshBasicMaterial,
|
||||
* PerspectiveCamera,
|
||||
* PlaneGeometry,
|
||||
* Scene,
|
||||
* TextureLoader,
|
||||
* WebGLRenderer
|
||||
* } from 'three'
|
||||
*
|
||||
* const renderer = new WebGLRenderer()
|
||||
*
|
||||
* const textureLoader = new TextureLoader()
|
||||
*
|
||||
* // load SDR Representation
|
||||
* const sdr = await textureLoader.loadAsync('sdr.jpg')
|
||||
* // load Gain map recovery image
|
||||
* const gainMap = await textureLoader.loadAsync('gainmap.jpg')
|
||||
* // load metadata
|
||||
* const metadata = await (await fetch('metadata.json')).json()
|
||||
*
|
||||
* const result = decode({
|
||||
* sdr,
|
||||
* gainMap,
|
||||
* // this allows to use `result.renderTarget.texture` directly
|
||||
* renderer,
|
||||
* // this will restore the full HDR range
|
||||
* maxDisplayBoost: Math.pow(2, metadata.hdrCapacityMax),
|
||||
* ...metadata
|
||||
* })
|
||||
*
|
||||
* const scene = new Scene()
|
||||
* // `result` can be used to populate a Texture
|
||||
* const mesh = new Mesh(
|
||||
* new PlaneGeometry(),
|
||||
* new MeshBasicMaterial({ map: result.renderTarget.texture })
|
||||
* )
|
||||
* scene.add(mesh)
|
||||
* renderer.render(scene, new PerspectiveCamera())
|
||||
*
|
||||
* // result must be manually disposed
|
||||
* // when you are done using it
|
||||
* result.dispose()
|
||||
*
|
||||
* @param params
|
||||
* @returns
|
||||
* @throws {Error} if the WebGLRenderer fails to render the gain map
|
||||
*/
|
||||
const decode = (params) => {
|
||||
// Ensure renderer is defined for the base function
|
||||
if (!params.renderer) {
|
||||
throw new Error('Renderer is required for decode function');
|
||||
}
|
||||
const quadRenderer = decodeImpl({
|
||||
...params,
|
||||
renderer: params.renderer
|
||||
});
|
||||
try {
|
||||
quadRenderer.render();
|
||||
}
|
||||
catch (e) {
|
||||
quadRenderer.disposeOnDemandRenderer();
|
||||
throw e;
|
||||
}
|
||||
return quadRenderer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for WebGL loaders
|
||||
* @template TUrl - The type of URL used to load resources
|
||||
*/
|
||||
class LoaderBaseWebGL extends LoaderBaseShared {
|
||||
constructor(renderer, manager) {
|
||||
super({
|
||||
renderer,
|
||||
createMaterial: (params) => new GainMapDecoderMaterial(params),
|
||||
createQuadRenderer: (params) => new QuadRenderer(params)
|
||||
}, manager);
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
* @param quadRenderer
|
||||
* @param metadata
|
||||
* @param sdrBuffer
|
||||
* @param gainMapBuffer
|
||||
*/
|
||||
async render(quadRenderer, metadata, sdrBuffer, gainMapBuffer) {
|
||||
const { sdrImage, gainMapImage, needsFlip } = await this.processImages(sdrBuffer, gainMapBuffer, 'flipY');
|
||||
const { gainMap, sdr } = this.createTextures(sdrImage, gainMapImage, needsFlip);
|
||||
this.updateQuadRenderer(quadRenderer, sdrImage, gainMap, sdr, metadata);
|
||||
quadRenderer.render();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Three.js Loader for the gain map format.
|
||||
*
|
||||
* @category Loaders
|
||||
* @group Loaders
|
||||
*
|
||||
* @example
|
||||
* import { GainMapLoader } from '@monogrid/gainmap-js'
|
||||
* import {
|
||||
* EquirectangularReflectionMapping,
|
||||
* Mesh,
|
||||
* MeshBasicMaterial,
|
||||
* PerspectiveCamera,
|
||||
* PlaneGeometry,
|
||||
* Scene,
|
||||
* WebGLRenderer
|
||||
* } from 'three'
|
||||
*
|
||||
* const renderer = new WebGLRenderer()
|
||||
*
|
||||
* const loader = new GainMapLoader(renderer)
|
||||
* .setRenderTargetOptions({ mapping: EquirectangularReflectionMapping })
|
||||
*
|
||||
* const result = await loader.loadAsync(['sdr.jpeg', 'gainmap.jpeg', 'metadata.json'])
|
||||
* // `result` can be used to populate a Texture
|
||||
*
|
||||
* const scene = new Scene()
|
||||
* const mesh = new Mesh(
|
||||
* new PlaneGeometry(),
|
||||
* new MeshBasicMaterial({ map: result.renderTarget.texture })
|
||||
* )
|
||||
* scene.add(mesh)
|
||||
* renderer.render(scene, new PerspectiveCamera())
|
||||
*
|
||||
* // Starting from three.js r159
|
||||
* // `result.renderTarget.texture` can
|
||||
* // also be used as Equirectangular scene background
|
||||
* //
|
||||
* // it was previously needed to convert it
|
||||
* // to a DataTexture with `result.toDataTexture()`
|
||||
* scene.background = result.renderTarget.texture
|
||||
*
|
||||
* // result must be manually disposed
|
||||
* // when you are done using it
|
||||
* result.dispose()
|
||||
*
|
||||
*/
|
||||
class GainMapLoader extends LoaderBaseWebGL {
|
||||
/**
|
||||
* Loads a gainmap using separate data
|
||||
* * sdr image
|
||||
* * gain map image
|
||||
* * metadata json
|
||||
*
|
||||
* useful for webp gain maps
|
||||
*
|
||||
* @param urls An array in the form of [sdr.jpg, gainmap.jpg, metadata.json]
|
||||
* @param onLoad Load complete callback, will receive the result
|
||||
* @param onProgress Progress callback, will receive a `ProgressEvent`
|
||||
* @param onError Error callback
|
||||
* @returns
|
||||
*/
|
||||
load([sdrUrl, gainMapUrl, metadataUrl], onLoad, onProgress, onError) {
|
||||
const quadRenderer = this.prepareQuadRenderer();
|
||||
let sdr;
|
||||
let gainMap;
|
||||
let metadata;
|
||||
const loadCheck = async () => {
|
||||
if (sdr && gainMap && metadata) {
|
||||
// solves #16
|
||||
try {
|
||||
await this.render(quadRenderer, metadata, sdr, gainMap);
|
||||
}
|
||||
catch (error) {
|
||||
this.manager.itemError(sdrUrl);
|
||||
this.manager.itemError(gainMapUrl);
|
||||
this.manager.itemError(metadataUrl);
|
||||
if (typeof onError === 'function')
|
||||
onError(error);
|
||||
quadRenderer.disposeOnDemandRenderer();
|
||||
return;
|
||||
}
|
||||
if (typeof onLoad === 'function')
|
||||
onLoad(quadRenderer);
|
||||
this.manager.itemEnd(sdrUrl);
|
||||
this.manager.itemEnd(gainMapUrl);
|
||||
this.manager.itemEnd(metadataUrl);
|
||||
quadRenderer.disposeOnDemandRenderer();
|
||||
}
|
||||
};
|
||||
let sdrLengthComputable = true;
|
||||
let sdrTotal = 0;
|
||||
let sdrLoaded = 0;
|
||||
let gainMapLengthComputable = true;
|
||||
let gainMapTotal = 0;
|
||||
let gainMapLoaded = 0;
|
||||
let metadataLengthComputable = true;
|
||||
let metadataTotal = 0;
|
||||
let metadataLoaded = 0;
|
||||
const progressHandler = () => {
|
||||
if (typeof onProgress === 'function') {
|
||||
const total = sdrTotal + gainMapTotal + metadataTotal;
|
||||
const loaded = sdrLoaded + gainMapLoaded + metadataLoaded;
|
||||
const lengthComputable = sdrLengthComputable && gainMapLengthComputable && metadataLengthComputable;
|
||||
onProgress(new ProgressEvent('progress', { lengthComputable, loaded, total }));
|
||||
}
|
||||
};
|
||||
this.manager.itemStart(sdrUrl);
|
||||
this.manager.itemStart(gainMapUrl);
|
||||
this.manager.itemStart(metadataUrl);
|
||||
const sdrLoader = new FileLoader(this._internalLoadingManager);
|
||||
sdrLoader.setResponseType('arraybuffer');
|
||||
sdrLoader.setRequestHeader(this.requestHeader);
|
||||
sdrLoader.setPath(this.path);
|
||||
sdrLoader.setWithCredentials(this.withCredentials);
|
||||
sdrLoader.load(sdrUrl, async (buffer) => {
|
||||
/* istanbul ignore if
|
||||
this condition exists only because of three.js types + strict mode
|
||||
*/
|
||||
if (typeof buffer === 'string')
|
||||
throw new Error('Invalid sdr buffer');
|
||||
sdr = buffer;
|
||||
await loadCheck();
|
||||
}, (e) => {
|
||||
sdrLengthComputable = e.lengthComputable;
|
||||
sdrLoaded = e.loaded;
|
||||
sdrTotal = e.total;
|
||||
progressHandler();
|
||||
}, (error) => {
|
||||
this.manager.itemError(sdrUrl);
|
||||
if (typeof onError === 'function')
|
||||
onError(error);
|
||||
});
|
||||
const gainMapLoader = new FileLoader(this._internalLoadingManager);
|
||||
gainMapLoader.setResponseType('arraybuffer');
|
||||
gainMapLoader.setRequestHeader(this.requestHeader);
|
||||
gainMapLoader.setPath(this.path);
|
||||
gainMapLoader.setWithCredentials(this.withCredentials);
|
||||
gainMapLoader.load(gainMapUrl, async (buffer) => {
|
||||
/* istanbul ignore if
|
||||
this condition exists only because of three.js types + strict mode
|
||||
*/
|
||||
if (typeof buffer === 'string')
|
||||
throw new Error('Invalid gainmap buffer');
|
||||
gainMap = buffer;
|
||||
await loadCheck();
|
||||
}, (e) => {
|
||||
gainMapLengthComputable = e.lengthComputable;
|
||||
gainMapLoaded = e.loaded;
|
||||
gainMapTotal = e.total;
|
||||
progressHandler();
|
||||
}, (error) => {
|
||||
this.manager.itemError(gainMapUrl);
|
||||
if (typeof onError === 'function')
|
||||
onError(error);
|
||||
});
|
||||
const metadataLoader = new FileLoader(this._internalLoadingManager);
|
||||
// metadataLoader.setResponseType('json')
|
||||
metadataLoader.setRequestHeader(this.requestHeader);
|
||||
metadataLoader.setPath(this.path);
|
||||
metadataLoader.setWithCredentials(this.withCredentials);
|
||||
metadataLoader.load(metadataUrl, async (json) => {
|
||||
/* istanbul ignore if
|
||||
this condition exists only because of three.js types + strict mode
|
||||
*/
|
||||
if (typeof json !== 'string')
|
||||
throw new Error('Invalid metadata string');
|
||||
// TODO: implement check on JSON file and remove this eslint disable
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
metadata = JSON.parse(json);
|
||||
await loadCheck();
|
||||
}, (e) => {
|
||||
metadataLengthComputable = e.lengthComputable;
|
||||
metadataLoaded = e.loaded;
|
||||
metadataTotal = e.total;
|
||||
progressHandler();
|
||||
}, (error) => {
|
||||
this.manager.itemError(metadataUrl);
|
||||
if (typeof onError === 'function')
|
||||
onError(error);
|
||||
});
|
||||
return quadRenderer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Three.js Loader for a JPEG with embedded gainmap metadata.
|
||||
*
|
||||
* @category Loaders
|
||||
* @group Loaders
|
||||
*
|
||||
* @example
|
||||
* import { HDRJPGLoader } from '@monogrid/gainmap-js'
|
||||
* import {
|
||||
* EquirectangularReflectionMapping,
|
||||
* Mesh,
|
||||
* MeshBasicMaterial,
|
||||
* PerspectiveCamera,
|
||||
* PlaneGeometry,
|
||||
* Scene,
|
||||
* WebGLRenderer
|
||||
* } from 'three'
|
||||
*
|
||||
* const renderer = new WebGLRenderer()
|
||||
*
|
||||
* const loader = new HDRJPGLoader(renderer)
|
||||
* .setRenderTargetOptions({ mapping: EquirectangularReflectionMapping })
|
||||
*
|
||||
* const result = await loader.loadAsync('gainmap.jpeg')
|
||||
* // `result` can be used to populate a Texture
|
||||
*
|
||||
* const scene = new Scene()
|
||||
* const mesh = new Mesh(
|
||||
* new PlaneGeometry(),
|
||||
* new MeshBasicMaterial({ map: result.renderTarget.texture })
|
||||
* )
|
||||
* scene.add(mesh)
|
||||
* renderer.render(scene, new PerspectiveCamera())
|
||||
*
|
||||
* // Starting from three.js r159
|
||||
* // `result.renderTarget.texture` can
|
||||
* // also be used as Equirectangular scene background
|
||||
* //
|
||||
* // it was previously needed to convert it
|
||||
* // to a DataTexture with `result.toDataTexture()`
|
||||
* scene.background = result.renderTarget.texture
|
||||
*
|
||||
* // result must be manually disposed
|
||||
* // when you are done using it
|
||||
* result.dispose()
|
||||
*
|
||||
*/
|
||||
class HDRJPGLoader extends LoaderBaseWebGL {
|
||||
/**
|
||||
* Loads a JPEG containing gain map metadata
|
||||
* Renders a normal SDR image if gainmap data is not found
|
||||
*
|
||||
* @param url Path to a JPEG file containing embedded gain map metadata
|
||||
* @param onLoad Load complete callback, will receive the result
|
||||
* @param onProgress Progress callback, will receive a `ProgressEvent`
|
||||
* @param onError Error callback
|
||||
* @returns
|
||||
*/
|
||||
load(url, onLoad, onProgress, onError) {
|
||||
const quadRenderer = this.prepareQuadRenderer();
|
||||
const loader = new FileLoader(this._internalLoadingManager);
|
||||
loader.setResponseType('arraybuffer');
|
||||
loader.setRequestHeader(this.requestHeader);
|
||||
loader.setPath(this.path);
|
||||
loader.setWithCredentials(this.withCredentials);
|
||||
this.manager.itemStart(url);
|
||||
loader.load(url, async (jpeg) => {
|
||||
/* istanbul ignore if
|
||||
this condition exists only because of three.js types + strict mode
|
||||
*/
|
||||
if (typeof jpeg === 'string')
|
||||
throw new Error('Invalid buffer, received [string], was expecting [ArrayBuffer]');
|
||||
const jpegBuffer = new Uint8Array(jpeg);
|
||||
let sdrJPEG;
|
||||
let gainMapJPEG;
|
||||
let metadata;
|
||||
try {
|
||||
const extractionResult = await extractGainmapFromJPEG(jpegBuffer);
|
||||
// gain map is successfully reconstructed
|
||||
sdrJPEG = extractionResult.sdr;
|
||||
gainMapJPEG = extractionResult.gainMap;
|
||||
metadata = extractionResult.metadata;
|
||||
}
|
||||
catch (e) {
|
||||
// render the SDR version if this is not a gainmap
|
||||
if (e instanceof XMPMetadataNotFoundError || e instanceof GainMapNotFoundError) {
|
||||
console.warn(`Failure to reconstruct an HDR image from ${url}: Gain map metadata not found in the file, HDRJPGLoader will render the SDR jpeg`);
|
||||
metadata = {
|
||||
gainMapMin: [0, 0, 0],
|
||||
gainMapMax: [1, 1, 1],
|
||||
gamma: [1, 1, 1],
|
||||
hdrCapacityMin: 0,
|
||||
hdrCapacityMax: 1,
|
||||
offsetHdr: [0, 0, 0],
|
||||
offsetSdr: [0, 0, 0]
|
||||
};
|
||||
sdrJPEG = jpegBuffer;
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
// solves #16
|
||||
try {
|
||||
await this.render(quadRenderer, metadata, sdrJPEG.buffer, gainMapJPEG?.buffer);
|
||||
}
|
||||
catch (error) {
|
||||
this.manager.itemError(url);
|
||||
if (typeof onError === 'function')
|
||||
onError(error);
|
||||
quadRenderer.disposeOnDemandRenderer();
|
||||
return;
|
||||
}
|
||||
if (typeof onLoad === 'function')
|
||||
onLoad(quadRenderer);
|
||||
this.manager.itemEnd(url);
|
||||
quadRenderer.disposeOnDemandRenderer();
|
||||
}, onProgress, (error) => {
|
||||
this.manager.itemError(url);
|
||||
if (typeof onError === 'function')
|
||||
onError(error);
|
||||
});
|
||||
return quadRenderer;
|
||||
}
|
||||
}
|
||||
|
||||
export { GainMapDecoderMaterial, GainMapLoader, GainMapNotFoundError, HDRJPGLoader, HDRJPGLoader as JPEGRLoader, LoaderBaseShared, QuadRenderer, XMPMetadataNotFoundError, createDecodeFunction, decode, extractGainmapFromJPEG };
|
||||
5
node_modules/@monogrid/gainmap-js/dist/decode.min.js
generated
vendored
Normal file
5
node_modules/@monogrid/gainmap-js/dist/decode.min.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1307
node_modules/@monogrid/gainmap-js/dist/decode.umd.cjs
generated
vendored
Normal file
1307
node_modules/@monogrid/gainmap-js/dist/decode.umd.cjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5
node_modules/@monogrid/gainmap-js/dist/decode.umd.min.cjs
generated
vendored
Normal file
5
node_modules/@monogrid/gainmap-js/dist/decode.umd.min.cjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
814
node_modules/@monogrid/gainmap-js/dist/decode.webgpu.js
generated
vendored
Normal file
814
node_modules/@monogrid/gainmap-js/dist/decode.webgpu.js
generated
vendored
Normal file
@@ -0,0 +1,814 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
|
||||
import { c as createDecodeFunction, L as LoaderBaseShared, e as extractGainmapFromJPEG, X as XMPMetadataNotFoundError, G as GainMapNotFoundError } from './Loader-DLI-_JDP.js';
|
||||
export { M as MPFExtractor, a as extractXMP } from './Loader-DLI-_JDP.js';
|
||||
import { ClampToEdgeWrapping, LinearFilter, Scene, OrthographicCamera, Mesh, PlaneGeometry, RenderTarget, RGBAFormat, UVMapping, WebGPURenderer, DataTexture, LinearSRGBColorSpace, ShaderMaterial, Texture, MeshBasicNodeMaterial, NoBlending, FileLoader } from 'three/webgpu';
|
||||
import 'three';
|
||||
import { vec3, texture, uniform, pow, sub, float, add, mul, exp2, max, min } from 'three/tsl';
|
||||
|
||||
/**
|
||||
* Utility class used for rendering a texture with a material (WebGPU version)
|
||||
*
|
||||
* @category Core
|
||||
* @group Core
|
||||
*/
|
||||
class QuadRenderer {
|
||||
_renderer;
|
||||
_rendererIsDisposable = false;
|
||||
_material;
|
||||
_scene;
|
||||
_camera;
|
||||
_quad;
|
||||
_renderTarget;
|
||||
_width;
|
||||
_height;
|
||||
_type;
|
||||
_colorSpace;
|
||||
_supportsReadPixels = true;
|
||||
/**
|
||||
* Constructs a new QuadRenderer
|
||||
*
|
||||
* @param options Parameters for this QuadRenderer
|
||||
*/
|
||||
constructor(options) {
|
||||
this._width = options.width;
|
||||
this._height = options.height;
|
||||
this._type = options.type;
|
||||
this._colorSpace = options.colorSpace;
|
||||
const rtOptions = {
|
||||
// fixed options
|
||||
format: RGBAFormat,
|
||||
depthBuffer: false,
|
||||
stencilBuffer: false,
|
||||
// user options
|
||||
type: this._type, // set in class property
|
||||
colorSpace: this._colorSpace, // set in class property
|
||||
anisotropy: options.renderTargetOptions?.anisotropy !== undefined ? options.renderTargetOptions?.anisotropy : 1,
|
||||
generateMipmaps: options.renderTargetOptions?.generateMipmaps !== undefined ? options.renderTargetOptions?.generateMipmaps : false,
|
||||
magFilter: options.renderTargetOptions?.magFilter !== undefined ? options.renderTargetOptions?.magFilter : LinearFilter,
|
||||
minFilter: options.renderTargetOptions?.minFilter !== undefined ? options.renderTargetOptions?.minFilter : LinearFilter,
|
||||
samples: options.renderTargetOptions?.samples !== undefined ? options.renderTargetOptions?.samples : undefined,
|
||||
wrapS: options.renderTargetOptions?.wrapS !== undefined ? options.renderTargetOptions?.wrapS : ClampToEdgeWrapping,
|
||||
wrapT: options.renderTargetOptions?.wrapT !== undefined ? options.renderTargetOptions?.wrapT : ClampToEdgeWrapping
|
||||
};
|
||||
this._material = options.material;
|
||||
if (options.renderer) {
|
||||
this._renderer = options.renderer;
|
||||
}
|
||||
else {
|
||||
this._renderer = QuadRenderer.instantiateRenderer();
|
||||
this._rendererIsDisposable = true;
|
||||
}
|
||||
this._scene = new Scene();
|
||||
this._camera = new OrthographicCamera();
|
||||
this._camera.position.set(0, 0, 10);
|
||||
this._camera.left = -0.5;
|
||||
this._camera.right = 0.5;
|
||||
this._camera.top = 0.5;
|
||||
this._camera.bottom = -0.5;
|
||||
this._camera.updateProjectionMatrix();
|
||||
this._quad = new Mesh(new PlaneGeometry(), this._material);
|
||||
this._quad.geometry.computeBoundingBox();
|
||||
this._scene.add(this._quad);
|
||||
this._renderTarget = new RenderTarget(this.width, this.height, rtOptions);
|
||||
this._renderTarget.texture.mapping = options.renderTargetOptions?.mapping !== undefined ? options.renderTargetOptions?.mapping : UVMapping;
|
||||
}
|
||||
/**
|
||||
* Instantiates a temporary renderer
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
static instantiateRenderer() {
|
||||
const renderer = new WebGPURenderer();
|
||||
renderer.setSize(128, 128);
|
||||
return renderer;
|
||||
}
|
||||
/**
|
||||
* Renders the input texture using the specified material
|
||||
*/
|
||||
render = async () => {
|
||||
if (!this._renderer.hasInitialized()) {
|
||||
await this._renderer.init();
|
||||
}
|
||||
this._renderer.setRenderTarget(this._renderTarget);
|
||||
try {
|
||||
this._renderer.render(this._scene, this._camera);
|
||||
}
|
||||
catch (e) {
|
||||
this._renderer.setRenderTarget(null);
|
||||
throw e;
|
||||
}
|
||||
this._renderer.setRenderTarget(null);
|
||||
};
|
||||
/**
|
||||
* Obtains a Buffer containing the rendered texture.
|
||||
*
|
||||
* @throws Error if the browser cannot read pixels from this RenderTarget type.
|
||||
* @returns a TypedArray containing RGBA values from this renderer
|
||||
*/
|
||||
async toArray() {
|
||||
if (!this._supportsReadPixels)
|
||||
throw new Error('Can\'t read pixels in this browser');
|
||||
const out = await this._renderer.readRenderTargetPixelsAsync(this._renderTarget, 0, 0, this._width, this._height);
|
||||
return out;
|
||||
}
|
||||
/**
|
||||
* Performs a readPixel operation in the renderTarget
|
||||
* and returns a DataTexture containing the read data
|
||||
*
|
||||
* @param options options
|
||||
* @returns
|
||||
*/
|
||||
async toDataTexture(options) {
|
||||
const returnValue = new DataTexture(
|
||||
// fixed values
|
||||
await this.toArray(), this.width, this.height, RGBAFormat, this._type,
|
||||
// user values
|
||||
options?.mapping || UVMapping, options?.wrapS || ClampToEdgeWrapping, options?.wrapT || ClampToEdgeWrapping, options?.magFilter || LinearFilter, options?.minFilter || LinearFilter, options?.anisotropy || 1,
|
||||
// fixed value
|
||||
LinearSRGBColorSpace);
|
||||
returnValue.flipY = options?.flipY !== undefined ? options?.flipY : true;
|
||||
// set this afterwards, we can't set it in constructor
|
||||
returnValue.generateMipmaps = options?.generateMipmaps !== undefined ? options?.generateMipmaps : false;
|
||||
return returnValue;
|
||||
}
|
||||
/**
|
||||
* If using a disposable renderer, it will dispose it.
|
||||
*/
|
||||
disposeOnDemandRenderer() {
|
||||
this._renderer.setRenderTarget(null);
|
||||
if (this._rendererIsDisposable) {
|
||||
this._renderer.dispose();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Will dispose of **all** assets used by this renderer.
|
||||
*
|
||||
*
|
||||
* @param disposeRenderTarget will dispose of the renderTarget which will not be usable later
|
||||
* set this to true if you passed the `renderTarget.texture` to a `PMREMGenerator`
|
||||
* or are otherwise done with it.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* const loader = new HDRJPGLoader(renderer)
|
||||
* const result = await loader.loadAsync('gainmap.jpeg')
|
||||
* const mesh = new Mesh(geometry, new MeshBasicMaterial({ map: result.renderTarget.texture }) )
|
||||
* // DO NOT dispose the renderTarget here,
|
||||
* // it is used directly in the material
|
||||
* result.dispose()
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* const loader = new HDRJPGLoader(renderer)
|
||||
* const pmremGenerator = new PMREMGenerator( renderer );
|
||||
* const result = await loader.loadAsync('gainmap.jpeg')
|
||||
* const envMap = pmremGenerator.fromEquirectangular(result.renderTarget.texture)
|
||||
* const mesh = new Mesh(geometry, new MeshStandardMaterial({ envMap }) )
|
||||
* // renderTarget can be disposed here
|
||||
* // because it was used to generate a PMREM texture
|
||||
* result.dispose(true)
|
||||
* ```
|
||||
*/
|
||||
dispose(disposeRenderTarget) {
|
||||
if (disposeRenderTarget) {
|
||||
this.renderTarget.dispose();
|
||||
}
|
||||
// dispose shader material texture uniforms
|
||||
if (this.material instanceof ShaderMaterial) {
|
||||
Object.values(this.material.uniforms).forEach(v => {
|
||||
if (v.value instanceof Texture)
|
||||
v.value.dispose();
|
||||
});
|
||||
}
|
||||
// dispose other material properties
|
||||
Object.values(this.material).forEach(value => {
|
||||
if (value instanceof Texture)
|
||||
value.dispose();
|
||||
});
|
||||
this.material.dispose();
|
||||
this._quad.geometry.dispose();
|
||||
this.disposeOnDemandRenderer();
|
||||
}
|
||||
/**
|
||||
* Width of the texture
|
||||
*/
|
||||
get width() { return this._width; }
|
||||
set width(value) {
|
||||
this._width = value;
|
||||
this._renderTarget.setSize(this._width, this._height);
|
||||
}
|
||||
/**
|
||||
* Height of the texture
|
||||
*/
|
||||
get height() { return this._height; }
|
||||
set height(value) {
|
||||
this._height = value;
|
||||
this._renderTarget.setSize(this._width, this._height);
|
||||
}
|
||||
/**
|
||||
* The renderer used
|
||||
*/
|
||||
get renderer() { return this._renderer; }
|
||||
/**
|
||||
* The `RenderTarget` used.
|
||||
*/
|
||||
get renderTarget() { return this._renderTarget; }
|
||||
set renderTarget(value) {
|
||||
this._renderTarget = value;
|
||||
this._width = value.width;
|
||||
this._height = value.height;
|
||||
}
|
||||
/**
|
||||
* The `Material` used.
|
||||
*/
|
||||
get material() { return this._material; }
|
||||
/**
|
||||
*
|
||||
*/
|
||||
get type() { return this._type; }
|
||||
get colorSpace() { return this._colorSpace; }
|
||||
}
|
||||
|
||||
// min half float value
|
||||
const HALF_FLOAT_MIN = vec3(-65504, -65504, -65504);
|
||||
// max half float value
|
||||
const HALF_FLOAT_MAX = vec3(65504, 65504, 65504);
|
||||
/**
|
||||
* A Material which is able to decode the Gainmap into a full HDR Representation using TSL (Three.js Shading Language)
|
||||
*
|
||||
* @category Materials
|
||||
* @group Materials
|
||||
*/
|
||||
class GainMapDecoderMaterial extends MeshBasicNodeMaterial {
|
||||
_maxDisplayBoost;
|
||||
_hdrCapacityMin;
|
||||
_hdrCapacityMax;
|
||||
// Uniforms for TSL
|
||||
_gammaUniform;
|
||||
_offsetHdrUniform;
|
||||
_offsetSdrUniform;
|
||||
_gainMapMinUniform;
|
||||
_gainMapMaxUniform;
|
||||
_weightFactorUniform;
|
||||
_sdrTexture;
|
||||
_gainMapTexture;
|
||||
/**
|
||||
*
|
||||
* @param params
|
||||
*/
|
||||
constructor({ gamma, offsetHdr, offsetSdr, gainMapMin, gainMapMax, maxDisplayBoost, hdrCapacityMin, hdrCapacityMax, sdr, gainMap }) {
|
||||
super();
|
||||
this.name = 'GainMapDecoderMaterial';
|
||||
this.blending = NoBlending;
|
||||
this.depthTest = false;
|
||||
this.depthWrite = false;
|
||||
this._sdrTexture = texture(sdr);
|
||||
this._gainMapTexture = texture(gainMap);
|
||||
// Create uniform nodes
|
||||
this._gammaUniform = uniform(vec3(1.0 / gamma[0], 1.0 / gamma[1], 1.0 / gamma[2]));
|
||||
this._offsetHdrUniform = uniform(vec3(offsetHdr[0], offsetHdr[1], offsetHdr[2]));
|
||||
this._offsetSdrUniform = uniform(vec3(offsetSdr[0], offsetSdr[1], offsetSdr[2]));
|
||||
this._gainMapMinUniform = uniform(vec3(gainMapMin[0], gainMapMin[1], gainMapMin[2]));
|
||||
this._gainMapMaxUniform = uniform(vec3(gainMapMax[0], gainMapMax[1], gainMapMax[2]));
|
||||
const weightFactor = (Math.log2(maxDisplayBoost) - hdrCapacityMin) / (hdrCapacityMax - hdrCapacityMin);
|
||||
this._weightFactorUniform = uniform(weightFactor);
|
||||
this._maxDisplayBoost = maxDisplayBoost;
|
||||
this._hdrCapacityMin = hdrCapacityMin;
|
||||
this._hdrCapacityMax = hdrCapacityMax;
|
||||
// Build the TSL shader graph
|
||||
// Get RGB values
|
||||
const rgb = this._sdrTexture.rgb;
|
||||
const recovery = this._gainMapTexture.rgb;
|
||||
// Apply gamma correction
|
||||
const logRecovery = pow(recovery, this._gammaUniform);
|
||||
// Calculate log boost
|
||||
// logBoost = gainMapMin * (1.0 - logRecovery) + gainMapMax * logRecovery
|
||||
const oneMinusLogRecovery = sub(float(1.0), logRecovery);
|
||||
const logBoost = add(mul(this._gainMapMinUniform, oneMinusLogRecovery), mul(this._gainMapMaxUniform, logRecovery));
|
||||
// Calculate HDR color
|
||||
// hdrColor = (rgb + offsetSdr) * exp2(logBoost * weightFactor) - offsetHdr
|
||||
const hdrColor = sub(mul(add(rgb, this._offsetSdrUniform), exp2(mul(logBoost, this._weightFactorUniform))), this._offsetHdrUniform);
|
||||
// Clamp to half float range
|
||||
const clampedHdrColor = max(HALF_FLOAT_MIN, min(HALF_FLOAT_MAX, hdrColor));
|
||||
// Set the color output
|
||||
this.colorNode = clampedHdrColor;
|
||||
}
|
||||
get sdr() { return this._sdrTexture.value; }
|
||||
set sdr(value) { this._sdrTexture.value = value; }
|
||||
get gainMap() { return this._gainMapTexture.value; }
|
||||
set gainMap(value) { this._gainMapTexture.value = value; }
|
||||
/**
|
||||
* @see {@link GainMapMetadata.offsetHdr}
|
||||
*/
|
||||
get offsetHdr() {
|
||||
return [this._offsetHdrUniform.value.x, this._offsetHdrUniform.value.y, this._offsetHdrUniform.value.z];
|
||||
}
|
||||
set offsetHdr(value) {
|
||||
this._offsetHdrUniform.value.x = value[0];
|
||||
this._offsetHdrUniform.value.y = value[1];
|
||||
this._offsetHdrUniform.value.z = value[2];
|
||||
}
|
||||
/**
|
||||
* @see {@link GainMapMetadata.offsetSdr}
|
||||
*/
|
||||
get offsetSdr() {
|
||||
return [this._offsetSdrUniform.value.x, this._offsetSdrUniform.value.y, this._offsetSdrUniform.value.z];
|
||||
}
|
||||
set offsetSdr(value) {
|
||||
this._offsetSdrUniform.value.x = value[0];
|
||||
this._offsetSdrUniform.value.y = value[1];
|
||||
this._offsetSdrUniform.value.z = value[2];
|
||||
}
|
||||
/**
|
||||
* @see {@link GainMapMetadata.gainMapMin}
|
||||
*/
|
||||
get gainMapMin() {
|
||||
return [this._gainMapMinUniform.value.x, this._gainMapMinUniform.value.y, this._gainMapMinUniform.value.z];
|
||||
}
|
||||
set gainMapMin(value) {
|
||||
this._gainMapMinUniform.value.x = value[0];
|
||||
this._gainMapMinUniform.value.y = value[1];
|
||||
this._gainMapMinUniform.value.z = value[2];
|
||||
}
|
||||
/**
|
||||
* @see {@link GainMapMetadata.gainMapMax}
|
||||
*/
|
||||
get gainMapMax() {
|
||||
return [this._gainMapMaxUniform.value.x, this._gainMapMaxUniform.value.y, this._gainMapMaxUniform.value.z];
|
||||
}
|
||||
set gainMapMax(value) {
|
||||
this._gainMapMaxUniform.value.x = value[0];
|
||||
this._gainMapMaxUniform.value.y = value[1];
|
||||
this._gainMapMaxUniform.value.z = value[2];
|
||||
}
|
||||
/**
|
||||
* @see {@link GainMapMetadata.gamma}
|
||||
*/
|
||||
get gamma() {
|
||||
return [1 / this._gammaUniform.value.x, 1 / this._gammaUniform.value.y, 1 / this._gammaUniform.value.z];
|
||||
}
|
||||
set gamma(value) {
|
||||
this._gammaUniform.value.x = 1.0 / value[0];
|
||||
this._gammaUniform.value.y = 1.0 / value[1];
|
||||
this._gammaUniform.value.z = 1.0 / value[2];
|
||||
}
|
||||
/**
|
||||
* @see {@link GainMapMetadata.hdrCapacityMin}
|
||||
* @remarks Logarithmic space
|
||||
*/
|
||||
get hdrCapacityMin() { return this._hdrCapacityMin; }
|
||||
set hdrCapacityMin(value) {
|
||||
this._hdrCapacityMin = value;
|
||||
this.calculateWeight();
|
||||
}
|
||||
/**
|
||||
* @see {@link GainMapMetadata.hdrCapacityMax}
|
||||
* @remarks Logarithmic space
|
||||
*/
|
||||
get hdrCapacityMax() { return this._hdrCapacityMax; }
|
||||
set hdrCapacityMax(value) {
|
||||
this._hdrCapacityMax = value;
|
||||
this.calculateWeight();
|
||||
}
|
||||
/**
|
||||
* @see {@link GainmapDecodingParameters.maxDisplayBoost}
|
||||
* @remarks Non Logarithmic space
|
||||
*/
|
||||
get maxDisplayBoost() { return this._maxDisplayBoost; }
|
||||
set maxDisplayBoost(value) {
|
||||
this._maxDisplayBoost = Math.max(1, Math.min(65504, value));
|
||||
this.calculateWeight();
|
||||
}
|
||||
calculateWeight() {
|
||||
const val = (Math.log2(this._maxDisplayBoost) - this._hdrCapacityMin) / (this._hdrCapacityMax - this._hdrCapacityMin);
|
||||
this._weightFactorUniform.value = Math.max(0, Math.min(1, val));
|
||||
}
|
||||
}
|
||||
|
||||
const decodeImpl = createDecodeFunction({
|
||||
renderer: WebGPURenderer,
|
||||
createMaterial: (params) => new GainMapDecoderMaterial(params),
|
||||
createQuadRenderer: (params) => new QuadRenderer(params)
|
||||
});
|
||||
/**
|
||||
* Decodes a gain map using WebGPU RenderTarget
|
||||
*
|
||||
* @category Decoding Functions
|
||||
* @group Decoding Functions
|
||||
* @example
|
||||
* import { decode } from '@monogrid/gainmap-js/webgpu'
|
||||
* import {
|
||||
* Mesh,
|
||||
* MeshBasicMaterial,
|
||||
* PerspectiveCamera,
|
||||
* PlaneGeometry,
|
||||
* Scene,
|
||||
* TextureLoader,
|
||||
* WebGPURenderer
|
||||
* } from 'three/webgpu'
|
||||
*
|
||||
* const renderer = new WebGPURenderer()
|
||||
*
|
||||
* const textureLoader = new TextureLoader()
|
||||
*
|
||||
* // load SDR Representation
|
||||
* const sdr = await textureLoader.loadAsync('sdr.jpg')
|
||||
* // load Gain map recovery image
|
||||
* const gainMap = await textureLoader.loadAsync('gainmap.jpg')
|
||||
* // load metadata
|
||||
* const metadata = await (await fetch('metadata.json')).json()
|
||||
*
|
||||
* const result = await decode({
|
||||
* sdr,
|
||||
* gainMap,
|
||||
* // this allows to use `result.renderTarget.texture` directly
|
||||
* renderer,
|
||||
* // this will restore the full HDR range
|
||||
* maxDisplayBoost: Math.pow(2, metadata.hdrCapacityMax),
|
||||
* ...metadata
|
||||
* })
|
||||
*
|
||||
* const scene = new Scene()
|
||||
* // `result` can be used to populate a Texture
|
||||
* const mesh = new Mesh(
|
||||
* new PlaneGeometry(),
|
||||
* new MeshBasicMaterial({ map: result.renderTarget.texture })
|
||||
* )
|
||||
* scene.add(mesh)
|
||||
* renderer.render(scene, new PerspectiveCamera())
|
||||
*
|
||||
* // result must be manually disposed
|
||||
* // when you are done using it
|
||||
* result.dispose()
|
||||
*
|
||||
* @param params
|
||||
* @returns
|
||||
* @throws {Error} if the WebGPURenderer fails to render the gain map
|
||||
*/
|
||||
const decode = async (params) => {
|
||||
// Ensure renderer is defined for the base function
|
||||
if (!params.renderer) {
|
||||
throw new Error('Renderer is required for decode function');
|
||||
}
|
||||
const quadRenderer = decodeImpl({
|
||||
...params,
|
||||
renderer: params.renderer
|
||||
});
|
||||
try {
|
||||
await quadRenderer.render();
|
||||
}
|
||||
catch (e) {
|
||||
quadRenderer.disposeOnDemandRenderer();
|
||||
throw e;
|
||||
}
|
||||
return quadRenderer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for WebGPU loaders
|
||||
* @template TUrl - The type of URL used to load resources
|
||||
*/
|
||||
class LoaderBaseWebGPU extends LoaderBaseShared {
|
||||
constructor(renderer, manager) {
|
||||
super({
|
||||
renderer,
|
||||
createMaterial: (params) => new GainMapDecoderMaterial(params),
|
||||
createQuadRenderer: (params) => new QuadRenderer(params)
|
||||
}, manager);
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
* @param quadRenderer
|
||||
* @param metadata
|
||||
* @param sdrBuffer
|
||||
* @param gainMapBuffer
|
||||
*/
|
||||
async render(quadRenderer, metadata, sdrBuffer, gainMapBuffer) {
|
||||
// in WebGPU we apparently don't need flipY under any circumstance
|
||||
// except in QuadRenderer.toDataTexture() where we perform it in the texture itself
|
||||
const { sdrImage, gainMapImage, needsFlip } = await this.processImages(sdrBuffer, gainMapBuffer, 'from-image');
|
||||
const { gainMap, sdr } = this.createTextures(sdrImage, gainMapImage, needsFlip);
|
||||
this.updateQuadRenderer(quadRenderer, sdrImage, gainMap, sdr, metadata);
|
||||
await quadRenderer.render();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Three.js Loader for the gain map format (WebGPU version).
|
||||
*
|
||||
* @category Loaders
|
||||
* @group Loaders
|
||||
*
|
||||
* @example
|
||||
* import { GainMapLoader } from '@monogrid/gainmap-js/webgpu'
|
||||
* import {
|
||||
* EquirectangularReflectionMapping,
|
||||
* Mesh,
|
||||
* MeshBasicMaterial,
|
||||
* PerspectiveCamera,
|
||||
* PlaneGeometry,
|
||||
* Scene,
|
||||
* WebGPURenderer
|
||||
* } from 'three/webgpu'
|
||||
*
|
||||
* const renderer = new WebGPURenderer()
|
||||
* await renderer.init()
|
||||
*
|
||||
* const loader = new GainMapLoader(renderer)
|
||||
* .setRenderTargetOptions({ mapping: EquirectangularReflectionMapping })
|
||||
*
|
||||
* const result = await loader.loadAsync(['sdr.jpeg', 'gainmap.jpeg', 'metadata.json'])
|
||||
* // `result` can be used to populate a Texture
|
||||
*
|
||||
* const scene = new Scene()
|
||||
* const mesh = new Mesh(
|
||||
* new PlaneGeometry(),
|
||||
* new MeshBasicMaterial({ map: result.renderTarget.texture })
|
||||
* )
|
||||
* scene.add(mesh)
|
||||
* renderer.render(scene, new PerspectiveCamera())
|
||||
*
|
||||
* // Starting from three.js r159
|
||||
* // `result.renderTarget.texture` can
|
||||
* // also be used as Equirectangular scene background
|
||||
* //
|
||||
* // it was previously needed to convert it
|
||||
* // to a DataTexture with `result.toDataTexture()`
|
||||
* scene.background = result.renderTarget.texture
|
||||
*
|
||||
* // result must be manually disposed
|
||||
* // when you are done using it
|
||||
* result.dispose()
|
||||
*
|
||||
*/
|
||||
class GainMapLoader extends LoaderBaseWebGPU {
|
||||
/**
|
||||
* Loads a gainmap using separate data
|
||||
* * sdr image
|
||||
* * gain map image
|
||||
* * metadata json
|
||||
*
|
||||
* useful for webp gain maps
|
||||
*
|
||||
* @param urls An array in the form of [sdr.jpg, gainmap.jpg, metadata.json]
|
||||
* @param onLoad Load complete callback, will receive the result
|
||||
* @param onProgress Progress callback, will receive a `ProgressEvent`
|
||||
* @param onError Error callback
|
||||
* @returns
|
||||
*/
|
||||
load([sdrUrl, gainMapUrl, metadataUrl], onLoad, onProgress, onError) {
|
||||
const quadRenderer = this.prepareQuadRenderer();
|
||||
let sdr;
|
||||
let gainMap;
|
||||
let metadata;
|
||||
const loadCheck = async () => {
|
||||
if (sdr && gainMap && metadata) {
|
||||
// solves #16
|
||||
try {
|
||||
await this.render(quadRenderer, metadata, sdr, gainMap);
|
||||
}
|
||||
catch (error) {
|
||||
this.manager.itemError(sdrUrl);
|
||||
this.manager.itemError(gainMapUrl);
|
||||
this.manager.itemError(metadataUrl);
|
||||
if (typeof onError === 'function')
|
||||
onError(error);
|
||||
quadRenderer.disposeOnDemandRenderer();
|
||||
return;
|
||||
}
|
||||
if (typeof onLoad === 'function')
|
||||
onLoad(quadRenderer);
|
||||
this.manager.itemEnd(sdrUrl);
|
||||
this.manager.itemEnd(gainMapUrl);
|
||||
this.manager.itemEnd(metadataUrl);
|
||||
quadRenderer.disposeOnDemandRenderer();
|
||||
}
|
||||
};
|
||||
let sdrLengthComputable = true;
|
||||
let sdrTotal = 0;
|
||||
let sdrLoaded = 0;
|
||||
let gainMapLengthComputable = true;
|
||||
let gainMapTotal = 0;
|
||||
let gainMapLoaded = 0;
|
||||
let metadataLengthComputable = true;
|
||||
let metadataTotal = 0;
|
||||
let metadataLoaded = 0;
|
||||
const progressHandler = () => {
|
||||
if (typeof onProgress === 'function') {
|
||||
const total = sdrTotal + gainMapTotal + metadataTotal;
|
||||
const loaded = sdrLoaded + gainMapLoaded + metadataLoaded;
|
||||
const lengthComputable = sdrLengthComputable && gainMapLengthComputable && metadataLengthComputable;
|
||||
onProgress(new ProgressEvent('progress', { lengthComputable, loaded, total }));
|
||||
}
|
||||
};
|
||||
this.manager.itemStart(sdrUrl);
|
||||
this.manager.itemStart(gainMapUrl);
|
||||
this.manager.itemStart(metadataUrl);
|
||||
const sdrLoader = new FileLoader(this._internalLoadingManager);
|
||||
sdrLoader.setResponseType('arraybuffer');
|
||||
sdrLoader.setRequestHeader(this.requestHeader);
|
||||
sdrLoader.setPath(this.path);
|
||||
sdrLoader.setWithCredentials(this.withCredentials);
|
||||
sdrLoader.load(sdrUrl, async (buffer) => {
|
||||
/* istanbul ignore if
|
||||
this condition exists only because of three.js types + strict mode
|
||||
*/
|
||||
if (typeof buffer === 'string')
|
||||
throw new Error('Invalid sdr buffer');
|
||||
sdr = buffer;
|
||||
await loadCheck();
|
||||
}, (e) => {
|
||||
sdrLengthComputable = e.lengthComputable;
|
||||
sdrLoaded = e.loaded;
|
||||
sdrTotal = e.total;
|
||||
progressHandler();
|
||||
}, (error) => {
|
||||
this.manager.itemError(sdrUrl);
|
||||
if (typeof onError === 'function')
|
||||
onError(error);
|
||||
});
|
||||
const gainMapLoader = new FileLoader(this._internalLoadingManager);
|
||||
gainMapLoader.setResponseType('arraybuffer');
|
||||
gainMapLoader.setRequestHeader(this.requestHeader);
|
||||
gainMapLoader.setPath(this.path);
|
||||
gainMapLoader.setWithCredentials(this.withCredentials);
|
||||
gainMapLoader.load(gainMapUrl, async (buffer) => {
|
||||
/* istanbul ignore if
|
||||
this condition exists only because of three.js types + strict mode
|
||||
*/
|
||||
if (typeof buffer === 'string')
|
||||
throw new Error('Invalid gainmap buffer');
|
||||
gainMap = buffer;
|
||||
await loadCheck();
|
||||
}, (e) => {
|
||||
gainMapLengthComputable = e.lengthComputable;
|
||||
gainMapLoaded = e.loaded;
|
||||
gainMapTotal = e.total;
|
||||
progressHandler();
|
||||
}, (error) => {
|
||||
this.manager.itemError(gainMapUrl);
|
||||
if (typeof onError === 'function')
|
||||
onError(error);
|
||||
});
|
||||
const metadataLoader = new FileLoader(this._internalLoadingManager);
|
||||
// metadataLoader.setResponseType('json')
|
||||
metadataLoader.setRequestHeader(this.requestHeader);
|
||||
metadataLoader.setPath(this.path);
|
||||
metadataLoader.setWithCredentials(this.withCredentials);
|
||||
metadataLoader.load(metadataUrl, async (json) => {
|
||||
/* istanbul ignore if
|
||||
this condition exists only because of three.js types + strict mode
|
||||
*/
|
||||
if (typeof json !== 'string')
|
||||
throw new Error('Invalid metadata string');
|
||||
// TODO: implement check on JSON file and remove this eslint disable
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
metadata = JSON.parse(json);
|
||||
await loadCheck();
|
||||
}, (e) => {
|
||||
metadataLengthComputable = e.lengthComputable;
|
||||
metadataLoaded = e.loaded;
|
||||
metadataTotal = e.total;
|
||||
progressHandler();
|
||||
}, (error) => {
|
||||
this.manager.itemError(metadataUrl);
|
||||
if (typeof onError === 'function')
|
||||
onError(error);
|
||||
});
|
||||
return quadRenderer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Three.js Loader for a JPEG with embedded gainmap metadata (WebGPU version).
|
||||
*
|
||||
* @category Loaders
|
||||
* @group Loaders
|
||||
*
|
||||
* @example
|
||||
* import { HDRJPGLoader } from '@monogrid/gainmap-js/webgpu'
|
||||
* import {
|
||||
* EquirectangularReflectionMapping,
|
||||
* Mesh,
|
||||
* MeshBasicMaterial,
|
||||
* PerspectiveCamera,
|
||||
* PlaneGeometry,
|
||||
* Scene,
|
||||
* WebGPURenderer
|
||||
* } from 'three/webgpu'
|
||||
*
|
||||
* const renderer = new WebGPURenderer()
|
||||
* await renderer.init()
|
||||
*
|
||||
* const loader = new HDRJPGLoader(renderer)
|
||||
* .setRenderTargetOptions({ mapping: EquirectangularReflectionMapping })
|
||||
*
|
||||
* const result = await loader.loadAsync('gainmap.jpeg')
|
||||
* // `result` can be used to populate a Texture
|
||||
*
|
||||
* const scene = new Scene()
|
||||
* const mesh = new Mesh(
|
||||
* new PlaneGeometry(),
|
||||
* new MeshBasicMaterial({ map: result.renderTarget.texture })
|
||||
* )
|
||||
* scene.add(mesh)
|
||||
* renderer.render(scene, new PerspectiveCamera())
|
||||
*
|
||||
* // Starting from three.js r159
|
||||
* // `result.renderTarget.texture` can
|
||||
* // also be used as Equirectangular scene background
|
||||
* //
|
||||
* // it was previously needed to convert it
|
||||
* // to a DataTexture with `result.toDataTexture()`
|
||||
* scene.background = result.renderTarget.texture
|
||||
*
|
||||
* // result must be manually disposed
|
||||
* // when you are done using it
|
||||
* result.dispose()
|
||||
*
|
||||
*/
|
||||
class HDRJPGLoader extends LoaderBaseWebGPU {
|
||||
/**
|
||||
* Loads a JPEG containing gain map metadata
|
||||
* Renders a normal SDR image if gainmap data is not found
|
||||
*
|
||||
* @param url Path to a JPEG file containing embedded gain map metadata
|
||||
* @param onLoad Load complete callback, will receive the result
|
||||
* @param onProgress Progress callback, will receive a `ProgressEvent`
|
||||
* @param onError Error callback
|
||||
* @returns
|
||||
*/
|
||||
load(url, onLoad, onProgress, onError) {
|
||||
const quadRenderer = this.prepareQuadRenderer();
|
||||
const loader = new FileLoader(this._internalLoadingManager);
|
||||
loader.setResponseType('arraybuffer');
|
||||
loader.setRequestHeader(this.requestHeader);
|
||||
loader.setPath(this.path);
|
||||
loader.setWithCredentials(this.withCredentials);
|
||||
this.manager.itemStart(url);
|
||||
loader.load(url, async (jpeg) => {
|
||||
/* istanbul ignore if
|
||||
this condition exists only because of three.js types + strict mode
|
||||
*/
|
||||
if (typeof jpeg === 'string')
|
||||
throw new Error('Invalid buffer, received [string], was expecting [ArrayBuffer]');
|
||||
const jpegBuffer = new Uint8Array(jpeg);
|
||||
let sdrJPEG;
|
||||
let gainMapJPEG;
|
||||
let metadata;
|
||||
try {
|
||||
const extractionResult = await extractGainmapFromJPEG(jpegBuffer);
|
||||
// gain map is successfully reconstructed
|
||||
sdrJPEG = extractionResult.sdr;
|
||||
gainMapJPEG = extractionResult.gainMap;
|
||||
metadata = extractionResult.metadata;
|
||||
}
|
||||
catch (e) {
|
||||
// render the SDR version if this is not a gainmap
|
||||
if (e instanceof XMPMetadataNotFoundError || e instanceof GainMapNotFoundError) {
|
||||
console.warn(`Failure to reconstruct an HDR image from ${url}: Gain map metadata not found in the file, HDRJPGLoader will render the SDR jpeg`);
|
||||
metadata = {
|
||||
gainMapMin: [0, 0, 0],
|
||||
gainMapMax: [1, 1, 1],
|
||||
gamma: [1, 1, 1],
|
||||
hdrCapacityMin: 0,
|
||||
hdrCapacityMax: 1,
|
||||
offsetHdr: [0, 0, 0],
|
||||
offsetSdr: [0, 0, 0]
|
||||
};
|
||||
sdrJPEG = jpegBuffer;
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
// solves #16
|
||||
try {
|
||||
await this.render(quadRenderer, metadata, sdrJPEG.buffer, gainMapJPEG?.buffer);
|
||||
}
|
||||
catch (error) {
|
||||
this.manager.itemError(url);
|
||||
if (typeof onError === 'function')
|
||||
onError(error);
|
||||
quadRenderer.disposeOnDemandRenderer();
|
||||
return;
|
||||
}
|
||||
if (typeof onLoad === 'function')
|
||||
onLoad(quadRenderer);
|
||||
this.manager.itemEnd(url);
|
||||
quadRenderer.disposeOnDemandRenderer();
|
||||
}, onProgress, (error) => {
|
||||
this.manager.itemError(url);
|
||||
if (typeof onError === 'function')
|
||||
onError(error);
|
||||
});
|
||||
return quadRenderer;
|
||||
}
|
||||
}
|
||||
|
||||
export { GainMapDecoderMaterial, GainMapLoader, GainMapNotFoundError, HDRJPGLoader, HDRJPGLoader as JPEGRLoader, LoaderBaseShared, QuadRenderer, XMPMetadataNotFoundError, createDecodeFunction, decode, extractGainmapFromJPEG };
|
||||
5
node_modules/@monogrid/gainmap-js/dist/decode.webgpu.min.js
generated
vendored
Normal file
5
node_modules/@monogrid/gainmap-js/dist/decode.webgpu.min.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1244
node_modules/@monogrid/gainmap-js/dist/decode.webgpu.umd.cjs
generated
vendored
Normal file
1244
node_modules/@monogrid/gainmap-js/dist/decode.webgpu.umd.cjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5
node_modules/@monogrid/gainmap-js/dist/decode.webgpu.umd.min.cjs
generated
vendored
Normal file
5
node_modules/@monogrid/gainmap-js/dist/decode.webgpu.umd.min.cjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/@monogrid/gainmap-js/dist/decode/index.d.ts
generated
vendored
Normal file
1
node_modules/@monogrid/gainmap-js/dist/decode/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './webgl/index';
|
||||
59
node_modules/@monogrid/gainmap-js/dist/decode/shared/Loader.d.ts
generated
vendored
Normal file
59
node_modules/@monogrid/gainmap-js/dist/decode/shared/Loader.d.ts
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
import { HalfFloatType, LinearSRGBColorSpace, Loader, LoadingManager, Texture } from 'three';
|
||||
import { type GainMapMetadata, QuadRendererTextureOptions } from '../../core/types';
|
||||
import { DecodeParameters } from './types';
|
||||
/**
|
||||
* Configuration for the loader base class
|
||||
*/
|
||||
export interface LoaderBaseConfig<TRenderer, TQuadRenderer, TMaterial> {
|
||||
renderer?: TRenderer;
|
||||
renderTargetOptions?: QuadRendererTextureOptions;
|
||||
createMaterial: (params: DecodeParameters) => TMaterial;
|
||||
createQuadRenderer: (params: {
|
||||
width: number;
|
||||
height: number;
|
||||
type: typeof HalfFloatType;
|
||||
colorSpace: typeof LinearSRGBColorSpace;
|
||||
material: TMaterial;
|
||||
renderer?: TRenderer;
|
||||
renderTargetOptions?: QuadRendererTextureOptions;
|
||||
}) => TQuadRenderer;
|
||||
}
|
||||
/**
|
||||
* Shared base class for loaders that extracts common logic
|
||||
*/
|
||||
export declare abstract class LoaderBaseShared<TRenderer, TQuadRenderer, TMaterial, TUrl = string> extends Loader<TQuadRenderer, TUrl> {
|
||||
private _renderer?;
|
||||
private _renderTargetOptions?;
|
||||
protected _internalLoadingManager: LoadingManager;
|
||||
protected _config: LoaderBaseConfig<TRenderer, TQuadRenderer, TMaterial>;
|
||||
constructor(config: LoaderBaseConfig<TRenderer, TQuadRenderer, TMaterial>, manager?: LoadingManager);
|
||||
setRenderer(renderer: TRenderer): this;
|
||||
setRenderTargetOptions(options: QuadRendererTextureOptions): this;
|
||||
protected prepareQuadRenderer(): TQuadRenderer;
|
||||
protected processImages(sdrBuffer: ArrayBuffer, gainMapBuffer?: ArrayBuffer, imageOrientation?: 'flipY' | 'from-image'): Promise<{
|
||||
sdrImage: ImageBitmap | HTMLImageElement;
|
||||
gainMapImage: ImageBitmap | HTMLImageElement | undefined;
|
||||
needsFlip: boolean;
|
||||
}>;
|
||||
protected createTextures(sdrImage: ImageBitmap | HTMLImageElement, gainMapImage: ImageBitmap | HTMLImageElement | undefined, needsFlip: boolean): {
|
||||
gainMap: Texture;
|
||||
sdr: Texture;
|
||||
};
|
||||
protected updateQuadRenderer(quadRenderer: TQuadRenderer & {
|
||||
width: number;
|
||||
height: number;
|
||||
material: TMaterial & {
|
||||
gainMap: Texture;
|
||||
sdr: Texture;
|
||||
gainMapMin: [number, number, number];
|
||||
gainMapMax: [number, number, number];
|
||||
offsetHdr: [number, number, number];
|
||||
offsetSdr: [number, number, number];
|
||||
gamma: [number, number, number];
|
||||
hdrCapacityMin: number;
|
||||
hdrCapacityMax: number;
|
||||
maxDisplayBoost: number;
|
||||
needsUpdate: boolean;
|
||||
};
|
||||
}, sdrImage: ImageBitmap | HTMLImageElement, gainMap: Texture, sdr: Texture, metadata: GainMapMetadata): void;
|
||||
}
|
||||
24
node_modules/@monogrid/gainmap-js/dist/decode/shared/decode.d.ts
generated
vendored
Normal file
24
node_modules/@monogrid/gainmap-js/dist/decode/shared/decode.d.ts
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
import { HalfFloatType, LinearSRGBColorSpace } from 'three';
|
||||
import { Constructor, QuadRendererTextureOptions } from '../../core';
|
||||
import { DecodeParametersWithRenderer } from './types';
|
||||
/**
|
||||
* Configuration for decode function
|
||||
*/
|
||||
export interface DecodeConfig<TRenderer extends Constructor, TQuadRenderer, TMaterial> {
|
||||
renderer: TRenderer;
|
||||
createMaterial: (params: DecodeParametersWithRenderer<InstanceType<TRenderer>>) => TMaterial;
|
||||
createQuadRenderer: (params: {
|
||||
width: number;
|
||||
height: number;
|
||||
type: typeof HalfFloatType;
|
||||
colorSpace: typeof LinearSRGBColorSpace;
|
||||
material: TMaterial;
|
||||
renderer: InstanceType<TRenderer>;
|
||||
renderTargetOptions?: QuadRendererTextureOptions;
|
||||
}) => TQuadRenderer;
|
||||
}
|
||||
/**
|
||||
* Shared decode implementation factory
|
||||
* Creates a decode function that prepares a QuadRenderer with the given parameters
|
||||
*/
|
||||
export declare function createDecodeFunction<TRenderer extends Constructor, TQuadRenderer, TMaterial>(config: DecodeConfig<TRenderer, TQuadRenderer, TMaterial>): (params: DecodeParametersWithRenderer<InstanceType<TRenderer>>) => TQuadRenderer;
|
||||
2
node_modules/@monogrid/gainmap-js/dist/decode/shared/errors/GainMapNotFoundError.d.ts
generated
vendored
Normal file
2
node_modules/@monogrid/gainmap-js/dist/decode/shared/errors/GainMapNotFoundError.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare class GainMapNotFoundError extends Error {
|
||||
}
|
||||
2
node_modules/@monogrid/gainmap-js/dist/decode/shared/errors/XMPMetadataNotFoundError.d.ts
generated
vendored
Normal file
2
node_modules/@monogrid/gainmap-js/dist/decode/shared/errors/XMPMetadataNotFoundError.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare class XMPMetadataNotFoundError extends Error {
|
||||
}
|
||||
25
node_modules/@monogrid/gainmap-js/dist/decode/shared/extract.d.ts
generated
vendored
Normal file
25
node_modules/@monogrid/gainmap-js/dist/decode/shared/extract.d.ts
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Extracts XMP Metadata and the gain map recovery image
|
||||
* from a single JPEG file.
|
||||
*
|
||||
* @category Decoding Functions
|
||||
* @group Decoding Functions
|
||||
* @param jpegFile an `Uint8Array` containing and encoded JPEG file
|
||||
* @returns an sdr `Uint8Array` compressed in JPEG, a gainMap `Uint8Array` compressed in JPEG and the XMP parsed XMP metadata
|
||||
* @throws Error if XMP Metadata is not found
|
||||
* @throws Error if Gain map image is not found
|
||||
* @example
|
||||
* import { FileLoader } from 'three'
|
||||
* import { extractGainmapFromJPEG } from '@monogrid/gainmap-js'
|
||||
*
|
||||
* const jpegFile = await new FileLoader()
|
||||
* .setResponseType('arraybuffer')
|
||||
* .loadAsync('image.jpg')
|
||||
*
|
||||
* const { sdr, gainMap, metadata } = extractGainmapFromJPEG(jpegFile)
|
||||
*/
|
||||
export declare const extractGainmapFromJPEG: (jpegFile: Uint8Array<ArrayBuffer>) => Promise<{
|
||||
sdr: Uint8Array<ArrayBuffer>;
|
||||
gainMap: Uint8Array<ArrayBuffer>;
|
||||
metadata: import("..").GainMapMetadata;
|
||||
}>;
|
||||
8
node_modules/@monogrid/gainmap-js/dist/decode/shared/index.d.ts
generated
vendored
Normal file
8
node_modules/@monogrid/gainmap-js/dist/decode/shared/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
export * from './decode';
|
||||
export * from './errors/GainMapNotFoundError';
|
||||
export * from './errors/XMPMetadataNotFoundError';
|
||||
export * from './extract';
|
||||
export * from './Loader';
|
||||
export * from './types';
|
||||
export * from './utils/extractXMP';
|
||||
export * from './utils/MPFExtractor';
|
||||
43
node_modules/@monogrid/gainmap-js/dist/decode/shared/types.d.ts
generated
vendored
Normal file
43
node_modules/@monogrid/gainmap-js/dist/decode/shared/types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
import { Texture } from 'three';
|
||||
import { GainMapMetadata, QuadRendererTextureOptions, TextureImageFormat } from '../../core';
|
||||
/**
|
||||
* Parameters related to the display used for decoding
|
||||
*/
|
||||
export type GainmapDecodingParameters = {
|
||||
/**
|
||||
* The maximum available boost supported by a display, at a given point in time.
|
||||
*
|
||||
* @remarks
|
||||
* This value can change over time based on device settings and other factors,
|
||||
* such as ambient light conditions, or how many bright pixels are on the screen.
|
||||
*
|
||||
* Non Logarithmic space
|
||||
*/
|
||||
maxDisplayBoost: number;
|
||||
};
|
||||
/**
|
||||
* Parameters for generic decoding
|
||||
*/
|
||||
export type DecodeParameters = {
|
||||
/**
|
||||
* A Texture containing the SDR Rendition
|
||||
*/
|
||||
sdr: Texture<TextureImageFormat>;
|
||||
/**
|
||||
* A Texture containing the GainMap recovery image
|
||||
*/
|
||||
gainMap: Texture<TextureImageFormat>;
|
||||
} & GainmapDecodingParameters & GainMapMetadata;
|
||||
/**
|
||||
* Parameters for decode function
|
||||
*/
|
||||
export type DecodeParametersWithRenderer<TRenderer> = {
|
||||
/**
|
||||
* The renderer used to decode the GainMap
|
||||
*/
|
||||
renderer: TRenderer;
|
||||
/**
|
||||
* Options to use when creating the output renderTarget
|
||||
*/
|
||||
renderTargetOptions?: QuadRendererTextureOptions;
|
||||
} & DecodeParameters & GainmapDecodingParameters & GainMapMetadata;
|
||||
21
node_modules/@monogrid/gainmap-js/dist/decode/shared/utils/MPFExtractor.d.ts
generated
vendored
Normal file
21
node_modules/@monogrid/gainmap-js/dist/decode/shared/utils/MPFExtractor.d.ts
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
export type MPFExtractorOptions = {
|
||||
debug: boolean;
|
||||
extractFII: boolean;
|
||||
extractNonFII: boolean;
|
||||
};
|
||||
/**
|
||||
* MPF Extractor (Multi Picture Format Extractor)
|
||||
* By Henrik S Nilsson 2019
|
||||
*
|
||||
* Extracts images stored in images based on the MPF format (found here: https://www.cipa.jp/e/std/std-sec.html
|
||||
* under "CIPA DC-007-Translation-2021 Multi-Picture Format"
|
||||
*
|
||||
* Overly commented, and without intention of being complete or production ready.
|
||||
* Created to extract depth maps from iPhone images, and to learn about image metadata.
|
||||
* Kudos to: Phil Harvey (exiftool), Jaume Sanchez (android-lens-blur-depth-extractor)
|
||||
*/
|
||||
export declare class MPFExtractor {
|
||||
options: MPFExtractorOptions;
|
||||
constructor(options?: Partial<MPFExtractorOptions>);
|
||||
extract(imageArrayBuffer: Uint8Array<ArrayBuffer>): Promise<Blob[]>;
|
||||
}
|
||||
2
node_modules/@monogrid/gainmap-js/dist/decode/shared/utils/extractXMP.d.ts
generated
vendored
Normal file
2
node_modules/@monogrid/gainmap-js/dist/decode/shared/utils/extractXMP.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import { GainMapMetadata } from '../../../core/types';
|
||||
export declare const extractXMP: (input: Uint8Array) => GainMapMetadata | undefined;
|
||||
7
node_modules/@monogrid/gainmap-js/dist/decode/shared/utils/get-html-image-from-blob.d.ts
generated
vendored
Normal file
7
node_modules/@monogrid/gainmap-js/dist/decode/shared/utils/get-html-image-from-blob.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* private function, async get image from blob
|
||||
*
|
||||
* @param blob
|
||||
* @returns
|
||||
*/
|
||||
export declare const getHTMLImageFromBlob: (blob: Blob) => Promise<HTMLImageElement>;
|
||||
60
node_modules/@monogrid/gainmap-js/dist/decode/webgl/decode.d.ts
generated
vendored
Normal file
60
node_modules/@monogrid/gainmap-js/dist/decode/webgl/decode.d.ts
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
import { HalfFloatType, WebGLRenderer } from 'three';
|
||||
import { QuadRenderer } from '../../core/QuadRenderer';
|
||||
import { DecodeParametersWithRenderer } from '../shared';
|
||||
import { GainMapDecoderMaterial } from './materials/GainMapDecoderMaterial';
|
||||
/**
|
||||
* Decodes a gain map using a WebGL RenderTarget
|
||||
*
|
||||
* @category Decoding Functions
|
||||
* @group Decoding Functions
|
||||
* @example
|
||||
* import { decode } from '@monogrid/gainmap-js'
|
||||
* import {
|
||||
* Mesh,
|
||||
* MeshBasicMaterial,
|
||||
* PerspectiveCamera,
|
||||
* PlaneGeometry,
|
||||
* Scene,
|
||||
* TextureLoader,
|
||||
* WebGLRenderer
|
||||
* } from 'three'
|
||||
*
|
||||
* const renderer = new WebGLRenderer()
|
||||
*
|
||||
* const textureLoader = new TextureLoader()
|
||||
*
|
||||
* // load SDR Representation
|
||||
* const sdr = await textureLoader.loadAsync('sdr.jpg')
|
||||
* // load Gain map recovery image
|
||||
* const gainMap = await textureLoader.loadAsync('gainmap.jpg')
|
||||
* // load metadata
|
||||
* const metadata = await (await fetch('metadata.json')).json()
|
||||
*
|
||||
* const result = decode({
|
||||
* sdr,
|
||||
* gainMap,
|
||||
* // this allows to use `result.renderTarget.texture` directly
|
||||
* renderer,
|
||||
* // this will restore the full HDR range
|
||||
* maxDisplayBoost: Math.pow(2, metadata.hdrCapacityMax),
|
||||
* ...metadata
|
||||
* })
|
||||
*
|
||||
* const scene = new Scene()
|
||||
* // `result` can be used to populate a Texture
|
||||
* const mesh = new Mesh(
|
||||
* new PlaneGeometry(),
|
||||
* new MeshBasicMaterial({ map: result.renderTarget.texture })
|
||||
* )
|
||||
* scene.add(mesh)
|
||||
* renderer.render(scene, new PerspectiveCamera())
|
||||
*
|
||||
* // result must be manually disposed
|
||||
* // when you are done using it
|
||||
* result.dispose()
|
||||
*
|
||||
* @param params
|
||||
* @returns
|
||||
* @throws {Error} if the WebGLRenderer fails to render the gain map
|
||||
*/
|
||||
export declare const decode: (params: DecodeParametersWithRenderer<WebGLRenderer>) => InstanceType<typeof QuadRenderer<typeof HalfFloatType, InstanceType<typeof GainMapDecoderMaterial>>>;
|
||||
8
node_modules/@monogrid/gainmap-js/dist/decode/webgl/index.d.ts
generated
vendored
Normal file
8
node_modules/@monogrid/gainmap-js/dist/decode/webgl/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
export * from '../../core/QuadRenderer';
|
||||
export * from '../../core/types';
|
||||
export * from '../shared';
|
||||
export * from './decode';
|
||||
export * from './loaders/GainMapLoader';
|
||||
export * from './loaders/HDRJPGLoader';
|
||||
export { HDRJPGLoader as JPEGRLoader } from './loaders/HDRJPGLoader';
|
||||
export * from './materials/GainMapDecoderMaterial';
|
||||
68
node_modules/@monogrid/gainmap-js/dist/decode/webgl/loaders/GainMapLoader.d.ts
generated
vendored
Normal file
68
node_modules/@monogrid/gainmap-js/dist/decode/webgl/loaders/GainMapLoader.d.ts
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
import { HalfFloatType } from 'three';
|
||||
import { QuadRenderer } from '../../../core/QuadRenderer';
|
||||
import { GainMapDecoderMaterial } from '../materials/GainMapDecoderMaterial';
|
||||
import { LoaderBaseWebGL } from './LoaderBaseWebGL';
|
||||
/**
|
||||
* A Three.js Loader for the gain map format.
|
||||
*
|
||||
* @category Loaders
|
||||
* @group Loaders
|
||||
*
|
||||
* @example
|
||||
* import { GainMapLoader } from '@monogrid/gainmap-js'
|
||||
* import {
|
||||
* EquirectangularReflectionMapping,
|
||||
* Mesh,
|
||||
* MeshBasicMaterial,
|
||||
* PerspectiveCamera,
|
||||
* PlaneGeometry,
|
||||
* Scene,
|
||||
* WebGLRenderer
|
||||
* } from 'three'
|
||||
*
|
||||
* const renderer = new WebGLRenderer()
|
||||
*
|
||||
* const loader = new GainMapLoader(renderer)
|
||||
* .setRenderTargetOptions({ mapping: EquirectangularReflectionMapping })
|
||||
*
|
||||
* const result = await loader.loadAsync(['sdr.jpeg', 'gainmap.jpeg', 'metadata.json'])
|
||||
* // `result` can be used to populate a Texture
|
||||
*
|
||||
* const scene = new Scene()
|
||||
* const mesh = new Mesh(
|
||||
* new PlaneGeometry(),
|
||||
* new MeshBasicMaterial({ map: result.renderTarget.texture })
|
||||
* )
|
||||
* scene.add(mesh)
|
||||
* renderer.render(scene, new PerspectiveCamera())
|
||||
*
|
||||
* // Starting from three.js r159
|
||||
* // `result.renderTarget.texture` can
|
||||
* // also be used as Equirectangular scene background
|
||||
* //
|
||||
* // it was previously needed to convert it
|
||||
* // to a DataTexture with `result.toDataTexture()`
|
||||
* scene.background = result.renderTarget.texture
|
||||
*
|
||||
* // result must be manually disposed
|
||||
* // when you are done using it
|
||||
* result.dispose()
|
||||
*
|
||||
*/
|
||||
export declare class GainMapLoader extends LoaderBaseWebGL<[string, string, string]> {
|
||||
/**
|
||||
* Loads a gainmap using separate data
|
||||
* * sdr image
|
||||
* * gain map image
|
||||
* * metadata json
|
||||
*
|
||||
* useful for webp gain maps
|
||||
*
|
||||
* @param urls An array in the form of [sdr.jpg, gainmap.jpg, metadata.json]
|
||||
* @param onLoad Load complete callback, will receive the result
|
||||
* @param onProgress Progress callback, will receive a `ProgressEvent`
|
||||
* @param onError Error callback
|
||||
* @returns
|
||||
*/
|
||||
load([sdrUrl, gainMapUrl, metadataUrl]: [string, string, string], onLoad?: (data: QuadRenderer<typeof HalfFloatType, GainMapDecoderMaterial>) => void, onProgress?: (event: ProgressEvent) => void, onError?: (err: unknown) => void): QuadRenderer<typeof HalfFloatType, GainMapDecoderMaterial>;
|
||||
}
|
||||
64
node_modules/@monogrid/gainmap-js/dist/decode/webgl/loaders/HDRJPGLoader.d.ts
generated
vendored
Normal file
64
node_modules/@monogrid/gainmap-js/dist/decode/webgl/loaders/HDRJPGLoader.d.ts
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
import { HalfFloatType } from 'three';
|
||||
import { QuadRenderer } from '../../../core/QuadRenderer';
|
||||
import { GainMapDecoderMaterial } from '../materials/GainMapDecoderMaterial';
|
||||
import { LoaderBaseWebGL } from './LoaderBaseWebGL';
|
||||
/**
|
||||
* A Three.js Loader for a JPEG with embedded gainmap metadata.
|
||||
*
|
||||
* @category Loaders
|
||||
* @group Loaders
|
||||
*
|
||||
* @example
|
||||
* import { HDRJPGLoader } from '@monogrid/gainmap-js'
|
||||
* import {
|
||||
* EquirectangularReflectionMapping,
|
||||
* Mesh,
|
||||
* MeshBasicMaterial,
|
||||
* PerspectiveCamera,
|
||||
* PlaneGeometry,
|
||||
* Scene,
|
||||
* WebGLRenderer
|
||||
* } from 'three'
|
||||
*
|
||||
* const renderer = new WebGLRenderer()
|
||||
*
|
||||
* const loader = new HDRJPGLoader(renderer)
|
||||
* .setRenderTargetOptions({ mapping: EquirectangularReflectionMapping })
|
||||
*
|
||||
* const result = await loader.loadAsync('gainmap.jpeg')
|
||||
* // `result` can be used to populate a Texture
|
||||
*
|
||||
* const scene = new Scene()
|
||||
* const mesh = new Mesh(
|
||||
* new PlaneGeometry(),
|
||||
* new MeshBasicMaterial({ map: result.renderTarget.texture })
|
||||
* )
|
||||
* scene.add(mesh)
|
||||
* renderer.render(scene, new PerspectiveCamera())
|
||||
*
|
||||
* // Starting from three.js r159
|
||||
* // `result.renderTarget.texture` can
|
||||
* // also be used as Equirectangular scene background
|
||||
* //
|
||||
* // it was previously needed to convert it
|
||||
* // to a DataTexture with `result.toDataTexture()`
|
||||
* scene.background = result.renderTarget.texture
|
||||
*
|
||||
* // result must be manually disposed
|
||||
* // when you are done using it
|
||||
* result.dispose()
|
||||
*
|
||||
*/
|
||||
export declare class HDRJPGLoader extends LoaderBaseWebGL<string> {
|
||||
/**
|
||||
* Loads a JPEG containing gain map metadata
|
||||
* Renders a normal SDR image if gainmap data is not found
|
||||
*
|
||||
* @param url Path to a JPEG file containing embedded gain map metadata
|
||||
* @param onLoad Load complete callback, will receive the result
|
||||
* @param onProgress Progress callback, will receive a `ProgressEvent`
|
||||
* @param onError Error callback
|
||||
* @returns
|
||||
*/
|
||||
load(url: string, onLoad?: (data: QuadRenderer<typeof HalfFloatType, GainMapDecoderMaterial>) => void, onProgress?: (event: ProgressEvent) => void, onError?: (err: unknown) => void): QuadRenderer<typeof HalfFloatType, GainMapDecoderMaterial>;
|
||||
}
|
||||
20
node_modules/@monogrid/gainmap-js/dist/decode/webgl/loaders/LoaderBaseWebGL.d.ts
generated
vendored
Normal file
20
node_modules/@monogrid/gainmap-js/dist/decode/webgl/loaders/LoaderBaseWebGL.d.ts
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import { HalfFloatType, LoadingManager, type WebGLRenderer } from 'three';
|
||||
import { QuadRenderer } from '../../../core/QuadRenderer';
|
||||
import { type GainMapMetadata } from '../../../core/types';
|
||||
import { LoaderBaseShared } from '../../shared';
|
||||
import { GainMapDecoderMaterial } from '../materials/GainMapDecoderMaterial';
|
||||
/**
|
||||
* Base class for WebGL loaders
|
||||
* @template TUrl - The type of URL used to load resources
|
||||
*/
|
||||
export declare abstract class LoaderBaseWebGL<TUrl = string> extends LoaderBaseShared<WebGLRenderer, QuadRenderer<typeof HalfFloatType, GainMapDecoderMaterial>, GainMapDecoderMaterial, TUrl> {
|
||||
constructor(renderer?: WebGLRenderer, manager?: LoadingManager);
|
||||
/**
|
||||
* @private
|
||||
* @param quadRenderer
|
||||
* @param metadata
|
||||
* @param sdrBuffer
|
||||
* @param gainMapBuffer
|
||||
*/
|
||||
protected render(quadRenderer: QuadRenderer<typeof HalfFloatType, GainMapDecoderMaterial>, metadata: GainMapMetadata, sdrBuffer: ArrayBuffer, gainMapBuffer?: ArrayBuffer): Promise<void>;
|
||||
}
|
||||
70
node_modules/@monogrid/gainmap-js/dist/decode/webgl/materials/GainMapDecoderMaterial.d.ts
generated
vendored
Normal file
70
node_modules/@monogrid/gainmap-js/dist/decode/webgl/materials/GainMapDecoderMaterial.d.ts
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
import { ShaderMaterial, Texture } from 'three';
|
||||
import { GainMapMetadata } from '../../../core/types';
|
||||
import { type GainmapDecodingParameters } from '../../shared';
|
||||
/**
|
||||
* A Material which is able to decode the Gainmap into a full HDR Representation
|
||||
*
|
||||
* @category Materials
|
||||
* @group Materials
|
||||
*/
|
||||
export declare class GainMapDecoderMaterial extends ShaderMaterial {
|
||||
private _maxDisplayBoost;
|
||||
private _hdrCapacityMin;
|
||||
private _hdrCapacityMax;
|
||||
/**
|
||||
*
|
||||
* @param params
|
||||
*/
|
||||
constructor({ gamma, offsetHdr, offsetSdr, gainMapMin, gainMapMax, maxDisplayBoost, hdrCapacityMin, hdrCapacityMax, sdr, gainMap }: GainMapMetadata & GainmapDecodingParameters & {
|
||||
sdr: Texture;
|
||||
gainMap: Texture;
|
||||
});
|
||||
get sdr(): Texture;
|
||||
set sdr(value: Texture);
|
||||
get gainMap(): Texture;
|
||||
set gainMap(value: Texture);
|
||||
/**
|
||||
* @see {@link GainMapMetadata.offsetHdr}
|
||||
*/
|
||||
get offsetHdr(): [number, number, number];
|
||||
set offsetHdr(value: [number, number, number]);
|
||||
/**
|
||||
* @see {@link GainMapMetadata.offsetSdr}
|
||||
*/
|
||||
get offsetSdr(): [number, number, number];
|
||||
set offsetSdr(value: [number, number, number]);
|
||||
/**
|
||||
* @see {@link GainMapMetadata.gainMapMin}
|
||||
*/
|
||||
get gainMapMin(): [number, number, number];
|
||||
set gainMapMin(value: [number, number, number]);
|
||||
/**
|
||||
* @see {@link GainMapMetadata.gainMapMax}
|
||||
*/
|
||||
get gainMapMax(): [number, number, number];
|
||||
set gainMapMax(value: [number, number, number]);
|
||||
/**
|
||||
* @see {@link GainMapMetadata.gamma}
|
||||
*/
|
||||
get gamma(): [number, number, number];
|
||||
set gamma(value: [number, number, number]);
|
||||
/**
|
||||
* @see {@link GainMapMetadata.hdrCapacityMin}
|
||||
* @remarks Logarithmic space
|
||||
*/
|
||||
get hdrCapacityMin(): number;
|
||||
set hdrCapacityMin(value: number);
|
||||
/**
|
||||
* @see {@link GainMapMetadata.hdrCapacityMin}
|
||||
* @remarks Logarithmic space
|
||||
*/
|
||||
get hdrCapacityMax(): number;
|
||||
set hdrCapacityMax(value: number);
|
||||
/**
|
||||
* @see {@link GainmapDecodingParameters.maxDisplayBoost}
|
||||
* @remarks Non Logarithmic space
|
||||
*/
|
||||
get maxDisplayBoost(): number;
|
||||
set maxDisplayBoost(value: number);
|
||||
private calculateWeight;
|
||||
}
|
||||
153
node_modules/@monogrid/gainmap-js/dist/decode/webgpu/core/QuadRenderer.d.ts
generated
vendored
Normal file
153
node_modules/@monogrid/gainmap-js/dist/decode/webgpu/core/QuadRenderer.d.ts
generated
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
import { ByteType, ColorSpace, DataTexture, FloatType, HalfFloatType, IntType, Material, RenderTarget, ShortType, TextureDataType, UnsignedByteType, UnsignedInt248Type, UnsignedInt5999Type, UnsignedInt101111Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, WebGPURenderer } from 'three/webgpu';
|
||||
import { QuadRendererTextureOptions } from '../../../core/types';
|
||||
/**
|
||||
* Utility Type that translates `three` texture types to their TypedArray counterparts.
|
||||
*
|
||||
* @category Utility
|
||||
* @group Utility
|
||||
*/
|
||||
export type TextureDataTypeToBufferType<TType extends TextureDataType> = TType extends typeof UnsignedByteType ? Uint8ClampedArray<ArrayBuffer> : TType extends typeof ByteType ? Int8Array<ArrayBuffer> : TType extends typeof ShortType ? Int16Array<ArrayBuffer> : TType extends typeof UnsignedShortType ? Uint16Array<ArrayBuffer> : TType extends typeof IntType ? Int32Array<ArrayBuffer> : TType extends typeof UnsignedIntType ? Uint32Array<ArrayBuffer> : TType extends typeof FloatType ? Float32Array<ArrayBuffer> : TType extends typeof HalfFloatType ? Uint16Array<ArrayBuffer> : TType extends typeof UnsignedShort4444Type ? Uint16Array<ArrayBuffer> : TType extends typeof UnsignedShort5551Type ? Uint16Array<ArrayBuffer> : TType extends typeof UnsignedInt248Type ? Uint32Array<ArrayBuffer> : TType extends typeof UnsignedInt5999Type ? Uint32Array<ArrayBuffer> : TType extends typeof UnsignedInt101111Type ? Uint32Array<ArrayBuffer> : never;
|
||||
export type QuadRendererOptions<TType extends TextureDataType, TMaterial extends Material> = {
|
||||
/**
|
||||
* Width of the render target
|
||||
*/
|
||||
width: number;
|
||||
/**
|
||||
* height of the renderTarget
|
||||
*/
|
||||
height: number;
|
||||
/**
|
||||
* TextureDataType of the renderTarget
|
||||
*/
|
||||
type: TType;
|
||||
/**
|
||||
* ColorSpace of the renderTarget
|
||||
*/
|
||||
colorSpace: ColorSpace;
|
||||
/**
|
||||
* material to use for rendering
|
||||
*/
|
||||
material: TMaterial;
|
||||
/**
|
||||
* Renderer instance to use
|
||||
*/
|
||||
renderer?: WebGPURenderer;
|
||||
/**
|
||||
* Additional renderTarget options
|
||||
*/
|
||||
renderTargetOptions?: QuadRendererTextureOptions;
|
||||
};
|
||||
/**
|
||||
* Utility class used for rendering a texture with a material (WebGPU version)
|
||||
*
|
||||
* @category Core
|
||||
* @group Core
|
||||
*/
|
||||
export declare class QuadRenderer<TType extends TextureDataType, TMaterial extends Material> {
|
||||
private _renderer;
|
||||
private _rendererIsDisposable;
|
||||
private _material;
|
||||
private _scene;
|
||||
private _camera;
|
||||
private _quad;
|
||||
private _renderTarget;
|
||||
private _width;
|
||||
private _height;
|
||||
private _type;
|
||||
private _colorSpace;
|
||||
private _supportsReadPixels;
|
||||
/**
|
||||
* Constructs a new QuadRenderer
|
||||
*
|
||||
* @param options Parameters for this QuadRenderer
|
||||
*/
|
||||
constructor(options: QuadRendererOptions<TType, TMaterial>);
|
||||
/**
|
||||
* Instantiates a temporary renderer
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
static instantiateRenderer(): WebGPURenderer;
|
||||
/**
|
||||
* Renders the input texture using the specified material
|
||||
*/
|
||||
render: () => Promise<void>;
|
||||
/**
|
||||
* Obtains a Buffer containing the rendered texture.
|
||||
*
|
||||
* @throws Error if the browser cannot read pixels from this RenderTarget type.
|
||||
* @returns a TypedArray containing RGBA values from this renderer
|
||||
*/
|
||||
toArray(): Promise<TextureDataTypeToBufferType<TType>>;
|
||||
/**
|
||||
* Performs a readPixel operation in the renderTarget
|
||||
* and returns a DataTexture containing the read data
|
||||
*
|
||||
* @param options options
|
||||
* @returns
|
||||
*/
|
||||
toDataTexture(options?: QuadRendererTextureOptions): Promise<DataTexture>;
|
||||
/**
|
||||
* If using a disposable renderer, it will dispose it.
|
||||
*/
|
||||
disposeOnDemandRenderer(): void;
|
||||
/**
|
||||
* Will dispose of **all** assets used by this renderer.
|
||||
*
|
||||
*
|
||||
* @param disposeRenderTarget will dispose of the renderTarget which will not be usable later
|
||||
* set this to true if you passed the `renderTarget.texture` to a `PMREMGenerator`
|
||||
* or are otherwise done with it.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* const loader = new HDRJPGLoader(renderer)
|
||||
* const result = await loader.loadAsync('gainmap.jpeg')
|
||||
* const mesh = new Mesh(geometry, new MeshBasicMaterial({ map: result.renderTarget.texture }) )
|
||||
* // DO NOT dispose the renderTarget here,
|
||||
* // it is used directly in the material
|
||||
* result.dispose()
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* const loader = new HDRJPGLoader(renderer)
|
||||
* const pmremGenerator = new PMREMGenerator( renderer );
|
||||
* const result = await loader.loadAsync('gainmap.jpeg')
|
||||
* const envMap = pmremGenerator.fromEquirectangular(result.renderTarget.texture)
|
||||
* const mesh = new Mesh(geometry, new MeshStandardMaterial({ envMap }) )
|
||||
* // renderTarget can be disposed here
|
||||
* // because it was used to generate a PMREM texture
|
||||
* result.dispose(true)
|
||||
* ```
|
||||
*/
|
||||
dispose(disposeRenderTarget?: boolean): void;
|
||||
/**
|
||||
* Width of the texture
|
||||
*/
|
||||
get width(): number;
|
||||
set width(value: number);
|
||||
/**
|
||||
* Height of the texture
|
||||
*/
|
||||
get height(): number;
|
||||
set height(value: number);
|
||||
/**
|
||||
* The renderer used
|
||||
*/
|
||||
get renderer(): WebGPURenderer;
|
||||
/**
|
||||
* The `RenderTarget` used.
|
||||
*/
|
||||
get renderTarget(): RenderTarget;
|
||||
set renderTarget(value: RenderTarget);
|
||||
/**
|
||||
* The `Material` used.
|
||||
*/
|
||||
get material(): TMaterial;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
get type(): TType;
|
||||
get colorSpace(): ColorSpace;
|
||||
}
|
||||
60
node_modules/@monogrid/gainmap-js/dist/decode/webgpu/decode.d.ts
generated
vendored
Normal file
60
node_modules/@monogrid/gainmap-js/dist/decode/webgpu/decode.d.ts
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
import { HalfFloatType, WebGPURenderer } from 'three/webgpu';
|
||||
import { DecodeParametersWithRenderer } from '../shared';
|
||||
import { QuadRenderer } from './core/QuadRenderer';
|
||||
import { GainMapDecoderMaterial } from './materials/GainMapDecoderMaterial';
|
||||
/**
|
||||
* Decodes a gain map using WebGPU RenderTarget
|
||||
*
|
||||
* @category Decoding Functions
|
||||
* @group Decoding Functions
|
||||
* @example
|
||||
* import { decode } from '@monogrid/gainmap-js/webgpu'
|
||||
* import {
|
||||
* Mesh,
|
||||
* MeshBasicMaterial,
|
||||
* PerspectiveCamera,
|
||||
* PlaneGeometry,
|
||||
* Scene,
|
||||
* TextureLoader,
|
||||
* WebGPURenderer
|
||||
* } from 'three/webgpu'
|
||||
*
|
||||
* const renderer = new WebGPURenderer()
|
||||
*
|
||||
* const textureLoader = new TextureLoader()
|
||||
*
|
||||
* // load SDR Representation
|
||||
* const sdr = await textureLoader.loadAsync('sdr.jpg')
|
||||
* // load Gain map recovery image
|
||||
* const gainMap = await textureLoader.loadAsync('gainmap.jpg')
|
||||
* // load metadata
|
||||
* const metadata = await (await fetch('metadata.json')).json()
|
||||
*
|
||||
* const result = await decode({
|
||||
* sdr,
|
||||
* gainMap,
|
||||
* // this allows to use `result.renderTarget.texture` directly
|
||||
* renderer,
|
||||
* // this will restore the full HDR range
|
||||
* maxDisplayBoost: Math.pow(2, metadata.hdrCapacityMax),
|
||||
* ...metadata
|
||||
* })
|
||||
*
|
||||
* const scene = new Scene()
|
||||
* // `result` can be used to populate a Texture
|
||||
* const mesh = new Mesh(
|
||||
* new PlaneGeometry(),
|
||||
* new MeshBasicMaterial({ map: result.renderTarget.texture })
|
||||
* )
|
||||
* scene.add(mesh)
|
||||
* renderer.render(scene, new PerspectiveCamera())
|
||||
*
|
||||
* // result must be manually disposed
|
||||
* // when you are done using it
|
||||
* result.dispose()
|
||||
*
|
||||
* @param params
|
||||
* @returns
|
||||
* @throws {Error} if the WebGPURenderer fails to render the gain map
|
||||
*/
|
||||
export declare const decode: (params: DecodeParametersWithRenderer<WebGPURenderer>) => Promise<InstanceType<typeof QuadRenderer<typeof HalfFloatType, InstanceType<typeof GainMapDecoderMaterial>>>>;
|
||||
8
node_modules/@monogrid/gainmap-js/dist/decode/webgpu/index.d.ts
generated
vendored
Normal file
8
node_modules/@monogrid/gainmap-js/dist/decode/webgpu/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
export * from '../../core/types';
|
||||
export * from '../shared';
|
||||
export * from './core/QuadRenderer';
|
||||
export * from './decode';
|
||||
export * from './loaders/GainMapLoader';
|
||||
export * from './loaders/HDRJPGLoader';
|
||||
export { HDRJPGLoader as JPEGRLoader } from './loaders/HDRJPGLoader';
|
||||
export * from './materials/GainMapDecoderMaterial';
|
||||
69
node_modules/@monogrid/gainmap-js/dist/decode/webgpu/loaders/GainMapLoader.d.ts
generated
vendored
Normal file
69
node_modules/@monogrid/gainmap-js/dist/decode/webgpu/loaders/GainMapLoader.d.ts
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
import { HalfFloatType } from 'three/webgpu';
|
||||
import { QuadRenderer } from '../core/QuadRenderer';
|
||||
import { GainMapDecoderMaterial } from '../materials/GainMapDecoderMaterial';
|
||||
import { LoaderBaseWebGPU } from './LoaderBaseWebGPU';
|
||||
/**
|
||||
* A Three.js Loader for the gain map format (WebGPU version).
|
||||
*
|
||||
* @category Loaders
|
||||
* @group Loaders
|
||||
*
|
||||
* @example
|
||||
* import { GainMapLoader } from '@monogrid/gainmap-js/webgpu'
|
||||
* import {
|
||||
* EquirectangularReflectionMapping,
|
||||
* Mesh,
|
||||
* MeshBasicMaterial,
|
||||
* PerspectiveCamera,
|
||||
* PlaneGeometry,
|
||||
* Scene,
|
||||
* WebGPURenderer
|
||||
* } from 'three/webgpu'
|
||||
*
|
||||
* const renderer = new WebGPURenderer()
|
||||
* await renderer.init()
|
||||
*
|
||||
* const loader = new GainMapLoader(renderer)
|
||||
* .setRenderTargetOptions({ mapping: EquirectangularReflectionMapping })
|
||||
*
|
||||
* const result = await loader.loadAsync(['sdr.jpeg', 'gainmap.jpeg', 'metadata.json'])
|
||||
* // `result` can be used to populate a Texture
|
||||
*
|
||||
* const scene = new Scene()
|
||||
* const mesh = new Mesh(
|
||||
* new PlaneGeometry(),
|
||||
* new MeshBasicMaterial({ map: result.renderTarget.texture })
|
||||
* )
|
||||
* scene.add(mesh)
|
||||
* renderer.render(scene, new PerspectiveCamera())
|
||||
*
|
||||
* // Starting from three.js r159
|
||||
* // `result.renderTarget.texture` can
|
||||
* // also be used as Equirectangular scene background
|
||||
* //
|
||||
* // it was previously needed to convert it
|
||||
* // to a DataTexture with `result.toDataTexture()`
|
||||
* scene.background = result.renderTarget.texture
|
||||
*
|
||||
* // result must be manually disposed
|
||||
* // when you are done using it
|
||||
* result.dispose()
|
||||
*
|
||||
*/
|
||||
export declare class GainMapLoader extends LoaderBaseWebGPU<[string, string, string]> {
|
||||
/**
|
||||
* Loads a gainmap using separate data
|
||||
* * sdr image
|
||||
* * gain map image
|
||||
* * metadata json
|
||||
*
|
||||
* useful for webp gain maps
|
||||
*
|
||||
* @param urls An array in the form of [sdr.jpg, gainmap.jpg, metadata.json]
|
||||
* @param onLoad Load complete callback, will receive the result
|
||||
* @param onProgress Progress callback, will receive a `ProgressEvent`
|
||||
* @param onError Error callback
|
||||
* @returns
|
||||
*/
|
||||
load([sdrUrl, gainMapUrl, metadataUrl]: [string, string, string], onLoad?: (data: QuadRenderer<typeof HalfFloatType, GainMapDecoderMaterial>) => void, onProgress?: (event: ProgressEvent) => void, onError?: (err: unknown) => void): QuadRenderer<typeof HalfFloatType, GainMapDecoderMaterial>;
|
||||
}
|
||||
65
node_modules/@monogrid/gainmap-js/dist/decode/webgpu/loaders/HDRJPGLoader.d.ts
generated
vendored
Normal file
65
node_modules/@monogrid/gainmap-js/dist/decode/webgpu/loaders/HDRJPGLoader.d.ts
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
import { HalfFloatType } from 'three/webgpu';
|
||||
import { QuadRenderer } from '../core/QuadRenderer';
|
||||
import { GainMapDecoderMaterial } from '../materials/GainMapDecoderMaterial';
|
||||
import { LoaderBaseWebGPU } from './LoaderBaseWebGPU';
|
||||
/**
|
||||
* A Three.js Loader for a JPEG with embedded gainmap metadata (WebGPU version).
|
||||
*
|
||||
* @category Loaders
|
||||
* @group Loaders
|
||||
*
|
||||
* @example
|
||||
* import { HDRJPGLoader } from '@monogrid/gainmap-js/webgpu'
|
||||
* import {
|
||||
* EquirectangularReflectionMapping,
|
||||
* Mesh,
|
||||
* MeshBasicMaterial,
|
||||
* PerspectiveCamera,
|
||||
* PlaneGeometry,
|
||||
* Scene,
|
||||
* WebGPURenderer
|
||||
* } from 'three/webgpu'
|
||||
*
|
||||
* const renderer = new WebGPURenderer()
|
||||
* await renderer.init()
|
||||
*
|
||||
* const loader = new HDRJPGLoader(renderer)
|
||||
* .setRenderTargetOptions({ mapping: EquirectangularReflectionMapping })
|
||||
*
|
||||
* const result = await loader.loadAsync('gainmap.jpeg')
|
||||
* // `result` can be used to populate a Texture
|
||||
*
|
||||
* const scene = new Scene()
|
||||
* const mesh = new Mesh(
|
||||
* new PlaneGeometry(),
|
||||
* new MeshBasicMaterial({ map: result.renderTarget.texture })
|
||||
* )
|
||||
* scene.add(mesh)
|
||||
* renderer.render(scene, new PerspectiveCamera())
|
||||
*
|
||||
* // Starting from three.js r159
|
||||
* // `result.renderTarget.texture` can
|
||||
* // also be used as Equirectangular scene background
|
||||
* //
|
||||
* // it was previously needed to convert it
|
||||
* // to a DataTexture with `result.toDataTexture()`
|
||||
* scene.background = result.renderTarget.texture
|
||||
*
|
||||
* // result must be manually disposed
|
||||
* // when you are done using it
|
||||
* result.dispose()
|
||||
*
|
||||
*/
|
||||
export declare class HDRJPGLoader extends LoaderBaseWebGPU<string> {
|
||||
/**
|
||||
* Loads a JPEG containing gain map metadata
|
||||
* Renders a normal SDR image if gainmap data is not found
|
||||
*
|
||||
* @param url Path to a JPEG file containing embedded gain map metadata
|
||||
* @param onLoad Load complete callback, will receive the result
|
||||
* @param onProgress Progress callback, will receive a `ProgressEvent`
|
||||
* @param onError Error callback
|
||||
* @returns
|
||||
*/
|
||||
load(url: string, onLoad?: (data: QuadRenderer<typeof HalfFloatType, GainMapDecoderMaterial>) => void, onProgress?: (event: ProgressEvent) => void, onError?: (err: unknown) => void): QuadRenderer<typeof HalfFloatType, GainMapDecoderMaterial>;
|
||||
}
|
||||
20
node_modules/@monogrid/gainmap-js/dist/decode/webgpu/loaders/LoaderBaseWebGPU.d.ts
generated
vendored
Normal file
20
node_modules/@monogrid/gainmap-js/dist/decode/webgpu/loaders/LoaderBaseWebGPU.d.ts
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import { HalfFloatType, LoadingManager, WebGPURenderer } from 'three/webgpu';
|
||||
import { type GainMapMetadata } from '../../../core/types';
|
||||
import { LoaderBaseShared } from '../../shared';
|
||||
import { QuadRenderer } from '../core/QuadRenderer';
|
||||
import { GainMapDecoderMaterial } from '../materials/GainMapDecoderMaterial';
|
||||
/**
|
||||
* Base class for WebGPU loaders
|
||||
* @template TUrl - The type of URL used to load resources
|
||||
*/
|
||||
export declare abstract class LoaderBaseWebGPU<TUrl = string> extends LoaderBaseShared<WebGPURenderer, QuadRenderer<typeof HalfFloatType, GainMapDecoderMaterial>, GainMapDecoderMaterial, TUrl> {
|
||||
constructor(renderer?: WebGPURenderer, manager?: LoadingManager);
|
||||
/**
|
||||
* @private
|
||||
* @param quadRenderer
|
||||
* @param metadata
|
||||
* @param sdrBuffer
|
||||
* @param gainMapBuffer
|
||||
*/
|
||||
protected render(quadRenderer: QuadRenderer<typeof HalfFloatType, GainMapDecoderMaterial>, metadata: GainMapMetadata, sdrBuffer: ArrayBuffer, gainMapBuffer?: ArrayBuffer): Promise<void>;
|
||||
}
|
||||
78
node_modules/@monogrid/gainmap-js/dist/decode/webgpu/materials/GainMapDecoderMaterial.d.ts
generated
vendored
Normal file
78
node_modules/@monogrid/gainmap-js/dist/decode/webgpu/materials/GainMapDecoderMaterial.d.ts
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
import { MeshBasicNodeMaterial, Texture } from 'three/webgpu';
|
||||
import { GainMapMetadata } from '../../../core/types';
|
||||
import { type GainmapDecodingParameters } from '../../shared';
|
||||
/**
|
||||
* A Material which is able to decode the Gainmap into a full HDR Representation using TSL (Three.js Shading Language)
|
||||
*
|
||||
* @category Materials
|
||||
* @group Materials
|
||||
*/
|
||||
export declare class GainMapDecoderMaterial extends MeshBasicNodeMaterial {
|
||||
private _maxDisplayBoost;
|
||||
private _hdrCapacityMin;
|
||||
private _hdrCapacityMax;
|
||||
private _gammaUniform;
|
||||
private _offsetHdrUniform;
|
||||
private _offsetSdrUniform;
|
||||
private _gainMapMinUniform;
|
||||
private _gainMapMaxUniform;
|
||||
private _weightFactorUniform;
|
||||
private _sdrTexture;
|
||||
private _gainMapTexture;
|
||||
/**
|
||||
*
|
||||
* @param params
|
||||
*/
|
||||
constructor({ gamma, offsetHdr, offsetSdr, gainMapMin, gainMapMax, maxDisplayBoost, hdrCapacityMin, hdrCapacityMax, sdr, gainMap }: GainMapMetadata & GainmapDecodingParameters & {
|
||||
sdr: Texture;
|
||||
gainMap: Texture;
|
||||
});
|
||||
get sdr(): Texture;
|
||||
set sdr(value: Texture);
|
||||
get gainMap(): Texture;
|
||||
set gainMap(value: Texture);
|
||||
/**
|
||||
* @see {@link GainMapMetadata.offsetHdr}
|
||||
*/
|
||||
get offsetHdr(): [number, number, number];
|
||||
set offsetHdr(value: [number, number, number]);
|
||||
/**
|
||||
* @see {@link GainMapMetadata.offsetSdr}
|
||||
*/
|
||||
get offsetSdr(): [number, number, number];
|
||||
set offsetSdr(value: [number, number, number]);
|
||||
/**
|
||||
* @see {@link GainMapMetadata.gainMapMin}
|
||||
*/
|
||||
get gainMapMin(): [number, number, number];
|
||||
set gainMapMin(value: [number, number, number]);
|
||||
/**
|
||||
* @see {@link GainMapMetadata.gainMapMax}
|
||||
*/
|
||||
get gainMapMax(): [number, number, number];
|
||||
set gainMapMax(value: [number, number, number]);
|
||||
/**
|
||||
* @see {@link GainMapMetadata.gamma}
|
||||
*/
|
||||
get gamma(): [number, number, number];
|
||||
set gamma(value: [number, number, number]);
|
||||
/**
|
||||
* @see {@link GainMapMetadata.hdrCapacityMin}
|
||||
* @remarks Logarithmic space
|
||||
*/
|
||||
get hdrCapacityMin(): number;
|
||||
set hdrCapacityMin(value: number);
|
||||
/**
|
||||
* @see {@link GainMapMetadata.hdrCapacityMax}
|
||||
* @remarks Logarithmic space
|
||||
*/
|
||||
get hdrCapacityMax(): number;
|
||||
set hdrCapacityMax(value: number);
|
||||
/**
|
||||
* @see {@link GainmapDecodingParameters.maxDisplayBoost}
|
||||
* @remarks Non Logarithmic space
|
||||
*/
|
||||
get maxDisplayBoost(): number;
|
||||
set maxDisplayBoost(value: number);
|
||||
private calculateWeight;
|
||||
}
|
||||
1
node_modules/@monogrid/gainmap-js/dist/encode.d.ts
generated
vendored
Normal file
1
node_modules/@monogrid/gainmap-js/dist/encode.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './encode/index';
|
||||
917
node_modules/@monogrid/gainmap-js/dist/encode.js
generated
vendored
Normal file
917
node_modules/@monogrid/gainmap-js/dist/encode.js
generated
vendored
Normal file
@@ -0,0 +1,917 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
|
||||
import { c as compress } from './compress-C-X439Jm.js';
|
||||
import { DataTexture, RGBAFormat, UVMapping, RepeatWrapping, LinearFilter, LinearSRGBColorSpace, ShaderMaterial, NoBlending, Vector3, UnsignedByteType, ACESFilmicToneMapping, LinearToneMapping, NeutralToneMapping, AgXToneMapping, CineonToneMapping, ReinhardToneMapping, SRGBColorSpace, AlphaFormat, RGBFormat, DepthFormat, DepthStencilFormat, RedFormat, RedIntegerFormat, RGFormat, RGIntegerFormat, RGBIntegerFormat, RGBAIntegerFormat, Vector2, WebGLRenderTarget, ClampToEdgeWrapping, NearestFilter, DataUtils, FloatType } from 'three';
|
||||
import { Q as QuadRenderer } from './QuadRenderer-Bj1xl_EK.js';
|
||||
|
||||
/**
|
||||
* Utility function to obtain a `DataTexture` from various input formats
|
||||
*
|
||||
* @category Utility
|
||||
* @group Utility
|
||||
*
|
||||
* @param image
|
||||
* @returns
|
||||
*/
|
||||
const getDataTexture = (image) => {
|
||||
let dataTexture;
|
||||
if (image instanceof DataTexture) {
|
||||
if (!(image.image.data instanceof Uint16Array) && !(image.image.data instanceof Float32Array)) {
|
||||
throw new Error('Provided image is not HDR');
|
||||
}
|
||||
dataTexture = image;
|
||||
}
|
||||
else {
|
||||
dataTexture = new DataTexture(image.data, image.width, image.height, 'format' in image ? image.format : RGBAFormat, image.type, UVMapping, RepeatWrapping, RepeatWrapping, LinearFilter, LinearFilter, 1, 'colorSpace' in image && image.colorSpace === 'srgb' ? image.colorSpace : LinearSRGBColorSpace);
|
||||
// TODO: This tries to detect a raw RGBE and applies flipY
|
||||
// see if there's a better way to detect it?
|
||||
if ('header' in image && 'gamma' in image) {
|
||||
dataTexture.flipY = true;
|
||||
}
|
||||
dataTexture.needsUpdate = true;
|
||||
}
|
||||
return dataTexture;
|
||||
};
|
||||
|
||||
const vertexShader$2 = /* glsl */ `
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`;
|
||||
const fragmentShader$2 = /* glsl */ `
|
||||
#ifndef saturate
|
||||
#define saturate( a ) clamp( a, 0.0, 1.0 )
|
||||
#endif
|
||||
uniform sampler2D sdr;
|
||||
uniform sampler2D hdr;
|
||||
uniform vec3 gamma;
|
||||
uniform vec3 offsetSdr;
|
||||
uniform vec3 offsetHdr;
|
||||
uniform float minLog2;
|
||||
uniform float maxLog2;
|
||||
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vec3 sdrColor = texture2D(sdr, vUv).rgb;
|
||||
vec3 hdrColor = texture2D(hdr, vUv).rgb;
|
||||
|
||||
vec3 pixelGain = (hdrColor + offsetHdr) / (sdrColor + offsetSdr);
|
||||
vec3 logRecovery = (log2(pixelGain) - minLog2) / (maxLog2 - minLog2);
|
||||
vec3 clampedRecovery = saturate(logRecovery);
|
||||
gl_FragColor = vec4(pow(clampedRecovery, gamma), 1.0);
|
||||
}
|
||||
`;
|
||||
/**
|
||||
* A Material which is able to encode a gainmap
|
||||
*
|
||||
* @category Materials
|
||||
* @group Materials
|
||||
*/
|
||||
class GainMapEncoderMaterial extends ShaderMaterial {
|
||||
_minContentBoost;
|
||||
_maxContentBoost;
|
||||
_offsetSdr;
|
||||
_offsetHdr;
|
||||
_gamma;
|
||||
/**
|
||||
*
|
||||
* @param params
|
||||
*/
|
||||
constructor({ sdr, hdr, offsetSdr, offsetHdr, maxContentBoost, minContentBoost, gamma }) {
|
||||
if (!maxContentBoost)
|
||||
throw new Error('maxContentBoost is required');
|
||||
if (!sdr)
|
||||
throw new Error('sdr is required');
|
||||
if (!hdr)
|
||||
throw new Error('hdr is required');
|
||||
const _gamma = gamma || [1, 1, 1];
|
||||
const _offsetSdr = offsetSdr || [1 / 64, 1 / 64, 1 / 64];
|
||||
const _offsetHdr = offsetHdr || [1 / 64, 1 / 64, 1 / 64];
|
||||
const _minContentBoost = minContentBoost || 1;
|
||||
const _maxContentBoost = Math.max(maxContentBoost, 1.0001);
|
||||
super({
|
||||
name: 'GainMapEncoderMaterial',
|
||||
vertexShader: vertexShader$2,
|
||||
fragmentShader: fragmentShader$2,
|
||||
uniforms: {
|
||||
sdr: { value: sdr },
|
||||
hdr: { value: hdr },
|
||||
gamma: { value: new Vector3().fromArray(_gamma) },
|
||||
offsetSdr: { value: new Vector3().fromArray(_offsetSdr) },
|
||||
offsetHdr: { value: new Vector3().fromArray(_offsetHdr) },
|
||||
minLog2: { value: Math.log2(_minContentBoost) },
|
||||
maxLog2: { value: Math.log2(_maxContentBoost) }
|
||||
},
|
||||
blending: NoBlending,
|
||||
depthTest: false,
|
||||
depthWrite: false
|
||||
});
|
||||
this._minContentBoost = _minContentBoost;
|
||||
this._maxContentBoost = _maxContentBoost;
|
||||
this._offsetSdr = _offsetSdr;
|
||||
this._offsetHdr = _offsetHdr;
|
||||
this._gamma = _gamma;
|
||||
this.needsUpdate = true;
|
||||
this.uniformsNeedUpdate = true;
|
||||
}
|
||||
/**
|
||||
* @see {@link GainmapEncodingParameters.gamma}
|
||||
*/
|
||||
get gamma() { return this._gamma; }
|
||||
set gamma(value) {
|
||||
this._gamma = value;
|
||||
this.uniforms.gamma.value = new Vector3().fromArray(value);
|
||||
}
|
||||
/**
|
||||
* @see {@link GainmapEncodingParameters.offsetHdr}
|
||||
*/
|
||||
get offsetHdr() { return this._offsetHdr; }
|
||||
set offsetHdr(value) {
|
||||
this._offsetHdr = value;
|
||||
this.uniforms.offsetHdr.value = new Vector3().fromArray(value);
|
||||
}
|
||||
/**
|
||||
* @see {@link GainmapEncodingParameters.offsetSdr}
|
||||
*/
|
||||
get offsetSdr() { return this._offsetSdr; }
|
||||
set offsetSdr(value) {
|
||||
this._offsetSdr = value;
|
||||
this.uniforms.offsetSdr.value = new Vector3().fromArray(value);
|
||||
}
|
||||
/**
|
||||
* @see {@link GainmapEncodingParameters.minContentBoost}
|
||||
* @remarks Non logarithmic space
|
||||
*/
|
||||
get minContentBoost() { return this._minContentBoost; }
|
||||
set minContentBoost(value) {
|
||||
this._minContentBoost = value;
|
||||
this.uniforms.minLog2.value = Math.log2(value);
|
||||
}
|
||||
/**
|
||||
* @see {@link GainmapEncodingParameters.maxContentBoost}
|
||||
* @remarks Non logarithmic space
|
||||
*/
|
||||
get maxContentBoost() { return this._maxContentBoost; }
|
||||
set maxContentBoost(value) {
|
||||
this._maxContentBoost = value;
|
||||
this.uniforms.maxLog2.value = Math.log2(value);
|
||||
}
|
||||
/**
|
||||
* @see {@link GainMapMetadata.gainMapMin}
|
||||
* @remarks Logarithmic space
|
||||
*/
|
||||
get gainMapMin() { return [Math.log2(this._minContentBoost), Math.log2(this._minContentBoost), Math.log2(this._minContentBoost)]; }
|
||||
/**
|
||||
* @see {@link GainMapMetadata.gainMapMax}
|
||||
* @remarks Logarithmic space
|
||||
*/
|
||||
get gainMapMax() { return [Math.log2(this._maxContentBoost), Math.log2(this._maxContentBoost), Math.log2(this._maxContentBoost)]; }
|
||||
/**
|
||||
* @see {@link GainMapMetadata.hdrCapacityMin}
|
||||
* @remarks Logarithmic space
|
||||
*/
|
||||
get hdrCapacityMin() { return Math.min(Math.max(0, this.gainMapMin[0]), Math.max(0, this.gainMapMin[1]), Math.max(0, this.gainMapMin[2])); }
|
||||
/**
|
||||
* @see {@link GainMapMetadata.hdrCapacityMax}
|
||||
* @remarks Logarithmic space
|
||||
*/
|
||||
get hdrCapacityMax() { return Math.max(Math.max(0, this.gainMapMax[0]), Math.max(0, this.gainMapMax[1]), Math.max(0, this.gainMapMax[2])); }
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param params
|
||||
* @returns
|
||||
* @category Encoding Functions
|
||||
* @group Encoding Functions
|
||||
*/
|
||||
const getGainMap = (params) => {
|
||||
const { image, sdr, renderer } = params;
|
||||
const dataTexture = getDataTexture(image);
|
||||
const material = new GainMapEncoderMaterial({
|
||||
...params,
|
||||
sdr: sdr.renderTarget.texture,
|
||||
hdr: dataTexture
|
||||
});
|
||||
const quadRenderer = new QuadRenderer({
|
||||
width: dataTexture.image.width,
|
||||
height: dataTexture.image.height,
|
||||
type: UnsignedByteType,
|
||||
colorSpace: LinearSRGBColorSpace,
|
||||
material,
|
||||
renderer,
|
||||
renderTargetOptions: params.renderTargetOptions
|
||||
});
|
||||
try {
|
||||
quadRenderer.render();
|
||||
}
|
||||
catch (e) {
|
||||
quadRenderer.disposeOnDemandRenderer();
|
||||
throw e;
|
||||
}
|
||||
return quadRenderer;
|
||||
};
|
||||
|
||||
const vertexShader$1 = /* glsl */ `
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`;
|
||||
const fragmentShader$1 = /* glsl */ `
|
||||
#ifndef saturate
|
||||
#define saturate( a ) clamp( a, 0.0, 1.0 )
|
||||
#endif
|
||||
|
||||
uniform sampler2D map;
|
||||
uniform float brightness;
|
||||
uniform float contrast;
|
||||
uniform float saturation;
|
||||
uniform float exposure;
|
||||
|
||||
varying vec2 vUv;
|
||||
|
||||
mat4 brightnessMatrix( float brightness ) {
|
||||
return mat4(
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
brightness, brightness, brightness, 1
|
||||
);
|
||||
}
|
||||
|
||||
mat4 contrastMatrix( float contrast ) {
|
||||
float t = ( 1.0 - contrast ) / 2.0;
|
||||
return mat4(
|
||||
contrast, 0, 0, 0,
|
||||
0, contrast, 0, 0,
|
||||
0, 0, contrast, 0,
|
||||
t, t, t, 1
|
||||
);
|
||||
}
|
||||
|
||||
mat4 saturationMatrix( float saturation ) {
|
||||
vec3 luminance = vec3( 0.3086, 0.6094, 0.0820 );
|
||||
float oneMinusSat = 1.0 - saturation;
|
||||
vec3 red = vec3( luminance.x * oneMinusSat );
|
||||
red+= vec3( saturation, 0, 0 );
|
||||
vec3 green = vec3( luminance.y * oneMinusSat );
|
||||
green += vec3( 0, saturation, 0 );
|
||||
vec3 blue = vec3( luminance.z * oneMinusSat );
|
||||
blue += vec3( 0, 0, saturation );
|
||||
return mat4(
|
||||
red, 0,
|
||||
green, 0,
|
||||
blue, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
|
||||
vec3 RRTAndODTFit( vec3 v ) {
|
||||
vec3 a = v * ( v + 0.0245786 ) - 0.000090537;
|
||||
vec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;
|
||||
return a / b;
|
||||
}
|
||||
|
||||
vec3 ACESFilmicToneMapping( vec3 color ) {
|
||||
// sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT
|
||||
const mat3 ACESInputMat = mat3(
|
||||
vec3( 0.59719, 0.07600, 0.02840 ), // transposed from source
|
||||
vec3( 0.35458, 0.90834, 0.13383 ),
|
||||
vec3( 0.04823, 0.01566, 0.83777 )
|
||||
);
|
||||
// ODT_SAT => XYZ => D60_2_D65 => sRGB
|
||||
const mat3 ACESOutputMat = mat3(
|
||||
vec3( 1.60475, -0.10208, -0.00327 ), // transposed from source
|
||||
vec3( -0.53108, 1.10813, -0.07276 ),
|
||||
vec3( -0.07367, -0.00605, 1.07602 )
|
||||
);
|
||||
color = ACESInputMat * color;
|
||||
// Apply RRT and ODT
|
||||
color = RRTAndODTFit( color );
|
||||
color = ACESOutputMat * color;
|
||||
// Clamp to [0, 1]
|
||||
return saturate( color );
|
||||
}
|
||||
|
||||
// source: https://www.cs.utah.edu/docs/techreports/2002/pdf/UUCS-02-001.pdf
|
||||
vec3 ReinhardToneMapping( vec3 color ) {
|
||||
return saturate( color / ( vec3( 1.0 ) + color ) );
|
||||
}
|
||||
|
||||
// source: http://filmicworlds.com/blog/filmic-tonemapping-operators/
|
||||
vec3 CineonToneMapping( vec3 color ) {
|
||||
// optimized filmic operator by Jim Hejl and Richard Burgess-Dawson
|
||||
color = max( vec3( 0.0 ), color - 0.004 );
|
||||
return pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );
|
||||
}
|
||||
|
||||
// nothing
|
||||
vec3 LinearToneMapping ( vec3 color ) {
|
||||
return color;
|
||||
}
|
||||
|
||||
// Matrices for rec 2020 <> rec 709 color space conversion
|
||||
// matrix provided in row-major order so it has been transposed
|
||||
// https://www.itu.int/pub/R-REP-BT.2407-2017
|
||||
const mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3(
|
||||
vec3( 1.6605, - 0.1246, - 0.0182 ),
|
||||
vec3( - 0.5876, 1.1329, - 0.1006 ),
|
||||
vec3( - 0.0728, - 0.0083, 1.1187 )
|
||||
);
|
||||
|
||||
const mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3(
|
||||
vec3( 0.6274, 0.0691, 0.0164 ),
|
||||
vec3( 0.3293, 0.9195, 0.0880 ),
|
||||
vec3( 0.0433, 0.0113, 0.8956 )
|
||||
);
|
||||
|
||||
// https://iolite-engine.com/blog_posts/minimal_agx_implementation
|
||||
// Mean error^2: 3.6705141e-06
|
||||
vec3 agxDefaultContrastApprox( vec3 x ) {
|
||||
vec3 x2 = x * x;
|
||||
vec3 x4 = x2 * x2;
|
||||
return + 15.5 * x4 * x2
|
||||
- 40.14 * x4 * x
|
||||
+ 31.96 * x4
|
||||
- 6.868 * x2 * x
|
||||
+ 0.4298 * x2
|
||||
+ 0.1191 * x
|
||||
- 0.00232;
|
||||
}
|
||||
|
||||
// AgX Tone Mapping implementation based on Filament, which in turn is based
|
||||
// on Blender's implementation using rec 2020 primaries
|
||||
// https://github.com/google/filament/pull/7236
|
||||
// Inputs and outputs are encoded as Linear-sRGB.
|
||||
|
||||
vec3 AgXToneMapping( vec3 color ) {
|
||||
|
||||
// AgX constants
|
||||
const mat3 AgXInsetMatrix = mat3(
|
||||
vec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ),
|
||||
vec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ),
|
||||
vec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 )
|
||||
);
|
||||
|
||||
// explicit AgXOutsetMatrix generated from Filaments AgXOutsetMatrixInv
|
||||
const mat3 AgXOutsetMatrix = mat3(
|
||||
vec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ),
|
||||
vec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ),
|
||||
vec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 )
|
||||
);
|
||||
|
||||
// LOG2_MIN = -10.0
|
||||
// LOG2_MAX = +6.5
|
||||
// MIDDLE_GRAY = 0.18
|
||||
const float AgxMinEv = - 12.47393; // log2( pow( 2, LOG2_MIN ) * MIDDLE_GRAY )
|
||||
const float AgxMaxEv = 4.026069; // log2( pow( 2, LOG2_MAX ) * MIDDLE_GRAY )
|
||||
|
||||
color = LINEAR_SRGB_TO_LINEAR_REC2020 * color;
|
||||
|
||||
color = AgXInsetMatrix * color;
|
||||
|
||||
// Log2 encoding
|
||||
color = max( color, 1e-10 ); // avoid 0 or negative numbers for log2
|
||||
color = log2( color );
|
||||
color = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv );
|
||||
|
||||
color = clamp( color, 0.0, 1.0 );
|
||||
|
||||
// Apply sigmoid
|
||||
color = agxDefaultContrastApprox( color );
|
||||
|
||||
// Apply AgX look
|
||||
// v = agxLook(v, look);
|
||||
|
||||
color = AgXOutsetMatrix * color;
|
||||
|
||||
// Linearize
|
||||
color = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) );
|
||||
|
||||
color = LINEAR_REC2020_TO_LINEAR_SRGB * color;
|
||||
|
||||
// Gamut mapping. Simple clamp for now.
|
||||
color = clamp( color, 0.0, 1.0 );
|
||||
|
||||
return color;
|
||||
|
||||
}
|
||||
|
||||
// https://modelviewer.dev/examples/tone-mapping
|
||||
|
||||
vec3 NeutralToneMapping( vec3 color ) {
|
||||
|
||||
const float StartCompression = 0.8 - 0.04;
|
||||
const float Desaturation = 0.15;
|
||||
|
||||
float x = min( color.r, min( color.g, color.b ) );
|
||||
|
||||
float offset = x < 0.08 ? x - 6.25 * x * x : 0.04;
|
||||
|
||||
color -= offset;
|
||||
|
||||
float peak = max( color.r, max( color.g, color.b ) );
|
||||
|
||||
if ( peak < StartCompression ) return color;
|
||||
|
||||
float d = 1. - StartCompression;
|
||||
|
||||
float newPeak = 1. - d * d / ( peak + d - StartCompression );
|
||||
|
||||
color *= newPeak / peak;
|
||||
|
||||
float g = 1. - 1. / ( Desaturation * ( peak - newPeak ) + 1. );
|
||||
|
||||
return mix( color, vec3( newPeak ), g );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void main() {
|
||||
vec4 color = texture2D(map, vUv);
|
||||
|
||||
vec4 exposed = vec4(exposure * color.rgb, color.a);
|
||||
|
||||
vec4 tonemapped = vec4(TONEMAPPING_FUNCTION(exposed.rgb), color.a);
|
||||
|
||||
vec4 adjusted =
|
||||
brightnessMatrix( brightness ) *
|
||||
contrastMatrix( contrast ) *
|
||||
saturationMatrix( saturation ) *
|
||||
tonemapped;
|
||||
|
||||
gl_FragColor = adjusted;
|
||||
}
|
||||
`;
|
||||
/**
|
||||
* A Material used to adjust the SDR representation of an HDR image
|
||||
*
|
||||
* @category Materials
|
||||
* @group Materials
|
||||
*/
|
||||
class SDRMaterial extends ShaderMaterial {
|
||||
_brightness = 0;
|
||||
_contrast = 1;
|
||||
_saturation = 1;
|
||||
_exposure = 1;
|
||||
_toneMapping;
|
||||
_map;
|
||||
/**
|
||||
*
|
||||
* @param params
|
||||
*/
|
||||
constructor({ map, toneMapping }) {
|
||||
super({
|
||||
name: 'SDRMaterial',
|
||||
vertexShader: vertexShader$1,
|
||||
fragmentShader: fragmentShader$1,
|
||||
uniforms: {
|
||||
map: { value: map },
|
||||
brightness: { value: 0 },
|
||||
contrast: { value: 1 },
|
||||
saturation: { value: 1 },
|
||||
exposure: { value: 1 }
|
||||
},
|
||||
blending: NoBlending,
|
||||
depthTest: false,
|
||||
depthWrite: false
|
||||
});
|
||||
this._map = map;
|
||||
this.toneMapping = this._toneMapping = toneMapping || ACESFilmicToneMapping;
|
||||
this.needsUpdate = true;
|
||||
this.uniformsNeedUpdate = true;
|
||||
}
|
||||
get toneMapping() { return this._toneMapping; }
|
||||
set toneMapping(value) {
|
||||
let valid = false;
|
||||
switch (value) {
|
||||
case ACESFilmicToneMapping:
|
||||
this.defines.TONEMAPPING_FUNCTION = 'ACESFilmicToneMapping';
|
||||
valid = true;
|
||||
break;
|
||||
case ReinhardToneMapping:
|
||||
this.defines.TONEMAPPING_FUNCTION = 'ReinhardToneMapping';
|
||||
valid = true;
|
||||
break;
|
||||
case CineonToneMapping:
|
||||
this.defines.TONEMAPPING_FUNCTION = 'CineonToneMapping';
|
||||
valid = true;
|
||||
break;
|
||||
case LinearToneMapping:
|
||||
this.defines.TONEMAPPING_FUNCTION = 'LinearToneMapping';
|
||||
valid = true;
|
||||
break;
|
||||
case AgXToneMapping:
|
||||
this.defines.TONEMAPPING_FUNCTION = 'AgXToneMapping';
|
||||
valid = true;
|
||||
break;
|
||||
case NeutralToneMapping:
|
||||
this.defines.TONEMAPPING_FUNCTION = 'NeutralToneMapping';
|
||||
valid = true;
|
||||
break;
|
||||
default:
|
||||
console.error(`Unsupported toneMapping: ${value}. Using LinearToneMapping.`);
|
||||
this.defines.TONEMAPPING_FUNCTION = 'LinearToneMapping';
|
||||
this._toneMapping = LinearToneMapping;
|
||||
}
|
||||
if (valid) {
|
||||
this._toneMapping = value;
|
||||
}
|
||||
this.needsUpdate = true;
|
||||
}
|
||||
get brightness() { return this._brightness; }
|
||||
set brightness(value) {
|
||||
this._brightness = value;
|
||||
this.uniforms.brightness.value = value;
|
||||
}
|
||||
get contrast() { return this._contrast; }
|
||||
set contrast(value) {
|
||||
this._contrast = value;
|
||||
this.uniforms.contrast.value = value;
|
||||
}
|
||||
get saturation() { return this._saturation; }
|
||||
set saturation(value) {
|
||||
this._saturation = value;
|
||||
this.uniforms.saturation.value = value;
|
||||
}
|
||||
get exposure() { return this._exposure; }
|
||||
set exposure(value) {
|
||||
this._exposure = value;
|
||||
this.uniforms.exposure.value = value;
|
||||
}
|
||||
get map() { return this._map; }
|
||||
set map(value) {
|
||||
this._map = value;
|
||||
this.uniforms.map.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an SDR Representation of an HDR Image
|
||||
*
|
||||
* @category Encoding Functions
|
||||
* @group Encoding Functions
|
||||
*
|
||||
* @param hdrTexture The HDR image to be rendered
|
||||
* @param renderer (optional) WebGLRenderer to use during the rendering, a disposable renderer will be create and destroyed if this is not provided.
|
||||
* @param toneMapping (optional) Tone mapping to be applied to the SDR Rendition
|
||||
* @param renderTargetOptions (optional) Options to use when creating the output renderTarget
|
||||
* @throws {Error} if the WebGLRenderer fails to render the SDR image
|
||||
*/
|
||||
const getSDRRendition = (hdrTexture, renderer, toneMapping, renderTargetOptions) => {
|
||||
hdrTexture.needsUpdate = true;
|
||||
const quadRenderer = new QuadRenderer({
|
||||
width: hdrTexture.image.width,
|
||||
height: hdrTexture.image.height,
|
||||
type: UnsignedByteType,
|
||||
colorSpace: SRGBColorSpace,
|
||||
material: new SDRMaterial({ map: hdrTexture, toneMapping }),
|
||||
renderer,
|
||||
renderTargetOptions
|
||||
});
|
||||
try {
|
||||
quadRenderer.render();
|
||||
}
|
||||
catch (e) {
|
||||
quadRenderer.disposeOnDemandRenderer();
|
||||
throw e;
|
||||
}
|
||||
return quadRenderer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encodes a Gainmap starting from an HDR file.
|
||||
*
|
||||
* @remarks
|
||||
* if you do not pass a `renderer` parameter
|
||||
* you must manually dispose the result
|
||||
* ```js
|
||||
* const encodingResult = await encode({ ... })
|
||||
* // do something with the buffers
|
||||
* const sdr = encodingResult.sdr.getArray()
|
||||
* const gainMap = encodingResult.gainMap.getArray()
|
||||
* // after that
|
||||
* encodingResult.sdr.dispose()
|
||||
* encodingResult.gainMap.dispose()
|
||||
* ```
|
||||
*
|
||||
* @category Encoding Functions
|
||||
* @group Encoding Functions
|
||||
*
|
||||
* @example
|
||||
* import { encode, findTextureMinMax } from '@monogrid/gainmap-js'
|
||||
* import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js'
|
||||
*
|
||||
* // load an HDR file
|
||||
* const loader = new EXRLoader()
|
||||
* const image = await loader.loadAsync('image.exr')
|
||||
*
|
||||
* // find RAW RGB Max value of a texture
|
||||
* const textureMax = findTextureMinMax(image)
|
||||
*
|
||||
* // Encode the gainmap
|
||||
* const encodingResult = encode({
|
||||
* image,
|
||||
* // this will encode the full HDR range
|
||||
* maxContentBoost: Math.max.apply(this, textureMax)
|
||||
* })
|
||||
* // can be re-encoded after changing parameters
|
||||
* encodingResult.sdr.material.exposure = 0.9
|
||||
* encodingResult.sdr.render()
|
||||
* // or
|
||||
* encodingResult.gainMap.material.gamma = [1.1, 1.1, 1.1]
|
||||
* encodingResult.gainMap.render()
|
||||
*
|
||||
* // do something with encodingResult.gainMap.toArray()
|
||||
* // and encodingResult.sdr.toArray()
|
||||
*
|
||||
* // renderers must be manually disposed
|
||||
* encodingResult.sdr.dispose()
|
||||
* encodingResult.gainMap.dispose()
|
||||
*
|
||||
* @param params Encoding Parameters
|
||||
* @returns
|
||||
*/
|
||||
const encode = (params) => {
|
||||
const { image, renderer } = params;
|
||||
const dataTexture = getDataTexture(image);
|
||||
const sdr = getSDRRendition(dataTexture, renderer, params.toneMapping, params.renderTargetOptions);
|
||||
const gainMapRenderer = getGainMap({
|
||||
...params,
|
||||
image: dataTexture,
|
||||
sdr,
|
||||
renderer: sdr.renderer // reuse the same (maybe disposable?) renderer
|
||||
});
|
||||
return {
|
||||
sdr,
|
||||
gainMap: gainMapRenderer,
|
||||
hdr: dataTexture,
|
||||
getMetadata: () => {
|
||||
return {
|
||||
gainMapMax: gainMapRenderer.material.gainMapMax,
|
||||
gainMapMin: gainMapRenderer.material.gainMapMin,
|
||||
gamma: gainMapRenderer.material.gamma,
|
||||
hdrCapacityMax: gainMapRenderer.material.hdrCapacityMax,
|
||||
hdrCapacityMin: gainMapRenderer.material.hdrCapacityMin,
|
||||
offsetHdr: gainMapRenderer.material.offsetHdr,
|
||||
offsetSdr: gainMapRenderer.material.offsetSdr
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Encodes a Gainmap starting from an HDR file into compressed file formats (`image/jpeg`, `image/webp` or `image/png`).
|
||||
*
|
||||
* Uses {@link encode} internally, then pipes the results to {@link compress}.
|
||||
*
|
||||
* @remarks
|
||||
* if a `renderer` parameter is not provided
|
||||
* This function will automatically dispose its "disposable"
|
||||
* renderer, no need to dispose it manually later
|
||||
*
|
||||
* @category Encoding Functions
|
||||
* @group Encoding Functions
|
||||
* @example
|
||||
* import { encodeAndCompress, findTextureMinMax } from '@monogrid/gainmap-js'
|
||||
* import { encodeJPEGMetadata } from '@monogrid/gainmap-js/libultrahdr'
|
||||
* import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js'
|
||||
*
|
||||
* // load an HDR file
|
||||
* const loader = new EXRLoader()
|
||||
* const image = await loader.loadAsync('image.exr')
|
||||
*
|
||||
* // find RAW RGB Max value of a texture
|
||||
* const textureMax = findTextureMinMax(image)
|
||||
*
|
||||
* // Encode the gainmap
|
||||
* const encodingResult = await encodeAndCompress({
|
||||
* image,
|
||||
* maxContentBoost: Math.max.apply(this, textureMax),
|
||||
* mimeType: 'image/jpeg'
|
||||
* })
|
||||
*
|
||||
* // embed the compressed images + metadata into a single
|
||||
* // JPEG file
|
||||
* const jpeg = encodeJPEGMetadata({
|
||||
* ...encodingResult,
|
||||
* sdr: encodingResult.sdr,
|
||||
* gainMap: encodingResult.gainMap
|
||||
* })
|
||||
*
|
||||
* // `jpeg` will be an `Uint8Array` which can be saved somewhere
|
||||
*
|
||||
*
|
||||
* @param params Encoding Parameters
|
||||
* @throws {Error} if the browser does not support [createImageBitmap](https://caniuse.com/createimagebitmap)
|
||||
*/
|
||||
const encodeAndCompress = async (params) => {
|
||||
const encodingResult = encode(params);
|
||||
const { mimeType, quality, flipY, withWorker } = params;
|
||||
let compressResult;
|
||||
let rawSDR;
|
||||
let rawGainMap;
|
||||
const sdrImageData = new ImageData(encodingResult.sdr.toArray(), encodingResult.sdr.width, encodingResult.sdr.height);
|
||||
const gainMapImageData = new ImageData(encodingResult.gainMap.toArray(), encodingResult.gainMap.width, encodingResult.gainMap.height);
|
||||
if (withWorker) {
|
||||
const workerResult = await Promise.all([
|
||||
withWorker.compress({
|
||||
source: sdrImageData,
|
||||
mimeType,
|
||||
quality,
|
||||
flipY
|
||||
}),
|
||||
withWorker.compress({
|
||||
source: gainMapImageData,
|
||||
mimeType,
|
||||
quality,
|
||||
flipY
|
||||
})
|
||||
]);
|
||||
compressResult = workerResult;
|
||||
rawSDR = workerResult[0].source;
|
||||
rawGainMap = workerResult[1].source;
|
||||
}
|
||||
else {
|
||||
compressResult = await Promise.all([
|
||||
compress({
|
||||
source: sdrImageData,
|
||||
mimeType,
|
||||
quality,
|
||||
flipY
|
||||
}),
|
||||
compress({
|
||||
source: gainMapImageData,
|
||||
mimeType,
|
||||
quality,
|
||||
flipY
|
||||
})
|
||||
]);
|
||||
rawSDR = sdrImageData.data;
|
||||
rawGainMap = gainMapImageData.data;
|
||||
}
|
||||
encodingResult.sdr.dispose();
|
||||
encodingResult.gainMap.dispose();
|
||||
return {
|
||||
...encodingResult,
|
||||
...encodingResult.getMetadata(),
|
||||
sdr: compressResult[0],
|
||||
gainMap: compressResult[1],
|
||||
rawSDR,
|
||||
rawGainMap
|
||||
};
|
||||
};
|
||||
|
||||
const vertexShader = /* glsl */ `
|
||||
varying vec2 vUv;
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`;
|
||||
const fragmentShader = /* glsl */ `
|
||||
precision mediump float;
|
||||
|
||||
#ifndef CELL_SIZE
|
||||
#define CELL_SIZE 2
|
||||
#endif
|
||||
|
||||
#ifndef COMPARE_FUNCTION
|
||||
#define COMPARE_FUNCTION max
|
||||
#endif
|
||||
|
||||
#ifndef INITIAL_VALUE
|
||||
#define INITIAL_VALUE 0
|
||||
#endif
|
||||
|
||||
uniform sampler2D map;
|
||||
uniform vec2 u_srcResolution;
|
||||
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
// compute the first pixel the source cell
|
||||
vec2 srcPixel = floor(gl_FragCoord.xy) * float(CELL_SIZE);
|
||||
|
||||
// one pixel in source
|
||||
vec2 onePixel = vec2(1) / u_srcResolution;
|
||||
|
||||
// uv for first pixel in cell. +0.5 for center of pixel
|
||||
vec2 uv = (srcPixel + 0.5) * onePixel;
|
||||
|
||||
vec4 resultColor = vec4(INITIAL_VALUE);
|
||||
|
||||
for (int y = 0; y < CELL_SIZE; ++y) {
|
||||
for (int x = 0; x < CELL_SIZE; ++x) {
|
||||
resultColor = COMPARE_FUNCTION(resultColor, texture2D(map, uv + vec2(x, y) * onePixel));
|
||||
}
|
||||
}
|
||||
|
||||
gl_FragColor = resultColor;
|
||||
}
|
||||
`;
|
||||
/**
|
||||
*
|
||||
* @category Utility
|
||||
* @group Utility
|
||||
*
|
||||
* @param image
|
||||
* @param mode
|
||||
* @param renderer
|
||||
* @returns
|
||||
*/
|
||||
const findTextureMinMax = (image, mode = 'max', renderer) => {
|
||||
const srcTex = getDataTexture(image);
|
||||
// check if texture has a valid format
|
||||
if (srcTex.format !== AlphaFormat &&
|
||||
srcTex.format !== RGBFormat &&
|
||||
srcTex.format !== RGBAFormat &&
|
||||
srcTex.format !== DepthFormat &&
|
||||
srcTex.format !== DepthStencilFormat &&
|
||||
srcTex.format !== RedFormat &&
|
||||
srcTex.format !== RedIntegerFormat &&
|
||||
srcTex.format !== RGFormat &&
|
||||
srcTex.format !== RGIntegerFormat &&
|
||||
srcTex.format !== RGBIntegerFormat &&
|
||||
srcTex.format !== RGBAIntegerFormat) {
|
||||
throw new Error('Unsupported texture format');
|
||||
}
|
||||
const cellSize = 2;
|
||||
const mat = new ShaderMaterial({
|
||||
vertexShader,
|
||||
fragmentShader,
|
||||
uniforms: {
|
||||
u_srcResolution: { value: new Vector2(srcTex.image.width, srcTex.image.height) },
|
||||
map: { value: srcTex }
|
||||
},
|
||||
defines: {
|
||||
CELL_SIZE: cellSize,
|
||||
COMPARE_FUNCTION: mode,
|
||||
INITIAL_VALUE: mode === 'max' ? 0 : 65504 // max half float value
|
||||
}
|
||||
});
|
||||
srcTex.needsUpdate = true;
|
||||
mat.needsUpdate = true;
|
||||
let w = srcTex.image.width;
|
||||
let h = srcTex.image.height;
|
||||
const quadRenderer = new QuadRenderer({
|
||||
width: w,
|
||||
height: h,
|
||||
type: srcTex.type,
|
||||
colorSpace: srcTex.colorSpace,
|
||||
material: mat,
|
||||
renderer
|
||||
});
|
||||
const frameBuffers = [];
|
||||
while (w > 1 || h > 1) {
|
||||
w = Math.max(1, (w + cellSize - 1) / cellSize | 0);
|
||||
h = Math.max(1, (h + cellSize - 1) / cellSize | 0);
|
||||
const fb = new WebGLRenderTarget(w, h, {
|
||||
type: quadRenderer.type,
|
||||
format: srcTex.format,
|
||||
colorSpace: quadRenderer.colorSpace,
|
||||
minFilter: NearestFilter,
|
||||
magFilter: NearestFilter,
|
||||
wrapS: ClampToEdgeWrapping,
|
||||
wrapT: ClampToEdgeWrapping,
|
||||
generateMipmaps: false,
|
||||
depthBuffer: false,
|
||||
stencilBuffer: false
|
||||
});
|
||||
frameBuffers.push(fb);
|
||||
}
|
||||
w = srcTex.image.width;
|
||||
h = srcTex.image.height;
|
||||
frameBuffers.forEach((fbi) => {
|
||||
w = Math.max(1, (w + cellSize - 1) / cellSize | 0);
|
||||
h = Math.max(1, (h + cellSize - 1) / cellSize | 0);
|
||||
quadRenderer.renderTarget = fbi;
|
||||
quadRenderer.render();
|
||||
mat.uniforms.map.value = fbi.texture;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
mat.uniforms.u_srcResolution.value.x = w;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
mat.uniforms.u_srcResolution.value.y = h;
|
||||
});
|
||||
const out = quadRenderer.toArray();
|
||||
quadRenderer.dispose();
|
||||
frameBuffers.forEach(fb => fb.dispose());
|
||||
return [
|
||||
quadRenderer.type === FloatType ? out[0] : DataUtils.fromHalfFloat(out[0]),
|
||||
quadRenderer.type === FloatType ? out[1] : DataUtils.fromHalfFloat(out[1]),
|
||||
quadRenderer.type === FloatType ? out[2] : DataUtils.fromHalfFloat(out[2])
|
||||
];
|
||||
};
|
||||
|
||||
export { GainMapEncoderMaterial, SDRMaterial, compress, encode, encodeAndCompress, findTextureMinMax, getGainMap, getSDRRendition };
|
||||
5
node_modules/@monogrid/gainmap-js/dist/encode.min.js
generated
vendored
Normal file
5
node_modules/@monogrid/gainmap-js/dist/encode.min.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1316
node_modules/@monogrid/gainmap-js/dist/encode.umd.cjs
generated
vendored
Normal file
1316
node_modules/@monogrid/gainmap-js/dist/encode.umd.cjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5
node_modules/@monogrid/gainmap-js/dist/encode.umd.min.cjs
generated
vendored
Normal file
5
node_modules/@monogrid/gainmap-js/dist/encode.umd.min.cjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
12
node_modules/@monogrid/gainmap-js/dist/encode/compress.d.ts
generated
vendored
Normal file
12
node_modules/@monogrid/gainmap-js/dist/encode/compress.d.ts
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import { CompressedImage, CompressParameters } from './types';
|
||||
/**
|
||||
* Converts a RAW RGBA image buffer into the provided `mimeType` using the provided `quality`
|
||||
*
|
||||
* @category Compression
|
||||
* @group Compression
|
||||
* @param params
|
||||
* @throws {Error} if the browser does not support [createImageBitmap](https://caniuse.com/createimagebitmap)
|
||||
* @throws {Error} if the provided source image cannot be decoded
|
||||
* @throws {Error} if the function fails to create a canvas context
|
||||
*/
|
||||
export declare const compress: (params: CompressParameters) => Promise<CompressedImage>;
|
||||
61
node_modules/@monogrid/gainmap-js/dist/encode/encode-and-compress.d.ts
generated
vendored
Normal file
61
node_modules/@monogrid/gainmap-js/dist/encode/encode-and-compress.d.ts
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
import { CompressedImage, EncodingParametersWithCompression } from './types';
|
||||
/**
|
||||
* Encodes a Gainmap starting from an HDR file into compressed file formats (`image/jpeg`, `image/webp` or `image/png`).
|
||||
*
|
||||
* Uses {@link encode} internally, then pipes the results to {@link compress}.
|
||||
*
|
||||
* @remarks
|
||||
* if a `renderer` parameter is not provided
|
||||
* This function will automatically dispose its "disposable"
|
||||
* renderer, no need to dispose it manually later
|
||||
*
|
||||
* @category Encoding Functions
|
||||
* @group Encoding Functions
|
||||
* @example
|
||||
* import { encodeAndCompress, findTextureMinMax } from '@monogrid/gainmap-js'
|
||||
* import { encodeJPEGMetadata } from '@monogrid/gainmap-js/libultrahdr'
|
||||
* import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js'
|
||||
*
|
||||
* // load an HDR file
|
||||
* const loader = new EXRLoader()
|
||||
* const image = await loader.loadAsync('image.exr')
|
||||
*
|
||||
* // find RAW RGB Max value of a texture
|
||||
* const textureMax = findTextureMinMax(image)
|
||||
*
|
||||
* // Encode the gainmap
|
||||
* const encodingResult = await encodeAndCompress({
|
||||
* image,
|
||||
* maxContentBoost: Math.max.apply(this, textureMax),
|
||||
* mimeType: 'image/jpeg'
|
||||
* })
|
||||
*
|
||||
* // embed the compressed images + metadata into a single
|
||||
* // JPEG file
|
||||
* const jpeg = encodeJPEGMetadata({
|
||||
* ...encodingResult,
|
||||
* sdr: encodingResult.sdr,
|
||||
* gainMap: encodingResult.gainMap
|
||||
* })
|
||||
*
|
||||
* // `jpeg` will be an `Uint8Array` which can be saved somewhere
|
||||
*
|
||||
*
|
||||
* @param params Encoding Parameters
|
||||
* @throws {Error} if the browser does not support [createImageBitmap](https://caniuse.com/createimagebitmap)
|
||||
*/
|
||||
export declare const encodeAndCompress: (params: EncodingParametersWithCompression) => Promise<{
|
||||
sdr: CompressedImage;
|
||||
gainMap: CompressedImage;
|
||||
rawSDR: Uint8ClampedArray<ArrayBufferLike>;
|
||||
rawGainMap: Uint8ClampedArray<ArrayBufferLike>;
|
||||
gamma: [number, number, number];
|
||||
hdrCapacityMin: number;
|
||||
hdrCapacityMax: number;
|
||||
offsetSdr: [number, number, number];
|
||||
offsetHdr: [number, number, number];
|
||||
gainMapMin: [number, number, number];
|
||||
gainMapMax: [number, number, number];
|
||||
hdr: import("three").DataTexture;
|
||||
getMetadata: () => import(".").GainMapMetadata;
|
||||
}>;
|
||||
61
node_modules/@monogrid/gainmap-js/dist/encode/encode.d.ts
generated
vendored
Normal file
61
node_modules/@monogrid/gainmap-js/dist/encode/encode.d.ts
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
import { GainMapMetadata } from '../core/types';
|
||||
import { EncodingParametersBase } from './types';
|
||||
/**
|
||||
* Encodes a Gainmap starting from an HDR file.
|
||||
*
|
||||
* @remarks
|
||||
* if you do not pass a `renderer` parameter
|
||||
* you must manually dispose the result
|
||||
* ```js
|
||||
* const encodingResult = await encode({ ... })
|
||||
* // do something with the buffers
|
||||
* const sdr = encodingResult.sdr.getArray()
|
||||
* const gainMap = encodingResult.gainMap.getArray()
|
||||
* // after that
|
||||
* encodingResult.sdr.dispose()
|
||||
* encodingResult.gainMap.dispose()
|
||||
* ```
|
||||
*
|
||||
* @category Encoding Functions
|
||||
* @group Encoding Functions
|
||||
*
|
||||
* @example
|
||||
* import { encode, findTextureMinMax } from '@monogrid/gainmap-js'
|
||||
* import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js'
|
||||
*
|
||||
* // load an HDR file
|
||||
* const loader = new EXRLoader()
|
||||
* const image = await loader.loadAsync('image.exr')
|
||||
*
|
||||
* // find RAW RGB Max value of a texture
|
||||
* const textureMax = findTextureMinMax(image)
|
||||
*
|
||||
* // Encode the gainmap
|
||||
* const encodingResult = encode({
|
||||
* image,
|
||||
* // this will encode the full HDR range
|
||||
* maxContentBoost: Math.max.apply(this, textureMax)
|
||||
* })
|
||||
* // can be re-encoded after changing parameters
|
||||
* encodingResult.sdr.material.exposure = 0.9
|
||||
* encodingResult.sdr.render()
|
||||
* // or
|
||||
* encodingResult.gainMap.material.gamma = [1.1, 1.1, 1.1]
|
||||
* encodingResult.gainMap.render()
|
||||
*
|
||||
* // do something with encodingResult.gainMap.toArray()
|
||||
* // and encodingResult.sdr.toArray()
|
||||
*
|
||||
* // renderers must be manually disposed
|
||||
* encodingResult.sdr.dispose()
|
||||
* encodingResult.gainMap.dispose()
|
||||
*
|
||||
* @param params Encoding Parameters
|
||||
* @returns
|
||||
*/
|
||||
export declare const encode: (params: EncodingParametersBase) => {
|
||||
sdr: import("../core").QuadRenderer<1009, import(".").SDRMaterial>;
|
||||
gainMap: import("../core").QuadRenderer<1009, import(".").GainMapEncoderMaterial>;
|
||||
hdr: import("three").DataTexture;
|
||||
getMetadata: () => GainMapMetadata;
|
||||
};
|
||||
15
node_modules/@monogrid/gainmap-js/dist/encode/find-texture-min-max.d.ts
generated
vendored
Normal file
15
node_modules/@monogrid/gainmap-js/dist/encode/find-texture-min-max.d.ts
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import { DataTexture, WebGLRenderer } from 'three';
|
||||
import { EXR } from 'three/examples/jsm/loaders/EXRLoader.js';
|
||||
import { HDR } from 'three/examples/jsm/loaders/HDRLoader.js';
|
||||
import { RGBE } from 'three/examples/jsm/loaders/RGBELoader.js';
|
||||
/**
|
||||
*
|
||||
* @category Utility
|
||||
* @group Utility
|
||||
*
|
||||
* @param image
|
||||
* @param mode
|
||||
* @param renderer
|
||||
* @returns
|
||||
*/
|
||||
export declare const findTextureMinMax: (image: EXR | RGBE | HDR | DataTexture, mode?: "min" | "max", renderer?: WebGLRenderer) => number[];
|
||||
13
node_modules/@monogrid/gainmap-js/dist/encode/get-gainmap.d.ts
generated
vendored
Normal file
13
node_modules/@monogrid/gainmap-js/dist/encode/get-gainmap.d.ts
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import { QuadRenderer } from '../core/QuadRenderer';
|
||||
import { GainMapEncoderMaterial } from './materials/GainMapEncoderMaterial';
|
||||
import { EncodingParametersBase } from './types';
|
||||
/**
|
||||
*
|
||||
* @param params
|
||||
* @returns
|
||||
* @category Encoding Functions
|
||||
* @group Encoding Functions
|
||||
*/
|
||||
export declare const getGainMap: (params: {
|
||||
sdr: InstanceType<typeof QuadRenderer>;
|
||||
} & EncodingParametersBase) => QuadRenderer<1009, GainMapEncoderMaterial>;
|
||||
17
node_modules/@monogrid/gainmap-js/dist/encode/get-sdr-rendition.d.ts
generated
vendored
Normal file
17
node_modules/@monogrid/gainmap-js/dist/encode/get-sdr-rendition.d.ts
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import { DataTexture, ToneMapping, UnsignedByteType, WebGLRenderer } from 'three';
|
||||
import { QuadRenderer } from '../core/QuadRenderer';
|
||||
import { QuadRendererTextureOptions } from '../decode';
|
||||
import { SDRMaterial } from './materials/SDRMaterial';
|
||||
/**
|
||||
* Renders an SDR Representation of an HDR Image
|
||||
*
|
||||
* @category Encoding Functions
|
||||
* @group Encoding Functions
|
||||
*
|
||||
* @param hdrTexture The HDR image to be rendered
|
||||
* @param renderer (optional) WebGLRenderer to use during the rendering, a disposable renderer will be create and destroyed if this is not provided.
|
||||
* @param toneMapping (optional) Tone mapping to be applied to the SDR Rendition
|
||||
* @param renderTargetOptions (optional) Options to use when creating the output renderTarget
|
||||
* @throws {Error} if the WebGLRenderer fails to render the SDR image
|
||||
*/
|
||||
export declare const getSDRRendition: (hdrTexture: DataTexture, renderer?: WebGLRenderer, toneMapping?: ToneMapping, renderTargetOptions?: QuadRendererTextureOptions) => InstanceType<typeof QuadRenderer<typeof UnsignedByteType, InstanceType<typeof SDRMaterial>>>;
|
||||
10
node_modules/@monogrid/gainmap-js/dist/encode/index.d.ts
generated
vendored
Normal file
10
node_modules/@monogrid/gainmap-js/dist/encode/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
export * from '../core/types';
|
||||
export * from './compress';
|
||||
export * from './encode';
|
||||
export * from './encode-and-compress';
|
||||
export * from './find-texture-min-max';
|
||||
export * from './get-gainmap';
|
||||
export * from './get-sdr-rendition';
|
||||
export * from './materials/GainMapEncoderMaterial';
|
||||
export * from './materials/SDRMaterial';
|
||||
export * from './types';
|
||||
70
node_modules/@monogrid/gainmap-js/dist/encode/materials/GainMapEncoderMaterial.d.ts
generated
vendored
Normal file
70
node_modules/@monogrid/gainmap-js/dist/encode/materials/GainMapEncoderMaterial.d.ts
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
import { ShaderMaterial, Texture } from 'three';
|
||||
import { GainmapEncodingParameters } from '../types';
|
||||
/**
|
||||
* A Material which is able to encode a gainmap
|
||||
*
|
||||
* @category Materials
|
||||
* @group Materials
|
||||
*/
|
||||
export declare class GainMapEncoderMaterial extends ShaderMaterial {
|
||||
private _minContentBoost;
|
||||
private _maxContentBoost;
|
||||
private _offsetSdr;
|
||||
private _offsetHdr;
|
||||
private _gamma;
|
||||
/**
|
||||
*
|
||||
* @param params
|
||||
*/
|
||||
constructor({ sdr, hdr, offsetSdr, offsetHdr, maxContentBoost, minContentBoost, gamma }: {
|
||||
sdr: Texture;
|
||||
hdr: Texture;
|
||||
} & GainmapEncodingParameters);
|
||||
/**
|
||||
* @see {@link GainmapEncodingParameters.gamma}
|
||||
*/
|
||||
get gamma(): [number, number, number];
|
||||
set gamma(value: [number, number, number]);
|
||||
/**
|
||||
* @see {@link GainmapEncodingParameters.offsetHdr}
|
||||
*/
|
||||
get offsetHdr(): [number, number, number];
|
||||
set offsetHdr(value: [number, number, number]);
|
||||
/**
|
||||
* @see {@link GainmapEncodingParameters.offsetSdr}
|
||||
*/
|
||||
get offsetSdr(): [number, number, number];
|
||||
set offsetSdr(value: [number, number, number]);
|
||||
/**
|
||||
* @see {@link GainmapEncodingParameters.minContentBoost}
|
||||
* @remarks Non logarithmic space
|
||||
*/
|
||||
get minContentBoost(): number;
|
||||
set minContentBoost(value: number);
|
||||
/**
|
||||
* @see {@link GainmapEncodingParameters.maxContentBoost}
|
||||
* @remarks Non logarithmic space
|
||||
*/
|
||||
get maxContentBoost(): number;
|
||||
set maxContentBoost(value: number);
|
||||
/**
|
||||
* @see {@link GainMapMetadata.gainMapMin}
|
||||
* @remarks Logarithmic space
|
||||
*/
|
||||
get gainMapMin(): [number, number, number];
|
||||
/**
|
||||
* @see {@link GainMapMetadata.gainMapMax}
|
||||
* @remarks Logarithmic space
|
||||
*/
|
||||
get gainMapMax(): [number, number, number];
|
||||
/**
|
||||
* @see {@link GainMapMetadata.hdrCapacityMin}
|
||||
* @remarks Logarithmic space
|
||||
*/
|
||||
get hdrCapacityMin(): number;
|
||||
/**
|
||||
* @see {@link GainMapMetadata.hdrCapacityMax}
|
||||
* @remarks Logarithmic space
|
||||
*/
|
||||
get hdrCapacityMax(): number;
|
||||
}
|
||||
35
node_modules/@monogrid/gainmap-js/dist/encode/materials/SDRMaterial.d.ts
generated
vendored
Normal file
35
node_modules/@monogrid/gainmap-js/dist/encode/materials/SDRMaterial.d.ts
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
import { ShaderMaterial, Texture, ToneMapping } from 'three';
|
||||
/**
|
||||
* A Material used to adjust the SDR representation of an HDR image
|
||||
*
|
||||
* @category Materials
|
||||
* @group Materials
|
||||
*/
|
||||
export declare class SDRMaterial extends ShaderMaterial {
|
||||
private _brightness;
|
||||
private _contrast;
|
||||
private _saturation;
|
||||
private _exposure;
|
||||
private _toneMapping;
|
||||
private _map;
|
||||
/**
|
||||
*
|
||||
* @param params
|
||||
*/
|
||||
constructor({ map, toneMapping }: {
|
||||
map: Texture;
|
||||
toneMapping?: ToneMapping;
|
||||
});
|
||||
get toneMapping(): ToneMapping;
|
||||
set toneMapping(value: ToneMapping);
|
||||
get brightness(): number;
|
||||
set brightness(value: number);
|
||||
get contrast(): number;
|
||||
set contrast(value: number);
|
||||
get saturation(): number;
|
||||
set saturation(value: number);
|
||||
get exposure(): number;
|
||||
set exposure(value: number);
|
||||
get map(): Texture;
|
||||
set map(value: Texture);
|
||||
}
|
||||
177
node_modules/@monogrid/gainmap-js/dist/encode/types.d.ts
generated
vendored
Normal file
177
node_modules/@monogrid/gainmap-js/dist/encode/types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
import { type DataTexture, ToneMapping, WebGLRenderer } from 'three';
|
||||
import { type EXR } from 'three/examples/jsm/loaders/EXRLoader.js';
|
||||
import { type HDR } from 'three/examples/jsm/loaders/HDRLoader.js';
|
||||
import { type RGBE } from 'three/examples/jsm/loaders/RGBELoader.js';
|
||||
import { QuadRendererTextureOptions } from '../decode';
|
||||
import { WorkerInterfaceImplementation } from '../worker-types';
|
||||
/**
|
||||
* Parameters used by content Creators in order to create a GainMap
|
||||
* @category Specs
|
||||
* @group Specs
|
||||
*/
|
||||
export type GainmapEncodingParameters = {
|
||||
/**
|
||||
* This is the offset to apply to the HDR pixel values during gain map generation and application.
|
||||
* @defaultValue [1/64, 1/64, 1/64]
|
||||
*/
|
||||
offsetHdr?: [number, number, number];
|
||||
/**
|
||||
* This is the offset to apply to the SDR pixel values during gain map generation and application
|
||||
* @defaultValue [1/64, 1/64, 1/64]
|
||||
*/
|
||||
offsetSdr?: [number, number, number];
|
||||
/**
|
||||
* This value lets the content creator constrain how much darker an image can get, when shown on an HDR display, relative to the SDR rendition.
|
||||
* This value is a constant for a particular image.
|
||||
* @defaultValue 1
|
||||
* @remarks
|
||||
* * If, for example, the value is 0.5, then for any given pixel, the linear luminance of the displayed HDR rendition must be (at the least) 0.5x the linear luminance of the SDR rendition.
|
||||
* * In practice, this value is typically equal to or just less than 1.0.
|
||||
* * Always less than or equal to Max content boost.
|
||||
*
|
||||
* Non Logarithmic space
|
||||
*/
|
||||
minContentBoost?: number;
|
||||
/**
|
||||
* This value lets the content creator constrain how much brighter an image can get, when shown on an HDR display, relative to the SDR rendition.
|
||||
*
|
||||
* @remarks
|
||||
* * This value is a constant for a particular image.
|
||||
* For example, if the value is four, then for any given pixel, the linear luminance of the
|
||||
* displayed HDR rendition must be, at the most, 4x the linear luminance of the SDR rendition.
|
||||
* In practice, this means that the brighter parts of the scene can be shown up to 4x brighter.
|
||||
* * In practice, this value is typically greater than 1.0.
|
||||
* * Always greater than or equal to Min content boost.
|
||||
*
|
||||
* Non Logarithmic space
|
||||
*/
|
||||
maxContentBoost: number;
|
||||
/**
|
||||
* This is the gamma to apply to the stored map values.
|
||||
*
|
||||
* @defaultValue [1, 1, 1]
|
||||
* @remarks
|
||||
* * Typically you can use a gamma of 1.0.
|
||||
* * You can use a different value if your gain map has a very uneven distribution of log_recovery(x, y) values.
|
||||
* For example, this might apply if a gain map has a lot of detail just above SDR range
|
||||
* (represented as small log_recovery(x, y) values), and a very large map_max_log2 for the top
|
||||
* end of the HDR rendition's desired brightness (represented by large log_recovery(x, y) values).
|
||||
* In this case, you can use a map_gamma higher than 1.0 so that recovery(x, y)
|
||||
* can precisely encode the detail in both the low end and high end of log_recovery(x, y).
|
||||
*/
|
||||
gamma?: [number, number, number];
|
||||
};
|
||||
/**
|
||||
* Parameters used to Encode a GainMap
|
||||
*
|
||||
* @category Encoding Parameters
|
||||
* @group Encoding Parameters
|
||||
*/
|
||||
export type EncodingParametersBase = GainmapEncodingParameters & {
|
||||
/**
|
||||
* Input image for encoding, must be an HDR image
|
||||
*/
|
||||
image: EXR | RGBE | HDR | DataTexture;
|
||||
/**
|
||||
* Optional WebGLRenderer
|
||||
* @remarks
|
||||
* will be created and destroyed on demand if not provided.
|
||||
*/
|
||||
renderer?: WebGLRenderer;
|
||||
/**
|
||||
* Optional tone mapping to apply to the SDR Rendition
|
||||
* @defaultValue `ACESFilmicToneMapping`
|
||||
*/
|
||||
toneMapping?: ToneMapping;
|
||||
/**
|
||||
* Options to use when creating the output renderTarget
|
||||
*/
|
||||
renderTargetOptions?: QuadRendererTextureOptions;
|
||||
};
|
||||
/**
|
||||
* This library can provide gainmap compressed in these mimeTypes
|
||||
*
|
||||
* @category Compression
|
||||
* @group Compression
|
||||
*/
|
||||
export type CompressionMimeType = 'image/png' | 'image/jpeg' | 'image/webp';
|
||||
/**
|
||||
* Accepted HDR image buffers, definitions coming from the THREE.js Library types
|
||||
*
|
||||
* @category Utility
|
||||
* @group Utility
|
||||
*/
|
||||
export type HDRRawImageBuffer = EXR['data'] | RGBE['data'];
|
||||
/**
|
||||
* Raw HDR image data
|
||||
*
|
||||
* @category Utility
|
||||
* @group Utility
|
||||
*/
|
||||
export type HDRRawImage = {
|
||||
data: HDRRawImageBuffer;
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
/**
|
||||
* Options for compressing a RAW RGBA image into the specified mimeType
|
||||
*
|
||||
* @category Compression
|
||||
* @group Compression
|
||||
*/
|
||||
export type CompressOptions = {
|
||||
/**
|
||||
* The mimeType of the output
|
||||
*/
|
||||
mimeType: CompressionMimeType;
|
||||
/**
|
||||
* Encoding quality [0-1]
|
||||
*/
|
||||
quality?: number;
|
||||
/**
|
||||
* FlipY of the encoding process
|
||||
*/
|
||||
flipY?: boolean;
|
||||
};
|
||||
/**
|
||||
* Data structure representing a compressed image with a mimeType
|
||||
*
|
||||
* @category Compression
|
||||
* @group Compression
|
||||
*/
|
||||
export type CompressedImage = {
|
||||
data: Uint8Array<ArrayBuffer>;
|
||||
mimeType: CompressionMimeType;
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
/**
|
||||
* @category Compression
|
||||
* @group Compression
|
||||
*/
|
||||
export type CompressParameters = CompressOptions & ({
|
||||
/**
|
||||
* RAW RGBA Image Data
|
||||
*/
|
||||
source: ImageData;
|
||||
} | {
|
||||
/**
|
||||
* Encoded Image Data with a mimeType
|
||||
*/
|
||||
source: Uint8Array<ArrayBuffer> | Uint8ClampedArray<ArrayBuffer>;
|
||||
/**
|
||||
* mimeType of the encoded input
|
||||
*/
|
||||
sourceMimeType: string;
|
||||
});
|
||||
/**
|
||||
* Additional parameters to encode a GainMap compressed with a mimeType
|
||||
* @category Encoding Parameters
|
||||
* @group Encoding Parameters
|
||||
*/
|
||||
export type EncodingParametersWithCompression = EncodingParametersBase & CompressOptions & {
|
||||
/**
|
||||
* Encodes the Gainmap using a Web Worker
|
||||
*/
|
||||
withWorker?: WorkerInterfaceImplementation;
|
||||
};
|
||||
1
node_modules/@monogrid/gainmap-js/dist/libultrahdr.d.ts
generated
vendored
Normal file
1
node_modules/@monogrid/gainmap-js/dist/libultrahdr.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './libultrahdr/encode-jpeg-metadata';
|
||||
650
node_modules/@monogrid/gainmap-js/dist/libultrahdr.js
generated
vendored
Normal file
650
node_modules/@monogrid/gainmap-js/dist/libultrahdr.js
generated
vendored
Normal file
@@ -0,0 +1,650 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* JPEG marker constants
|
||||
* Based on JPEG specification and libultrahdr implementation
|
||||
*/
|
||||
/**
|
||||
* JPEG marker prefix - all markers start with this byte
|
||||
*/
|
||||
const MARKER_PREFIX = 0xff;
|
||||
/**
|
||||
* JPEG markers
|
||||
*/
|
||||
const MARKERS = {
|
||||
/** Start of Image */
|
||||
SOI: 0xd8,
|
||||
/** Application segment 1 (EXIF/XMP) */
|
||||
APP1: 0xe1,
|
||||
/** Application segment 2 (ICC/MPF) */
|
||||
APP2: 0xe2,
|
||||
/** Start of Scan */
|
||||
SOS: 0xda};
|
||||
/**
|
||||
* XMP namespace identifier for APP1 marker
|
||||
*/
|
||||
const XMP_NAMESPACE = 'http://ns.adobe.com/xap/1.0/\0';
|
||||
|
||||
/**
|
||||
* Multi-Picture Format (MPF) generator
|
||||
* Based on CIPA DC-007 specification and libultrahdr multipictureformat.cpp
|
||||
*
|
||||
* MPF is used to embed multiple images in a single JPEG file
|
||||
*/
|
||||
/**
|
||||
* MPF constants from the specification
|
||||
*/
|
||||
const MPF_CONSTANTS = {
|
||||
/** MPF signature "MPF\0" */
|
||||
SIGNATURE: new Uint8Array([0x4d, 0x50, 0x46, 0x00]),
|
||||
/** Big endian marker "MM" */
|
||||
BIG_ENDIAN: new Uint8Array([0x4d, 0x4d]),
|
||||
/** TIFF magic number */
|
||||
TIFF_MAGIC: 0x002a,
|
||||
/** Number of pictures in MPF */
|
||||
NUM_PICTURES: 2,
|
||||
/** Number of tags to serialize */
|
||||
TAG_COUNT: 3,
|
||||
/** Size of each tag in bytes */
|
||||
TAG_SIZE: 12,
|
||||
/** Size of each MP entry in bytes */
|
||||
MP_ENTRY_SIZE: 16
|
||||
};
|
||||
/**
|
||||
* MPF tag identifiers
|
||||
*/
|
||||
const MPF_TAGS = {
|
||||
/** MPF version tag */
|
||||
VERSION: 0xb000,
|
||||
/** Number of images tag */
|
||||
NUMBER_OF_IMAGES: 0xb001,
|
||||
/** MP entry tag */
|
||||
MP_ENTRY: 0xb002
|
||||
};
|
||||
/**
|
||||
* MPF tag types
|
||||
*/
|
||||
const MPF_TAG_TYPES = {
|
||||
/** Undefined type */
|
||||
UNDEFINED: 7,
|
||||
/** Unsigned long type */
|
||||
ULONG: 4
|
||||
};
|
||||
/**
|
||||
* MP entry attributes
|
||||
*/
|
||||
const MP_ENTRY_ATTRIBUTES = {
|
||||
/** JPEG format */
|
||||
FORMAT_JPEG: 0x00000000,
|
||||
/** Primary image type */
|
||||
TYPE_PRIMARY: 0x20000000
|
||||
};
|
||||
/**
|
||||
* MPF version string
|
||||
*/
|
||||
const MPF_VERSION = new Uint8Array([0x30, 0x31, 0x30, 0x30]); // "0100"
|
||||
/**
|
||||
* Calculate the total size of the MPF structure
|
||||
*/
|
||||
function calculateMpfSize() {
|
||||
return (MPF_CONSTANTS.SIGNATURE.length + // Signature "MPF\0"
|
||||
2 + // Endianness marker
|
||||
2 + // TIFF magic number
|
||||
4 + // Index IFD Offset
|
||||
2 + // Tag count
|
||||
MPF_CONSTANTS.TAG_COUNT * MPF_CONSTANTS.TAG_SIZE + // Tags
|
||||
4 + // Attribute IFD offset
|
||||
MPF_CONSTANTS.NUM_PICTURES * MPF_CONSTANTS.MP_ENTRY_SIZE // MP Entries
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Generate MPF (Multi-Picture Format) data structure
|
||||
*
|
||||
* @param primaryImageSize - Size of the primary image in bytes
|
||||
* @param primaryImageOffset - Offset of the primary image (typically 0 for FII - First Individual Image)
|
||||
* @param secondaryImageSize - Size of the secondary (gain map) image in bytes
|
||||
* @param secondaryImageOffset - Offset of the secondary image from the MP Endian field
|
||||
* @returns Uint8Array containing the MPF data
|
||||
*/
|
||||
function generateMpf(primaryImageSize, primaryImageOffset, secondaryImageSize, secondaryImageOffset) {
|
||||
const mpfSize = calculateMpfSize();
|
||||
const buffer = new ArrayBuffer(mpfSize);
|
||||
const view = new DataView(buffer);
|
||||
const uint8View = new Uint8Array(buffer);
|
||||
let pos = 0;
|
||||
// Write MPF signature "MPF\0"
|
||||
uint8View.set(MPF_CONSTANTS.SIGNATURE, pos);
|
||||
pos += MPF_CONSTANTS.SIGNATURE.length;
|
||||
// Write endianness marker (big endian "MM")
|
||||
// Using big endian to match the C++ implementation's USE_BIG_ENDIAN
|
||||
uint8View.set(MPF_CONSTANTS.BIG_ENDIAN, pos);
|
||||
const bigEndian = false; // DataView uses little endian by default, so we need to flip this
|
||||
pos += 2;
|
||||
// Write TIFF magic number (0x002A)
|
||||
view.setUint16(pos, MPF_CONSTANTS.TIFF_MAGIC, bigEndian);
|
||||
pos += 2;
|
||||
// Set the Index IFD offset
|
||||
// This offset is from the start of the TIFF header (the endianness marker)
|
||||
// After: endianness (2) + magic (2) + this offset field (4) = 8 bytes
|
||||
const indexIfdOffset = 8;
|
||||
view.setUint32(pos, indexIfdOffset, bigEndian);
|
||||
pos += 4;
|
||||
// Write tag count (3 tags: version, number of images, MP entries)
|
||||
view.setUint16(pos, MPF_CONSTANTS.TAG_COUNT, bigEndian);
|
||||
pos += 2;
|
||||
// Write version tag
|
||||
view.setUint16(pos, MPF_TAGS.VERSION, bigEndian);
|
||||
pos += 2;
|
||||
view.setUint16(pos, MPF_TAG_TYPES.UNDEFINED, bigEndian);
|
||||
pos += 2;
|
||||
view.setUint32(pos, MPF_VERSION.length, bigEndian);
|
||||
pos += 4;
|
||||
uint8View.set(MPF_VERSION, pos);
|
||||
pos += 4; // Version is 4 bytes, embedded in the tag
|
||||
// Write number of images tag
|
||||
view.setUint16(pos, MPF_TAGS.NUMBER_OF_IMAGES, bigEndian);
|
||||
pos += 2;
|
||||
view.setUint16(pos, MPF_TAG_TYPES.ULONG, bigEndian);
|
||||
pos += 2;
|
||||
view.setUint32(pos, 1, bigEndian); // Count = 1
|
||||
pos += 4;
|
||||
view.setUint32(pos, MPF_CONSTANTS.NUM_PICTURES, bigEndian);
|
||||
pos += 4;
|
||||
// Write MP entry tag
|
||||
view.setUint16(pos, MPF_TAGS.MP_ENTRY, bigEndian);
|
||||
pos += 2;
|
||||
view.setUint16(pos, MPF_TAG_TYPES.UNDEFINED, bigEndian);
|
||||
pos += 2;
|
||||
view.setUint32(pos, MPF_CONSTANTS.MP_ENTRY_SIZE * MPF_CONSTANTS.NUM_PICTURES, bigEndian);
|
||||
pos += 4;
|
||||
// Calculate MP entry offset
|
||||
// The offset is from the start of the MP Endian field (after signature)
|
||||
// Current position is at the value field of MP Entry tag
|
||||
const mpEntryOffset = pos - MPF_CONSTANTS.SIGNATURE.length + 4 + 4;
|
||||
view.setUint32(pos, mpEntryOffset, bigEndian);
|
||||
pos += 4;
|
||||
// Write attribute IFD offset (0 = none)
|
||||
view.setUint32(pos, 0, bigEndian);
|
||||
pos += 4;
|
||||
// Write MP entries for primary image
|
||||
// Attribute format: JPEG (0x00000000) | Type: Primary (0x20000000)
|
||||
view.setUint32(pos, MP_ENTRY_ATTRIBUTES.FORMAT_JPEG | MP_ENTRY_ATTRIBUTES.TYPE_PRIMARY, bigEndian);
|
||||
pos += 4;
|
||||
view.setUint32(pos, primaryImageSize, bigEndian);
|
||||
pos += 4;
|
||||
view.setUint32(pos, primaryImageOffset, bigEndian);
|
||||
pos += 4;
|
||||
view.setUint16(pos, 0, bigEndian); // Dependent image 1
|
||||
pos += 2;
|
||||
view.setUint16(pos, 0, bigEndian); // Dependent image 2
|
||||
pos += 2;
|
||||
// Write MP entries for secondary image (gain map)
|
||||
// Attribute format: JPEG only (no type flag)
|
||||
view.setUint32(pos, MP_ENTRY_ATTRIBUTES.FORMAT_JPEG, bigEndian);
|
||||
pos += 4;
|
||||
view.setUint32(pos, secondaryImageSize, bigEndian);
|
||||
pos += 4;
|
||||
view.setUint32(pos, secondaryImageOffset, bigEndian);
|
||||
pos += 4;
|
||||
view.setUint16(pos, 0, bigEndian); // Dependent image 1
|
||||
pos += 2;
|
||||
view.setUint16(pos, 0, bigEndian); // Dependent image 2
|
||||
// pos += 2
|
||||
return uint8View;
|
||||
}
|
||||
|
||||
/**
|
||||
* XMP metadata generator for gain map images
|
||||
* Based on libultrahdr jpegrutils.cpp implementation
|
||||
*/
|
||||
/**
|
||||
* Item semantic types
|
||||
*/
|
||||
const ITEM_SEMANTIC = {
|
||||
PRIMARY: 'Primary',
|
||||
GAIN_MAP: 'GainMap'
|
||||
};
|
||||
/**
|
||||
* MIME type for JPEG images
|
||||
*/
|
||||
const MIME_IMAGE_JPEG = 'image/jpeg';
|
||||
/**
|
||||
* Escape XML special characters
|
||||
*/
|
||||
function escapeXml(str) {
|
||||
return String(str)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
/**
|
||||
* Generate XMP metadata for the primary image
|
||||
*
|
||||
* This XMP contains:
|
||||
* - Container directory with references to primary and gain map images
|
||||
* - Gain map version
|
||||
* - Item metadata for both images
|
||||
*
|
||||
* @param secondaryImageLength - Length of the secondary (gain map) JPEG in bytes
|
||||
* @param metadata - Gain map metadata
|
||||
* @returns XMP packet as string
|
||||
*/
|
||||
function generateXmpForPrimaryImage(secondaryImageLength, metadata) {
|
||||
const lines = [];
|
||||
// XMP packet header
|
||||
lines.push('<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>');
|
||||
lines.push('<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.1.2">');
|
||||
lines.push(' <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">');
|
||||
lines.push(' <rdf:Description');
|
||||
lines.push(' xmlns:Container="http://ns.google.com/photos/1.0/container/"');
|
||||
lines.push(' xmlns:Item="http://ns.google.com/photos/1.0/container/item/"');
|
||||
lines.push(' xmlns:hdrgm="http://ns.adobe.com/hdr-gain-map/1.0/"');
|
||||
lines.push(` hdrgm:Version="${escapeXml(metadata.version)}"`);
|
||||
lines.push(' rdf:about="">');
|
||||
// Container directory
|
||||
lines.push(' <Container:Directory>');
|
||||
lines.push(' <rdf:Seq>');
|
||||
// Primary image item
|
||||
lines.push(' <rdf:li rdf:parseType="Resource">');
|
||||
lines.push(' <Container:Item');
|
||||
lines.push(` Item:Semantic="${ITEM_SEMANTIC.PRIMARY}"`);
|
||||
lines.push(` Item:Mime="${MIME_IMAGE_JPEG}"/>`);
|
||||
lines.push(' </rdf:li>');
|
||||
// Gain map image item
|
||||
lines.push(' <rdf:li rdf:parseType="Resource">');
|
||||
lines.push(' <Container:Item');
|
||||
lines.push(` Item:Semantic="${ITEM_SEMANTIC.GAIN_MAP}"`);
|
||||
lines.push(` Item:Mime="${MIME_IMAGE_JPEG}"`);
|
||||
lines.push(` Item:Length="${secondaryImageLength}"/>`);
|
||||
lines.push(' </rdf:li>');
|
||||
lines.push(' </rdf:Seq>');
|
||||
lines.push(' </Container:Directory>');
|
||||
lines.push(' </rdf:Description>');
|
||||
lines.push(' </rdf:RDF>');
|
||||
lines.push('</x:xmpmeta>');
|
||||
lines.push('<?xpacket end="w"?>');
|
||||
return lines.join('\n');
|
||||
}
|
||||
/**
|
||||
* Generate XMP metadata for the secondary (gain map) image
|
||||
*
|
||||
* This XMP contains all the gain map parameters:
|
||||
* - Version
|
||||
* - Gain map min/max
|
||||
* - Gamma
|
||||
* - Offset SDR/HDR
|
||||
* - HDR capacity min/max
|
||||
* - Base rendition flag
|
||||
*
|
||||
* @param metadata - Gain map metadata
|
||||
* @returns XMP packet as string
|
||||
*/
|
||||
function generateXmpForSecondaryImage(metadata) {
|
||||
const lines = [];
|
||||
// hdrCapacityMin/Max are already in log2 space (from GainMapEncoderMaterial)
|
||||
// No conversion needed
|
||||
const hdrCapacityMin = metadata.hdrCapacityMin;
|
||||
const hdrCapacityMax = metadata.hdrCapacityMax;
|
||||
// Handle array values - take average if array, or use single value
|
||||
const getAverage = (val) => {
|
||||
if (Array.isArray(val)) {
|
||||
return val.reduce((sum, v) => sum + v, 0) / val.length;
|
||||
}
|
||||
return val;
|
||||
};
|
||||
const gainMapMinAvg = getAverage(metadata.gainMapMin);
|
||||
const gainMapMaxAvg = getAverage(metadata.gainMapMax);
|
||||
const gammaAvg = getAverage(metadata.gamma);
|
||||
const offsetSdrAvg = getAverage(metadata.offsetSdr);
|
||||
const offsetHdrAvg = getAverage(metadata.offsetHdr);
|
||||
// XMP packet header
|
||||
lines.push('<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>');
|
||||
lines.push('<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.1.2">');
|
||||
lines.push(' <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">');
|
||||
lines.push(' <rdf:Description');
|
||||
lines.push(' xmlns:hdrgm="http://ns.adobe.com/hdr-gain-map/1.0/"');
|
||||
lines.push(` hdrgm:Version="${escapeXml(metadata.version)}"`);
|
||||
lines.push(` hdrgm:GainMapMin="${escapeXml(gainMapMinAvg)}"`);
|
||||
lines.push(` hdrgm:GainMapMax="${escapeXml(gainMapMaxAvg)}"`);
|
||||
lines.push(` hdrgm:Gamma="${escapeXml(gammaAvg)}"`);
|
||||
lines.push(` hdrgm:OffsetSDR="${escapeXml(offsetSdrAvg)}"`);
|
||||
lines.push(` hdrgm:OffsetHDR="${escapeXml(offsetHdrAvg)}"`);
|
||||
lines.push(` hdrgm:HDRCapacityMin="${escapeXml(hdrCapacityMin)}"`);
|
||||
lines.push(` hdrgm:HDRCapacityMax="${escapeXml(hdrCapacityMax)}"`);
|
||||
lines.push(' hdrgm:BaseRenditionIsHDR="False"');
|
||||
lines.push(' rdf:about=""/>');
|
||||
lines.push(' </rdf:RDF>');
|
||||
lines.push('</x:xmpmeta>');
|
||||
lines.push('<?xpacket end="w"?>');
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* JPEG assembler for creating JPEG-R (JPEG with gain map) files
|
||||
* Based on libultrahdr jpegr.cpp implementation
|
||||
*/
|
||||
/**
|
||||
* Extract EXIF data from a JPEG if present
|
||||
*
|
||||
* @param jpegData - JPEG file data
|
||||
* @returns Object containing EXIF data and position, or null if not found
|
||||
*/
|
||||
function extractExif(jpegData) {
|
||||
const view = new DataView(jpegData.buffer, jpegData.byteOffset, jpegData.byteLength);
|
||||
// Check for JPEG SOI marker
|
||||
if (view.getUint8(0) !== MARKER_PREFIX || view.getUint8(1) !== MARKERS.SOI) {
|
||||
return null;
|
||||
}
|
||||
let offset = 2;
|
||||
const EXIF_SIGNATURE = 'Exif\0\0';
|
||||
while (offset < jpegData.length - 1) {
|
||||
// Check for marker prefix
|
||||
if (view.getUint8(offset) !== MARKER_PREFIX) {
|
||||
break;
|
||||
}
|
||||
const marker = view.getUint8(offset + 1);
|
||||
// Check for SOS (Start of Scan) - end of metadata
|
||||
if (marker === MARKERS.SOS) {
|
||||
break;
|
||||
}
|
||||
// Check for APP1 marker (EXIF/XMP)
|
||||
if (marker === MARKERS.APP1) {
|
||||
const length = view.getUint16(offset + 2, false); // Big endian
|
||||
const dataStart = offset + 4;
|
||||
// Check if this APP1 contains EXIF
|
||||
let isExif = true;
|
||||
for (let i = 0; i < EXIF_SIGNATURE.length; i++) {
|
||||
if (dataStart + i >= jpegData.length || jpegData[dataStart + i] !== EXIF_SIGNATURE.charCodeAt(i)) {
|
||||
isExif = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isExif) {
|
||||
// Found EXIF data
|
||||
const exifSize = length - 2; // Length includes the 2-byte length field itself
|
||||
const exifData = jpegData.slice(dataStart, dataStart + exifSize);
|
||||
return {
|
||||
data: exifData,
|
||||
pos: offset,
|
||||
size: length + 2 // Include marker (2 bytes) + length (2 bytes) + data
|
||||
};
|
||||
}
|
||||
}
|
||||
// Move to next marker
|
||||
const length = view.getUint16(offset + 2, false);
|
||||
offset += 2 + length;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Copy JPEG data without EXIF segment
|
||||
*
|
||||
* @param jpegData - Original JPEG data
|
||||
* @param exifPos - Position of EXIF segment
|
||||
* @param exifSize - Size of EXIF segment (including marker and length)
|
||||
* @returns JPEG data without EXIF
|
||||
*/
|
||||
function copyJpegWithoutExif(jpegData, exifPos, exifSize) {
|
||||
const newSize = jpegData.length - exifSize;
|
||||
const result = new Uint8Array(newSize);
|
||||
// Copy data before EXIF
|
||||
result.set(jpegData.subarray(0, exifPos), 0);
|
||||
// Copy data after EXIF
|
||||
result.set(jpegData.subarray(exifPos + exifSize), exifPos);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Write a JPEG marker and its data
|
||||
*
|
||||
* @param buffer - Target buffer
|
||||
* @param pos - Current position in buffer
|
||||
* @param marker - Marker type (without 0xFF prefix)
|
||||
* @param data - Data to write after marker
|
||||
* @returns New position after writing
|
||||
*/
|
||||
function writeMarker(buffer, pos, marker, data) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
||||
// Write marker
|
||||
view.setUint8(pos++, MARKER_PREFIX);
|
||||
view.setUint8(pos++, marker);
|
||||
// Write data if present
|
||||
if (data && data.length > 0) {
|
||||
// Write length (big endian, includes the 2-byte length field itself)
|
||||
const length = data.length + 2;
|
||||
view.setUint16(pos, length, false);
|
||||
pos += 2;
|
||||
// Write data
|
||||
buffer.set(data, pos);
|
||||
pos += data.length;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
/**
|
||||
* Assemble a JPEG-R file (JPEG with embedded gain map)
|
||||
*
|
||||
* The structure is:
|
||||
* 1. Primary image:
|
||||
* - SOI
|
||||
* - APP1 (EXIF if present)
|
||||
* - APP1 (XMP with gain map metadata)
|
||||
* - APP2 (ICC profile if present)
|
||||
* - APP2 (MPF data)
|
||||
* - Rest of primary JPEG data
|
||||
* 2. Secondary image (gain map):
|
||||
* - SOI
|
||||
* - APP1 (XMP with gain map parameters)
|
||||
* - Rest of gain map JPEG data
|
||||
*
|
||||
* @param options - Assembly options
|
||||
* @returns Complete JPEG-R file as Uint8Array
|
||||
*/
|
||||
function assembleJpegWithGainMap(options) {
|
||||
const { sdr, gainMap, metadata, exif: externalExif, icc } = options;
|
||||
// Validate input
|
||||
if (sdr.mimeType !== 'image/jpeg') {
|
||||
throw new Error('SDR image must be JPEG format');
|
||||
}
|
||||
if (gainMap.mimeType !== 'image/jpeg') {
|
||||
throw new Error('Gain map image must be JPEG format');
|
||||
}
|
||||
// Check for EXIF in primary image
|
||||
const exifFromJpeg = extractExif(sdr.data);
|
||||
if (exifFromJpeg && externalExif) {
|
||||
throw new Error('Primary image already contains EXIF data, cannot add external EXIF');
|
||||
}
|
||||
// Prepare primary JPEG (remove embedded EXIF if present)
|
||||
let primaryJpegData = sdr.data;
|
||||
let exifData = externalExif;
|
||||
if (exifFromJpeg) {
|
||||
primaryJpegData = copyJpegWithoutExif(sdr.data, exifFromJpeg.pos, exifFromJpeg.size);
|
||||
exifData = exifFromJpeg.data;
|
||||
}
|
||||
// Generate XMP for secondary image
|
||||
const xmpSecondary = generateXmpForSecondaryImage(metadata);
|
||||
const xmpSecondaryBytes = new TextEncoder().encode(xmpSecondary);
|
||||
// Calculate secondary image size
|
||||
// 2 bytes SOI + 2 bytes marker + 2 bytes length field + namespace + XMP data + gain map data (without SOI)
|
||||
const namespaceBytes = new TextEncoder().encode(XMP_NAMESPACE);
|
||||
const secondaryImageSize = 2 + 2 + 2 + namespaceBytes.length + xmpSecondaryBytes.length + (gainMap.data.length - 2);
|
||||
// Generate XMP for primary image
|
||||
const xmpPrimary = generateXmpForPrimaryImage(secondaryImageSize, metadata);
|
||||
const xmpPrimaryBytes = new TextEncoder().encode(xmpPrimary);
|
||||
const xmpPrimaryData = new Uint8Array(namespaceBytes.length + xmpPrimaryBytes.length);
|
||||
xmpPrimaryData.set(namespaceBytes, 0);
|
||||
xmpPrimaryData.set(xmpPrimaryBytes, namespaceBytes.length);
|
||||
// Calculate MPF size and offset
|
||||
const mpfLength = calculateMpfSize();
|
||||
// Calculate total size
|
||||
let totalSize = 2; // SOI
|
||||
if (exifData)
|
||||
totalSize += 2 + 2 + exifData.length; // APP1 + length + EXIF
|
||||
totalSize += 2 + 2 + xmpPrimaryData.length; // APP1 + length + XMP primary
|
||||
if (icc)
|
||||
totalSize += 2 + 2 + icc.length; // APP2 + length + ICC
|
||||
totalSize += 2 + 2 + mpfLength; // APP2 + length + MPF
|
||||
totalSize += primaryJpegData.length - 2; // Primary JPEG without SOI
|
||||
totalSize += secondaryImageSize; // Secondary image
|
||||
// Calculate offsets for MPF
|
||||
const primaryImageSize = totalSize - secondaryImageSize;
|
||||
// Offset is from MP Endian field (after APP2 marker + length + MPF signature)
|
||||
const secondaryImageOffset = primaryImageSize - (2 + // SOI
|
||||
(exifData ? 2 + 2 + exifData.length : 0) +
|
||||
2 + 2 + xmpPrimaryData.length +
|
||||
(icc ? 2 + 2 + icc.length : 0) +
|
||||
2 + 2 + 4 // APP2 marker + length + MPF signature
|
||||
);
|
||||
// Generate MPF data
|
||||
const mpfDataActual = generateMpf(primaryImageSize, 0, secondaryImageSize, secondaryImageOffset);
|
||||
// Allocate output buffer
|
||||
const output = new Uint8Array(totalSize);
|
||||
let pos = 0;
|
||||
// === PRIMARY IMAGE ===
|
||||
// Write SOI
|
||||
pos = writeMarker(output, pos, MARKERS.SOI);
|
||||
// Write EXIF if present
|
||||
if (exifData) {
|
||||
pos = writeMarker(output, pos, MARKERS.APP1, exifData);
|
||||
}
|
||||
// Write XMP for primary image (already created above)
|
||||
pos = writeMarker(output, pos, MARKERS.APP1, xmpPrimaryData);
|
||||
// Write ICC profile if present
|
||||
if (icc) {
|
||||
pos = writeMarker(output, pos, MARKERS.APP2, icc);
|
||||
}
|
||||
// Write MPF
|
||||
pos = writeMarker(output, pos, MARKERS.APP2, mpfDataActual);
|
||||
// Write rest of primary JPEG (skip SOI)
|
||||
output.set(primaryJpegData.subarray(2), pos);
|
||||
pos += primaryJpegData.length - 2;
|
||||
// === SECONDARY IMAGE (GAIN MAP) ===
|
||||
// Write SOI
|
||||
pos = writeMarker(output, pos, MARKERS.SOI);
|
||||
// Write XMP for secondary image
|
||||
const xmpSecondaryData = new Uint8Array(namespaceBytes.length + xmpSecondaryBytes.length);
|
||||
xmpSecondaryData.set(namespaceBytes, 0);
|
||||
xmpSecondaryData.set(xmpSecondaryBytes, namespaceBytes.length);
|
||||
pos = writeMarker(output, pos, MARKERS.APP1, xmpSecondaryData);
|
||||
// Write rest of gain map JPEG (skip SOI)
|
||||
output.set(gainMap.data.subarray(2), pos);
|
||||
// pos += gainMap.data.length - 2
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates a Gainmap into a single JPEG file (aka: JPEG-R) with the base map
|
||||
* as the sdr visualization and the gainMap encoded into a MPF (Multi-Picture Format) tag.
|
||||
*
|
||||
* @category Encoding
|
||||
* @group Encoding
|
||||
*
|
||||
* @example
|
||||
* import { compress, encode, findTextureMinMax } from '@monogrid/gainmap-js'
|
||||
* import { encodeJPEGMetadata } from '@monogrid/gainmap-js/libultrahdr'
|
||||
* import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js'
|
||||
*
|
||||
* // load an HDR file
|
||||
* const loader = new EXRLoader()
|
||||
* const image = await loader.loadAsync('image.exr')
|
||||
*
|
||||
* // find RAW RGB Max value of a texture
|
||||
* const textureMax = findTextureMinMax(image)
|
||||
*
|
||||
* // Encode the gainmap
|
||||
* const encodingResult = encode({
|
||||
* image,
|
||||
* maxContentBoost: Math.max.apply(this, textureMax)
|
||||
* })
|
||||
*
|
||||
* // obtain the RAW RGBA SDR buffer and create an ImageData
|
||||
* const sdrImageData = new ImageData(
|
||||
* encodingResult.sdr.toArray(),
|
||||
* encodingResult.sdr.width,
|
||||
* encodingResult.sdr.height
|
||||
* )
|
||||
* // obtain the RAW RGBA Gain map buffer and create an ImageData
|
||||
* const gainMapImageData = new ImageData(
|
||||
* encodingResult.gainMap.toArray(),
|
||||
* encodingResult.gainMap.width,
|
||||
* encodingResult.gainMap.height
|
||||
* )
|
||||
*
|
||||
* // parallel compress the RAW buffers into the specified mimeType
|
||||
* const mimeType = 'image/jpeg'
|
||||
* const quality = 0.9
|
||||
*
|
||||
* const [sdr, gainMap] = await Promise.all([
|
||||
* compress({
|
||||
* source: sdrImageData,
|
||||
* mimeType,
|
||||
* quality,
|
||||
* flipY: true // output needs to be flipped
|
||||
* }),
|
||||
* compress({
|
||||
* source: gainMapImageData,
|
||||
* mimeType,
|
||||
* quality,
|
||||
* flipY: true // output needs to be flipped
|
||||
* })
|
||||
* ])
|
||||
*
|
||||
* // obtain the metadata which will be embedded into
|
||||
* // and XMP tag inside the final JPEG file
|
||||
* const metadata = encodingResult.getMetadata()
|
||||
*
|
||||
* // embed the compressed images + metadata into a single
|
||||
* // JPEG file
|
||||
* const jpeg = encodeJPEGMetadata({
|
||||
* ...encodingResult,
|
||||
* ...metadata,
|
||||
* sdr,
|
||||
* gainMap
|
||||
* })
|
||||
*
|
||||
* // `jpeg` will be an `Uint8Array` which can be saved somewhere
|
||||
*
|
||||
*
|
||||
* @param encodingResult - Encoding result containing SDR image, gain map image, and metadata
|
||||
* @returns A Uint8Array representing a JPEG-R file
|
||||
* @throws {Error} If `encodingResult.sdr.mimeType !== 'image/jpeg'`
|
||||
* @throws {Error} If `encodingResult.gainMap.mimeType !== 'image/jpeg'`
|
||||
*/
|
||||
const encodeJPEGMetadata = (encodingResult) => {
|
||||
// Validate input
|
||||
if (encodingResult.sdr.mimeType !== 'image/jpeg') {
|
||||
throw new Error('This function expects an SDR image compressed in jpeg');
|
||||
}
|
||||
if (encodingResult.gainMap.mimeType !== 'image/jpeg') {
|
||||
throw new Error('This function expects a GainMap image compressed in jpeg');
|
||||
}
|
||||
// Prepare metadata with proper conversions
|
||||
// The XMP generator handles the log2 conversion internally for gain map min/max values
|
||||
const metadata = {
|
||||
version: '1.0',
|
||||
gainMapMin: encodingResult.gainMapMin,
|
||||
gainMapMax: encodingResult.gainMapMax,
|
||||
gamma: encodingResult.gamma,
|
||||
offsetSdr: encodingResult.offsetSdr,
|
||||
offsetHdr: encodingResult.offsetHdr,
|
||||
hdrCapacityMin: encodingResult.hdrCapacityMin,
|
||||
hdrCapacityMax: encodingResult.hdrCapacityMax,
|
||||
minContentBoost: Array.isArray(encodingResult.gainMapMin)
|
||||
? Math.pow(2, encodingResult.gainMapMin.reduce((a, b) => a + b, 0) / encodingResult.gainMapMin.length)
|
||||
: Math.pow(2, encodingResult.gainMapMin),
|
||||
maxContentBoost: Array.isArray(encodingResult.gainMapMax)
|
||||
? Math.pow(2, encodingResult.gainMapMax.reduce((a, b) => a + b, 0) / encodingResult.gainMapMax.length)
|
||||
: Math.pow(2, encodingResult.gainMapMax)
|
||||
};
|
||||
// Assemble the JPEG with gain map using pure JavaScript
|
||||
return assembleJpegWithGainMap({
|
||||
sdr: encodingResult.sdr,
|
||||
gainMap: encodingResult.gainMap,
|
||||
metadata
|
||||
});
|
||||
};
|
||||
|
||||
export { encodeJPEGMetadata };
|
||||
5
node_modules/@monogrid/gainmap-js/dist/libultrahdr.min.js
generated
vendored
Normal file
5
node_modules/@monogrid/gainmap-js/dist/libultrahdr.min.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
658
node_modules/@monogrid/gainmap-js/dist/libultrahdr.umd.cjs
generated
vendored
Normal file
658
node_modules/@monogrid/gainmap-js/dist/libultrahdr.umd.cjs
generated
vendored
Normal file
@@ -0,0 +1,658 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.libultrahdr = {}));
|
||||
})(this, (function (exports) { 'use strict';
|
||||
|
||||
/**
|
||||
* JPEG marker constants
|
||||
* Based on JPEG specification and libultrahdr implementation
|
||||
*/
|
||||
/**
|
||||
* JPEG marker prefix - all markers start with this byte
|
||||
*/
|
||||
const MARKER_PREFIX = 0xff;
|
||||
/**
|
||||
* JPEG markers
|
||||
*/
|
||||
const MARKERS = {
|
||||
/** Start of Image */
|
||||
SOI: 0xd8,
|
||||
/** Application segment 1 (EXIF/XMP) */
|
||||
APP1: 0xe1,
|
||||
/** Application segment 2 (ICC/MPF) */
|
||||
APP2: 0xe2,
|
||||
/** Start of Scan */
|
||||
SOS: 0xda};
|
||||
/**
|
||||
* XMP namespace identifier for APP1 marker
|
||||
*/
|
||||
const XMP_NAMESPACE = 'http://ns.adobe.com/xap/1.0/\0';
|
||||
|
||||
/**
|
||||
* Multi-Picture Format (MPF) generator
|
||||
* Based on CIPA DC-007 specification and libultrahdr multipictureformat.cpp
|
||||
*
|
||||
* MPF is used to embed multiple images in a single JPEG file
|
||||
*/
|
||||
/**
|
||||
* MPF constants from the specification
|
||||
*/
|
||||
const MPF_CONSTANTS = {
|
||||
/** MPF signature "MPF\0" */
|
||||
SIGNATURE: new Uint8Array([0x4d, 0x50, 0x46, 0x00]),
|
||||
/** Big endian marker "MM" */
|
||||
BIG_ENDIAN: new Uint8Array([0x4d, 0x4d]),
|
||||
/** TIFF magic number */
|
||||
TIFF_MAGIC: 0x002a,
|
||||
/** Number of pictures in MPF */
|
||||
NUM_PICTURES: 2,
|
||||
/** Number of tags to serialize */
|
||||
TAG_COUNT: 3,
|
||||
/** Size of each tag in bytes */
|
||||
TAG_SIZE: 12,
|
||||
/** Size of each MP entry in bytes */
|
||||
MP_ENTRY_SIZE: 16
|
||||
};
|
||||
/**
|
||||
* MPF tag identifiers
|
||||
*/
|
||||
const MPF_TAGS = {
|
||||
/** MPF version tag */
|
||||
VERSION: 0xb000,
|
||||
/** Number of images tag */
|
||||
NUMBER_OF_IMAGES: 0xb001,
|
||||
/** MP entry tag */
|
||||
MP_ENTRY: 0xb002
|
||||
};
|
||||
/**
|
||||
* MPF tag types
|
||||
*/
|
||||
const MPF_TAG_TYPES = {
|
||||
/** Undefined type */
|
||||
UNDEFINED: 7,
|
||||
/** Unsigned long type */
|
||||
ULONG: 4
|
||||
};
|
||||
/**
|
||||
* MP entry attributes
|
||||
*/
|
||||
const MP_ENTRY_ATTRIBUTES = {
|
||||
/** JPEG format */
|
||||
FORMAT_JPEG: 0x00000000,
|
||||
/** Primary image type */
|
||||
TYPE_PRIMARY: 0x20000000
|
||||
};
|
||||
/**
|
||||
* MPF version string
|
||||
*/
|
||||
const MPF_VERSION = new Uint8Array([0x30, 0x31, 0x30, 0x30]); // "0100"
|
||||
/**
|
||||
* Calculate the total size of the MPF structure
|
||||
*/
|
||||
function calculateMpfSize() {
|
||||
return (MPF_CONSTANTS.SIGNATURE.length + // Signature "MPF\0"
|
||||
2 + // Endianness marker
|
||||
2 + // TIFF magic number
|
||||
4 + // Index IFD Offset
|
||||
2 + // Tag count
|
||||
MPF_CONSTANTS.TAG_COUNT * MPF_CONSTANTS.TAG_SIZE + // Tags
|
||||
4 + // Attribute IFD offset
|
||||
MPF_CONSTANTS.NUM_PICTURES * MPF_CONSTANTS.MP_ENTRY_SIZE // MP Entries
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Generate MPF (Multi-Picture Format) data structure
|
||||
*
|
||||
* @param primaryImageSize - Size of the primary image in bytes
|
||||
* @param primaryImageOffset - Offset of the primary image (typically 0 for FII - First Individual Image)
|
||||
* @param secondaryImageSize - Size of the secondary (gain map) image in bytes
|
||||
* @param secondaryImageOffset - Offset of the secondary image from the MP Endian field
|
||||
* @returns Uint8Array containing the MPF data
|
||||
*/
|
||||
function generateMpf(primaryImageSize, primaryImageOffset, secondaryImageSize, secondaryImageOffset) {
|
||||
const mpfSize = calculateMpfSize();
|
||||
const buffer = new ArrayBuffer(mpfSize);
|
||||
const view = new DataView(buffer);
|
||||
const uint8View = new Uint8Array(buffer);
|
||||
let pos = 0;
|
||||
// Write MPF signature "MPF\0"
|
||||
uint8View.set(MPF_CONSTANTS.SIGNATURE, pos);
|
||||
pos += MPF_CONSTANTS.SIGNATURE.length;
|
||||
// Write endianness marker (big endian "MM")
|
||||
// Using big endian to match the C++ implementation's USE_BIG_ENDIAN
|
||||
uint8View.set(MPF_CONSTANTS.BIG_ENDIAN, pos);
|
||||
const bigEndian = false; // DataView uses little endian by default, so we need to flip this
|
||||
pos += 2;
|
||||
// Write TIFF magic number (0x002A)
|
||||
view.setUint16(pos, MPF_CONSTANTS.TIFF_MAGIC, bigEndian);
|
||||
pos += 2;
|
||||
// Set the Index IFD offset
|
||||
// This offset is from the start of the TIFF header (the endianness marker)
|
||||
// After: endianness (2) + magic (2) + this offset field (4) = 8 bytes
|
||||
const indexIfdOffset = 8;
|
||||
view.setUint32(pos, indexIfdOffset, bigEndian);
|
||||
pos += 4;
|
||||
// Write tag count (3 tags: version, number of images, MP entries)
|
||||
view.setUint16(pos, MPF_CONSTANTS.TAG_COUNT, bigEndian);
|
||||
pos += 2;
|
||||
// Write version tag
|
||||
view.setUint16(pos, MPF_TAGS.VERSION, bigEndian);
|
||||
pos += 2;
|
||||
view.setUint16(pos, MPF_TAG_TYPES.UNDEFINED, bigEndian);
|
||||
pos += 2;
|
||||
view.setUint32(pos, MPF_VERSION.length, bigEndian);
|
||||
pos += 4;
|
||||
uint8View.set(MPF_VERSION, pos);
|
||||
pos += 4; // Version is 4 bytes, embedded in the tag
|
||||
// Write number of images tag
|
||||
view.setUint16(pos, MPF_TAGS.NUMBER_OF_IMAGES, bigEndian);
|
||||
pos += 2;
|
||||
view.setUint16(pos, MPF_TAG_TYPES.ULONG, bigEndian);
|
||||
pos += 2;
|
||||
view.setUint32(pos, 1, bigEndian); // Count = 1
|
||||
pos += 4;
|
||||
view.setUint32(pos, MPF_CONSTANTS.NUM_PICTURES, bigEndian);
|
||||
pos += 4;
|
||||
// Write MP entry tag
|
||||
view.setUint16(pos, MPF_TAGS.MP_ENTRY, bigEndian);
|
||||
pos += 2;
|
||||
view.setUint16(pos, MPF_TAG_TYPES.UNDEFINED, bigEndian);
|
||||
pos += 2;
|
||||
view.setUint32(pos, MPF_CONSTANTS.MP_ENTRY_SIZE * MPF_CONSTANTS.NUM_PICTURES, bigEndian);
|
||||
pos += 4;
|
||||
// Calculate MP entry offset
|
||||
// The offset is from the start of the MP Endian field (after signature)
|
||||
// Current position is at the value field of MP Entry tag
|
||||
const mpEntryOffset = pos - MPF_CONSTANTS.SIGNATURE.length + 4 + 4;
|
||||
view.setUint32(pos, mpEntryOffset, bigEndian);
|
||||
pos += 4;
|
||||
// Write attribute IFD offset (0 = none)
|
||||
view.setUint32(pos, 0, bigEndian);
|
||||
pos += 4;
|
||||
// Write MP entries for primary image
|
||||
// Attribute format: JPEG (0x00000000) | Type: Primary (0x20000000)
|
||||
view.setUint32(pos, MP_ENTRY_ATTRIBUTES.FORMAT_JPEG | MP_ENTRY_ATTRIBUTES.TYPE_PRIMARY, bigEndian);
|
||||
pos += 4;
|
||||
view.setUint32(pos, primaryImageSize, bigEndian);
|
||||
pos += 4;
|
||||
view.setUint32(pos, primaryImageOffset, bigEndian);
|
||||
pos += 4;
|
||||
view.setUint16(pos, 0, bigEndian); // Dependent image 1
|
||||
pos += 2;
|
||||
view.setUint16(pos, 0, bigEndian); // Dependent image 2
|
||||
pos += 2;
|
||||
// Write MP entries for secondary image (gain map)
|
||||
// Attribute format: JPEG only (no type flag)
|
||||
view.setUint32(pos, MP_ENTRY_ATTRIBUTES.FORMAT_JPEG, bigEndian);
|
||||
pos += 4;
|
||||
view.setUint32(pos, secondaryImageSize, bigEndian);
|
||||
pos += 4;
|
||||
view.setUint32(pos, secondaryImageOffset, bigEndian);
|
||||
pos += 4;
|
||||
view.setUint16(pos, 0, bigEndian); // Dependent image 1
|
||||
pos += 2;
|
||||
view.setUint16(pos, 0, bigEndian); // Dependent image 2
|
||||
// pos += 2
|
||||
return uint8View;
|
||||
}
|
||||
|
||||
/**
|
||||
* XMP metadata generator for gain map images
|
||||
* Based on libultrahdr jpegrutils.cpp implementation
|
||||
*/
|
||||
/**
|
||||
* Item semantic types
|
||||
*/
|
||||
const ITEM_SEMANTIC = {
|
||||
PRIMARY: 'Primary',
|
||||
GAIN_MAP: 'GainMap'
|
||||
};
|
||||
/**
|
||||
* MIME type for JPEG images
|
||||
*/
|
||||
const MIME_IMAGE_JPEG = 'image/jpeg';
|
||||
/**
|
||||
* Escape XML special characters
|
||||
*/
|
||||
function escapeXml(str) {
|
||||
return String(str)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
/**
|
||||
* Generate XMP metadata for the primary image
|
||||
*
|
||||
* This XMP contains:
|
||||
* - Container directory with references to primary and gain map images
|
||||
* - Gain map version
|
||||
* - Item metadata for both images
|
||||
*
|
||||
* @param secondaryImageLength - Length of the secondary (gain map) JPEG in bytes
|
||||
* @param metadata - Gain map metadata
|
||||
* @returns XMP packet as string
|
||||
*/
|
||||
function generateXmpForPrimaryImage(secondaryImageLength, metadata) {
|
||||
const lines = [];
|
||||
// XMP packet header
|
||||
lines.push('<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>');
|
||||
lines.push('<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.1.2">');
|
||||
lines.push(' <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">');
|
||||
lines.push(' <rdf:Description');
|
||||
lines.push(' xmlns:Container="http://ns.google.com/photos/1.0/container/"');
|
||||
lines.push(' xmlns:Item="http://ns.google.com/photos/1.0/container/item/"');
|
||||
lines.push(' xmlns:hdrgm="http://ns.adobe.com/hdr-gain-map/1.0/"');
|
||||
lines.push(` hdrgm:Version="${escapeXml(metadata.version)}"`);
|
||||
lines.push(' rdf:about="">');
|
||||
// Container directory
|
||||
lines.push(' <Container:Directory>');
|
||||
lines.push(' <rdf:Seq>');
|
||||
// Primary image item
|
||||
lines.push(' <rdf:li rdf:parseType="Resource">');
|
||||
lines.push(' <Container:Item');
|
||||
lines.push(` Item:Semantic="${ITEM_SEMANTIC.PRIMARY}"`);
|
||||
lines.push(` Item:Mime="${MIME_IMAGE_JPEG}"/>`);
|
||||
lines.push(' </rdf:li>');
|
||||
// Gain map image item
|
||||
lines.push(' <rdf:li rdf:parseType="Resource">');
|
||||
lines.push(' <Container:Item');
|
||||
lines.push(` Item:Semantic="${ITEM_SEMANTIC.GAIN_MAP}"`);
|
||||
lines.push(` Item:Mime="${MIME_IMAGE_JPEG}"`);
|
||||
lines.push(` Item:Length="${secondaryImageLength}"/>`);
|
||||
lines.push(' </rdf:li>');
|
||||
lines.push(' </rdf:Seq>');
|
||||
lines.push(' </Container:Directory>');
|
||||
lines.push(' </rdf:Description>');
|
||||
lines.push(' </rdf:RDF>');
|
||||
lines.push('</x:xmpmeta>');
|
||||
lines.push('<?xpacket end="w"?>');
|
||||
return lines.join('\n');
|
||||
}
|
||||
/**
|
||||
* Generate XMP metadata for the secondary (gain map) image
|
||||
*
|
||||
* This XMP contains all the gain map parameters:
|
||||
* - Version
|
||||
* - Gain map min/max
|
||||
* - Gamma
|
||||
* - Offset SDR/HDR
|
||||
* - HDR capacity min/max
|
||||
* - Base rendition flag
|
||||
*
|
||||
* @param metadata - Gain map metadata
|
||||
* @returns XMP packet as string
|
||||
*/
|
||||
function generateXmpForSecondaryImage(metadata) {
|
||||
const lines = [];
|
||||
// hdrCapacityMin/Max are already in log2 space (from GainMapEncoderMaterial)
|
||||
// No conversion needed
|
||||
const hdrCapacityMin = metadata.hdrCapacityMin;
|
||||
const hdrCapacityMax = metadata.hdrCapacityMax;
|
||||
// Handle array values - take average if array, or use single value
|
||||
const getAverage = (val) => {
|
||||
if (Array.isArray(val)) {
|
||||
return val.reduce((sum, v) => sum + v, 0) / val.length;
|
||||
}
|
||||
return val;
|
||||
};
|
||||
const gainMapMinAvg = getAverage(metadata.gainMapMin);
|
||||
const gainMapMaxAvg = getAverage(metadata.gainMapMax);
|
||||
const gammaAvg = getAverage(metadata.gamma);
|
||||
const offsetSdrAvg = getAverage(metadata.offsetSdr);
|
||||
const offsetHdrAvg = getAverage(metadata.offsetHdr);
|
||||
// XMP packet header
|
||||
lines.push('<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>');
|
||||
lines.push('<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.1.2">');
|
||||
lines.push(' <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">');
|
||||
lines.push(' <rdf:Description');
|
||||
lines.push(' xmlns:hdrgm="http://ns.adobe.com/hdr-gain-map/1.0/"');
|
||||
lines.push(` hdrgm:Version="${escapeXml(metadata.version)}"`);
|
||||
lines.push(` hdrgm:GainMapMin="${escapeXml(gainMapMinAvg)}"`);
|
||||
lines.push(` hdrgm:GainMapMax="${escapeXml(gainMapMaxAvg)}"`);
|
||||
lines.push(` hdrgm:Gamma="${escapeXml(gammaAvg)}"`);
|
||||
lines.push(` hdrgm:OffsetSDR="${escapeXml(offsetSdrAvg)}"`);
|
||||
lines.push(` hdrgm:OffsetHDR="${escapeXml(offsetHdrAvg)}"`);
|
||||
lines.push(` hdrgm:HDRCapacityMin="${escapeXml(hdrCapacityMin)}"`);
|
||||
lines.push(` hdrgm:HDRCapacityMax="${escapeXml(hdrCapacityMax)}"`);
|
||||
lines.push(' hdrgm:BaseRenditionIsHDR="False"');
|
||||
lines.push(' rdf:about=""/>');
|
||||
lines.push(' </rdf:RDF>');
|
||||
lines.push('</x:xmpmeta>');
|
||||
lines.push('<?xpacket end="w"?>');
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* JPEG assembler for creating JPEG-R (JPEG with gain map) files
|
||||
* Based on libultrahdr jpegr.cpp implementation
|
||||
*/
|
||||
/**
|
||||
* Extract EXIF data from a JPEG if present
|
||||
*
|
||||
* @param jpegData - JPEG file data
|
||||
* @returns Object containing EXIF data and position, or null if not found
|
||||
*/
|
||||
function extractExif(jpegData) {
|
||||
const view = new DataView(jpegData.buffer, jpegData.byteOffset, jpegData.byteLength);
|
||||
// Check for JPEG SOI marker
|
||||
if (view.getUint8(0) !== MARKER_PREFIX || view.getUint8(1) !== MARKERS.SOI) {
|
||||
return null;
|
||||
}
|
||||
let offset = 2;
|
||||
const EXIF_SIGNATURE = 'Exif\0\0';
|
||||
while (offset < jpegData.length - 1) {
|
||||
// Check for marker prefix
|
||||
if (view.getUint8(offset) !== MARKER_PREFIX) {
|
||||
break;
|
||||
}
|
||||
const marker = view.getUint8(offset + 1);
|
||||
// Check for SOS (Start of Scan) - end of metadata
|
||||
if (marker === MARKERS.SOS) {
|
||||
break;
|
||||
}
|
||||
// Check for APP1 marker (EXIF/XMP)
|
||||
if (marker === MARKERS.APP1) {
|
||||
const length = view.getUint16(offset + 2, false); // Big endian
|
||||
const dataStart = offset + 4;
|
||||
// Check if this APP1 contains EXIF
|
||||
let isExif = true;
|
||||
for (let i = 0; i < EXIF_SIGNATURE.length; i++) {
|
||||
if (dataStart + i >= jpegData.length || jpegData[dataStart + i] !== EXIF_SIGNATURE.charCodeAt(i)) {
|
||||
isExif = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isExif) {
|
||||
// Found EXIF data
|
||||
const exifSize = length - 2; // Length includes the 2-byte length field itself
|
||||
const exifData = jpegData.slice(dataStart, dataStart + exifSize);
|
||||
return {
|
||||
data: exifData,
|
||||
pos: offset,
|
||||
size: length + 2 // Include marker (2 bytes) + length (2 bytes) + data
|
||||
};
|
||||
}
|
||||
}
|
||||
// Move to next marker
|
||||
const length = view.getUint16(offset + 2, false);
|
||||
offset += 2 + length;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Copy JPEG data without EXIF segment
|
||||
*
|
||||
* @param jpegData - Original JPEG data
|
||||
* @param exifPos - Position of EXIF segment
|
||||
* @param exifSize - Size of EXIF segment (including marker and length)
|
||||
* @returns JPEG data without EXIF
|
||||
*/
|
||||
function copyJpegWithoutExif(jpegData, exifPos, exifSize) {
|
||||
const newSize = jpegData.length - exifSize;
|
||||
const result = new Uint8Array(newSize);
|
||||
// Copy data before EXIF
|
||||
result.set(jpegData.subarray(0, exifPos), 0);
|
||||
// Copy data after EXIF
|
||||
result.set(jpegData.subarray(exifPos + exifSize), exifPos);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Write a JPEG marker and its data
|
||||
*
|
||||
* @param buffer - Target buffer
|
||||
* @param pos - Current position in buffer
|
||||
* @param marker - Marker type (without 0xFF prefix)
|
||||
* @param data - Data to write after marker
|
||||
* @returns New position after writing
|
||||
*/
|
||||
function writeMarker(buffer, pos, marker, data) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
||||
// Write marker
|
||||
view.setUint8(pos++, MARKER_PREFIX);
|
||||
view.setUint8(pos++, marker);
|
||||
// Write data if present
|
||||
if (data && data.length > 0) {
|
||||
// Write length (big endian, includes the 2-byte length field itself)
|
||||
const length = data.length + 2;
|
||||
view.setUint16(pos, length, false);
|
||||
pos += 2;
|
||||
// Write data
|
||||
buffer.set(data, pos);
|
||||
pos += data.length;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
/**
|
||||
* Assemble a JPEG-R file (JPEG with embedded gain map)
|
||||
*
|
||||
* The structure is:
|
||||
* 1. Primary image:
|
||||
* - SOI
|
||||
* - APP1 (EXIF if present)
|
||||
* - APP1 (XMP with gain map metadata)
|
||||
* - APP2 (ICC profile if present)
|
||||
* - APP2 (MPF data)
|
||||
* - Rest of primary JPEG data
|
||||
* 2. Secondary image (gain map):
|
||||
* - SOI
|
||||
* - APP1 (XMP with gain map parameters)
|
||||
* - Rest of gain map JPEG data
|
||||
*
|
||||
* @param options - Assembly options
|
||||
* @returns Complete JPEG-R file as Uint8Array
|
||||
*/
|
||||
function assembleJpegWithGainMap(options) {
|
||||
const { sdr, gainMap, metadata, exif: externalExif, icc } = options;
|
||||
// Validate input
|
||||
if (sdr.mimeType !== 'image/jpeg') {
|
||||
throw new Error('SDR image must be JPEG format');
|
||||
}
|
||||
if (gainMap.mimeType !== 'image/jpeg') {
|
||||
throw new Error('Gain map image must be JPEG format');
|
||||
}
|
||||
// Check for EXIF in primary image
|
||||
const exifFromJpeg = extractExif(sdr.data);
|
||||
if (exifFromJpeg && externalExif) {
|
||||
throw new Error('Primary image already contains EXIF data, cannot add external EXIF');
|
||||
}
|
||||
// Prepare primary JPEG (remove embedded EXIF if present)
|
||||
let primaryJpegData = sdr.data;
|
||||
let exifData = externalExif;
|
||||
if (exifFromJpeg) {
|
||||
primaryJpegData = copyJpegWithoutExif(sdr.data, exifFromJpeg.pos, exifFromJpeg.size);
|
||||
exifData = exifFromJpeg.data;
|
||||
}
|
||||
// Generate XMP for secondary image
|
||||
const xmpSecondary = generateXmpForSecondaryImage(metadata);
|
||||
const xmpSecondaryBytes = new TextEncoder().encode(xmpSecondary);
|
||||
// Calculate secondary image size
|
||||
// 2 bytes SOI + 2 bytes marker + 2 bytes length field + namespace + XMP data + gain map data (without SOI)
|
||||
const namespaceBytes = new TextEncoder().encode(XMP_NAMESPACE);
|
||||
const secondaryImageSize = 2 + 2 + 2 + namespaceBytes.length + xmpSecondaryBytes.length + (gainMap.data.length - 2);
|
||||
// Generate XMP for primary image
|
||||
const xmpPrimary = generateXmpForPrimaryImage(secondaryImageSize, metadata);
|
||||
const xmpPrimaryBytes = new TextEncoder().encode(xmpPrimary);
|
||||
const xmpPrimaryData = new Uint8Array(namespaceBytes.length + xmpPrimaryBytes.length);
|
||||
xmpPrimaryData.set(namespaceBytes, 0);
|
||||
xmpPrimaryData.set(xmpPrimaryBytes, namespaceBytes.length);
|
||||
// Calculate MPF size and offset
|
||||
const mpfLength = calculateMpfSize();
|
||||
// Calculate total size
|
||||
let totalSize = 2; // SOI
|
||||
if (exifData)
|
||||
totalSize += 2 + 2 + exifData.length; // APP1 + length + EXIF
|
||||
totalSize += 2 + 2 + xmpPrimaryData.length; // APP1 + length + XMP primary
|
||||
if (icc)
|
||||
totalSize += 2 + 2 + icc.length; // APP2 + length + ICC
|
||||
totalSize += 2 + 2 + mpfLength; // APP2 + length + MPF
|
||||
totalSize += primaryJpegData.length - 2; // Primary JPEG without SOI
|
||||
totalSize += secondaryImageSize; // Secondary image
|
||||
// Calculate offsets for MPF
|
||||
const primaryImageSize = totalSize - secondaryImageSize;
|
||||
// Offset is from MP Endian field (after APP2 marker + length + MPF signature)
|
||||
const secondaryImageOffset = primaryImageSize - (2 + // SOI
|
||||
(exifData ? 2 + 2 + exifData.length : 0) +
|
||||
2 + 2 + xmpPrimaryData.length +
|
||||
(icc ? 2 + 2 + icc.length : 0) +
|
||||
2 + 2 + 4 // APP2 marker + length + MPF signature
|
||||
);
|
||||
// Generate MPF data
|
||||
const mpfDataActual = generateMpf(primaryImageSize, 0, secondaryImageSize, secondaryImageOffset);
|
||||
// Allocate output buffer
|
||||
const output = new Uint8Array(totalSize);
|
||||
let pos = 0;
|
||||
// === PRIMARY IMAGE ===
|
||||
// Write SOI
|
||||
pos = writeMarker(output, pos, MARKERS.SOI);
|
||||
// Write EXIF if present
|
||||
if (exifData) {
|
||||
pos = writeMarker(output, pos, MARKERS.APP1, exifData);
|
||||
}
|
||||
// Write XMP for primary image (already created above)
|
||||
pos = writeMarker(output, pos, MARKERS.APP1, xmpPrimaryData);
|
||||
// Write ICC profile if present
|
||||
if (icc) {
|
||||
pos = writeMarker(output, pos, MARKERS.APP2, icc);
|
||||
}
|
||||
// Write MPF
|
||||
pos = writeMarker(output, pos, MARKERS.APP2, mpfDataActual);
|
||||
// Write rest of primary JPEG (skip SOI)
|
||||
output.set(primaryJpegData.subarray(2), pos);
|
||||
pos += primaryJpegData.length - 2;
|
||||
// === SECONDARY IMAGE (GAIN MAP) ===
|
||||
// Write SOI
|
||||
pos = writeMarker(output, pos, MARKERS.SOI);
|
||||
// Write XMP for secondary image
|
||||
const xmpSecondaryData = new Uint8Array(namespaceBytes.length + xmpSecondaryBytes.length);
|
||||
xmpSecondaryData.set(namespaceBytes, 0);
|
||||
xmpSecondaryData.set(xmpSecondaryBytes, namespaceBytes.length);
|
||||
pos = writeMarker(output, pos, MARKERS.APP1, xmpSecondaryData);
|
||||
// Write rest of gain map JPEG (skip SOI)
|
||||
output.set(gainMap.data.subarray(2), pos);
|
||||
// pos += gainMap.data.length - 2
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates a Gainmap into a single JPEG file (aka: JPEG-R) with the base map
|
||||
* as the sdr visualization and the gainMap encoded into a MPF (Multi-Picture Format) tag.
|
||||
*
|
||||
* @category Encoding
|
||||
* @group Encoding
|
||||
*
|
||||
* @example
|
||||
* import { compress, encode, findTextureMinMax } from '@monogrid/gainmap-js'
|
||||
* import { encodeJPEGMetadata } from '@monogrid/gainmap-js/libultrahdr'
|
||||
* import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js'
|
||||
*
|
||||
* // load an HDR file
|
||||
* const loader = new EXRLoader()
|
||||
* const image = await loader.loadAsync('image.exr')
|
||||
*
|
||||
* // find RAW RGB Max value of a texture
|
||||
* const textureMax = findTextureMinMax(image)
|
||||
*
|
||||
* // Encode the gainmap
|
||||
* const encodingResult = encode({
|
||||
* image,
|
||||
* maxContentBoost: Math.max.apply(this, textureMax)
|
||||
* })
|
||||
*
|
||||
* // obtain the RAW RGBA SDR buffer and create an ImageData
|
||||
* const sdrImageData = new ImageData(
|
||||
* encodingResult.sdr.toArray(),
|
||||
* encodingResult.sdr.width,
|
||||
* encodingResult.sdr.height
|
||||
* )
|
||||
* // obtain the RAW RGBA Gain map buffer and create an ImageData
|
||||
* const gainMapImageData = new ImageData(
|
||||
* encodingResult.gainMap.toArray(),
|
||||
* encodingResult.gainMap.width,
|
||||
* encodingResult.gainMap.height
|
||||
* )
|
||||
*
|
||||
* // parallel compress the RAW buffers into the specified mimeType
|
||||
* const mimeType = 'image/jpeg'
|
||||
* const quality = 0.9
|
||||
*
|
||||
* const [sdr, gainMap] = await Promise.all([
|
||||
* compress({
|
||||
* source: sdrImageData,
|
||||
* mimeType,
|
||||
* quality,
|
||||
* flipY: true // output needs to be flipped
|
||||
* }),
|
||||
* compress({
|
||||
* source: gainMapImageData,
|
||||
* mimeType,
|
||||
* quality,
|
||||
* flipY: true // output needs to be flipped
|
||||
* })
|
||||
* ])
|
||||
*
|
||||
* // obtain the metadata which will be embedded into
|
||||
* // and XMP tag inside the final JPEG file
|
||||
* const metadata = encodingResult.getMetadata()
|
||||
*
|
||||
* // embed the compressed images + metadata into a single
|
||||
* // JPEG file
|
||||
* const jpeg = encodeJPEGMetadata({
|
||||
* ...encodingResult,
|
||||
* ...metadata,
|
||||
* sdr,
|
||||
* gainMap
|
||||
* })
|
||||
*
|
||||
* // `jpeg` will be an `Uint8Array` which can be saved somewhere
|
||||
*
|
||||
*
|
||||
* @param encodingResult - Encoding result containing SDR image, gain map image, and metadata
|
||||
* @returns A Uint8Array representing a JPEG-R file
|
||||
* @throws {Error} If `encodingResult.sdr.mimeType !== 'image/jpeg'`
|
||||
* @throws {Error} If `encodingResult.gainMap.mimeType !== 'image/jpeg'`
|
||||
*/
|
||||
const encodeJPEGMetadata = (encodingResult) => {
|
||||
// Validate input
|
||||
if (encodingResult.sdr.mimeType !== 'image/jpeg') {
|
||||
throw new Error('This function expects an SDR image compressed in jpeg');
|
||||
}
|
||||
if (encodingResult.gainMap.mimeType !== 'image/jpeg') {
|
||||
throw new Error('This function expects a GainMap image compressed in jpeg');
|
||||
}
|
||||
// Prepare metadata with proper conversions
|
||||
// The XMP generator handles the log2 conversion internally for gain map min/max values
|
||||
const metadata = {
|
||||
version: '1.0',
|
||||
gainMapMin: encodingResult.gainMapMin,
|
||||
gainMapMax: encodingResult.gainMapMax,
|
||||
gamma: encodingResult.gamma,
|
||||
offsetSdr: encodingResult.offsetSdr,
|
||||
offsetHdr: encodingResult.offsetHdr,
|
||||
hdrCapacityMin: encodingResult.hdrCapacityMin,
|
||||
hdrCapacityMax: encodingResult.hdrCapacityMax,
|
||||
minContentBoost: Array.isArray(encodingResult.gainMapMin)
|
||||
? Math.pow(2, encodingResult.gainMapMin.reduce((a, b) => a + b, 0) / encodingResult.gainMapMin.length)
|
||||
: Math.pow(2, encodingResult.gainMapMin),
|
||||
maxContentBoost: Array.isArray(encodingResult.gainMapMax)
|
||||
? Math.pow(2, encodingResult.gainMapMax.reduce((a, b) => a + b, 0) / encodingResult.gainMapMax.length)
|
||||
: Math.pow(2, encodingResult.gainMapMax)
|
||||
};
|
||||
// Assemble the JPEG with gain map using pure JavaScript
|
||||
return assembleJpegWithGainMap({
|
||||
sdr: encodingResult.sdr,
|
||||
gainMap: encodingResult.gainMap,
|
||||
metadata
|
||||
});
|
||||
};
|
||||
|
||||
exports.encodeJPEGMetadata = encodeJPEGMetadata;
|
||||
|
||||
}));
|
||||
5
node_modules/@monogrid/gainmap-js/dist/libultrahdr.umd.min.cjs
generated
vendored
Normal file
5
node_modules/@monogrid/gainmap-js/dist/libultrahdr.umd.min.cjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
84
node_modules/@monogrid/gainmap-js/dist/libultrahdr/encode-jpeg-metadata.d.ts
generated
vendored
Normal file
84
node_modules/@monogrid/gainmap-js/dist/libultrahdr/encode-jpeg-metadata.d.ts
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
import { GainMapMetadata } from '../core/types';
|
||||
import { type CompressedImage } from '../encode/types';
|
||||
/**
|
||||
* Encapsulates a Gainmap into a single JPEG file (aka: JPEG-R) with the base map
|
||||
* as the sdr visualization and the gainMap encoded into a MPF (Multi-Picture Format) tag.
|
||||
*
|
||||
* @category Encoding
|
||||
* @group Encoding
|
||||
*
|
||||
* @example
|
||||
* import { compress, encode, findTextureMinMax } from '@monogrid/gainmap-js'
|
||||
* import { encodeJPEGMetadata } from '@monogrid/gainmap-js/libultrahdr'
|
||||
* import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js'
|
||||
*
|
||||
* // load an HDR file
|
||||
* const loader = new EXRLoader()
|
||||
* const image = await loader.loadAsync('image.exr')
|
||||
*
|
||||
* // find RAW RGB Max value of a texture
|
||||
* const textureMax = findTextureMinMax(image)
|
||||
*
|
||||
* // Encode the gainmap
|
||||
* const encodingResult = encode({
|
||||
* image,
|
||||
* maxContentBoost: Math.max.apply(this, textureMax)
|
||||
* })
|
||||
*
|
||||
* // obtain the RAW RGBA SDR buffer and create an ImageData
|
||||
* const sdrImageData = new ImageData(
|
||||
* encodingResult.sdr.toArray(),
|
||||
* encodingResult.sdr.width,
|
||||
* encodingResult.sdr.height
|
||||
* )
|
||||
* // obtain the RAW RGBA Gain map buffer and create an ImageData
|
||||
* const gainMapImageData = new ImageData(
|
||||
* encodingResult.gainMap.toArray(),
|
||||
* encodingResult.gainMap.width,
|
||||
* encodingResult.gainMap.height
|
||||
* )
|
||||
*
|
||||
* // parallel compress the RAW buffers into the specified mimeType
|
||||
* const mimeType = 'image/jpeg'
|
||||
* const quality = 0.9
|
||||
*
|
||||
* const [sdr, gainMap] = await Promise.all([
|
||||
* compress({
|
||||
* source: sdrImageData,
|
||||
* mimeType,
|
||||
* quality,
|
||||
* flipY: true // output needs to be flipped
|
||||
* }),
|
||||
* compress({
|
||||
* source: gainMapImageData,
|
||||
* mimeType,
|
||||
* quality,
|
||||
* flipY: true // output needs to be flipped
|
||||
* })
|
||||
* ])
|
||||
*
|
||||
* // obtain the metadata which will be embedded into
|
||||
* // and XMP tag inside the final JPEG file
|
||||
* const metadata = encodingResult.getMetadata()
|
||||
*
|
||||
* // embed the compressed images + metadata into a single
|
||||
* // JPEG file
|
||||
* const jpeg = encodeJPEGMetadata({
|
||||
* ...encodingResult,
|
||||
* ...metadata,
|
||||
* sdr,
|
||||
* gainMap
|
||||
* })
|
||||
*
|
||||
* // `jpeg` will be an `Uint8Array` which can be saved somewhere
|
||||
*
|
||||
*
|
||||
* @param encodingResult - Encoding result containing SDR image, gain map image, and metadata
|
||||
* @returns A Uint8Array representing a JPEG-R file
|
||||
* @throws {Error} If `encodingResult.sdr.mimeType !== 'image/jpeg'`
|
||||
* @throws {Error} If `encodingResult.gainMap.mimeType !== 'image/jpeg'`
|
||||
*/
|
||||
export declare const encodeJPEGMetadata: (encodingResult: GainMapMetadata & {
|
||||
sdr: CompressedImage;
|
||||
gainMap: CompressedImage;
|
||||
}) => Uint8Array<ArrayBuffer>;
|
||||
41
node_modules/@monogrid/gainmap-js/dist/libultrahdr/jpeg-assembler.d.ts
generated
vendored
Normal file
41
node_modules/@monogrid/gainmap-js/dist/libultrahdr/jpeg-assembler.d.ts
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* JPEG assembler for creating JPEG-R (JPEG with gain map) files
|
||||
* Based on libultrahdr jpegr.cpp implementation
|
||||
*/
|
||||
import { GainMapMetadataExtended } from '../core/types';
|
||||
import { type CompressedImage } from '../encode/types';
|
||||
/**
|
||||
* Options for assembling a JPEG with gain map
|
||||
*/
|
||||
export interface AssembleJpegOptions {
|
||||
/** Primary (SDR) JPEG image */
|
||||
sdr: CompressedImage;
|
||||
/** Gain map JPEG image */
|
||||
gainMap: CompressedImage;
|
||||
/** Gain map metadata */
|
||||
metadata: GainMapMetadataExtended;
|
||||
/** Optional EXIF data to embed */
|
||||
exif?: Uint8Array<ArrayBuffer>;
|
||||
/** Optional ICC color profile */
|
||||
icc?: Uint8Array<ArrayBuffer>;
|
||||
}
|
||||
/**
|
||||
* Assemble a JPEG-R file (JPEG with embedded gain map)
|
||||
*
|
||||
* The structure is:
|
||||
* 1. Primary image:
|
||||
* - SOI
|
||||
* - APP1 (EXIF if present)
|
||||
* - APP1 (XMP with gain map metadata)
|
||||
* - APP2 (ICC profile if present)
|
||||
* - APP2 (MPF data)
|
||||
* - Rest of primary JPEG data
|
||||
* 2. Secondary image (gain map):
|
||||
* - SOI
|
||||
* - APP1 (XMP with gain map parameters)
|
||||
* - Rest of gain map JPEG data
|
||||
*
|
||||
* @param options - Assembly options
|
||||
* @returns Complete JPEG-R file as Uint8Array
|
||||
*/
|
||||
export declare function assembleJpegWithGainMap(options: AssembleJpegOptions): Uint8Array<ArrayBuffer>;
|
||||
47
node_modules/@monogrid/gainmap-js/dist/libultrahdr/jpeg-markers.d.ts
generated
vendored
Normal file
47
node_modules/@monogrid/gainmap-js/dist/libultrahdr/jpeg-markers.d.ts
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* JPEG marker constants
|
||||
* Based on JPEG specification and libultrahdr implementation
|
||||
*/
|
||||
/**
|
||||
* JPEG marker prefix - all markers start with this byte
|
||||
*/
|
||||
export declare const MARKER_PREFIX = 255;
|
||||
/**
|
||||
* JPEG markers
|
||||
*/
|
||||
export declare const MARKERS: {
|
||||
/** Start of Image */
|
||||
readonly SOI: 216;
|
||||
/** End of Image */
|
||||
readonly EOI: 217;
|
||||
/** Application segment 0 */
|
||||
readonly APP0: 224;
|
||||
/** Application segment 1 (EXIF/XMP) */
|
||||
readonly APP1: 225;
|
||||
/** Application segment 2 (ICC/MPF) */
|
||||
readonly APP2: 226;
|
||||
/** Start of Scan */
|
||||
readonly SOS: 218;
|
||||
/** Define Quantization Table */
|
||||
readonly DQT: 219;
|
||||
/** Define Huffman Table */
|
||||
readonly DHT: 196;
|
||||
/** Start of Frame (baseline DCT) */
|
||||
readonly SOF0: 192;
|
||||
};
|
||||
/**
|
||||
* XMP namespace identifier for APP1 marker
|
||||
*/
|
||||
export declare const XMP_NAMESPACE = "http://ns.adobe.com/xap/1.0/\0";
|
||||
/**
|
||||
* EXIF identifier for APP1 marker
|
||||
*/
|
||||
export declare const EXIF_IDENTIFIER = "Exif\0\0";
|
||||
/**
|
||||
* MPF signature for APP2 marker
|
||||
*/
|
||||
export declare const MPF_SIGNATURE = "MPF\0";
|
||||
/**
|
||||
* ICC profile identifier for APP2 marker
|
||||
*/
|
||||
export declare const ICC_IDENTIFIER = "ICC_PROFILE\0";
|
||||
20
node_modules/@monogrid/gainmap-js/dist/libultrahdr/mpf-generator.d.ts
generated
vendored
Normal file
20
node_modules/@monogrid/gainmap-js/dist/libultrahdr/mpf-generator.d.ts
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Multi-Picture Format (MPF) generator
|
||||
* Based on CIPA DC-007 specification and libultrahdr multipictureformat.cpp
|
||||
*
|
||||
* MPF is used to embed multiple images in a single JPEG file
|
||||
*/
|
||||
/**
|
||||
* Calculate the total size of the MPF structure
|
||||
*/
|
||||
export declare function calculateMpfSize(): number;
|
||||
/**
|
||||
* Generate MPF (Multi-Picture Format) data structure
|
||||
*
|
||||
* @param primaryImageSize - Size of the primary image in bytes
|
||||
* @param primaryImageOffset - Offset of the primary image (typically 0 for FII - First Individual Image)
|
||||
* @param secondaryImageSize - Size of the secondary (gain map) image in bytes
|
||||
* @param secondaryImageOffset - Offset of the secondary image from the MP Endian field
|
||||
* @returns Uint8Array containing the MPF data
|
||||
*/
|
||||
export declare function generateMpf(primaryImageSize: number, primaryImageOffset: number, secondaryImageSize: number, secondaryImageOffset: number): Uint8Array<ArrayBuffer>;
|
||||
33
node_modules/@monogrid/gainmap-js/dist/libultrahdr/xmp-generator.d.ts
generated
vendored
Normal file
33
node_modules/@monogrid/gainmap-js/dist/libultrahdr/xmp-generator.d.ts
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* XMP metadata generator for gain map images
|
||||
* Based on libultrahdr jpegrutils.cpp implementation
|
||||
*/
|
||||
import { type GainMapMetadataExtended } from '../core/types';
|
||||
/**
|
||||
* Generate XMP metadata for the primary image
|
||||
*
|
||||
* This XMP contains:
|
||||
* - Container directory with references to primary and gain map images
|
||||
* - Gain map version
|
||||
* - Item metadata for both images
|
||||
*
|
||||
* @param secondaryImageLength - Length of the secondary (gain map) JPEG in bytes
|
||||
* @param metadata - Gain map metadata
|
||||
* @returns XMP packet as string
|
||||
*/
|
||||
export declare function generateXmpForPrimaryImage(secondaryImageLength: number, metadata: GainMapMetadataExtended): string;
|
||||
/**
|
||||
* Generate XMP metadata for the secondary (gain map) image
|
||||
*
|
||||
* This XMP contains all the gain map parameters:
|
||||
* - Version
|
||||
* - Gain map min/max
|
||||
* - Gamma
|
||||
* - Offset SDR/HDR
|
||||
* - HDR capacity min/max
|
||||
* - Base rendition flag
|
||||
*
|
||||
* @param metadata - Gain map metadata
|
||||
* @returns XMP packet as string
|
||||
*/
|
||||
export declare function generateXmpForSecondaryImage(metadata: GainMapMetadataExtended): string;
|
||||
301
node_modules/@monogrid/gainmap-js/dist/third-party.txt
generated
vendored
Normal file
301
node_modules/@monogrid/gainmap-js/dist/third-party.txt
generated
vendored
Normal file
@@ -0,0 +1,301 @@
|
||||
Name: is-promise
|
||||
Version: 2.2.2
|
||||
License: MIT
|
||||
Private: false
|
||||
Description: Test whether an object looks like a promises-a+ promise
|
||||
Repository: https://github.com/then/is-promise.git
|
||||
Author: ForbesLindesay
|
||||
License Copyright:
|
||||
===
|
||||
|
||||
Copyright (c) 2014 Forbes Lindesay
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
---
|
||||
|
||||
Name: promise-worker-transferable
|
||||
Version: 1.0.4
|
||||
License: Apache-2.0
|
||||
Private: false
|
||||
Description: Communicate with a Web Worker using Promises, allowing transferList
|
||||
Repository: git+https://github.com/terikon/promise-worker-transferable.git
|
||||
Homepage: https://github.com/terikon/promise-worker-transferable#readme
|
||||
Author: Roman Viskin <npm@terikon.com>
|
||||
License Copyright:
|
||||
===
|
||||
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
---
|
||||
|
||||
Name: immediate
|
||||
Version: 3.0.6
|
||||
License: MIT
|
||||
Private: false
|
||||
Description: A cross browser microtask library
|
||||
Repository: git://github.com/calvinmetcalf/immediate.git
|
||||
Contributors:
|
||||
Domenic Denicola <domenic@domenicdenicola.com> (http://domenicdenicola.com)
|
||||
Donavon West <github@donavon.com> (http://donavon.com)
|
||||
Yaffle
|
||||
Calvin Metcalf <calvin.metcalf@gmail.com>
|
||||
License Copyright:
|
||||
===
|
||||
|
||||
Copyright (c) 2012 Barnesandnoble.com, llc, Donavon West, Domenic Denicola, Brian Cavalier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
---
|
||||
|
||||
Name: lie
|
||||
Version: 3.3.0
|
||||
License: MIT
|
||||
Private: false
|
||||
Description: A basic but performant promise implementation
|
||||
Repository: https://github.com/calvinmetcalf/lie.git
|
||||
License Copyright:
|
||||
===
|
||||
|
||||
#Copyright (c) 2014-2018 Calvin Metcalf, Jordan Harband
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
**THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.**
|
||||
26
node_modules/@monogrid/gainmap-js/dist/worker-interface.d.ts
generated
vendored
Normal file
26
node_modules/@monogrid/gainmap-js/dist/worker-interface.d.ts
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
import { type PromiseWorkerType, type WorkerInterfaceImplementation } from './worker-types';
|
||||
export * from './worker-types';
|
||||
/**
|
||||
* Wraps a Regular worker into a `PromiseWorker`
|
||||
*
|
||||
* @param worker
|
||||
* @returns
|
||||
*/
|
||||
export declare const getPromiseWorker: (worker: Worker) => PromiseWorkerType;
|
||||
/**
|
||||
* Returns an interface where methods of the worker can be called by the host site
|
||||
*
|
||||
* @example
|
||||
* // this assumes a vite-like bundler understands the `?worker` import
|
||||
* import GainMapWorker from '@monogrid/gainmap-js/worker?worker'
|
||||
* import { getPromiseWorker, getWorkerInterface } from '@monogrid/gainmap-js/worker-interface'
|
||||
*
|
||||
* // turn our Worker into a PromiseWorker
|
||||
* const promiseWorker = getPromiseWorker(new GainMapWorker())
|
||||
* // get the interface
|
||||
* const workerInterface = getWorkerInterface(promiseWorker)
|
||||
*
|
||||
* @param worker
|
||||
* @returns
|
||||
*/
|
||||
export declare const getWorkerInterface: (worker: PromiseWorkerType) => WorkerInterfaceImplementation;
|
||||
512
node_modules/@monogrid/gainmap-js/dist/worker-interface.js
generated
vendored
Normal file
512
node_modules/@monogrid/gainmap-js/dist/worker-interface.js
generated
vendored
Normal file
@@ -0,0 +1,512 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
|
||||
import { c as commonjsGlobal, g as getDefaultExportFromCjs } from './_commonjsHelpers-v3qvwW2J.js';
|
||||
|
||||
var lib$1;
|
||||
var hasRequiredLib$1;
|
||||
|
||||
function requireLib$1 () {
|
||||
if (hasRequiredLib$1) return lib$1;
|
||||
hasRequiredLib$1 = 1;
|
||||
var Mutation = commonjsGlobal.MutationObserver || commonjsGlobal.WebKitMutationObserver;
|
||||
|
||||
var scheduleDrain;
|
||||
|
||||
if (process.browser) {
|
||||
if (Mutation) {
|
||||
var called = 0;
|
||||
var observer = new Mutation(nextTick);
|
||||
var element = commonjsGlobal.document.createTextNode('');
|
||||
observer.observe(element, {
|
||||
characterData: true
|
||||
});
|
||||
scheduleDrain = function () {
|
||||
element.data = (called = ++called % 2);
|
||||
};
|
||||
} else if (!commonjsGlobal.setImmediate && typeof commonjsGlobal.MessageChannel !== 'undefined') {
|
||||
var channel = new commonjsGlobal.MessageChannel();
|
||||
channel.port1.onmessage = nextTick;
|
||||
scheduleDrain = function () {
|
||||
channel.port2.postMessage(0);
|
||||
};
|
||||
} else if ('document' in commonjsGlobal && 'onreadystatechange' in commonjsGlobal.document.createElement('script')) {
|
||||
scheduleDrain = function () {
|
||||
|
||||
// Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
|
||||
// into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
|
||||
var scriptEl = commonjsGlobal.document.createElement('script');
|
||||
scriptEl.onreadystatechange = function () {
|
||||
nextTick();
|
||||
|
||||
scriptEl.onreadystatechange = null;
|
||||
scriptEl.parentNode.removeChild(scriptEl);
|
||||
scriptEl = null;
|
||||
};
|
||||
commonjsGlobal.document.documentElement.appendChild(scriptEl);
|
||||
};
|
||||
} else {
|
||||
scheduleDrain = function () {
|
||||
setTimeout(nextTick, 0);
|
||||
};
|
||||
}
|
||||
} else {
|
||||
scheduleDrain = function () {
|
||||
process.nextTick(nextTick);
|
||||
};
|
||||
}
|
||||
|
||||
var draining;
|
||||
var queue = [];
|
||||
//named nextTick for less confusing stack traces
|
||||
function nextTick() {
|
||||
draining = true;
|
||||
var i, oldQueue;
|
||||
var len = queue.length;
|
||||
while (len) {
|
||||
oldQueue = queue;
|
||||
queue = [];
|
||||
i = -1;
|
||||
while (++i < len) {
|
||||
oldQueue[i]();
|
||||
}
|
||||
len = queue.length;
|
||||
}
|
||||
draining = false;
|
||||
}
|
||||
|
||||
lib$1 = immediate;
|
||||
function immediate(task) {
|
||||
if (queue.push(task) === 1 && !draining) {
|
||||
scheduleDrain();
|
||||
}
|
||||
}
|
||||
return lib$1;
|
||||
}
|
||||
|
||||
var lib;
|
||||
var hasRequiredLib;
|
||||
|
||||
function requireLib () {
|
||||
if (hasRequiredLib) return lib;
|
||||
hasRequiredLib = 1;
|
||||
var immediate = requireLib$1();
|
||||
|
||||
/* istanbul ignore next */
|
||||
function INTERNAL() {}
|
||||
|
||||
var handlers = {};
|
||||
|
||||
var REJECTED = ['REJECTED'];
|
||||
var FULFILLED = ['FULFILLED'];
|
||||
var PENDING = ['PENDING'];
|
||||
/* istanbul ignore else */
|
||||
if (!process.browser) {
|
||||
// in which we actually take advantage of JS scoping
|
||||
var UNHANDLED = ['UNHANDLED'];
|
||||
}
|
||||
|
||||
lib = Promise;
|
||||
|
||||
function Promise(resolver) {
|
||||
if (typeof resolver !== 'function') {
|
||||
throw new TypeError('resolver must be a function');
|
||||
}
|
||||
this.state = PENDING;
|
||||
this.queue = [];
|
||||
this.outcome = void 0;
|
||||
/* istanbul ignore else */
|
||||
if (!process.browser) {
|
||||
this.handled = UNHANDLED;
|
||||
}
|
||||
if (resolver !== INTERNAL) {
|
||||
safelyResolveThenable(this, resolver);
|
||||
}
|
||||
}
|
||||
|
||||
Promise.prototype.finally = function (callback) {
|
||||
if (typeof callback !== 'function') {
|
||||
return this;
|
||||
}
|
||||
var p = this.constructor;
|
||||
return this.then(resolve, reject);
|
||||
|
||||
function resolve(value) {
|
||||
function yes () {
|
||||
return value;
|
||||
}
|
||||
return p.resolve(callback()).then(yes);
|
||||
}
|
||||
function reject(reason) {
|
||||
function no () {
|
||||
throw reason;
|
||||
}
|
||||
return p.resolve(callback()).then(no);
|
||||
}
|
||||
};
|
||||
Promise.prototype.catch = function (onRejected) {
|
||||
return this.then(null, onRejected);
|
||||
};
|
||||
Promise.prototype.then = function (onFulfilled, onRejected) {
|
||||
if (typeof onFulfilled !== 'function' && this.state === FULFILLED ||
|
||||
typeof onRejected !== 'function' && this.state === REJECTED) {
|
||||
return this;
|
||||
}
|
||||
var promise = new this.constructor(INTERNAL);
|
||||
/* istanbul ignore else */
|
||||
if (!process.browser) {
|
||||
if (this.handled === UNHANDLED) {
|
||||
this.handled = null;
|
||||
}
|
||||
}
|
||||
if (this.state !== PENDING) {
|
||||
var resolver = this.state === FULFILLED ? onFulfilled : onRejected;
|
||||
unwrap(promise, resolver, this.outcome);
|
||||
} else {
|
||||
this.queue.push(new QueueItem(promise, onFulfilled, onRejected));
|
||||
}
|
||||
|
||||
return promise;
|
||||
};
|
||||
function QueueItem(promise, onFulfilled, onRejected) {
|
||||
this.promise = promise;
|
||||
if (typeof onFulfilled === 'function') {
|
||||
this.onFulfilled = onFulfilled;
|
||||
this.callFulfilled = this.otherCallFulfilled;
|
||||
}
|
||||
if (typeof onRejected === 'function') {
|
||||
this.onRejected = onRejected;
|
||||
this.callRejected = this.otherCallRejected;
|
||||
}
|
||||
}
|
||||
QueueItem.prototype.callFulfilled = function (value) {
|
||||
handlers.resolve(this.promise, value);
|
||||
};
|
||||
QueueItem.prototype.otherCallFulfilled = function (value) {
|
||||
unwrap(this.promise, this.onFulfilled, value);
|
||||
};
|
||||
QueueItem.prototype.callRejected = function (value) {
|
||||
handlers.reject(this.promise, value);
|
||||
};
|
||||
QueueItem.prototype.otherCallRejected = function (value) {
|
||||
unwrap(this.promise, this.onRejected, value);
|
||||
};
|
||||
|
||||
function unwrap(promise, func, value) {
|
||||
immediate(function () {
|
||||
var returnValue;
|
||||
try {
|
||||
returnValue = func(value);
|
||||
} catch (e) {
|
||||
return handlers.reject(promise, e);
|
||||
}
|
||||
if (returnValue === promise) {
|
||||
handlers.reject(promise, new TypeError('Cannot resolve promise with itself'));
|
||||
} else {
|
||||
handlers.resolve(promise, returnValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handlers.resolve = function (self, value) {
|
||||
var result = tryCatch(getThen, value);
|
||||
if (result.status === 'error') {
|
||||
return handlers.reject(self, result.value);
|
||||
}
|
||||
var thenable = result.value;
|
||||
|
||||
if (thenable) {
|
||||
safelyResolveThenable(self, thenable);
|
||||
} else {
|
||||
self.state = FULFILLED;
|
||||
self.outcome = value;
|
||||
var i = -1;
|
||||
var len = self.queue.length;
|
||||
while (++i < len) {
|
||||
self.queue[i].callFulfilled(value);
|
||||
}
|
||||
}
|
||||
return self;
|
||||
};
|
||||
handlers.reject = function (self, error) {
|
||||
self.state = REJECTED;
|
||||
self.outcome = error;
|
||||
/* istanbul ignore else */
|
||||
if (!process.browser) {
|
||||
if (self.handled === UNHANDLED) {
|
||||
immediate(function () {
|
||||
if (self.handled === UNHANDLED) {
|
||||
process.emit('unhandledRejection', error, self);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
var i = -1;
|
||||
var len = self.queue.length;
|
||||
while (++i < len) {
|
||||
self.queue[i].callRejected(error);
|
||||
}
|
||||
return self;
|
||||
};
|
||||
|
||||
function getThen(obj) {
|
||||
// Make sure we only access the accessor once as required by the spec
|
||||
var then = obj && obj.then;
|
||||
if (obj && (typeof obj === 'object' || typeof obj === 'function') && typeof then === 'function') {
|
||||
return function appyThen() {
|
||||
then.apply(obj, arguments);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function safelyResolveThenable(self, thenable) {
|
||||
// Either fulfill, reject or reject with error
|
||||
var called = false;
|
||||
function onError(value) {
|
||||
if (called) {
|
||||
return;
|
||||
}
|
||||
called = true;
|
||||
handlers.reject(self, value);
|
||||
}
|
||||
|
||||
function onSuccess(value) {
|
||||
if (called) {
|
||||
return;
|
||||
}
|
||||
called = true;
|
||||
handlers.resolve(self, value);
|
||||
}
|
||||
|
||||
function tryToUnwrap() {
|
||||
thenable(onSuccess, onError);
|
||||
}
|
||||
|
||||
var result = tryCatch(tryToUnwrap);
|
||||
if (result.status === 'error') {
|
||||
onError(result.value);
|
||||
}
|
||||
}
|
||||
|
||||
function tryCatch(func, value) {
|
||||
var out = {};
|
||||
try {
|
||||
out.value = func(value);
|
||||
out.status = 'success';
|
||||
} catch (e) {
|
||||
out.status = 'error';
|
||||
out.value = e;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Promise.resolve = resolve;
|
||||
function resolve(value) {
|
||||
if (value instanceof this) {
|
||||
return value;
|
||||
}
|
||||
return handlers.resolve(new this(INTERNAL), value);
|
||||
}
|
||||
|
||||
Promise.reject = reject;
|
||||
function reject(reason) {
|
||||
var promise = new this(INTERNAL);
|
||||
return handlers.reject(promise, reason);
|
||||
}
|
||||
|
||||
Promise.all = all;
|
||||
function all(iterable) {
|
||||
var self = this;
|
||||
if (Object.prototype.toString.call(iterable) !== '[object Array]') {
|
||||
return this.reject(new TypeError('must be an array'));
|
||||
}
|
||||
|
||||
var len = iterable.length;
|
||||
var called = false;
|
||||
if (!len) {
|
||||
return this.resolve([]);
|
||||
}
|
||||
|
||||
var values = new Array(len);
|
||||
var resolved = 0;
|
||||
var i = -1;
|
||||
var promise = new this(INTERNAL);
|
||||
|
||||
while (++i < len) {
|
||||
allResolver(iterable[i], i);
|
||||
}
|
||||
return promise;
|
||||
function allResolver(value, i) {
|
||||
self.resolve(value).then(resolveFromAll, function (error) {
|
||||
if (!called) {
|
||||
called = true;
|
||||
handlers.reject(promise, error);
|
||||
}
|
||||
});
|
||||
function resolveFromAll(outValue) {
|
||||
values[i] = outValue;
|
||||
if (++resolved === len && !called) {
|
||||
called = true;
|
||||
handlers.resolve(promise, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Promise.race = race;
|
||||
function race(iterable) {
|
||||
var self = this;
|
||||
if (Object.prototype.toString.call(iterable) !== '[object Array]') {
|
||||
return this.reject(new TypeError('must be an array'));
|
||||
}
|
||||
|
||||
var len = iterable.length;
|
||||
var called = false;
|
||||
if (!len) {
|
||||
return this.resolve([]);
|
||||
}
|
||||
|
||||
var i = -1;
|
||||
var promise = new this(INTERNAL);
|
||||
|
||||
while (++i < len) {
|
||||
resolver(iterable[i]);
|
||||
}
|
||||
return promise;
|
||||
function resolver(value) {
|
||||
self.resolve(value).then(function (response) {
|
||||
if (!called) {
|
||||
called = true;
|
||||
handlers.resolve(promise, response);
|
||||
}
|
||||
}, function (error) {
|
||||
if (!called) {
|
||||
called = true;
|
||||
handlers.reject(promise, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return lib;
|
||||
}
|
||||
|
||||
var promiseWorkerTransferable;
|
||||
var hasRequiredPromiseWorkerTransferable;
|
||||
|
||||
function requirePromiseWorkerTransferable () {
|
||||
if (hasRequiredPromiseWorkerTransferable) return promiseWorkerTransferable;
|
||||
hasRequiredPromiseWorkerTransferable = 1;
|
||||
|
||||
/* istanbul ignore next */
|
||||
var MyPromise = typeof Promise !== 'undefined' ? Promise : requireLib();
|
||||
|
||||
var messageIds = 0;
|
||||
|
||||
function onMessage(self, e) {
|
||||
var message = e.data;
|
||||
if (!Array.isArray(message) || message.length < 2) {
|
||||
// Ignore - this message is not for us.
|
||||
return;
|
||||
}
|
||||
var messageId = message[0];
|
||||
var error = message[1];
|
||||
var result = message[2];
|
||||
|
||||
var callback = self._callbacks[messageId];
|
||||
|
||||
if (!callback) {
|
||||
// Ignore - user might have created multiple PromiseWorkers.
|
||||
// This message is not for us.
|
||||
return;
|
||||
}
|
||||
|
||||
delete self._callbacks[messageId];
|
||||
callback(error, result);
|
||||
}
|
||||
|
||||
function PromiseWorker(worker) {
|
||||
var self = this;
|
||||
self._worker = worker;
|
||||
self._callbacks = {};
|
||||
|
||||
worker.addEventListener('message', function (e) {
|
||||
onMessage(self, e);
|
||||
});
|
||||
}
|
||||
|
||||
PromiseWorker.prototype.postMessage = function (userMessage, transferList) {
|
||||
var self = this;
|
||||
var messageId = messageIds++;
|
||||
|
||||
var messageToSend = [messageId, userMessage];
|
||||
|
||||
return new MyPromise(function (resolve, reject) {
|
||||
self._callbacks[messageId] = function (error, result) {
|
||||
if (error) {
|
||||
return reject(new Error(error.message));
|
||||
}
|
||||
resolve(result);
|
||||
};
|
||||
/* istanbul ignore if */
|
||||
if (typeof self._worker.controller !== 'undefined') {
|
||||
// service worker, use MessageChannels because e.source is broken in Chrome < 51:
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=543198
|
||||
var channel = new MessageChannel();
|
||||
channel.port1.onmessage = function (e) {
|
||||
onMessage(self, e);
|
||||
};
|
||||
self._worker.controller.postMessage(messageToSend, [channel.port2].concat(transferList));
|
||||
} else {
|
||||
// web worker
|
||||
self._worker.postMessage(messageToSend, transferList);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
PromiseWorker.prototype.terminate = function () {
|
||||
this._worker.terminate();
|
||||
};
|
||||
|
||||
promiseWorkerTransferable = PromiseWorker;
|
||||
return promiseWorkerTransferable;
|
||||
}
|
||||
|
||||
var promiseWorkerTransferableExports = requirePromiseWorkerTransferable();
|
||||
var PromiseWorker = /*@__PURE__*/getDefaultExportFromCjs(promiseWorkerTransferableExports);
|
||||
|
||||
// @ts-expect-error untyped lib
|
||||
/**
|
||||
* Wraps a Regular worker into a `PromiseWorker`
|
||||
*
|
||||
* @param worker
|
||||
* @returns
|
||||
*/
|
||||
const getPromiseWorker = (worker) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
return new PromiseWorker(worker);
|
||||
};
|
||||
/**
|
||||
* Returns an interface where methods of the worker can be called by the host site
|
||||
*
|
||||
* @example
|
||||
* // this assumes a vite-like bundler understands the `?worker` import
|
||||
* import GainMapWorker from '@monogrid/gainmap-js/worker?worker'
|
||||
* import { getPromiseWorker, getWorkerInterface } from '@monogrid/gainmap-js/worker-interface'
|
||||
*
|
||||
* // turn our Worker into a PromiseWorker
|
||||
* const promiseWorker = getPromiseWorker(new GainMapWorker())
|
||||
* // get the interface
|
||||
* const workerInterface = getWorkerInterface(promiseWorker)
|
||||
*
|
||||
* @param worker
|
||||
* @returns
|
||||
*/
|
||||
const getWorkerInterface = (worker) => {
|
||||
return {
|
||||
compress: (payload) => worker.postMessage({ type: 'compress', payload })
|
||||
};
|
||||
};
|
||||
|
||||
export { getPromiseWorker, getWorkerInterface };
|
||||
5
node_modules/@monogrid/gainmap-js/dist/worker-interface.min.js
generated
vendored
Normal file
5
node_modules/@monogrid/gainmap-js/dist/worker-interface.min.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
525
node_modules/@monogrid/gainmap-js/dist/worker-interface.umd.cjs
generated
vendored
Normal file
525
node_modules/@monogrid/gainmap-js/dist/worker-interface.umd.cjs
generated
vendored
Normal file
@@ -0,0 +1,525 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["worker-interface"] = {}));
|
||||
})(this, (function (exports) { 'use strict';
|
||||
|
||||
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
||||
|
||||
function getDefaultExportFromCjs (x) {
|
||||
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
||||
}
|
||||
|
||||
var lib$1;
|
||||
var hasRequiredLib$1;
|
||||
|
||||
function requireLib$1 () {
|
||||
if (hasRequiredLib$1) return lib$1;
|
||||
hasRequiredLib$1 = 1;
|
||||
var Mutation = commonjsGlobal.MutationObserver || commonjsGlobal.WebKitMutationObserver;
|
||||
|
||||
var scheduleDrain;
|
||||
|
||||
if (process.browser) {
|
||||
if (Mutation) {
|
||||
var called = 0;
|
||||
var observer = new Mutation(nextTick);
|
||||
var element = commonjsGlobal.document.createTextNode('');
|
||||
observer.observe(element, {
|
||||
characterData: true
|
||||
});
|
||||
scheduleDrain = function () {
|
||||
element.data = (called = ++called % 2);
|
||||
};
|
||||
} else if (!commonjsGlobal.setImmediate && typeof commonjsGlobal.MessageChannel !== 'undefined') {
|
||||
var channel = new commonjsGlobal.MessageChannel();
|
||||
channel.port1.onmessage = nextTick;
|
||||
scheduleDrain = function () {
|
||||
channel.port2.postMessage(0);
|
||||
};
|
||||
} else if ('document' in commonjsGlobal && 'onreadystatechange' in commonjsGlobal.document.createElement('script')) {
|
||||
scheduleDrain = function () {
|
||||
|
||||
// Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
|
||||
// into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
|
||||
var scriptEl = commonjsGlobal.document.createElement('script');
|
||||
scriptEl.onreadystatechange = function () {
|
||||
nextTick();
|
||||
|
||||
scriptEl.onreadystatechange = null;
|
||||
scriptEl.parentNode.removeChild(scriptEl);
|
||||
scriptEl = null;
|
||||
};
|
||||
commonjsGlobal.document.documentElement.appendChild(scriptEl);
|
||||
};
|
||||
} else {
|
||||
scheduleDrain = function () {
|
||||
setTimeout(nextTick, 0);
|
||||
};
|
||||
}
|
||||
} else {
|
||||
scheduleDrain = function () {
|
||||
process.nextTick(nextTick);
|
||||
};
|
||||
}
|
||||
|
||||
var draining;
|
||||
var queue = [];
|
||||
//named nextTick for less confusing stack traces
|
||||
function nextTick() {
|
||||
draining = true;
|
||||
var i, oldQueue;
|
||||
var len = queue.length;
|
||||
while (len) {
|
||||
oldQueue = queue;
|
||||
queue = [];
|
||||
i = -1;
|
||||
while (++i < len) {
|
||||
oldQueue[i]();
|
||||
}
|
||||
len = queue.length;
|
||||
}
|
||||
draining = false;
|
||||
}
|
||||
|
||||
lib$1 = immediate;
|
||||
function immediate(task) {
|
||||
if (queue.push(task) === 1 && !draining) {
|
||||
scheduleDrain();
|
||||
}
|
||||
}
|
||||
return lib$1;
|
||||
}
|
||||
|
||||
var lib;
|
||||
var hasRequiredLib;
|
||||
|
||||
function requireLib () {
|
||||
if (hasRequiredLib) return lib;
|
||||
hasRequiredLib = 1;
|
||||
var immediate = requireLib$1();
|
||||
|
||||
/* istanbul ignore next */
|
||||
function INTERNAL() {}
|
||||
|
||||
var handlers = {};
|
||||
|
||||
var REJECTED = ['REJECTED'];
|
||||
var FULFILLED = ['FULFILLED'];
|
||||
var PENDING = ['PENDING'];
|
||||
/* istanbul ignore else */
|
||||
if (!process.browser) {
|
||||
// in which we actually take advantage of JS scoping
|
||||
var UNHANDLED = ['UNHANDLED'];
|
||||
}
|
||||
|
||||
lib = Promise;
|
||||
|
||||
function Promise(resolver) {
|
||||
if (typeof resolver !== 'function') {
|
||||
throw new TypeError('resolver must be a function');
|
||||
}
|
||||
this.state = PENDING;
|
||||
this.queue = [];
|
||||
this.outcome = void 0;
|
||||
/* istanbul ignore else */
|
||||
if (!process.browser) {
|
||||
this.handled = UNHANDLED;
|
||||
}
|
||||
if (resolver !== INTERNAL) {
|
||||
safelyResolveThenable(this, resolver);
|
||||
}
|
||||
}
|
||||
|
||||
Promise.prototype.finally = function (callback) {
|
||||
if (typeof callback !== 'function') {
|
||||
return this;
|
||||
}
|
||||
var p = this.constructor;
|
||||
return this.then(resolve, reject);
|
||||
|
||||
function resolve(value) {
|
||||
function yes () {
|
||||
return value;
|
||||
}
|
||||
return p.resolve(callback()).then(yes);
|
||||
}
|
||||
function reject(reason) {
|
||||
function no () {
|
||||
throw reason;
|
||||
}
|
||||
return p.resolve(callback()).then(no);
|
||||
}
|
||||
};
|
||||
Promise.prototype.catch = function (onRejected) {
|
||||
return this.then(null, onRejected);
|
||||
};
|
||||
Promise.prototype.then = function (onFulfilled, onRejected) {
|
||||
if (typeof onFulfilled !== 'function' && this.state === FULFILLED ||
|
||||
typeof onRejected !== 'function' && this.state === REJECTED) {
|
||||
return this;
|
||||
}
|
||||
var promise = new this.constructor(INTERNAL);
|
||||
/* istanbul ignore else */
|
||||
if (!process.browser) {
|
||||
if (this.handled === UNHANDLED) {
|
||||
this.handled = null;
|
||||
}
|
||||
}
|
||||
if (this.state !== PENDING) {
|
||||
var resolver = this.state === FULFILLED ? onFulfilled : onRejected;
|
||||
unwrap(promise, resolver, this.outcome);
|
||||
} else {
|
||||
this.queue.push(new QueueItem(promise, onFulfilled, onRejected));
|
||||
}
|
||||
|
||||
return promise;
|
||||
};
|
||||
function QueueItem(promise, onFulfilled, onRejected) {
|
||||
this.promise = promise;
|
||||
if (typeof onFulfilled === 'function') {
|
||||
this.onFulfilled = onFulfilled;
|
||||
this.callFulfilled = this.otherCallFulfilled;
|
||||
}
|
||||
if (typeof onRejected === 'function') {
|
||||
this.onRejected = onRejected;
|
||||
this.callRejected = this.otherCallRejected;
|
||||
}
|
||||
}
|
||||
QueueItem.prototype.callFulfilled = function (value) {
|
||||
handlers.resolve(this.promise, value);
|
||||
};
|
||||
QueueItem.prototype.otherCallFulfilled = function (value) {
|
||||
unwrap(this.promise, this.onFulfilled, value);
|
||||
};
|
||||
QueueItem.prototype.callRejected = function (value) {
|
||||
handlers.reject(this.promise, value);
|
||||
};
|
||||
QueueItem.prototype.otherCallRejected = function (value) {
|
||||
unwrap(this.promise, this.onRejected, value);
|
||||
};
|
||||
|
||||
function unwrap(promise, func, value) {
|
||||
immediate(function () {
|
||||
var returnValue;
|
||||
try {
|
||||
returnValue = func(value);
|
||||
} catch (e) {
|
||||
return handlers.reject(promise, e);
|
||||
}
|
||||
if (returnValue === promise) {
|
||||
handlers.reject(promise, new TypeError('Cannot resolve promise with itself'));
|
||||
} else {
|
||||
handlers.resolve(promise, returnValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handlers.resolve = function (self, value) {
|
||||
var result = tryCatch(getThen, value);
|
||||
if (result.status === 'error') {
|
||||
return handlers.reject(self, result.value);
|
||||
}
|
||||
var thenable = result.value;
|
||||
|
||||
if (thenable) {
|
||||
safelyResolveThenable(self, thenable);
|
||||
} else {
|
||||
self.state = FULFILLED;
|
||||
self.outcome = value;
|
||||
var i = -1;
|
||||
var len = self.queue.length;
|
||||
while (++i < len) {
|
||||
self.queue[i].callFulfilled(value);
|
||||
}
|
||||
}
|
||||
return self;
|
||||
};
|
||||
handlers.reject = function (self, error) {
|
||||
self.state = REJECTED;
|
||||
self.outcome = error;
|
||||
/* istanbul ignore else */
|
||||
if (!process.browser) {
|
||||
if (self.handled === UNHANDLED) {
|
||||
immediate(function () {
|
||||
if (self.handled === UNHANDLED) {
|
||||
process.emit('unhandledRejection', error, self);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
var i = -1;
|
||||
var len = self.queue.length;
|
||||
while (++i < len) {
|
||||
self.queue[i].callRejected(error);
|
||||
}
|
||||
return self;
|
||||
};
|
||||
|
||||
function getThen(obj) {
|
||||
// Make sure we only access the accessor once as required by the spec
|
||||
var then = obj && obj.then;
|
||||
if (obj && (typeof obj === 'object' || typeof obj === 'function') && typeof then === 'function') {
|
||||
return function appyThen() {
|
||||
then.apply(obj, arguments);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function safelyResolveThenable(self, thenable) {
|
||||
// Either fulfill, reject or reject with error
|
||||
var called = false;
|
||||
function onError(value) {
|
||||
if (called) {
|
||||
return;
|
||||
}
|
||||
called = true;
|
||||
handlers.reject(self, value);
|
||||
}
|
||||
|
||||
function onSuccess(value) {
|
||||
if (called) {
|
||||
return;
|
||||
}
|
||||
called = true;
|
||||
handlers.resolve(self, value);
|
||||
}
|
||||
|
||||
function tryToUnwrap() {
|
||||
thenable(onSuccess, onError);
|
||||
}
|
||||
|
||||
var result = tryCatch(tryToUnwrap);
|
||||
if (result.status === 'error') {
|
||||
onError(result.value);
|
||||
}
|
||||
}
|
||||
|
||||
function tryCatch(func, value) {
|
||||
var out = {};
|
||||
try {
|
||||
out.value = func(value);
|
||||
out.status = 'success';
|
||||
} catch (e) {
|
||||
out.status = 'error';
|
||||
out.value = e;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Promise.resolve = resolve;
|
||||
function resolve(value) {
|
||||
if (value instanceof this) {
|
||||
return value;
|
||||
}
|
||||
return handlers.resolve(new this(INTERNAL), value);
|
||||
}
|
||||
|
||||
Promise.reject = reject;
|
||||
function reject(reason) {
|
||||
var promise = new this(INTERNAL);
|
||||
return handlers.reject(promise, reason);
|
||||
}
|
||||
|
||||
Promise.all = all;
|
||||
function all(iterable) {
|
||||
var self = this;
|
||||
if (Object.prototype.toString.call(iterable) !== '[object Array]') {
|
||||
return this.reject(new TypeError('must be an array'));
|
||||
}
|
||||
|
||||
var len = iterable.length;
|
||||
var called = false;
|
||||
if (!len) {
|
||||
return this.resolve([]);
|
||||
}
|
||||
|
||||
var values = new Array(len);
|
||||
var resolved = 0;
|
||||
var i = -1;
|
||||
var promise = new this(INTERNAL);
|
||||
|
||||
while (++i < len) {
|
||||
allResolver(iterable[i], i);
|
||||
}
|
||||
return promise;
|
||||
function allResolver(value, i) {
|
||||
self.resolve(value).then(resolveFromAll, function (error) {
|
||||
if (!called) {
|
||||
called = true;
|
||||
handlers.reject(promise, error);
|
||||
}
|
||||
});
|
||||
function resolveFromAll(outValue) {
|
||||
values[i] = outValue;
|
||||
if (++resolved === len && !called) {
|
||||
called = true;
|
||||
handlers.resolve(promise, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Promise.race = race;
|
||||
function race(iterable) {
|
||||
var self = this;
|
||||
if (Object.prototype.toString.call(iterable) !== '[object Array]') {
|
||||
return this.reject(new TypeError('must be an array'));
|
||||
}
|
||||
|
||||
var len = iterable.length;
|
||||
var called = false;
|
||||
if (!len) {
|
||||
return this.resolve([]);
|
||||
}
|
||||
|
||||
var i = -1;
|
||||
var promise = new this(INTERNAL);
|
||||
|
||||
while (++i < len) {
|
||||
resolver(iterable[i]);
|
||||
}
|
||||
return promise;
|
||||
function resolver(value) {
|
||||
self.resolve(value).then(function (response) {
|
||||
if (!called) {
|
||||
called = true;
|
||||
handlers.resolve(promise, response);
|
||||
}
|
||||
}, function (error) {
|
||||
if (!called) {
|
||||
called = true;
|
||||
handlers.reject(promise, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return lib;
|
||||
}
|
||||
|
||||
var promiseWorkerTransferable;
|
||||
var hasRequiredPromiseWorkerTransferable;
|
||||
|
||||
function requirePromiseWorkerTransferable () {
|
||||
if (hasRequiredPromiseWorkerTransferable) return promiseWorkerTransferable;
|
||||
hasRequiredPromiseWorkerTransferable = 1;
|
||||
|
||||
/* istanbul ignore next */
|
||||
var MyPromise = typeof Promise !== 'undefined' ? Promise : requireLib();
|
||||
|
||||
var messageIds = 0;
|
||||
|
||||
function onMessage(self, e) {
|
||||
var message = e.data;
|
||||
if (!Array.isArray(message) || message.length < 2) {
|
||||
// Ignore - this message is not for us.
|
||||
return;
|
||||
}
|
||||
var messageId = message[0];
|
||||
var error = message[1];
|
||||
var result = message[2];
|
||||
|
||||
var callback = self._callbacks[messageId];
|
||||
|
||||
if (!callback) {
|
||||
// Ignore - user might have created multiple PromiseWorkers.
|
||||
// This message is not for us.
|
||||
return;
|
||||
}
|
||||
|
||||
delete self._callbacks[messageId];
|
||||
callback(error, result);
|
||||
}
|
||||
|
||||
function PromiseWorker(worker) {
|
||||
var self = this;
|
||||
self._worker = worker;
|
||||
self._callbacks = {};
|
||||
|
||||
worker.addEventListener('message', function (e) {
|
||||
onMessage(self, e);
|
||||
});
|
||||
}
|
||||
|
||||
PromiseWorker.prototype.postMessage = function (userMessage, transferList) {
|
||||
var self = this;
|
||||
var messageId = messageIds++;
|
||||
|
||||
var messageToSend = [messageId, userMessage];
|
||||
|
||||
return new MyPromise(function (resolve, reject) {
|
||||
self._callbacks[messageId] = function (error, result) {
|
||||
if (error) {
|
||||
return reject(new Error(error.message));
|
||||
}
|
||||
resolve(result);
|
||||
};
|
||||
/* istanbul ignore if */
|
||||
if (typeof self._worker.controller !== 'undefined') {
|
||||
// service worker, use MessageChannels because e.source is broken in Chrome < 51:
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=543198
|
||||
var channel = new MessageChannel();
|
||||
channel.port1.onmessage = function (e) {
|
||||
onMessage(self, e);
|
||||
};
|
||||
self._worker.controller.postMessage(messageToSend, [channel.port2].concat(transferList));
|
||||
} else {
|
||||
// web worker
|
||||
self._worker.postMessage(messageToSend, transferList);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
PromiseWorker.prototype.terminate = function () {
|
||||
this._worker.terminate();
|
||||
};
|
||||
|
||||
promiseWorkerTransferable = PromiseWorker;
|
||||
return promiseWorkerTransferable;
|
||||
}
|
||||
|
||||
var promiseWorkerTransferableExports = requirePromiseWorkerTransferable();
|
||||
var PromiseWorker = /*@__PURE__*/getDefaultExportFromCjs(promiseWorkerTransferableExports);
|
||||
|
||||
// @ts-expect-error untyped lib
|
||||
/**
|
||||
* Wraps a Regular worker into a `PromiseWorker`
|
||||
*
|
||||
* @param worker
|
||||
* @returns
|
||||
*/
|
||||
const getPromiseWorker = (worker) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
return new PromiseWorker(worker);
|
||||
};
|
||||
/**
|
||||
* Returns an interface where methods of the worker can be called by the host site
|
||||
*
|
||||
* @example
|
||||
* // this assumes a vite-like bundler understands the `?worker` import
|
||||
* import GainMapWorker from '@monogrid/gainmap-js/worker?worker'
|
||||
* import { getPromiseWorker, getWorkerInterface } from '@monogrid/gainmap-js/worker-interface'
|
||||
*
|
||||
* // turn our Worker into a PromiseWorker
|
||||
* const promiseWorker = getPromiseWorker(new GainMapWorker())
|
||||
* // get the interface
|
||||
* const workerInterface = getWorkerInterface(promiseWorker)
|
||||
*
|
||||
* @param worker
|
||||
* @returns
|
||||
*/
|
||||
const getWorkerInterface = (worker) => {
|
||||
return {
|
||||
compress: (payload) => worker.postMessage({ type: 'compress', payload })
|
||||
};
|
||||
};
|
||||
|
||||
exports.getPromiseWorker = getPromiseWorker;
|
||||
exports.getWorkerInterface = getWorkerInterface;
|
||||
|
||||
}));
|
||||
5
node_modules/@monogrid/gainmap-js/dist/worker-interface.umd.min.cjs
generated
vendored
Normal file
5
node_modules/@monogrid/gainmap-js/dist/worker-interface.umd.min.cjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
24
node_modules/@monogrid/gainmap-js/dist/worker-types.d.ts
generated
vendored
Normal file
24
node_modules/@monogrid/gainmap-js/dist/worker-types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
import { CompressedImage, type CompressParameters } from './encode/types';
|
||||
export type WorkerInterface = {
|
||||
compress: {
|
||||
request: {
|
||||
type: 'compress';
|
||||
payload: CompressParameters;
|
||||
};
|
||||
result: Awaited<CompressedImage> & {
|
||||
source: Uint8ClampedArray;
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Transferable
|
||||
*/
|
||||
export type Transferable = ArrayBufferLike | ImageBitmap;
|
||||
export type WorkerInterfaceImplementation = {
|
||||
[k in keyof WorkerInterface]: (payload: WorkerInterface[k]['request']['payload']) => Promise<WorkerInterface[k]['result']>;
|
||||
};
|
||||
export type WorkerRequest = WorkerInterface[keyof WorkerInterface]['request'];
|
||||
export type WithTransferListFunction = <T>(payload: T, transferList: Transferable[]) => T;
|
||||
export type PromiseWorkerType = {
|
||||
postMessage: (message: any, transferables?: Transferable[]) => Promise<any>;
|
||||
};
|
||||
1
node_modules/@monogrid/gainmap-js/dist/worker.d.ts
generated
vendored
Normal file
1
node_modules/@monogrid/gainmap-js/dist/worker.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
142
node_modules/@monogrid/gainmap-js/dist/worker.js
generated
vendored
Normal file
142
node_modules/@monogrid/gainmap-js/dist/worker.js
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
|
||||
import { g as getDefaultExportFromCjs } from './_commonjsHelpers-v3qvwW2J.js';
|
||||
import { c as compress } from './compress-C-X439Jm.js';
|
||||
|
||||
var isPromise = {exports: {}};
|
||||
|
||||
var hasRequiredIsPromise;
|
||||
|
||||
function requireIsPromise () {
|
||||
if (hasRequiredIsPromise) return isPromise.exports;
|
||||
hasRequiredIsPromise = 1;
|
||||
isPromise.exports = isPromise$1;
|
||||
isPromise.exports.default = isPromise$1;
|
||||
|
||||
function isPromise$1(obj) {
|
||||
return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
|
||||
}
|
||||
return isPromise.exports;
|
||||
}
|
||||
|
||||
var register;
|
||||
var hasRequiredRegister;
|
||||
|
||||
function requireRegister () {
|
||||
if (hasRequiredRegister) return register;
|
||||
hasRequiredRegister = 1;
|
||||
|
||||
var isPromise = requireIsPromise();
|
||||
|
||||
function registerPromiseWorker(callback) {
|
||||
|
||||
function postOutgoingMessage(e, messageId, error, result) {
|
||||
function postMessage(msg, transferList) {
|
||||
/* istanbul ignore if */
|
||||
if (typeof self.postMessage !== 'function') { // service worker
|
||||
e.ports[0].postMessage(msg, transferList);
|
||||
} else { // web worker
|
||||
self.postMessage(msg, transferList);
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
/* istanbul ignore else */
|
||||
if (typeof console !== 'undefined' && 'error' in console) {
|
||||
// This is to make errors easier to debug. I think it's important
|
||||
// enough to just leave here without giving the user an option
|
||||
// to silence it.
|
||||
console.error('Worker caught an error:', error);
|
||||
}
|
||||
postMessage([messageId, {
|
||||
message: error.message
|
||||
}]);
|
||||
} else {
|
||||
if (result instanceof MessageWithTransferList) {
|
||||
postMessage([messageId, null, result.message], result.transferList);
|
||||
} else {
|
||||
postMessage([messageId, null, result]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tryCatchFunc(callback, message) {
|
||||
try {
|
||||
return {res: callback(message, withTransferList)};
|
||||
} catch (e) {
|
||||
return {err: e};
|
||||
}
|
||||
}
|
||||
|
||||
function withTransferList(resMessage, transferList) {
|
||||
return new MessageWithTransferList(resMessage, transferList);
|
||||
}
|
||||
|
||||
function handleIncomingMessage(e, callback, messageId, message) {
|
||||
|
||||
var result = tryCatchFunc(callback, message);
|
||||
|
||||
if (result.err) {
|
||||
postOutgoingMessage(e, messageId, result.err);
|
||||
} else if (!isPromise(result.res)) {
|
||||
postOutgoingMessage(e, messageId, null, result.res);
|
||||
} else {
|
||||
result.res.then(function (finalResult) {
|
||||
postOutgoingMessage(e, messageId, null, finalResult);
|
||||
}, function (finalError) {
|
||||
postOutgoingMessage(e, messageId, finalError);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function onIncomingMessage(e) {
|
||||
var payload = e.data;
|
||||
if (!Array.isArray(payload) || payload.length !== 2) {
|
||||
// message doens't match communication format; ignore
|
||||
return;
|
||||
}
|
||||
var messageId = payload[0];
|
||||
var message = payload[1];
|
||||
|
||||
if (typeof callback !== 'function') {
|
||||
postOutgoingMessage(e, messageId, new Error(
|
||||
'Please pass a function into register().'));
|
||||
} else {
|
||||
handleIncomingMessage(e, callback, messageId, message);
|
||||
}
|
||||
}
|
||||
|
||||
function MessageWithTransferList(message, transferList) {
|
||||
this.message = message;
|
||||
this.transferList = transferList;
|
||||
}
|
||||
|
||||
self.addEventListener('message', onIncomingMessage);
|
||||
}
|
||||
|
||||
register = registerPromiseWorker;
|
||||
return register;
|
||||
}
|
||||
|
||||
var registerExports = requireRegister();
|
||||
var registerPromiseWorker = /*@__PURE__*/getDefaultExportFromCjs(registerExports);
|
||||
|
||||
// @ts-expect-error untyped lib
|
||||
const _compress = async (message, withTransferList) => {
|
||||
const result = await compress(message.payload);
|
||||
return withTransferList({
|
||||
...result,
|
||||
source: message.payload.source instanceof ImageData ? message.payload.source.data : new Uint8ClampedArray(message.payload.source)
|
||||
}, [result.data.buffer, message.payload.source instanceof ImageData ? message.payload.source.data.buffer : message.payload.source.buffer]);
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
registerPromiseWorker(async (message, withTransferList) => {
|
||||
switch (message.type) {
|
||||
// case 'encode-gainmap-buffers':
|
||||
// return encodeGainmapBuffers(message, withTransferList)
|
||||
case 'compress':
|
||||
return _compress(message, withTransferList);
|
||||
}
|
||||
});
|
||||
5
node_modules/@monogrid/gainmap-js/dist/worker.min.js
generated
vendored
Normal file
5
node_modules/@monogrid/gainmap-js/dist/worker.min.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
import{g as e}from"./_commonjsHelpers-CDmClQiF.js";import{c as r}from"./compress-DY-CSunh.js";var n,t,o,s={exports:{}};function a(){if(n)return s.exports;function e(e){return!!e&&("object"==typeof e||"function"==typeof e)&&"function"==typeof e.then}return n=1,s.exports=e,s.exports.default=e,s.exports}var f=function(){if(o)return t;o=1;var e=a();return t=function(r){function n(e,r,n,t){function o(r,n){"function"!=typeof self.postMessage?e.ports[0].postMessage(r,n):self.postMessage(r,n)}n?("undefined"!=typeof console&&"error"in console&&console.error("Worker caught an error:",n),o([r,{message:n.message}])):t instanceof s?o([r,null,t.message],t.transferList):o([r,null,t])}function t(e,r){return new s(e,r)}function o(r,o,s,a){var f=function(e,r){try{return{res:e(r,t)}}catch(e){return{err:e}}}(o,a);f.err?n(r,s,f.err):e(f.res)?f.res.then(function(e){n(r,s,null,e)},function(e){n(r,s,e)}):n(r,s,null,f.res)}function s(e,r){this.message=e,this.transferList=r}self.addEventListener("message",function(e){var t=e.data;if(Array.isArray(t)&&2===t.length){var s=t[0],a=t[1];"function"!=typeof r?n(e,s,new Error("Please pass a function into register().")):o(e,r,s,a)}})}}();e(f)(async(e,n)=>{if("compress"===e.type)return(async(e,n)=>{const t=await r(e.payload);return n({...t,source:e.payload.source instanceof ImageData?e.payload.source.data:new Uint8ClampedArray(e.payload.source)},[t.data.buffer,e.payload.source instanceof ImageData?e.payload.source.data.buffer:e.payload.source.buffer])})(e,n)});
|
||||
236
node_modules/@monogrid/gainmap-js/dist/worker.umd.cjs
generated
vendored
Normal file
236
node_modules/@monogrid/gainmap-js/dist/worker.umd.cjs
generated
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
|
||||
(function (factory) {
|
||||
typeof define === 'function' && define.amd ? define(factory) :
|
||||
factory();
|
||||
})((function () { 'use strict';
|
||||
|
||||
function getDefaultExportFromCjs (x) {
|
||||
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
||||
}
|
||||
|
||||
var isPromise = {exports: {}};
|
||||
|
||||
var hasRequiredIsPromise;
|
||||
|
||||
function requireIsPromise () {
|
||||
if (hasRequiredIsPromise) return isPromise.exports;
|
||||
hasRequiredIsPromise = 1;
|
||||
isPromise.exports = isPromise$1;
|
||||
isPromise.exports.default = isPromise$1;
|
||||
|
||||
function isPromise$1(obj) {
|
||||
return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
|
||||
}
|
||||
return isPromise.exports;
|
||||
}
|
||||
|
||||
var register;
|
||||
var hasRequiredRegister;
|
||||
|
||||
function requireRegister () {
|
||||
if (hasRequiredRegister) return register;
|
||||
hasRequiredRegister = 1;
|
||||
|
||||
var isPromise = requireIsPromise();
|
||||
|
||||
function registerPromiseWorker(callback) {
|
||||
|
||||
function postOutgoingMessage(e, messageId, error, result) {
|
||||
function postMessage(msg, transferList) {
|
||||
/* istanbul ignore if */
|
||||
if (typeof self.postMessage !== 'function') { // service worker
|
||||
e.ports[0].postMessage(msg, transferList);
|
||||
} else { // web worker
|
||||
self.postMessage(msg, transferList);
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
/* istanbul ignore else */
|
||||
if (typeof console !== 'undefined' && 'error' in console) {
|
||||
// This is to make errors easier to debug. I think it's important
|
||||
// enough to just leave here without giving the user an option
|
||||
// to silence it.
|
||||
console.error('Worker caught an error:', error);
|
||||
}
|
||||
postMessage([messageId, {
|
||||
message: error.message
|
||||
}]);
|
||||
} else {
|
||||
if (result instanceof MessageWithTransferList) {
|
||||
postMessage([messageId, null, result.message], result.transferList);
|
||||
} else {
|
||||
postMessage([messageId, null, result]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tryCatchFunc(callback, message) {
|
||||
try {
|
||||
return {res: callback(message, withTransferList)};
|
||||
} catch (e) {
|
||||
return {err: e};
|
||||
}
|
||||
}
|
||||
|
||||
function withTransferList(resMessage, transferList) {
|
||||
return new MessageWithTransferList(resMessage, transferList);
|
||||
}
|
||||
|
||||
function handleIncomingMessage(e, callback, messageId, message) {
|
||||
|
||||
var result = tryCatchFunc(callback, message);
|
||||
|
||||
if (result.err) {
|
||||
postOutgoingMessage(e, messageId, result.err);
|
||||
} else if (!isPromise(result.res)) {
|
||||
postOutgoingMessage(e, messageId, null, result.res);
|
||||
} else {
|
||||
result.res.then(function (finalResult) {
|
||||
postOutgoingMessage(e, messageId, null, finalResult);
|
||||
}, function (finalError) {
|
||||
postOutgoingMessage(e, messageId, finalError);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function onIncomingMessage(e) {
|
||||
var payload = e.data;
|
||||
if (!Array.isArray(payload) || payload.length !== 2) {
|
||||
// message doens't match communication format; ignore
|
||||
return;
|
||||
}
|
||||
var messageId = payload[0];
|
||||
var message = payload[1];
|
||||
|
||||
if (typeof callback !== 'function') {
|
||||
postOutgoingMessage(e, messageId, new Error(
|
||||
'Please pass a function into register().'));
|
||||
} else {
|
||||
handleIncomingMessage(e, callback, messageId, message);
|
||||
}
|
||||
}
|
||||
|
||||
function MessageWithTransferList(message, transferList) {
|
||||
this.message = message;
|
||||
this.transferList = transferList;
|
||||
}
|
||||
|
||||
self.addEventListener('message', onIncomingMessage);
|
||||
}
|
||||
|
||||
register = registerPromiseWorker;
|
||||
return register;
|
||||
}
|
||||
|
||||
var registerExports = requireRegister();
|
||||
var registerPromiseWorker = /*@__PURE__*/getDefaultExportFromCjs(registerExports);
|
||||
|
||||
/**
|
||||
* Used internally
|
||||
*
|
||||
* @internal
|
||||
* @param canvas
|
||||
* @param mimeType
|
||||
* @param quality
|
||||
* @returns
|
||||
*/
|
||||
const canvasToBlob = async (canvas, mimeType, quality) => {
|
||||
if (typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas) {
|
||||
return canvas.convertToBlob({ type: mimeType, quality: quality });
|
||||
}
|
||||
else if (canvas instanceof HTMLCanvasElement) {
|
||||
return new Promise((resolve, reject) => {
|
||||
canvas.toBlob((res) => {
|
||||
if (res)
|
||||
resolve(res);
|
||||
else
|
||||
reject(new Error('Failed to convert canvas to blob'));
|
||||
}, mimeType, quality);
|
||||
});
|
||||
}
|
||||
/* istanbul ignore next
|
||||
as long as this function is not exported this is only here
|
||||
to satisfy TS strict mode internally
|
||||
*/
|
||||
throw new Error('Unsupported canvas element');
|
||||
};
|
||||
/**
|
||||
* Converts a RAW RGBA image buffer into the provided `mimeType` using the provided `quality`
|
||||
*
|
||||
* @category Compression
|
||||
* @group Compression
|
||||
* @param params
|
||||
* @throws {Error} if the browser does not support [createImageBitmap](https://caniuse.com/createimagebitmap)
|
||||
* @throws {Error} if the provided source image cannot be decoded
|
||||
* @throws {Error} if the function fails to create a canvas context
|
||||
*/
|
||||
const compress = async (params) => {
|
||||
if (typeof createImageBitmap === 'undefined')
|
||||
throw new Error('createImageBitmap() not supported.');
|
||||
const { source, mimeType, quality, flipY } = params;
|
||||
let imageBitmapSource;
|
||||
if ((source instanceof Uint8Array || source instanceof Uint8ClampedArray) && 'sourceMimeType' in params) {
|
||||
imageBitmapSource = new Blob([source], { type: params.sourceMimeType });
|
||||
}
|
||||
else if (source instanceof ImageData) {
|
||||
imageBitmapSource = source;
|
||||
}
|
||||
else {
|
||||
throw new Error('Invalid source image');
|
||||
}
|
||||
const img = await createImageBitmap(imageBitmapSource);
|
||||
const width = img.width;
|
||||
const height = img.height;
|
||||
let canvas;
|
||||
if (typeof OffscreenCanvas !== 'undefined') {
|
||||
canvas = new OffscreenCanvas(width, height);
|
||||
}
|
||||
else {
|
||||
canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
}
|
||||
// apparently we do need to assert the type here for npx tsc to be happy
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx)
|
||||
throw new Error('Failed to create canvas Context');
|
||||
// flip Y
|
||||
if (flipY === true) {
|
||||
ctx.translate(0, height);
|
||||
ctx.scale(1, -1);
|
||||
}
|
||||
ctx.drawImage(img, 0, 0, width, height);
|
||||
const blob = await canvasToBlob(canvas, mimeType, quality || 0.9);
|
||||
const data = new Uint8Array(await blob.arrayBuffer());
|
||||
return {
|
||||
data,
|
||||
mimeType,
|
||||
width,
|
||||
height
|
||||
};
|
||||
};
|
||||
|
||||
// @ts-expect-error untyped lib
|
||||
const _compress = async (message, withTransferList) => {
|
||||
const result = await compress(message.payload);
|
||||
return withTransferList({
|
||||
...result,
|
||||
source: message.payload.source instanceof ImageData ? message.payload.source.data : new Uint8ClampedArray(message.payload.source)
|
||||
}, [result.data.buffer, message.payload.source instanceof ImageData ? message.payload.source.data.buffer : message.payload.source.buffer]);
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
registerPromiseWorker(async (message, withTransferList) => {
|
||||
switch (message.type) {
|
||||
// case 'encode-gainmap-buffers':
|
||||
// return encodeGainmapBuffers(message, withTransferList)
|
||||
case 'compress':
|
||||
return _compress(message, withTransferList);
|
||||
}
|
||||
});
|
||||
|
||||
}));
|
||||
5
node_modules/@monogrid/gainmap-js/dist/worker.umd.min.cjs
generated
vendored
Normal file
5
node_modules/@monogrid/gainmap-js/dist/worker.umd.min.cjs
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* @monogrid/gainmap-js v3.4.0
|
||||
* With ❤️, by MONOGRID <gainmap@monogrid.com>
|
||||
*/
|
||||
!function(e){"function"==typeof define&&define.amd?define(e):e()}(function(){"use strict";function e(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var t,n,r,a={exports:{}};function o(){if(t)return a.exports;function e(e){return!!e&&("object"==typeof e||"function"==typeof e)&&"function"==typeof e.then}return t=1,a.exports=e,a.exports.default=e,a.exports}var s=function(){if(r)return n;r=1;var e=o();return n=function(t){function n(e,t,n,r){function a(t,n){"function"!=typeof self.postMessage?e.ports[0].postMessage(t,n):self.postMessage(t,n)}n?("undefined"!=typeof console&&"error"in console&&console.error("Worker caught an error:",n),a([t,{message:n.message}])):r instanceof o?a([t,null,r.message],r.transferList):a([t,null,r])}function r(e,t){return new o(e,t)}function a(t,a,o,s){var i=function(e,t){try{return{res:e(t,r)}}catch(e){return{err:e}}}(a,s);i.err?n(t,o,i.err):e(i.res)?i.res.then(function(e){n(t,o,null,e)},function(e){n(t,o,e)}):n(t,o,null,i.res)}function o(e,t){this.message=e,this.transferList=t}self.addEventListener("message",function(e){var r=e.data;if(Array.isArray(r)&&2===r.length){var o=r[0],s=r[1];"function"!=typeof t?n(e,o,new Error("Please pass a function into register().")):a(e,t,o,s)}})}}();const i=async e=>{if("undefined"==typeof createImageBitmap)throw new Error("createImageBitmap() not supported.");const{source:t,mimeType:n,quality:r,flipY:a}=e;let o;if((t instanceof Uint8Array||t instanceof Uint8ClampedArray)&&"sourceMimeType"in e)o=new Blob([t],{type:e.sourceMimeType});else{if(!(t instanceof ImageData))throw new Error("Invalid source image");o=t}const s=await createImageBitmap(o),i=s.width,f=s.height;let c;"undefined"!=typeof OffscreenCanvas?c=new OffscreenCanvas(i,f):(c=document.createElement("canvas"),c.width=i,c.height=f);const u=c.getContext("2d");if(!u)throw new Error("Failed to create canvas Context");!0===a&&(u.translate(0,f),u.scale(1,-1)),u.drawImage(s,0,0,i,f);const l=await(async(e,t,n)=>{if("undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)return e.convertToBlob({type:t,quality:n});if(e instanceof HTMLCanvasElement)return new Promise((r,a)=>{e.toBlob(e=>{e?r(e):a(new Error("Failed to convert canvas to blob"))},t,n)});throw new Error("Unsupported canvas element")})(c,n,r||.9);return{data:new Uint8Array(await l.arrayBuffer()),mimeType:n,width:i,height:f}};e(s)(async(e,t)=>{if("compress"===e.type)return(async(e,t)=>{const n=await i(e.payload);return t({...n,source:e.payload.source instanceof ImageData?e.payload.source.data:new Uint8ClampedArray(e.payload.source)},[n.data.buffer,e.payload.source instanceof ImageData?e.payload.source.data.buffer:e.payload.source.buffer])})(e,t)})});
|
||||
167
node_modules/@monogrid/gainmap-js/package.json
generated
vendored
Normal file
167
node_modules/@monogrid/gainmap-js/package.json
generated
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
{
|
||||
"name": "@monogrid/gainmap-js",
|
||||
"version": "3.4.0",
|
||||
"description": "A Javascript (TypeScript) Port of Adobe Gainmap Technology for storing HDR Images using an SDR Image + a gain map",
|
||||
"keywords": [
|
||||
"hdr",
|
||||
"gain map",
|
||||
"gainmap",
|
||||
"three",
|
||||
"threejs"
|
||||
],
|
||||
"homepage": "https://github.com/MONOGRID/gainmap-js#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/MONOGRID/gainmap-js/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+ssh://git@github.com/MONOGRID/gainmap-js.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "MONOGRID <gainmap@monogrid.com>",
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/decode.d.ts",
|
||||
"import": "./dist/decode.js",
|
||||
"default": "./dist/decode.umd.cjs"
|
||||
},
|
||||
"./webgpu": {
|
||||
"types": "./dist/decode/webgpu/index.d.ts",
|
||||
"import": "./dist/decode.webgpu.js",
|
||||
"default": "./dist/decode.webgpu.umd.cjs"
|
||||
},
|
||||
"./encode": {
|
||||
"types": "./dist/encode.d.ts",
|
||||
"import": "./dist/encode.js",
|
||||
"default": "./dist/encode.umd.cjs"
|
||||
},
|
||||
"./libultrahdr": {
|
||||
"types": "./dist/libultrahdr.d.ts",
|
||||
"import": "./dist/libultrahdr.js",
|
||||
"default": "./dist/libultrahdr.umd.cjs"
|
||||
},
|
||||
"./worker": {
|
||||
"types": "./dist/worker.d.ts",
|
||||
"import": "./dist/worker.js",
|
||||
"default": "./dist/worker.umd.cjs"
|
||||
},
|
||||
"./worker-interface": {
|
||||
"types": "./dist/worker-interface.d.ts",
|
||||
"import": "./dist/worker-interface.js",
|
||||
"default": "./dist/worker-interface.umd.cjs"
|
||||
}
|
||||
},
|
||||
"main": "dist/decode.umd.cjs",
|
||||
"module": "dist/decode.js",
|
||||
"types": "dist/decode.d.ts",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
".": [
|
||||
"./dist/decode.d.ts"
|
||||
],
|
||||
"decode/webgpu": [
|
||||
"./dist/decode/webgpu/index.d.ts"
|
||||
],
|
||||
"decode/webgl": [
|
||||
"./dist/decode/webgl/index.d.ts"
|
||||
],
|
||||
"encode": [
|
||||
"./dist/encode.d.ts"
|
||||
],
|
||||
"libultrahdr": [
|
||||
"./dist/libultrahdr.d.ts"
|
||||
],
|
||||
"worker": [
|
||||
"./dist/worker.d.ts"
|
||||
],
|
||||
"worker-interface": [
|
||||
"./dist/worker-interface.d.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"check": "concurrently -c auto npm:check:*",
|
||||
"check:eslint-examples": "eslint \"examples/**/*.{ts,html}\"",
|
||||
"check:eslint-src": "eslint \"src/**/*.ts\"",
|
||||
"check:eslint-tests": "eslint \"tests/**/*.ts\"",
|
||||
"check:typecheck-examples": "tsc -p examples",
|
||||
"check:typecheck-src": "tsc -p src",
|
||||
"check:typecheck-tests": "tsc -p tests",
|
||||
"ci:check": "concurrently npm:ci:check:*",
|
||||
"ci:check:eslint-examples": "eslint --format json --output-file reports/eslint-examples.json \"examples/**/*.{ts,html}\"",
|
||||
"ci:check:eslint-src": "eslint --format json --output-file reports/eslint-src.json \"src/**/*.ts\"",
|
||||
"ci:check:eslint-tests": "eslint --format json --output-file reports/eslint-tests.json \"tests/**/*.ts\"",
|
||||
"ci:check:typecheck-examples": "tsc --pretty false -p examples > reports/typecheck-examples.log",
|
||||
"ci:check:typecheck-src": "tsc --pretty false -p src > reports/typecheck.log",
|
||||
"ci:check:typecheck-tests": "tsc --pretty false -p tests > reports/typecheck-tests.log",
|
||||
"dev": "concurrently -n rollup,servez -c magenta,green \"rollup -c -w\" \"servez\"",
|
||||
"prepack": "npm run build",
|
||||
"start": "concurrently -n rollup,servez -c magenta,green \"rollup -c -w\" \"servez\"",
|
||||
"test": "nyc --reporter=text --reporter=lcov playwright test",
|
||||
"test:codegen": "playwright codegen http://localhost:8080",
|
||||
"test:docker": "docker run --rm --network host -v $(pwd):/work -w /work -it -u $(id -u ${USER}):$(id -g ${USER}) mcr.microsoft.com/playwright:v1.56.1-jammy /bin/bash",
|
||||
"test:startserver": "rollup -c && servez"
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
"path": "./node_modules/cz-conventional-changelog"
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%, not dead, not ie 11, not op_mini all"
|
||||
],
|
||||
"dependencies": {
|
||||
"promise-worker-transferable": "^1.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@playwright/test": "^1.56.1",
|
||||
"@rollup/plugin-commonjs": "^29.0.0",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
"@rollup/plugin-node-resolve": "^16.0.3",
|
||||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"@rollup/plugin-typescript": "^12.3.0",
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/commit-analyzer": "^13.0.1",
|
||||
"@semantic-release/git": "github:semantic-release/git",
|
||||
"@semantic-release/github": "^12.0.0",
|
||||
"@semantic-release/npm": "^13.1.1",
|
||||
"@semantic-release/release-notes-generator": "^14.1.0",
|
||||
"@types/node": "^22.18.12",
|
||||
"@types/three": "^0.181.0",
|
||||
"concurrently": "^9.2.1",
|
||||
"conventional-changelog-conventionalcommits": "^9.1.0",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"eslint": "^9.38.0",
|
||||
"eslint-config-mdcs": "^5.0.0",
|
||||
"eslint-plugin-html": "^8.1.3",
|
||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||
"eslint-plugin-unused-imports": "^4.3.0",
|
||||
"globals": "^16.4.0",
|
||||
"neostandard": "^0.12.2",
|
||||
"nyc": "^17.1.0",
|
||||
"rollup": "^4.52.5",
|
||||
"rollup-plugin-copy": "^3.5.0",
|
||||
"rollup-plugin-delete": "^3.0.1",
|
||||
"rollup-plugin-istanbul": "^5.0.0",
|
||||
"rollup-plugin-license": "^3.6.0",
|
||||
"semantic-release": "^25.0.1",
|
||||
"servez": "^2.3.2",
|
||||
"sharp": "^0.34.4",
|
||||
"three": "^0.181.1",
|
||||
"typedoc": "^0.28.14",
|
||||
"typedoc-github-wiki-theme": "^2.1.0",
|
||||
"typedoc-plugin-markdown": "^4.9.0",
|
||||
"typescript": "~5.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"three": ">= 0.159.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user