diff --git a/.babelrc b/.babelrc new file mode 100644 index 000000000..c55288ee5 --- /dev/null +++ b/.babelrc @@ -0,0 +1,38 @@ +{ + "env": { + "test": { + "plugins": ["@babel/transform-modules-commonjs"] + }, + "npm": { + "presets": [ + [ + "@babel/env", + { + "targets": { + "node": 10 + } + } + ] + ] + }, + "browser": { + "presets": [ + [ + "@babel/env", + { + "modules": false, + "targets": { + "browsers": [ + "chrome >= 54", + "firefox >= 45", + "last 2 edge versions", + "last 2 safari versions" + ] + }, + "exclude": ["transform-for-of"] + } + ] + ] + } + } +} diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 000000000..cee281724 --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,19 @@ +extends: cheminfo + +env: + browser: true + node: true + es6: true + +parserOptions: + ecmaVersion: 2017 + sourceType: module + +rules: + no-var: error + no-multi-spaces: off + import/no-cycle: off + import/no-extraneous-dependencies: off + +settings: + import/core-modules: [ test ] diff --git a/.github/workflows/lactame.yml b/.github/workflows/lactame.yml deleted file mode 100644 index 8a1b45db0..000000000 --- a/.github/workflows/lactame.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Deploy build on lactame.com - -on: - release: - types: [published] - -env: - NODE_VERSION: 24.x - -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Get package name - run: echo "PACKAGE_NAME=$(jq .name package.json | tr -d '"')" >> $GITHUB_ENV - - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - - name: Install dependencies - run: npm install - - name: Build project - run: npm run build - - name: Deploy to lactame.com - uses: zakodium/lactame-action@v1 - with: - token: ${{ secrets.LACTAME_TOKEN }} - name: ${{ env.PACKAGE_NAME }} - folder: dist diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml deleted file mode 100644 index 71e0af24c..000000000 --- a/.github/workflows/nodejs.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Node.js CI - -on: - push: - branches: - - main - pull_request: - -jobs: - nodejs: - # Documentation: https://github.com/zakodium/workflows#nodejs-ci - uses: zakodium/workflows/.github/workflows/nodejs.yml@nodejs-v1 - with: - lint-check-types: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 7f5db58ad..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Release - -on: - push: - branches: - - main - -jobs: - release: - # Documentation: https://github.com/zakodium/workflows#release - uses: zakodium/workflows/.github/workflows/release.yml@release-v1 - with: - npm: true - secrets: - github-token: ${{ secrets.BOT_TOKEN }} - npm-token: ${{ secrets.NPM_BOT_TOKEN }} diff --git a/.github/workflows/typedoc.yml b/.github/workflows/typedoc.yml deleted file mode 100644 index ca9eecc56..000000000 --- a/.github/workflows/typedoc.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: TypeDoc - -on: - workflow_dispatch: - release: - types: [published] - -jobs: - typedoc: - # Documentation: https://github.com/zakodium/workflows#typedoc - uses: zakodium/workflows/.github/workflows/typedoc.yml@typedoc-v1 - secrets: - github-token: ${{ secrets.BOT_TOKEN }} diff --git a/.gitignore b/.gitignore index e0201db30..fe47bc449 100644 --- a/.gitignore +++ b/.gitignore @@ -1,140 +1,13 @@ -# Logs -logs +lib +/node_modules/ +.idea *.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Python stuff -.venv - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul +test/TMP +test/browser/Image.js +test/browser/image.js +.DS_Store coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache .eslintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt - -# api-extractor build output -dist-types - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* -yarn.lock - -.DS_Store - -dist -lib - -# debug images -src/**/*.tif -src/**/*.png -!src/**/__image_snapshots__/*.png - -# ignore images in test scripts folder -scripts/**/**.png -scripts/**/**.json - -private - -.jest-image-snapshot-touched-files +.vscode +/dist/ +package-lock.json diff --git a/.ncurc.yml b/.ncurc.yml deleted file mode 100644 index a694d3c4d..000000000 --- a/.ncurc.yml +++ /dev/null @@ -1,3 +0,0 @@ -reject: - # Package is now asynchronous - - 'image-type' diff --git a/.npmrc b/.npmrc index 97b895e2f..43c97e719 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1 @@ -ignore-scripts=true +package-lock=false diff --git a/.prettierignore b/.prettierignore index 1b763b1ba..c3e825dc5 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1 @@ -CHANGELOG.md +package*.json \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json deleted file mode 100644 index a23e760a0..000000000 --- a/.prettierrc.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "arrowParens": "always", - "semi": true, - "singleQuote": true, - "tabWidth": 2, - "trailingComma": "all" -} diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..8dee49cc7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,19 @@ +language: node_js +node_js: + - 11 + - 10 + - 8 +script: "npm run test-travis" +after_script: "bash <(curl -s https://codecov.io/bash)" +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - libcairo2-dev + - libjpeg8-dev + - libpango1.0-dev + - libgif-dev + - g++-4.9 +env: + - CXX=g++-4.9 diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 150240be4..000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,220 +0,0 @@ -# Changelog - -## [1.1.0](https://github.com/image-js/image-js/compare/v1.0.0...v1.1.0) (2025-10-31) - - -### Features - -* add new features from fast-bmp ([#748](https://github.com/image-js/image-js/issues/748)) ([147ef32](https://github.com/image-js/image-js/commit/147ef325f8337c0a9deee911dc35b2759e92449c)) -* add new tiff decoding features ([#751](https://github.com/image-js/image-js/issues/751)) ([32491a7](https://github.com/image-js/image-js/commit/32491a771dd8d36c8701b1660216ad354bd77263)) -* integrate new features from fast-png ([#749](https://github.com/image-js/image-js/issues/749)) ([9ad9566](https://github.com/image-js/image-js/commit/9ad9566a803256a87e94abadf3926af58da61461)) - - -### Bug Fixes - -* decoding palette PNG images with tRNS chunk ([#756](https://github.com/image-js/image-js/issues/756)) ([75c4231](https://github.com/image-js/image-js/commit/75c4231f742801fc1a8671e0bff991a86423339b)) - -## 1.0.0 (2025-08-20) - - -ImageJS 1.0 is a complete TypeScript rewrite of the library. - -Please read our announcement post at . - -## [0.37.0](https://www.github.com/image-js/image-js/compare/v0.36.1...v0.37.0) (2025-04-15) - - -### Features - -* add filledSurface on ROI ([019c71a](https://www.github.com/image-js/image-js/commit/019c71ab2b64217564b3eae8fd731b80c743ff3c)) -* ROI.toJSON expose hullSurface and hullPerimeter ([85471eb](https://www.github.com/image-js/image-js/commit/85471eb1318846a22563346680de9886e1c42bfc)) - -### [0.36.1](https://www.github.com/image-js/image-js/compare/v0.36.0...v0.36.1) (2025-04-09) - - -### Bug Fixes - -* add types and documentation for cannyEdge parameters ([f73f9b4](https://www.github.com/image-js/image-js/commit/f73f9b4864029eae39f8dd3412d3991b84798fab)) - -## [0.36.0](https://www.github.com/image-js/image-js/compare/v0.35.6...v0.36.0) (2024-12-26) - - -### Features - -* extract text field from png as meta information ([180ccd4](https://www.github.com/image-js/image-js/commit/180ccd40a833bc9279a29ba83d16a83e9e724427)) - -### [0.35.6](https://www.github.com/image-js/image-js/compare/v0.35.5...v0.35.6) (2024-07-05) - - -### Bug Fixes - -* add type for insert method ([faead4f](https://github.com/image-js/image-js/commit/faead4f71c0eb640e65fa9f2b17b31b3cc51351b)) - -### [0.35.5](https://www.github.com/image-js/image-js/compare/v0.35.4...v0.35.5) (2023-10-17) - - -### Bug Fixes - -* add TypeScript definition to RoiManager ([#630](https://www.github.com/image-js/image-js/issues/630)) ([10bec0b](https://www.github.com/image-js/image-js/commit/10bec0b4b4794cf8c9d8459ebf77380829fa814d)) - -### [0.35.4](https://www.github.com/image-js/image-js/compare/v0.35.3...v0.35.4) (2023-06-14) - - -### Bug Fixes - -* setMatrix() return this object ([#621](https://www.github.com/image-js/image-js/issues/621)) ([b4ca38e](https://www.github.com/image-js/image-js/commit/b4ca38efd196f87147f2f14f670b7214ed18f9b5)) - -### [0.35.3](https://www.github.com/image-js/image-js/compare/v0.35.2...v0.35.3) (2023-02-02) - - -### Bug Fixes - -* **types:** wrong matrix definition ([#616](https://www.github.com/image-js/image-js/issues/616)) ([e265e2a](https://www.github.com/image-js/image-js/commit/e265e2a38c835e8b09678e003426e128e7c951ae)) - -### [0.35.2](https://www.github.com/image-js/image-js/compare/v0.35.1...v0.35.2) (2022-10-07) - - -### Bug Fixes - -* add more typescript definitions ([#606](https://www.github.com/image-js/image-js/issues/606)) ([e4eb534](https://www.github.com/image-js/image-js/commit/e4eb5341314a322cb6addec998fd24b21e0c2143)) -* bump fast-bmp to 2.0.1 ([#608](https://www.github.com/image-js/image-js/issues/608)) ([2ddabf9](https://www.github.com/image-js/image-js/commit/2ddabf9a21824c094b30bc93849308a228007b19)) - -### [0.35.1](https://www.github.com/image-js/image-js/compare/v0.35.0...v0.35.1) (2022-08-10) - - -### Bug Fixes - -* add TypeScript definition to many methods ([#600](https://www.github.com/image-js/image-js/issues/600)) ([6caaf19](https://www.github.com/image-js/image-js/commit/6caaf19f0651945f798def1a1193b5d1ccf4d9f0)) - -## [0.35.0](https://www.github.com/image-js/image-js/compare/v0.34.1...v0.35.0) (2022-08-01) - - -### Features - -* allow rotate & crop for bitDepth = 1 images ([#596](https://www.github.com/image-js/image-js/issues/596)) ([622b909](https://www.github.com/image-js/image-js/commit/622b9093f17698dd18c3564773a59dd54d4e7f7e)) - - -### Bug Fixes - -* add TypeScript definition to setChannel() method ([#597](https://www.github.com/image-js/image-js/issues/597)) ([551c334](https://www.github.com/image-js/image-js/commit/551c334bdcd9f8ea2972c31197ee0847a14ead3b)) - -### [0.34.1](https://www.github.com/image-js/image-js/compare/v0.34.0...v0.34.1) (2022-05-17) - - -### Bug Fixes - -* add TypeScript definition for paintMasks() ([#591](https://www.github.com/image-js/image-js/issues/591)) ([6edd169](https://www.github.com/image-js/image-js/commit/6edd169cf161b3658a89dfa7d193fb718cd3c25c)) - -## [0.34.0](https://www.github.com/image-js/image-js/compare/v0.33.2...v0.34.0) (2022-04-11) - - -### Features - -* add option to ignore color palette in TIFF images ([#589](https://www.github.com/image-js/image-js/issues/589)) ([07aa7d5](https://www.github.com/image-js/image-js/commit/07aa7d591ca0f674fca83fbfef910e4e6243181e)) - -### [0.33.2](https://www.github.com/image-js/image-js/compare/v0.33.1...v0.33.2) (2022-03-28) - - -### Bug Fixes - -* add TypeScript definition for paintPolygon() ([#587](https://www.github.com/image-js/image-js/issues/587)) ([d0c0541](https://www.github.com/image-js/image-js/commit/d0c054124ef38b0dea6a791780a6b83fda842ee8)) - -### [0.33.1](https://www.github.com/image-js/image-js/compare/v0.33.0...v0.33.1) (2021-10-31) - - -### Bug Fixes - -* update TIFF decoder ([#575](https://www.github.com/image-js/image-js/issues/575)) ([8a09396](https://www.github.com/image-js/image-js/commit/8a0939620027957e41209549ffe595c7c3023a37)) - -## [0.33.0](https://www.github.com/image-js/image-js/compare/v0.32.0...v0.33.0) (2021-08-30) - - -### ⚠ BREAKING CHANGES - -* Improve MBR speed - -### Bug Fixes - -* Improve MBR speed ([c77fec2](https://www.github.com/image-js/image-js/commit/c77fec2308bf7d1f23ddc352d21f4f53ee911c8d)) - -## [0.32.0](https://www.github.com/image-js/image-js/compare/v0.31.4...v0.32.0) (2021-07-09) - - -### ⚠ BREAKING CHANGES - -* auto-correct orientation of JPEG images according to EXIF (#563) -* Removed support for Node.js 10 - -### Bug Fixes - -* auto-correct orientation of JPEG images according to EXIF ([#563](https://www.github.com/image-js/image-js/issues/563)) ([6a2bcf3](https://www.github.com/image-js/image-js/commit/6a2bcf3d479cf4ea700785a17fa4488892a3e448)) -* **types:** add flipX and flipY to types ([2c14a85](https://www.github.com/image-js/image-js/commit/2c14a8510f4958f0c39c048300a9b4596f6268ee)) -* **types:** remove bilinear from supported resize interpolations ([a96eb4c](https://www.github.com/image-js/image-js/commit/a96eb4c40867b715a4411e85fe13dff005179f5d)) - - -### Miscellaneous Chores - -* update dependencies ([ec97242](https://www.github.com/image-js/image-js/commit/ec972424fa6b1e34a65898d0dd4e179d7da0bb0b)) - -### [0.31.4](https://www.github.com/image-js/image-js/compare/v0.31.3...v0.31.4) (2021-01-21) - - -### Bug Fixes - -* roundness was not 1 for perfect circle ([#548](https://www.github.com/image-js/image-js/issues/548)) ([e73f596](https://www.github.com/image-js/image-js/commit/e73f59606218f274bbace969ae48af3bbe1d8b2a)) - -### [0.31.3](https://www.github.com/image-js/image-js/compare/v0.31.2...v0.31.3) (2020-12-14) - - -### Bug Fixes - -* update dependencies ([#539](https://www.github.com/image-js/image-js/issues/539)) ([c972f63](https://www.github.com/image-js/image-js/commit/c972f63a181706c65ea144ec1e6a6edf92deba5a)) - -### [0.31.2](https://www.github.com/image-js/image-js/compare/v0.31.1...v0.31.2) (2020-12-10) - - -### Performance Improvements - -* improve medianFilter ([#537](https://www.github.com/image-js/image-js/issues/537)) ([c341fac](https://www.github.com/image-js/image-js/commit/c341facf65745641510b5c53d1c00e6b3c69697e)) - -### [0.31.1](https://www.github.com/image-js/image-js/compare/v0.31.0...v0.31.1) (2020-11-17) - - -### Bug Fixes - -* correct hull filled mask ([81a8cd7](https://www.github.com/image-js/image-js/commit/81a8cd713add86fdb46f78024dacc343880d71cd)) - -## [0.31.0](https://www.github.com/image-js/image-js/compare/v0.30.3...v0.31.0) (2020-11-12) - - -### Features - -* restore old implementations of getMask with hull or mbr ([#532](https://www.github.com/image-js/image-js/issues/532)) ([4d51dbd](https://www.github.com/image-js/image-js/commit/4d51dbd7baffc4cc32d625b2912e4fbdabdf13a0)) - -### [0.30.3](https://www.github.com/image-js/image-js/compare/v0.30.2...v0.30.3) (2020-10-20) - - -### Bug Fixes - -* **types:** correct return type of Stack.getAverageImage to Image ([#529](https://www.github.com/image-js/image-js/issues/529)) ([ec6588c](https://www.github.com/image-js/image-js/commit/ec6588c2b0152bd865013ffe6fb3e5668c83cae3)) - -### [0.30.2](https://www.github.com/image-js/image-js/compare/v0.30.1...v0.30.2) (2020-10-18) - - -### Bug Fixes - -* add basic Stack type definition ([#525](https://www.github.com/image-js/image-js/issues/525)) ([d5f1972](https://www.github.com/image-js/image-js/commit/d5f1972fc1f39b506882f46b7c6c7722157bfd4c)) - -### [0.30.1](https://www.github.com/image-js/image-js/compare/v0.30.0...v0.30.1) (2020-10-13) - - -### Bug Fixes - -* include less files in npm package ([03903a6](https://www.github.com/image-js/image-js/commit/03903a692a3f4801d44d8d017fced52f218d0369)) - -## [0.30.0](https://www.github.com/image-js/image-js/compare/v0.29.0...v0.30.0) (2020-10-13) - - -### Bug Fixes - -* correct TIFF support in documentation ([7f3993f](https://www.github.com/image-js/image-js/commit/7f3993f189fe8adb32467b9c8522273778392871)) diff --git a/Development.md b/Development.md deleted file mode 100644 index ca55eee1a..000000000 --- a/Development.md +++ /dev/null @@ -1,26 +0,0 @@ -# Development documentation - -## Writing unit tests - -### Tests that compare with OpenCV - -[OpenCV](https://opencv.org/) is a popular image processing library for C++ and Python. -We use it as a reference for some of the functions implemented in ImageJS. - -All images used for comparison with OpenCV are generated by the Python script [`test/img/opencv/generate.py`](./test/img/opencv/generate.py). - -To add a new test reference file: - -- Update [`generate.py`](./test/img/opencv/generate.py) with the OpenCV code that creates the file. -- Run `generate.py` (see following paragraph). -- Add the new filename to the [`TestImagePath`](./test/TestImagePath.ts) type (alphabetical order). - -To run the generation script, use the following steps: - -- Install Python 3.x -- Run `python3 -m venv .venv` to create a virtual environment for the project -- Activate the venv or run the local `pip` and `python` commands. - - `source .venv/bin/activate` (UNIX) - - `.venv/Scripts/Activate.ps1` (Windows) -- Run `pip install opencv-python` -- Run `python test/img/opencv/generate.py` diff --git a/History.md b/History.md new file mode 100644 index 000000000..6a9e8cf14 --- /dev/null +++ b/History.md @@ -0,0 +1,705 @@ + +## [0.21.4](https://github.com/image-js/core/compare/v0.21.3...v0.21.4) (2018-09-17) + + + + +## [0.21.3](https://github.com/image-js/core/compare/v0.21.2...v0.21.3) (2018-09-17) + + + + +## [0.21.2](https://github.com/image-js/core/compare/v0.21.1...v0.21.2) (2018-09-16) + + + + +## [0.21.1](https://github.com/image-js/core/compare/v0.21.0...v0.21.1) (2018-09-08) + + +### Bug Fixes + +* pin canvas to alpha.12 ([1982ffb](https://github.com/image-js/core/commit/1982ffb)) +* **build:** correct babel 7 config ([da0c8a9](https://github.com/image-js/core/commit/da0c8a9)) +* **package:** update blob-util to version 2.0.2 ([#390](https://github.com/image-js/core/issues/390)) ([72780ce](https://github.com/image-js/core/commit/72780ce)), closes [#388](https://github.com/image-js/core/issues/388) + + +### Features + +* **load:** add support palette PNG ([f6042f1](https://github.com/image-js/core/commit/f6042f1)) + + + + +# [0.21.0](https://github.com/image-js/core/compare/v0.20.1...v0.21.0) (2018-04-26) + + +### Features + +* add toBuffer method ([f2fdfc7](https://github.com/image-js/core/commit/f2fdfc7)) + + + + +## [0.20.1](https://github.com/image-js/core/compare/v0.20.0...v0.20.1) (2018-04-13) + + +### Bug Fixes + +* **save:** fix jpeg saving ([c4d90d0](https://github.com/image-js/core/commit/c4d90d0)) + + + + +# [0.20.0](https://github.com/image-js/core/compare/v0.19.1...v0.20.0) (2018-03-15) + + +### Features + +* insert image into another one ([f690a30](https://github.com/image-js/core/commit/f690a30)) + + + + +## [0.19.1](https://github.com/image-js/core/compare/v0.19.0...v0.19.1) (2018-02-16) + + + + +# [0.19.0](https://github.com/image-js/core/compare/v0.18.1...v0.19.0) (2018-02-16) + + +### Performance Improvements + +* optimize dilate and erode for "only-1" kernels with grey images ([2119414](https://github.com/image-js/core/commit/2119414)) +* optimize erode and dilate for "only-1" kernels ([#374](https://github.com/image-js/core/issues/374)) ([6023f70](https://github.com/image-js/core/commit/6023f70)) + + + + +## [0.18.1](https://github.com/image-js/core/compare/v0.18.0...v0.18.1) (2018-02-06) + + +### Bug Fixes + +* allow again to export png from 1 or 32 bit images ([838f5e0](https://github.com/image-js/core/commit/838f5e0)) + + + + +# [0.18.0](https://github.com/image-js/core/compare/v0.17.0...v0.18.0) (2018-02-06) + + + + +# [0.17.0](https://github.com/image-js/core/compare/v0.16.1...v0.17.0) (2018-02-01) + + +* infer file format from filename when saving ([9a30c34](https://github.com/image-js/core/commit/9a30c34)) + + +### Bug Fixes + +* fix gaussian blur. kernels should sum to 1 ([ea70851](https://github.com/image-js/core/commit/ea70851)) +* pass bitDepth option in gradientFilter ([0b60bce](https://github.com/image-js/core/commit/0b60bce)) + + +### Features + +* add abs filter ([671f601](https://github.com/image-js/core/commit/671f601)) +* direction option in sobelFilter ([8b9034e](https://github.com/image-js/core/commit/8b9034e)) +* iteration parameter on erode ([4fd915a](https://github.com/image-js/core/commit/4fd915a)) +* support conversion of 32-bit images to rgba data ([5790815](https://github.com/image-js/core/commit/5790815)) + + +### BREAKING CHANGES + +* not specifying a file format will throw instead of saving to png +* sobelFilter no longer allows custom filters. Use gradientFilter instead + + + + +## [0.16.1](https://github.com/image-js/core/compare/v0.16.0...v0.16.1) (2018-01-24) + + +### Features + +* add getThreshold ([d4fdf9f](https://github.com/image-js/core/commit/d4fdf9f)) + + + + +# [0.16.0](https://github.com/image-js/core/compare/v0.15.0...v0.16.0) (2018-01-17) + + +### Bug Fixes + +* force version of rollup-plugin-node-resolve ([80b59bd](https://github.com/image-js/core/commit/80b59bd)) +* **package:** does not support node 6 ([a1660bd](https://github.com/image-js/core/commit/a1660bd)) + + +### Features + +* decode JPEG in JS ([8d92060](https://github.com/image-js/core/commit/8d92060)) + + + + +# [0.15.0](https://github.com/image-js/core/compare/v0.14.4...v0.15.0) (2017-12-11) + + + + +## [0.14.4](https://github.com/image-js/core/compare/v0.14.3...v0.14.4) (2017-08-16) + + +### Bug Fixes + +* fix problem caused by inversion between white and black ([8eaf922](https://github.com/image-js/core/commit/8eaf922)) + + + + +## [0.14.3](https://github.com/image-js/core/compare/v0.14.2...v0.14.3) (2017-08-15) + + +### Bug Fixes + +* errors in the call of the morphological transforms ([b99d938](https://github.com/image-js/core/commit/b99d938)) + + + + +## [0.14.2](https://github.com/image-js/core/compare/v0.14.1...v0.14.2) (2017-08-15) + + + + +## [0.14.1](https://github.com/image-js/core/compare/v0.14.0...v0.14.1) (2017-08-15) + + +### Bug Fixes + +* errors in some cases with erode and dilate ([717d173](https://github.com/image-js/core/commit/717d173)) +* errors in the definition of the dimensions of the submatrix ([e86e6a0](https://github.com/image-js/core/commit/e86e6a0)) + + + + +# [0.14.0](https://github.com/image-js/core/compare/v0.13.0...v0.14.0) (2017-08-15) + + +### Bug Fixes + +* add missing files ([3dc9491](https://github.com/image-js/core/commit/3dc9491)) +* add missing files ([51d45ff](https://github.com/image-js/core/commit/51d45ff)) +* change the arguments (replaced by one argument 'options') ([8f8ebc9](https://github.com/image-js/core/commit/8f8ebc9)) +* check image and kernel ([7ea982c](https://github.com/image-js/core/commit/7ea982c)) +* correction of the name of the errors ([afd79ba](https://github.com/image-js/core/commit/afd79ba)) +* modify names of the tests ([c41e611](https://github.com/image-js/core/commit/c41e611)) + + +### Features + +* Add an argument 'iterations' to the morphological transforms (except dilate and erode) ([671d318](https://github.com/image-js/core/commit/671d318)) +* Add erode and dilate functions ([e4e1dad](https://github.com/image-js/core/commit/e4e1dad)) +* add subtractImage with absolute values and use it for new function -> morphologicalGradient ([d3cbfe2](https://github.com/image-js/core/commit/d3cbfe2)) + + + + +# [0.13.0](https://github.com/image-js/core/compare/v0.12.0...v0.13.0) (2017-08-10) + + +### Bug Fixes + +* add deleted tests, default option options.filled = false ([b93f388](https://github.com/image-js/core/commit/b93f388)) +* bug when we want to draw polygon without fill it ([44013d4](https://github.com/image-js/core/commit/44013d4)) +* replace the word 'filtred' by 'filtered' ([3f092b9](https://github.com/image-js/core/commit/3f092b9)) +* revert rollup-plugin-babel to v2 ([57009cd](https://github.com/image-js/core/commit/57009cd)) +* update doc polygon ([a611eac](https://github.com/image-js/core/commit/a611eac)) + + +### Features + +* Add drawing of filled polygons ([3491905](https://github.com/image-js/core/commit/3491905)) +* Add the possibility to desactivate the computation of the aspect ratio. ([097f2a7](https://github.com/image-js/core/commit/097f2a7)) +* Add the warping with 4 fours (transform a quadrilateral to a rectangle) ([e8e9a5e](https://github.com/image-js/core/commit/e8e9a5e)) + + + + +# [0.12.0](https://github.com/image-js/core/compare/v0.11.11...v0.12.0) (2017-07-25) + + + + +## [0.11.11](https://github.com/image-js/core/compare/v0.11.10...v0.11.11) (2017-07-25) + + + + +## [0.11.10](https://github.com/image-js/core/compare/v0.11.9...v0.11.10) (2017-07-20) + + + + +## [0.11.9](https://github.com/image-js/core/compare/v0.11.8...v0.11.9) (2017-07-13) + + + + +## [0.11.8](https://github.com/image-js/core/compare/v0.11.7...v0.11.8) (2017-07-13) + + + + +## [0.11.7](https://github.com/image-js/core/compare/v0.11.6...v0.11.7) (2017-07-12) + + + + +## [0.11.6](https://github.com/image-js/core/compare/v0.11.5...v0.11.6) (2017-07-12) + + + + +## [0.11.5](https://github.com/image-js/core/compare/v0.11.4...v0.11.5) (2017-06-28) + + +### Features + +* add cannyEdge method ([c19b90a](https://github.com/image-js/core/commit/c19b90a)) + + + + +## [0.11.4](https://github.com/image-js/core/compare/v0.11.3...v0.11.4) (2017-06-28) + + + + +## [0.11.3](https://github.com/image-js/core/compare/v0.11.2...v0.11.3) (2017-06-13) + + + + +## [0.11.1](https://github.com/image-js/core/compare/v0.11.0...v0.11.1) (2017-06-07) + + +### Features + +* Add paintPolygon and don t close shape in paintPolyline ([e7cad0c](https://github.com/image-js/core/commit/e7cad0c)) + + + + +# [0.11.0](https://github.com/image-js/core/compare/v0.10.4...v0.11.0) (2017-05-29) + + + + +## [0.10.4](https://github.com/image-js/core/compare/v0.10.3...v0.10.4) (2017-05-22) + + +### Bug Fixes + +* allow separable algorithm for big images ([1e8b28a](https://github.com/image-js/core/commit/1e8b28a)) + + + + +## [0.10.3](https://github.com/image-js/core/compare/v0.10.2...v0.10.3) (2017-05-22) + + +### Features + +* add algorithm for convolution with separable kernels ([c11bd98](https://github.com/image-js/core/commit/c11bd98)) + + + + +## [0.10.2](https://github.com/image-js/core/compare/v0.10.1...v0.10.2) (2017-05-18) + + + + +## [0.10.1](https://github.com/image-js/core/compare/v0.10.0...v0.10.1) (2017-05-18) + + + + +# [0.10.0](https://github.com/image-js/core/compare/v0.9.13...v0.10.0) (2017-05-18) + + + + +## [0.9.13](https://github.com/image-js/core/compare/v0.9.12...v0.9.13) (2017-04-30) + + +### Bug Fixes + +* **package:** update ml-matrix to version 3.0.0 ([#312](https://github.com/image-js/core/issues/312)) ([1b9b9ea](https://github.com/image-js/core/commit/1b9b9ea)) + + + + +## [0.9.12](https://github.com/image-js/core/compare/v0.9.11...v0.9.12) (2017-04-16) + + + + +## [0.9.11](https://github.com/image-js/core/compare/v0.9.10...v0.9.11) (2017-04-15) + + + + +## [0.9.10](https://github.com/image-js/core/compare/v0.9.5...v0.9.10) (2017-04-12) + + +### Bug Fixes + +* **package:** update image-type to version 3.0.0 ([#299](https://github.com/image-js/core/issues/299)) ([8c62465](https://github.com/image-js/core/commit/8c62465)) + + +### Features + +* add monotoneChainConvexHull and minimalBoundingRectangle ([139aa21](https://github.com/image-js/core/commit/139aa21)) + + + + +## [0.9.5](https://github.com/image-js/core/compare/v0.9.4...v0.9.5) (2017-01-19) + + + + +## [0.9.4](https://github.com/image-js/core/compare/v0.9.3...v0.9.4) (2017-01-06) + + + + +## [0.9.3](https://github.com/image-js/core/compare/v0.9.2...v0.9.3) (2017-01-06) + + + + +## [0.9.2](https://github.com/image-js/core/compare/v0.9.1...v0.9.2) (2017-01-05) + + + + +## [0.9.1](https://github.com/image-js/core/compare/v0.9.0...v0.9.1) (2016-12-15) + + + + +# [0.9.0](https://github.com/image-js/core/compare/v0.8.9...v0.9.0) (2016-12-15) + + +### Features + +* add bmp support to save ([86a07a5](https://github.com/image-js/core/commit/86a07a5)) +* add support for bmp in toDataURL ([8b9fa61](https://github.com/image-js/core/commit/8b9fa61)) + + + + +## [0.8.9](https://github.com/image-js/core/compare/v0.8.8...v0.8.9) (2016-12-02) + + +### Features + +* implement cropAlpha ([149cf6b](https://github.com/image-js/core/commit/149cf6b)) +* implement floodFill for binary images ([5d7b190](https://github.com/image-js/core/commit/5d7b190)) + + + + +## [0.8.8](https://github.com/image-js/core/compare/v0.8.7...v0.8.8) (2016-12-01) + + +### Features + +* add free rotation support ([#111](https://github.com/image-js/core/issues/111)) ([92cf504](https://github.com/image-js/core/commit/92cf504)) + + + + +## [0.8.7](https://github.com/image-js/core/compare/v0.8.6...v0.8.7) (2016-11-30) + + +### Features + +* allow toBase64 to be async for Node.js ([4644d2e](https://github.com/image-js/core/commit/4644d2e)) + + + + +## [0.8.6](https://github.com/image-js/core/compare/v0.8.5...v0.8.6) (2016-11-30) + + +### Features + +* allow toDataURL to be async for Node.js ([a4b5fb1](https://github.com/image-js/core/commit/a4b5fb1)) + + + + +## [0.8.5](https://github.com/image-js/core/compare/v0.8.4...v0.8.5) (2016-11-30) + + +### Features + +* add toBase64 method ([e7e8633](https://github.com/image-js/core/commit/e7e8633)) + + + + +## [0.8.4](https://github.com/image-js/core/compare/v0.8.3...v0.8.4) (2016-11-30) + + + + +## [0.8.3](https://github.com/image-js/core/compare/v0.8.2...v0.8.3) (2016-11-29) + + + + +## [0.8.2](https://github.com/image-js/core/compare/v0.8.1...v0.8.2) (2016-11-27) + + + + +## [0.8.1](https://github.com/image-js/core/compare/v0.8.0...v0.8.1) (2016-11-26) + + + + +# [0.8.0](https://github.com/image-js/core/compare/v0.7.0...v0.8.0) (2016-11-21) + + +### Bug Fixes + +* inverted components and channels in checkProcessable ([7b8b4c2](https://github.com/image-js/core/commit/7b8b4c2)) +* **crop:** convert non-integer arguments ([e308ca6](https://github.com/image-js/core/commit/e308ca6)) +* **paintMasks:** accept images with 3 channels ([cbb9b00](https://github.com/image-js/core/commit/cbb9b00)) +* **save:** don't create write stream if getCanvas failed ([ce4271e](https://github.com/image-js/core/commit/ce4271e)) + + +### Features + +* **scale:** add preserveAspectRatio option ([6976c11](https://github.com/image-js/core/commit/6976c11)), closes [#259](https://github.com/image-js/core/issues/259) +* add img.rotate, img.rotateLeft and img.rotateRight ([a189747](https://github.com/image-js/core/commit/a189747)), closes [#235](https://github.com/image-js/core/issues/235) + + + + +# [0.7.0](https://github.com/image-js/core/compare/v0.6.3...v0.7.0) (2016-11-05) + + +### Bug Fixes + +* correctly read bitsPerSample on RGB TIFF images ([5acf2a0](https://github.com/image-js/core/commit/5acf2a0)) + + +### Features + +* update tiff to add support for RGB images ([372e126](https://github.com/image-js/core/commit/372e126)) + + + + +## [0.6.3](https://github.com/image-js/core/compare/v0.6.2...v0.6.3) (2016-10-31) + + +### Features + +* add support for loading an image from buffers ([65830dd](https://github.com/image-js/core/commit/65830dd)) +* add support for loading an image from buffers ([b701a0f](https://github.com/image-js/core/commit/b701a0f)) + + + + +## [0.6.2](https://github.com/image-js/core/compare/v0.6.1...v0.6.2) (2016-10-18) + + +### Bug Fixes + +* add missing GREY color model ([cd2f22e](https://github.com/image-js/core/commit/cd2f22e)) + + + + +## [0.6.1](https://github.com/image-js/core/compare/v0.6.0...v0.6.1) (2016-10-13) + + + + +# [0.6.0](https://github.com/image-js/core/compare/v0.5.9...v0.6.0) (2016-10-12) + + +### Bug Fixes + +* crop in fft convolution missed columns and rows ([9483fc0](https://github.com/image-js/core/commit/9483fc0)) + + + + +## [0.5.9](https://github.com/image-js/core/compare/v0.5.8...v0.5.9) (2016-10-05) + + +### Features + +* add getPixelsArray method ([8891fd1](https://github.com/image-js/core/commit/8891fd1)) + + + + +## [0.5.8](https://github.com/image-js/core/compare/v0.5.7...v0.5.8) (2016-09-27) + + + + +## [0.5.7](https://github.com/image-js/core/compare/v0.5.6...v0.5.7) (2016-09-27) + + + + +## [0.5.6](https://github.com/image-js/core/compare/v0.5.5...v0.5.6) (2016-09-27) + + + + +## [0.5.5](https://github.com/image-js/core/compare/v0.5.4...v0.5.5) (2016-09-27) + + + + +## [0.5.4](https://github.com/image-js/core/compare/v0.5.3...v0.5.4) (2016-09-26) + + + + +## [0.5.3](https://github.com/image-js/core/compare/v0.5.0...v0.5.3) (2016-09-26) + + + + +# [0.5.0](https://github.com/image-js/core/compare/v0.2.3...v0.5.0) (2016-09-25) + + +### Features + +* Add cmyk model and conversion from rgb and rgba to cmyk ([288ffd6](https://github.com/image-js/core/commit/288ffd6)) +* add support for tiff and jpeg metadata ([1d6fcac](https://github.com/image-js/core/commit/1d6fcac)) + + + + +## [0.2.3](https://github.com/image-js/core/compare/v0.1.12...v0.2.3) (2016-09-17) + + + + +## [0.1.12](https://github.com/image-js/core/compare/v0.1.11...v0.1.12) (2016-08-29) + + +### Bug Fixes + +* **load:** allow to set withCredentials option ([6d16a2f](https://github.com/image-js/core/commit/6d16a2f)) + + + + +## [0.1.11](https://github.com/image-js/core/compare/v0.1.10...v0.1.11) (2016-08-25) + + +### Bug Fixes + +* **stack:** fix check of Symbol.species ([4ca66ed](https://github.com/image-js/core/commit/4ca66ed)) + + + + +## [0.1.10](https://github.com/image-js/core/compare/v0.1.9...v0.1.10) (2016-08-03) + + +### Features + +* add Image.fromCanvas ([b75f03c](https://github.com/image-js/core/commit/b75f03c)) +* allow 8 neighbours connectivity for map creator ([e0ba870](https://github.com/image-js/core/commit/e0ba870)) + + + + +## [0.1.9](https://github.com/image-js/core/compare/v0.1.8...v0.1.9) (2016-04-25) + + + + +## [0.1.8](https://github.com/image-js/core/compare/v0.1.7...v0.1.8) (2016-01-29) + + + + +## [0.1.7](https://github.com/image-js/core/compare/v0.1.6...v0.1.7) (2015-12-12) + + + + +## [0.1.6](https://github.com/image-js/core/compare/v0.1.5...v0.1.6) (2015-10-23) + + + + +## [0.1.5](https://github.com/image-js/core/compare/v0.1.4...v0.1.5) (2015-10-23) + + + + +## [0.1.4](https://github.com/image-js/core/compare/v0.1.3...v0.1.4) (2015-10-14) + + +### Features + +* Improve ROI manager to create RGBA image for painting ([3d21bdb](https://github.com/image-js/core/commit/3d21bdb)) + + + + +## [0.1.3](https://github.com/image-js/core/compare/v0.1.2...v0.1.3) (2015-10-02) + + + + +## [0.1.2](https://github.com/image-js/core/compare/v0.1.1...v0.1.2) (2015-09-20) + + + + +## [0.1.1](https://github.com/image-js/core/compare/v0.1.0...v0.1.1) (2015-09-20) + + + + +# [0.1.0](https://github.com/image-js/core/compare/v0.0.5...v0.1.0) (2015-09-19) + + + + +## [0.0.5](https://github.com/image-js/core/compare/v0.0.4...v0.0.5) (2015-08-14) + + + + +## [0.0.4](https://github.com/image-js/core/compare/v0.0.3...v0.0.4) (2015-07-21) + + + + +## 0.0.3 (2015-07-17) + + + diff --git a/LICENSE b/LICENSE index febe0f740..f5ec24247 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ -MIT License +The MIT License (MIT) -Copyright (c) 2021 image-js +Copyright (c) 2015 image-js Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 86237dce2..74df05841 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,203 @@ -

- - Zakodium logo - -

- Maintained by Zakodium -

-

- # image-js -[![NPM version](https://img.shields.io/npm/v/image-js.svg)](https://www.npmjs.com/package/image-js) -[![npm download](https://img.shields.io/npm/dm/image-js.svg)](https://www.npmjs.com/package/image-js) -[![test coverage](https://img.shields.io/codecov/c/github/image-js/image-js.svg)](https://codecov.io/gh/image-js/image-js) -[![license](https://img.shields.io/npm/l/image-js.svg)](https://github.com/image-js/image-js/blob/main/LICENSE) +[![NPM version][npm-image]][npm-url] +[![build status][travis-image]][travis-url] +[![Test coverage][codecov-image]][codecov-url] +[![npm download][download-image]][download-url] + +Advanced image processing and manipulation in JavaScript. -Image processing and manipulation in JavaScript. +image-js is a full-featured library that can deal with simple image processing +(color leveling, grey image, mask, resize, rotation, etc.) as well as advanced +processing on scientific images (Region of interest (ROI), Hull curve, minimal +boundary rectangle (MBR), particle size and orientation, cell imaging, etc.). + +## [API Documentation](https://image-js.github.io/image-js/) ## Installation +`$ npm install image-js` + +## Features + +### Supported image formats + +The following formats can be loaded by image-js: + +- PNG (8 or 16 bits, color or greyscale, with or without alpha, palette 1 - 8 bits) +- JPEG +- TIFF (8 or 16 bits, greyscale) + +The following formats can be saved by image-js: + +- PNG (8 or 16 bits) +- JPEG +- BMP (black and white) + +### Native support for various bit depths and image kinds + +image-js was developed to be used in scientific applications where we often +have to work on images that have more that 8 bits per channel. +Unlike many other libraries, if a 16-bit greyscale PNG is decoded, the resulting +image has only one 16-bit channel and no pixel information is lost. + +image-js can work with images that have 1 (binary), 8, 16 or 32 bits per channel. +It can accept an arbitrary amount of color channels (usually 1 or 3) and can +handle an additional alpha component. + +### Basic image manipulation + +image-js can be used to do simple image manipulations such as: + +- Resize +- Crop +- Rotate +- Convert to greyscale +- Invert colors +- Gaussian blur +- Extract individual channels (red, green or blue) +- And more... + +### Statistics + +image-js implements a number of functions to get statistics about an image: + +- Histogram +- Max, min, median value +- And more ... + +### Advanced features for computer vision + +- Image thresholding (otsu, triangle, ...) +- Regions of interest +- Convolution with custom kernel +- Sobel filter +- Morphological transformations (open, close, erode, ...) + +## An example using npm and node + +Install the library: + +```console +npm i image-js +``` + +An example of code manipulating the image 'cat.jpg' (you need to create it). + +```js +const { Image } = require('image-js'); + +execute().catch(console.error); + +async function execute() { + let image = await Image.load('cat.jpg'); + let grey = image + .grey() // convert the image to greyscale. + .resize({ width: 200 }) // resize the image, forcing a width of 200 pixels. The height is computed automatically to preserve the aspect ratio. + .rotate(30); // rotate the image clockwise by 30 degrees. + return grey.save('cat.png'); +} +``` + ```console -npm install image-js +node index.js +``` + +A greyscale image will be saved in the same folder. + +## Examples in the browser + +### Load an image and convert it to grey + +```html + + + + + + + + + + + + + + + ``` -## API + + +[Try it](https://www.w3schools.com/code/tryit.asp?filename=FVD6UC9S7RSV) + +### Create a mask + + + +[Try it](https://www.w3schools.com/code/tryit.asp?filename=FVD6TP7ICRZM) + +### Paint a mask -### [Complete API documentation](https://api.image-js.org/) + -### [Usage docs and guides](https://docs.image-js.org/) +[Try it](https://www.w3schools.com/code/tryit.asp?filename=FVD6T1Y63MUH) + +### Filter a mask using Region Of Interests (ROIs) + +Image-js has a powerful Region of Interests Manager that allows to create ROIs from different sources. The ROIs can then be filtered, manipulated and finally painted to an RGBA image. + + + +[Try it](https://www.w3schools.com/code/tryit.asp?filename=FVD6SE2F4MWE) + +When extracting a mask from a ROI you have many options (`contour`, `box`, `filled`, `center`, `hull` or `normal`). Here it looks better to use the `filled` ROI. + + + +[Try it](https://www.w3schools.com/code/tryit.asp?filename=FVD6QQISMLZ2) + +### Advanced analysis of SEM / TEM images + +This library is able to deal with complex analysis involving images of cell or SEM / TEM. It will deal correctly with 16 bits grey scale images (TIFF or PNG) commonly found in scientific results. + +In this example we will annotate an SEM / TEM image by coloring each particle and show the surface of them. + + + + +We also display a table containing a summary of all the identified particles. + +[Try it](https://www.w3schools.com/code/tryit.asp?filename=FVCJLR0VNK33) ## Development -See [Development documentation](./Development.md). +Contributions to code or documentation are welcome! Here are a few tips on how to +setup a development environment for image-js. + +### Canvas + +The `canvas` native addon library is required for all tests to pass. You can +follow the instructions to install it on your OS [here](https://github.com/Automattic/node-canvas#installation). ## License [MIT](./LICENSE) + +[npm-image]: https://img.shields.io/npm/v/image-js.svg?style=flat-square +[npm-url]: https://www.npmjs.com/package/image-js +[travis-image]: https://img.shields.io/travis/image-js/image-js/master.svg?style=flat-square +[travis-url]: https://travis-ci.org/image-js/image-js +[codecov-image]: https://img.shields.io/codecov/c/github/image-js/image-js.svg?style=flat-square +[codecov-url]: https://codecov.io/gh/image-js/image-js +[download-image]: https://img.shields.io/npm/dm/image-js.svg?style=flat-square +[download-url]: https://www.npmjs.com/package/image-js diff --git a/api-extractor.json b/api-extractor.json deleted file mode 100644 index da652662f..000000000 --- a/api-extractor.json +++ /dev/null @@ -1,427 +0,0 @@ -/** - * Config file for API Extractor. For more info, please visit: https://api-extractor.com - */ -{ - "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - /** - * Optionally specifies another JSON config file that this file extends from. This provides a way for - * standard settings to be shared across multiple projects. - * - * If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains - * the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be - * resolved using NodeJS require(). - * - * SUPPORTED TOKENS: none - * DEFAULT VALUE: "" - */ - // "extends": "./shared/api-extractor-base.json" - // "extends": "my-package/include/api-extractor-base.json" - - /** - * Determines the "" token that can be used with other config file settings. The project folder - * typically contains the tsconfig.json and package.json config files, but the path is user-defined. - * - * The path is resolved relative to the folder of the config file that contains the setting. - * - * The default value for "projectFolder" is the token "", which means the folder is determined by traversing - * parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder - * that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error - * will be reported. - * - * SUPPORTED TOKENS: - * DEFAULT VALUE: "" - */ - // "projectFolder": "..", - - /** - * (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor - * analyzes the symbols exported by this module. - * - * The file extension must be ".d.ts" and not ".ts". - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - */ - "mainEntryPointFilePath": "/lib/index.d.ts", - - /** - * A list of NPM package names whose exports should be treated as part of this package. - * - * For example, suppose that Webpack is used to generate a distributed bundle for the project "library1", - * and another NPM package "library2" is embedded in this bundle. Some types from library2 may become part - * of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly - * imports library2. To avoid this, we can specify: - * - * "bundledPackages": [ "library2" ], - * - * This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been - * local files for library1. - */ - "bundledPackages": ["colord"], - - /** - * Specifies what type of newlines API Extractor should use when writing output files. By default, the output files - * will be written with Windows-style newlines. To use POSIX-style newlines, specify "lf" instead. - * To use the OS's default newline kind, specify "os". - * - * DEFAULT VALUE: "crlf" - */ - // "newlineKind": "crlf", - - /** - * Set to true when invoking API Extractor's test harness. When `testMode` is true, the `toolVersion` field in the - * .api.json file is assigned an empty string to prevent spurious diffs in output files tracked for tests. - * - * DEFAULT VALUE: "false" - */ - // "testMode": false, - - /** - * Specifies how API Extractor sorts members of an enum when generating the .api.json file. By default, the output - * files will be sorted alphabetically, which is "by-name". To keep the ordering in the source code, specify - * "preserve". - * - * DEFAULT VALUE: "by-name" - */ - // "enumMemberOrder": "by-name", - - /** - * Determines how the TypeScript compiler engine will be invoked by API Extractor. - */ - "compiler": { - /** - * Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * Note: This setting will be ignored if "overrideTsconfig" is used. - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/tsconfig.json" - */ - "tsconfigFilePath": "/tsconfig.build.json" - /** - * Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk. - * The object must conform to the TypeScript tsconfig schema: - * - * http://json.schemastore.org/tsconfig - * - * If omitted, then the tsconfig.json file will be read from the "projectFolder". - * - * DEFAULT VALUE: no overrideTsconfig section - */ - // "overrideTsconfig": { - // . . . - // } - /** - * This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended - * and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when - * dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses - * for its analysis. Where possible, the underlying issue should be fixed rather than relying on skipLibCheck. - * - * DEFAULT VALUE: false - */ - // "skipLibCheck": true, - }, - - /** - * Configures how the API report file (*.api.md) will be generated. - */ - "apiReport": { - /** - * (REQUIRED) Whether to generate an API report. - */ - "enabled": false - - /** - * The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce - * a full file path. - * - * The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/". - * - * SUPPORTED TOKENS: , - * DEFAULT VALUE: ".api.md" - */ - // "reportFileName": ".api.md", - - /** - * Specifies the folder where the API report file is written. The file name portion is determined by - * the "reportFileName" setting. - * - * The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy, - * e.g. for an API review. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/temp/" - */ - // "reportFolder": "/temp/", - - /** - * Specifies the folder where the temporary report file is written. The file name portion is determined by - * the "reportFileName" setting. - * - * After the temporary file is written to disk, it is compared with the file in the "reportFolder". - * If they are different, a production build will fail. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/temp/" - */ - // "reportTempFolder": "/temp/", - - /** - * Whether "forgotten exports" should be included in the API report file. Forgotten exports are declarations - * flagged with `ae-forgotten-export` warnings. See https://api-extractor.com/pages/messages/ae-forgotten-export/ to - * learn more. - * - * DEFAULT VALUE: "false" - */ - // "includeForgottenExports": false - }, - - /** - * Configures how the doc model file (*.api.json) will be generated. - */ - "docModel": { - /** - * (REQUIRED) Whether to generate a doc model file. - */ - "enabled": false - - /** - * The output path for the doc model file. The file extension should be ".api.json". - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/temp/.api.json" - */ - // "apiJsonFilePath": "/temp/.api.json", - - /** - * Whether "forgotten exports" should be included in the doc model file. Forgotten exports are declarations - * flagged with `ae-forgotten-export` warnings. See https://api-extractor.com/pages/messages/ae-forgotten-export/ to - * learn more. - * - * DEFAULT VALUE: "false" - */ - // "includeForgottenExports": false, - - /** - * The base URL where the project's source code can be viewed on a website such as GitHub or - * Azure DevOps. This URL path corresponds to the `` path on disk. - * - * This URL is concatenated with the file paths serialized to the doc model to produce URL file paths to individual API items. - * For example, if the `projectFolderUrl` is "https://github.com/microsoft/rushstack/tree/main/apps/api-extractor" and an API - * item's file path is "api/ExtractorConfig.ts", the full URL file path would be - * "https://github.com/microsoft/rushstack/tree/main/apps/api-extractor/api/ExtractorConfig.js". - * - * Can be omitted if you don't need source code links in your API documentation reference. - * - * SUPPORTED TOKENS: none - * DEFAULT VALUE: "" - */ - // "projectFolderUrl": "http://github.com/path/to/your/projectFolder" - }, - - /** - * Configures how the .d.ts rollup file will be generated. - */ - "dtsRollup": { - /** - * (REQUIRED) Whether to generate the .d.ts rollup file. - */ - "enabled": true, - - /** - * Specifies the output path for a .d.ts rollup file to be generated without any trimming. - * This file will include all declarations that are exported by the main entry point. - * - * If the path is an empty string, then this file will not be written. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/dist/.d.ts" - */ - "untrimmedFilePath": "/dist-types/.d.ts" - - /** - * Specifies the output path for a .d.ts rollup file to be generated with trimming for an "alpha" release. - * This file will include only declarations that are marked as "@public", "@beta", or "@alpha". - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "" - */ - // "alphaTrimmedFilePath": "/dist/-alpha.d.ts", - - /** - * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release. - * This file will include only declarations that are marked as "@public" or "@beta". - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "" - */ - // "betaTrimmedFilePath": "/dist/-beta.d.ts", - - /** - * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release. - * This file will include only declarations that are marked as "@public". - * - * If the path is an empty string, then this file will not be written. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "" - */ - // "publicTrimmedFilePath": "/dist/-public.d.ts", - - /** - * When a declaration is trimmed, by default it will be replaced by a code comment such as - * "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the - * declaration completely. - * - * DEFAULT VALUE: false - */ - // "omitTrimmingComments": true - }, - - /** - * Configures how the tsdoc-metadata.json file will be generated. - */ - "tsdocMetadata": { - /** - * Whether to generate the tsdoc-metadata.json file. - * - * DEFAULT VALUE: true - */ - "enabled": false - /** - * Specifies where the TSDoc metadata file should be written. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * The default value is "", which causes the path to be automatically inferred from the "tsdocMetadata", - * "typings" or "main" fields of the project's package.json. If none of these fields are set, the lookup - * falls back to "tsdoc-metadata.json" in the package folder. - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "" - */ - // "tsdocMetadataFilePath": "/dist/tsdoc-metadata.json" - }, - - /** - * Configures how API Extractor reports error and warning messages produced during analysis. - * - * There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages. - */ - "messages": { - /** - * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing - * the input .d.ts files. - * - * TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551" - * - * DEFAULT VALUE: A single "default" entry with logLevel=warning. - */ - "compilerMessageReporting": { - /** - * Configures the default routing for messages that don't match an explicit rule in this table. - */ - "default": { - /** - * Specifies whether the message should be written to the the tool's output log. Note that - * the "addToApiReportFile" property may supersede this option. - * - * Possible values: "error", "warning", "none" - * - * Errors cause the build to fail and return a nonzero exit code. Warnings cause a production build fail - * and return a nonzero exit code. For a non-production build (e.g. when "api-extractor run" includes - * the "--local" option), the warning is displayed but the build will not fail. - * - * DEFAULT VALUE: "warning" - */ - "logLevel": "warning" - - /** - * When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md), - * then the message will be written inside that file; otherwise, the message is instead logged according to - * the "logLevel" option. - * - * DEFAULT VALUE: false - */ - // "addToApiReportFile": false - } - - // "TS2551": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - }, - - /** - * Configures handling of messages reported by API Extractor during its analysis. - * - * API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag" - * - * DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings - */ - "extractorMessageReporting": { - "default": { - "logLevel": "warning" - // "addToApiReportFile": false - } - - // "ae-extra-release-tag": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - }, - - /** - * Configures handling of messages reported by the TSDoc parser when analyzing code comments. - * - * TSDoc message identifiers start with "tsdoc-". For example: "tsdoc-link-tag-unescaped-text" - * - * DEFAULT VALUE: A single "default" entry with logLevel=warning. - */ - "tsdocMessageReporting": { - "default": { - "logLevel": "warning" - // "addToApiReportFile": false - } - - // "tsdoc-link-tag-unescaped-text": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - } - } -} diff --git a/benchmark/.eslintrc.yml b/benchmark/.eslintrc.yml new file mode 100644 index 000000000..5f0292e4e --- /dev/null +++ b/benchmark/.eslintrc.yml @@ -0,0 +1,4 @@ +parserOptions: + sourceType: script +rules: + no-console: off diff --git a/benchmark/base.js b/benchmark/base.js new file mode 100644 index 000000000..7597da956 --- /dev/null +++ b/benchmark/base.js @@ -0,0 +1,17 @@ +'use strict'; + +const { Image } = require('..'); + +const image = new Image(1000, 1000, { bitDepth: 8 }); + +function test(n) { + for (let i = 0; i < n; i++) { + image.invert(); + } +} + +test(10); + +console.time('test'); +test(100); +console.timeEnd('test'); diff --git a/benchmark/dataFormat.js b/benchmark/dataFormat.js new file mode 100644 index 000000000..ba5b7b26e --- /dev/null +++ b/benchmark/dataFormat.js @@ -0,0 +1,452 @@ +'use strict'; + +const ITER = 10000; + +let height = 4000; +let width = 4000; +let pixels = width * height; +let channels = 4; +let data8 = new Uint8Array(pixels * channels); +let data16 = new Uint16Array(pixels * channels); + +let newWidth = 30; +let newHeight = 30; +let newPixels = newWidth * newHeight; +let x = 1000; +let y = 1000; + +let dataUint8 = new Array(channels); + +for (var i = 0; i < channels; i++) { + var arr = new Uint8Array(pixels); + dataUint8[i] = arr; + for (var j = 0; j < pixels; j++) { + arr[j] = data8[j * channels + i]; + } +} + +let dataUint16 = new Array(channels); + +for (var i = 0; i < channels; i++) { + var arr = new Uint16Array(pixels); + dataUint16[i] = arr; + for (var j = 0; j < pixels; j++) { + arr[j] = data16[j * channels + i]; + } +} + +let matrixA8 = new Array(channels); + +for (var i = 0; i < channels; i++) { + var matrix = new Array(width); + matrixA8[i] = matrix; + for (var j = 0; j < width; j++) { + var col = new Array(height); + matrix[j] = col; + for (var k = 0; k < height; k++) { + col[k] = data8[(width * j + k) * channels + i]; + } + } +} + +let matrixA16 = new Array(channels); + +for (var i = 0; i < channels; i++) { + var matrix = new Array(width); + matrixA16[i] = matrix; + for (var j = 0; j < width; j++) { + var col = new Array(height); + matrix[j] = col; + for (var k = 0; k < height; k++) { + col[k] = data16[(width * j + k) * channels + i]; + } + } +} + +let matrixU8 = new Array(channels); + +for (var i = 0; i < channels; i++) { + var matrix = new Array(width); + matrixU8[i] = matrix; + for (var j = 0; j < width; j++) { + var col = new Uint8Array(height); + matrix[j] = col; + for (var k = 0; k < height; k++) { + col[k] = data8[(width * j + k) * channels + i]; + } + } +} + +let matrixU16 = new Array(channels); + +for (var i = 0; i < channels; i++) { + var matrix = new Array(width); + matrixU16[i] = matrix; + for (var j = 0; j < width; j++) { + var col = new Uint16Array(height); + matrix[j] = col; + for (var k = 0; k < height; k++) { + col[k] = data16[(width * j + k) * channels + i]; + } + } +} + + +test('Uint8Array', function () { + let newData = new Array(channels); + for (var i = 0; i < channels; i++) { + newData[i] = new Uint8Array(newPixels); + } + + let y1 = y + newHeight; + + let ptr = 0; + for (var i = y; i < y1; i++) { + let j = i * width + x; + let jL = j + newWidth; + for (; j < jL; j++) { + for (let c = 0; c < channels; c++) { + newData[c][ptr] = dataUint8[c][j]; + ptr++; + } + } + } +}); + +test('Uint16Array', function () { + let newData = new Array(channels); + for (var i = 0; i < channels; i++) { + newData[i] = new Uint16Array(newPixels); + } + + let y1 = y + newHeight; + + let ptr = 0; + for (var i = y; i < y1; i++) { + let j = i * width + x; + let jL = j + newWidth; + for (; j < jL; j++) { + for (let c = 0; c < channels; c++) { + newData[c][ptr] = dataUint16[c][j]; + ptr++; + } + } + } +}); + +// test('Matrix of Uint8Arrays', function () { +// var newData = new Array(channels); +// +// for (var i = 0; i < channels; i++) { +// var matrix = new Array(width); +// newData[i] = matrix; +// for (var j = 0; j < width; j++) { +// matrix[j] = new Uint8Array(height); +// } +// } +// +// var ptrX = 0; +// for (var i = x; i < (x + newWidth); i++) { +// var ptrY = 0; +// for (var j = y; j < (y + newHeight); j++) { +// for (var c = 0; c < channels; c++) { +// newData[c][ptrX][ptrY] = matrixU8[c][i][j]; +// } +// ptrY++; +// } +// ptrX++; +// } +// }) +// +// test('Matrix of Uint16Arrays', function () { +// var newData = new Array(channels); +// +// for (var i = 0; i < channels; i++) { +// var matrix = new Array(width); +// newData[i] = matrix; +// for (var j = 0; j < width; j++) { +// matrix[j] = new Uint16Array(height); +// } +// } +// +// var ptrX = 0; +// for (var i = x; i < (x + newWidth); i++) { +// var ptrY = 0; +// for (var j = y; j < (y + newHeight); j++) { +// for (var c = 0; c < channels; c++) { +// newData[c][ptrX][ptrY] = matrixU16[c][i][j]; +// } +// ptrY++; +// } +// ptrX++; +// } +// }); +// +// test('Matrix of Uint8Arrays iter on newArray', function () { +// var newData = new Array(channels); +// +// for (var i = 0; i < channels; i++) { +// var matrix = new Array(width); +// newData[i] = matrix; +// for (var j = 0; j < width; j++) { +// matrix[j] = new Uint8Array(height); +// } +// } +// +// +// for (var i = 0; i < newWidth; i++) { +// for (var j = 0; j < newHeight; j++) { +// for (var c = 0; c < channels; c++) { +// newData[c][i][j] = matrixU8[c][x+i][y+j]; +// } +// } +// } +// }); + +test('Matrix of Uint8Arrays outer channel loop', function () { + let newData = new Array(channels); + + for (var i = 0; i < channels; i++) { + let matrix = new Array(newWidth); + newData[i] = matrix; + for (var j = 0; j < newWidth; j++) { + matrix[j] = new Uint8Array(newHeight); + } + } + + for (let c = 0; c < channels; c++) { + for (var i = 0; i < newWidth; i++) { + for (var j = 0; j < newHeight; j++) { + newData[c][i][j] = matrixU8[c][x + i][y + j]; + } + } + } +}); + +test('Uint8Array outer channel loop', function () { + let newData = new Array(channels); + for (var i = 0; i < channels; i++) { + newData[i] = new Uint8Array(newPixels); + } + + let y1 = y + newHeight; + + for (let c = 0; c < channels; c++) { + let ptr = 0; + for (var i = y; i < y1; i++) { + let j = i * width + x; + let jL = j + newWidth; + for (; j < jL; j++) { + newData[c][ptr++] = dataUint8[c][j]; + } + } + } +}); + +test('Uint8ClampedArray outer channel loop', function () { + let newData = new Array(channels); + for (var i = 0; i < channels; i++) { + newData[i] = new Uint8ClampedArray(newPixels); + } + + let y1 = y + newHeight; + + for (let c = 0; c < channels; c++) { + let ptr = 0; + for (var i = y; i < y1; i++) { + let j = i * width + x; + let jL = j + newWidth; + for (; j < jL; j++) { + newData[c][ptr++] = dataUint16[c][j]; + } + } + } +}); + +test('Uint16Array outer channel loop', function () { + let newData = new Array(channels); + for (var i = 0; i < channels; i++) { + newData[i] = new Uint16Array(newPixels); + } + + let y1 = y + newHeight; + + for (let c = 0; c < channels; c++) { + let ptr = 0; + for (var i = y; i < y1; i++) { + let j = i * width + x; + let jL = j + newWidth; + for (; j < jL; j++) { + newData[c][ptr++] = dataUint16[c][j]; + } + } + } +}); + +test('Array outer channel loop', function () { + let newData = new Array(channels); + for (var i = 0; i < channels; i++) { + newData[i] = new Array(newPixels); + } + + let y1 = y + newHeight; + + for (let c = 0; c < channels; c++) { + let ptr = 0; + for (var i = y; i < y1; i++) { + let j = i * width + x; + let jL = j + newWidth; + for (; j < jL; j++) { + newData[c][ptr++] = dataUint8[c][j]; + } + } + } +}); + +test('Uint8Array outer channel loop more complex', function () { + let newData = new Array(channels); + for (var i = 0; i < channels; i++) { + newData[i] = new Uint8Array(newPixels); + } + + for (let c = 0; c < channels; c++) { + let ptr = 0; + for (var i = 0; i < newWidth; i++) { + for (let j = 0; j < newHeight; j++) { + newData[c][ptr++] = dataUint8[c][(i + y) * width + x + j]; + } + } + } +}); + +test('Uint8Array outer channel loop with definition', function () { + let newData = new Array(channels); + for (var i = 0; i < channels; i++) { + newData[i] = new Uint8Array(newPixels); + } + + let y1 = y + newHeight; + + for (let c = 0; c < channels; c++) { + let ptr = 0; + let channel = newData[c]; + let dataChannel = dataUint8[c]; + for (var i = y; i < y1; i++) { + let j = i * width + x; + let jL = j + newWidth; + for (; j < jL; j++) { + channel[ptr++] = dataChannel[j]; + } + } + } +}); + +test('Uint8Array outer channel loop more complex with definition', function () { + let newData = new Array(channels); + for (var i = 0; i < channels; i++) { + newData[i] = new Uint8Array(newPixels); + } + + for (let c = 0; c < channels; c++) { + let ptr = 0; + let channel = newData[c]; + let dataChannel = dataUint8[c]; + for (var i = 0; i < newWidth; i++) { + for (let j = 0; j < newHeight; j++) { + channel[ptr++] = dataChannel[(i + y) * width + x + j]; + } + } + } +}); + +test('matrix outer channel uint8', function () { + let newData = new Array(channels); + + for (var i = 0; i < channels; i++) { + let matrix = new Array(newWidth); + newData[i] = matrix; + for (var j = 0; j < newWidth; j++) { + matrix[j] = new Uint8Array(newHeight); + } + } + + for (let c = 0; c < channels; c++) { + let newDataChannel = newData[c]; + let matrixChannel = matrixU8[c]; + for (var i = 0; i < newWidth; i++) { + let newDataRow = newDataChannel[i]; + let matrixRow = matrixChannel[x + i]; + for (var j = 0; j < newHeight; j++) { + newDataRow[j] = matrixRow[y + j]; + } + } + } +}); + +test('getValue / setValue', function () { + let newData = new Array(channels); + for (var i = 0; i < channels; i++) { + newData[i] = new Uint8Array(newPixels); + } + for (let c = 0; c < channels; c++) { + for (var i = 0; i < newWidth; i++) { + for (let j = 0; j < newHeight; j++) { + setValue(newData[c], i, j, getValue(dataUint8[c], x + i, y + j)); + } + } + } +}); + +test('getValue / setValue cached channel', function () { + let newData = new Array(channels); + for (var i = 0; i < channels; i++) { + newData[i] = new Uint8Array(newPixels); + } + for (let c = 0; c < channels; c++) { + let nC = newData[c]; + let oC = dataUint8[c]; + for (var i = 0; i < newWidth; i++) { + for (let j = 0; j < newHeight; j++) { + setValue(nC, i, j, getValue(oC, x + i, y + j)); + } + } + } +}); + +test('Uint8Array original', function () { + let newData = new Uint8Array(newPixels * channels); + + let xWidth = newWidth * channels; + let y1 = y + newHeight; + + let ptr = 0; // pointer for new array + + let jLeft = x * channels; + + for (let i = y; i < y1; i++) { + let j = (i * width * channels) + jLeft; + let jL = j + xWidth; + for (; j < jL; j++) { + newData[ptr++] = data8[j]; + } + } +}); + +function setValue(data, i, j, value) { + data[j * newWidth + i] = value; +} + +function getValue(data, i, j) { + return data[j * newWidth + i]; +} + +function test(name, func) { + func(); func(); func(); + let start = process.hrtime(); + for (let i = 0; i < ITER; i++) { + func(); + } + let result = process.hrtime(start); + // console.log('\n'); + console.log(`${name} took ${result[0]}s and ${result[1] / 1000 / 1000}ms`); +} diff --git a/benchmark/erode.js b/benchmark/erode.js new file mode 100644 index 000000000..dd15dd77b --- /dev/null +++ b/benchmark/erode.js @@ -0,0 +1,27 @@ +'use strict'; + +const { Image } = require('..'); + + +function getImage() { + const image = new Image(1000, 500, { kind: 'BINARY' }); + for (let x = 0; x < image.width; x++) { + for (let y = 0; y < image.height; y++) { + if (Math.random() > 0.5) { + image.setBitXY(x, y); + } + } + } + return image; +} + +const kSize = 50; +const kernel = new Array(kSize).fill(new Array(kSize).fill(1)); + +let image = getImage(); +image.erode({ kernel }); + +image = getImage(); +console.time('erode'); +image.erode({ kernel }); +console.timeEnd('erode'); diff --git a/benchmark/gaussianFilter.js b/benchmark/gaussianFilter.js new file mode 100644 index 000000000..2854356e6 --- /dev/null +++ b/benchmark/gaussianFilter.js @@ -0,0 +1,32 @@ +'use strict'; + +const path = require('path'); + +const Benchmark = require('benchmark'); + +const Image = require('..').default; + +const suite = new Benchmark.Suite(); + +const filename = 'cells/cells.jpg'; + +Image.load(path.join(__dirname, '../test/img', filename)).then(function (img) { + img = img.resize({ factor: 0.25 }); + suite + .add('direct', function () { + img.gaussianFilter({ algorithm: 'direct', radius: 17 }); + }) + .add('fft', function () { + img.gaussianFilter({ algorithm: 'fft', radius: 17 }); + }) + .add('separable', function () { + img.gaussianFilter({ algorithm: 'separable', radius: 17 }); + }) + .on('cycle', function (event) { + console.log(String(event.target)); + }) + .on('complete', function () { + console.log(`Fastest is ${this.filter('fastest').map('name')}`); + }) + .run(); +}).catch(console.error); diff --git a/benchmark/grey.js b/benchmark/grey.js new file mode 100644 index 000000000..713dfa46e --- /dev/null +++ b/benchmark/grey.js @@ -0,0 +1,39 @@ +'use strict'; + +let Benchmark = require('benchmark'); + +let { Image } = require('../src'); +let Test = require('../test/test-util'); + +let suite = new Benchmark.Suite(); + +let filename = 'cells/cells.jpg'; + +// TODO Order of testing is EXTREMELY important !!!!! +// So basically this test is really useless ... + +Image.load(Test.getImage(filename)) + .then(function (img) { + suite + .add('yellow', function () { + img.grey({ algorithm: 'luma709' }); + }) + .add('grey', function () { + img.grey({ algorithm: 'luma709' }); + }) + .add('red', function () { + img.grey({ algorithm: 'red' }); + }) + + // .add('grey lightness', function () { + // img.grey({algorithm:'lightness'}); + // }) + .on('cycle', function (event) { + console.log(String(event.target)); + }) + .on('complete', function () { + console.log(`Fastest is ${this.filter('fastest').map('name')}`); + }) + .run(); + }) + .catch(console.error); diff --git a/benchmark/invert.js b/benchmark/invert.js new file mode 100644 index 000000000..9dc61a248 --- /dev/null +++ b/benchmark/invert.js @@ -0,0 +1,43 @@ +'use strict'; + +let Benchmark = require('benchmark'); + +let Image = require('..'); + +let Test = require('../test/test'); + +let suite = new Benchmark.Suite(); + +let filename = 'cells/cells.jpg'; +// filename='ecoli.png'; +// filename='cat.jpg'; + +Image.load(Test.getImage(filename)).then(function (img) { + suite + .add('invert', function () { + img.invert(); + }) + .add('invertOneLoop', function () { + img.invertOneLoop(); + }) + /* .add('invertIterator', function () { + img.invertIterator(); + }) + */ + .add('invertApply', function () { + img.invertApply(); + }) + .add('invertApplyAll', function () { + img.invertApplyAll(); + }) + .add('invertPixel', function () { + img.invertPixel(); + }) + .on('cycle', function (event) { + console.log(String(event.target)); + }) + .on('complete', function () { + console.log(`Fastest is ${this.filter('fastest').map('name')}`); + }) + .run(); +}).catch(console.error); diff --git a/benchmark/invertBinaryImage.js b/benchmark/invertBinaryImage.js new file mode 100644 index 000000000..a3250fd97 --- /dev/null +++ b/benchmark/invertBinaryImage.js @@ -0,0 +1,29 @@ +'use strict'; + +let Benchmark = require('benchmark'); + +let Image = require('..'); + +let Test = require('../test/test'); + +let suite = new Benchmark.Suite(); + + +Image.load(Test.getImage('rgb8.png')).then(function (img) { + let mask = img.split()[0].mask(); + + suite + .add('invert', function () { + mask.invert(); + }) + .add('invertBinaryLoop', function () { + mask.invertBinaryLoop(); + }) + .on('cycle', function (event) { + console.log(String(event.target)); + }) + .on('complete', function () { + console.log(`Fastest is ${this.filter('fastest').pluck('name')}`); + }) + .run(); +}); diff --git a/benchmark/invertFilters/invertApply.js b/benchmark/invertFilters/invertApply.js new file mode 100644 index 000000000..720960190 --- /dev/null +++ b/benchmark/invertFilters/invertApply.js @@ -0,0 +1,29 @@ +// this code gives the same result as invert() +// but is based on a matrix of pixels +// may be easier to implement some algorithm +// but it will likely be much slower + +// this method is 50 times SLOWER than invert !!!!!! + +export default function invertApply() { + + + if (this.bitDepth === 1) { + // we simply invert all the integers value + // there could be a small mistake if the number of points + // is not a multiple of 8 but it is not important + let data = this.data; + for (let i = 0; i < data.length; i++) { + data[i] = ~data[i]; + } + } else { + this.checkProcessable('invertApply', { + bitDepth: [8, 16] + }); + this.apply(function (index) { + for (let k = 0; k < this.components; k++) { + this.data[index + k] = this.maxValue - this.data[index + k]; + } + }); + } +} diff --git a/benchmark/invertFilters/invertBinaryLoop.js b/benchmark/invertFilters/invertBinaryLoop.js new file mode 100644 index 000000000..96ff86de6 --- /dev/null +++ b/benchmark/invertFilters/invertBinaryLoop.js @@ -0,0 +1,9 @@ +export default function invertBinaryLoop() { + this.checkProcessable('invertBinaryLoop', { + bitDepth: [1] + }); + + for (let i = 0; i < this.size; i++) { + this.toggleBit(i); + } +} diff --git a/benchmark/invertFilters/invertGetSet.js b/benchmark/invertFilters/invertGetSet.js new file mode 100644 index 000000000..603673a1c --- /dev/null +++ b/benchmark/invertFilters/invertGetSet.js @@ -0,0 +1,24 @@ +export default function invert() { + this.checkProcessable('invert', { + bitDepth: [1, 8, 16] + }); + + if (this.bitDepth === 1) { + // we simply invert all the integers value + // there could be a small mistake if the number of points + // is not a multiple of 8 but it is not important + let data = this.data; + for (let i = 0; i < data.length; i++) { + data[i] = ~data[i]; + } + } else { + for (let x = 0; x < this.width; x++) { + for (let y = 0; y < this.height; y++) { + for (let k = 0; k < this.components; k++) { + let value = this.getValueXY(x, y, k); + this.setValueXY(x, y, k, this.maxValue - value); + } + } + } + } +} diff --git a/benchmark/invertFilters/invertIterator.js b/benchmark/invertFilters/invertIterator.js new file mode 100644 index 000000000..86da64d89 --- /dev/null +++ b/benchmark/invertFilters/invertIterator.js @@ -0,0 +1,21 @@ +export default function invertIterator() { + this.checkProcessable('invert', { + bitDepth: [1, 8, 16] + }); + + if (this.bitDepth === 1) { + // we simply invert all the integers value + // there could be a small mistake if the number of points + // is not a multiple of 8 but it is not important + let data = this.data; + for (let i = 0; i < data.length; i++) { + data[i] = ~data[i]; + } + } else { + for (let { index, pixel } of this.pixels()) { + for (let k = 0; k < this.components; k++) { + this.setValue(index, k, this.maxValue - pixel[k]); + } + } + } +} diff --git a/benchmark/invertFilters/invertOneLoop.js b/benchmark/invertFilters/invertOneLoop.js new file mode 100644 index 000000000..21e700ecc --- /dev/null +++ b/benchmark/invertFilters/invertOneLoop.js @@ -0,0 +1,12 @@ +export default function invertOneLoop() { + this.checkProcessable('invertOneLoop', { + bitDepth: [8, 16] + }); + + let data = this.data; + for (let i = 0; i < data.length; i += this.channels) { + for (let j = 0; j < this.components; j++) { + data[i + j] = this.maxValue - data[i + j]; + } + } +} diff --git a/benchmark/invertFilters/invertPixel.js b/benchmark/invertFilters/invertPixel.js new file mode 100644 index 000000000..3398d3771 --- /dev/null +++ b/benchmark/invertFilters/invertPixel.js @@ -0,0 +1,22 @@ +// this code gives the same result as invert() +// but is based on a matrix of pixels +// may be easier to implement some algorithm +// but it will likely be much slower + +export default function invertPixel() { + this.checkProcessable('invertPixel', { + bitDepth: [8, 16] + }); + + + for (let x = 0; x < this.width; x++) { + for (let y = 0; y < this.height; y++) { + let value = this.getPixelXY(x, y); + for (let k = 0; k < this.components; k++) { + value[k] = this.maxValue - value[k]; + } + this.setPixelXY(x, y, value); + } + } + +} diff --git a/benchmark/iterator-compute.js b/benchmark/iterator-compute.js new file mode 100644 index 000000000..48323baee --- /dev/null +++ b/benchmark/iterator-compute.js @@ -0,0 +1,103 @@ +/* eslint-disable */ +'use strict'; + +class Standard { + constructor(x, y) { + this.x = x; + this.y = y; + } + + computeSum() { + let sum = 0; + for (let x = 0; x < this.x; x++) { + for (let y = 0; y < this.y; y++) { + sum += x * y; + } + } + return sum; + } +} + +class Iterator { + constructor(x, y) { + this.x = x; + this.y = y; + } + + computeSum() { + let sum = 0; + for (const {x, y} of this.keys()) { + sum += x * y; + } + return sum; + } + + *keys() { + for (let x = 0; x < this.x; x++) { + for (let y = 0; y < this.y; y++) { + yield {x, y}; + } + } + } +} + +class Iterator2 { + constructor(x, y) { + this.x = x; + this.y = y; + } + + computeSum() { + let sum = 0; + for (const {x, y} of this.keys()) { + sum += x * y; + } + return sum; + } + + keys() { + return { + [Symbol.iterator]: () => { + let x = 0, y = 0; + return { + next: () => { + if (y === this.y) { + y = 0; + x++; + } + if (x === this.x) return {done: true}; + return {done: false, value: {x, y: y++}}; + } + }; + } + }; + } +} + +const standard = new Standard(10, 15); +const iterator = new Iterator(10, 15); +const iterator2 = new Iterator2(10, 15); + +// warm up +for (let i = 0; i < 1000; i++) { + standard.computeSum(); + iterator.computeSum(); + iterator2.computeSum(); +} + +// check result +if (standard.computeSum() !== 4725) throw new Error('wrong value: ' + standard.computeSum()); +if (iterator.computeSum() !== 4725) throw new Error('wrong value: ' + iterator.computeSum()); +if (iterator2.computeSum() !== 4725) throw new Error('wrong value: ' + iterator2.computeSum()); + +test('standard', standard); +test('iterator', iterator); +test('iterator2', iterator2); + +function test(name, fun) { + console.time(name); + for (let i = 0; i < 1e6; i++) { + fun.computeSum(); + } + console.timeEnd(name); +} diff --git a/benchmark/iterator.js b/benchmark/iterator.js new file mode 100644 index 000000000..95d2a5e6f --- /dev/null +++ b/benchmark/iterator.js @@ -0,0 +1,61 @@ +/* eslint-disable */ +'use strict'; + +class Standard { + constructor(x, y) { + this.x = x; + this.y = y; + this.array = new Uint32Array(x * y); + } + + addOne() { + for (let x = 0; x < this.x; x++) { + for (let y = 0; y < this.y; y++) { + this.array[y + x * this.y]++; + } + } + } +} + +class Iterator { + constructor(x, y) { + this.x = x; + this.y = y; + this.array = new Uint32Array(x * y); + } + + addOne() { + for (const {x, y} of this.keys()) { + this.array[y + x * this.y]++; + } + } + + *keys() { + for (let x = 0; x < this.x; x++) { + for (let y = 0; y < this.y; y++) { + yield {x, y}; + } + } + } +} + + +const standard = new Standard(10, 15); +const iterator = new Iterator(10, 15); + +// warm up +for (let i = 0; i < 1000; i++) { + standard.addOne(); + // iterator.addOne(); +} +return; +test('standard', standard); +test('iterator', iterator); + +function test(name, fun) { + console.time(name); + for (let i = 0; i < 1e6; i++) { + fun.addOne(); + } + console.timeEnd(name); +} diff --git a/benchmark/mask.js b/benchmark/mask.js new file mode 100644 index 000000000..49d00a941 --- /dev/null +++ b/benchmark/mask.js @@ -0,0 +1,38 @@ +'use strict'; + +let Benchmark = require('benchmark'); + +let Image = require('..'); + +let Test = require('../test/test'); + +let suite = new Benchmark.Suite(); + +let filename = 'cells/cells.jpg'; + + +// TODO Order of testing is EXTREMELY important !!!!! +// So basically this test is really useless ... + +Image.load(Test.getImage(filename)).then(function (img) { + let grey = img.grey(); + let mask = grey.mask({ threshold: 50 }); + let manager = img.getRoiManager(); + + + suite + .add('fromMask2', function () { + manager.fromMask(mask); + }) + .add('fromMask', function () { + manager.fromMask2(mask); + }) + + .on('cycle', function (event) { + console.log(String(event.target)); + }) + .on('complete', function () { + console.log(`Fastest is ${this.filter('fastest').map('name')}`); + }) + .run(); +}).catch(console.error); diff --git a/benchmark/rotate.js b/benchmark/rotate.js new file mode 100644 index 000000000..3d3bb6271 --- /dev/null +++ b/benchmark/rotate.js @@ -0,0 +1,25 @@ +'use strict'; + +const { Image } = require('..'); + + +function getImage() { + const image = new Image(1200, 800); + for (let x = 0; x < image.width; x++) { + for (let y = 0; y < image.height; y++) { + for (let c = 0; c < 4; c++) { + const value = Math.round(Math.random() * 255); + image.setValueXY(x, y, c, value); + } + } + } + return image; +} + +let image = getImage(); +image.rotate(30, { interpolation: 'bilinear' }); + +image = getImage(); +console.time('rotate'); +image.rotate(30, { interpolation: 'bilinear' }); +console.timeEnd('rotate'); diff --git a/demo/components/App.tsx b/demo/components/App.tsx deleted file mode 100644 index 637d461df..000000000 --- a/demo/components/App.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { HashRouter, Route, Routes } from 'react-router-dom'; - -import { CameraProvider } from '../contexts/cameraContext.provider.js'; - -import Filters from './Filters.js'; -import Home from './Home.js'; - -export default function App() { - return ( - - - - } /> - } /> - - - - ); -} diff --git a/demo/components/CameraFeed.tsx b/demo/components/CameraFeed.tsx deleted file mode 100644 index e0a882355..000000000 --- a/demo/components/CameraFeed.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { useEffect, useRef } from 'react'; - -import { useCameraContext } from '../contexts/cameraContext.js'; - -import UnavailableCamera from './UnavailableCamera.js'; - -export default function CameraFeed() { - const [{ selectedCamera }] = useCameraContext(); - const videoRef = useRef(null); - useEffect(() => { - const video = videoRef.current; - if (!video || !selectedCamera) return; - video.srcObject = selectedCamera.stream; - const onLoadedMetadata = () => { - video.play().catch((error: unknown) => console.error(error)); - }; - video.addEventListener('loadedmetadata', onLoadedMetadata); - return () => { - video.removeEventListener('loadedmetadata', onLoadedMetadata); - }; - }, [selectedCamera]); - if (!selectedCamera) { - return ; - } - - return