From 1412126be9291a3dfb0376bd25d038b840eaafa1 Mon Sep 17 00:00:00 2001 From: Alireza Date: Wed, 23 Nov 2022 22:28:49 -0500 Subject: [PATCH 01/14] initial commit for dicom image loader in mono repo --- .webpack/webpack.base.js | 10 +- api-extractor.json | 3 +- lerna.json | 3 +- package.json | 1 + packages/core/.webpack/webpack.dev.js | 30 +- packages/core/src/cache/cache.ts | 1 + packages/dicom-image-loader/.gitignore | 1 + .../.webpack/webpack-base.js | 92 + .../.webpack/webpack-dynamic-import.js | 32 + .../.webpack/webpack.dev.js | 36 + .../.webpack/webpack.prod.js | 36 + packages/dicom-image-loader/CHANGELOG.md | 866 ++++++++ packages/dicom-image-loader/README.md | 7 + .../dicom-image-loader/api-extractor.json | 9 + packages/dicom-image-loader/babel.config.js | 1 + packages/dicom-image-loader/codecs/jpeg.js | 1156 +++++++++++ .../dicom-image-loader/codecs/jpegLossless.js | 1756 +++++++++++++++++ packages/dicom-image-loader/package.json | 50 + .../dicom-image-loader/src/externalModules.js | 47 + .../convertPALETTECOLOR.js | 77 + .../convertRGBColorByPixel.js | 28 + .../convertRGBColorByPlane.js | 32 + .../convertYBRFull422ByPixel.js | 54 + .../convertYBRFullByPixel.js | 41 + .../convertYBRFullByPlane.js | 45 + .../imageLoader/colorSpaceConverters/index.js | 15 + .../src/imageLoader/configure.js | 7 + .../src/imageLoader/convertColorSpace.js | 45 + .../src/imageLoader/createImage.js | 390 ++++ .../imageLoader/decodeImageFrame-noWorkers.js | 112 ++ .../src/imageLoader/decodeImageFrame.js | 107 + .../decodeJPEGBaseline8BitColor.js | 89 + .../src/imageLoader/getImageFrame.js | 37 + .../src/imageLoader/getMinMax.js | 22 + .../src/imageLoader/getScalingParameters.js | 29 + .../src/imageLoader/imageIdToURI.js | 12 + .../src/imageLoader/index-noWorkers.js | 73 + .../src/imageLoader/index.js | 71 + .../src/imageLoader/internal/index.js | 10 + .../src/imageLoader/internal/options.js | 22 + .../src/imageLoader/internal/xhrRequest.js | 169 ++ .../src/imageLoader/isColorImage.js | 12 + .../imageLoader/isJPEGBaseline8BitColor.js | 13 + .../src/imageLoader/registerLoaders.js | 15 + .../imageLoader/wadors/findIndexOfString.js | 43 + .../src/imageLoader/wadors/getPixelData.js | 81 + .../src/imageLoader/wadors/index.js | 30 + .../src/imageLoader/wadors/loadImage.js | 132 ++ .../src/imageLoader/wadors/loadImage_test.js | 49 + .../wadors/metaData/getNumberString.js | 21 + .../wadors/metaData/getNumberValue.js | 13 + .../wadors/metaData/getNumberValues.js | 30 + .../wadors/metaData/getOverlayPlaneModule.js | 48 + .../imageLoader/wadors/metaData/getValue.js | 26 + .../src/imageLoader/wadors/metaData/index.js | 5 + .../wadors/metaData/metaDataProvider.js | 170 ++ .../src/imageLoader/wadors/metaDataManager.js | 32 + .../src/imageLoader/wadors/register.js | 8 + .../wadouri/dataSetCacheManager.js | 142 ++ .../wadouri/dataSetCacheManager_test.js | 13 + .../src/imageLoader/wadouri/fileManager.js | 26 + .../wadouri/getEncapsulatedImageFrame.js | 50 + .../src/imageLoader/wadouri/getPixelData.js | 19 + .../wadouri/getUncompressedImageFrame.js | 94 + .../src/imageLoader/wadouri/index.js | 44 + .../imageLoader/wadouri/loadFileRequest.js | 24 + .../src/imageLoader/wadouri/loadImage.js | 178 ++ .../wadouri/metaData/getImagePixelModule.js | 132 ++ .../imageLoader/wadouri/metaData/getLUTs.js | 53 + ...getModalityLUTOutputPixelRepresentation.js | 52 + .../wadouri/metaData/getNumberValues.js | 20 + .../wadouri/metaData/getOverlayPlaneModule.js | 45 + .../src/imageLoader/wadouri/metaData/index.js | 5 + .../wadouri/metaData/metaDataProvider.js | 159 ++ .../src/imageLoader/wadouri/parseImageId.js | 24 + .../src/imageLoader/wadouri/register.js | 12 + .../imageLoader/wadouri/unpackBinaryFrame.js | 31 + .../src/imageLoader/webWorkerManager.js | 362 ++++ .../src/imageLoader/webWorkerManager_test.js | 26 + packages/dicom-image-loader/src/index.ts | 1 + .../src/shared/calculateMinMax.js | 41 + .../src/shared/calculateMinMax_test.js | 58 + .../src/shared/decodeImageFrame.js | 263 +++ .../src/shared/decoders/decodeBigEndian.js | 36 + .../src/shared/decoders/decodeJPEG2000.js | 161 ++ .../decoders/decodeJPEGBaseline12Bit-js.js | 46 + ...eJPEGBaseline12Bit-wasm-not-yet-working.js | 105 + .../shared/decoders/decodeJPEGBaseline8Bit.js | 105 + .../src/shared/decoders/decodeJPEGLS.js | 148 ++ .../src/shared/decoders/decodeJPEGLossless.js | 61 + .../src/shared/decoders/decodeLittleEndian.js | 35 + .../src/shared/decoders/decodeRLE.js | 169 ++ .../src/shared/getMinMax.js | 30 + .../src/shared/getMinMax_test.js | 11 + .../src/shared/scaling/scaleArray.js | 20 + .../src/webWorker/decodeTask.js | 81 + .../src/webWorker/index.worker.js | 13 + .../src/webWorker/webWorker.js | 145 ++ packages/dicom-image-loader/tsconfig.cjs.json | 7 + packages/dicom-image-loader/tsconfig.esm.json | 7 + packages/dicom-image-loader/tsconfig.json | 4 + packages/docs/package.json | 2 +- packages/docs/webpackConfigurationPlugin.js | 2 +- .../.webpack/webpack.dev.js | 30 +- .../package.json | 4 +- .../src/sharedArrayBufferImageLoader.ts | 2 +- packages/tools/.webpack/webpack.dev.js | 30 +- packages/tools/examples/local/index.ts | 2 +- packages/tools/examples/localCPU/index.ts | 2 +- .../examples/volumeAnnotationTools/index.ts | 6 +- tsconfig.json | 3 +- utils/ExampleRunner/template-config.js | 29 +- .../template-multiexample-config.js | 12 +- .../helpers/createImageIdsAndCacheMetaData.js | 2 +- .../helpers/initCornerstoneWADOImageLoader.js | 2 +- yarn.lock | 36 +- 116 files changed, 9518 insertions(+), 56 deletions(-) create mode 100644 packages/dicom-image-loader/.gitignore create mode 100644 packages/dicom-image-loader/.webpack/webpack-base.js create mode 100644 packages/dicom-image-loader/.webpack/webpack-dynamic-import.js create mode 100644 packages/dicom-image-loader/.webpack/webpack.dev.js create mode 100644 packages/dicom-image-loader/.webpack/webpack.prod.js create mode 100644 packages/dicom-image-loader/CHANGELOG.md create mode 100644 packages/dicom-image-loader/README.md create mode 100644 packages/dicom-image-loader/api-extractor.json create mode 100644 packages/dicom-image-loader/babel.config.js create mode 100644 packages/dicom-image-loader/codecs/jpeg.js create mode 100644 packages/dicom-image-loader/codecs/jpegLossless.js create mode 100644 packages/dicom-image-loader/package.json create mode 100644 packages/dicom-image-loader/src/externalModules.js create mode 100644 packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.js create mode 100644 packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.js create mode 100644 packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.js create mode 100644 packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.js create mode 100644 packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.js create mode 100644 packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.js create mode 100644 packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/index.js create mode 100644 packages/dicom-image-loader/src/imageLoader/configure.js create mode 100644 packages/dicom-image-loader/src/imageLoader/convertColorSpace.js create mode 100644 packages/dicom-image-loader/src/imageLoader/createImage.js create mode 100644 packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.js create mode 100644 packages/dicom-image-loader/src/imageLoader/decodeImageFrame.js create mode 100644 packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.js create mode 100644 packages/dicom-image-loader/src/imageLoader/getImageFrame.js create mode 100644 packages/dicom-image-loader/src/imageLoader/getMinMax.js create mode 100644 packages/dicom-image-loader/src/imageLoader/getScalingParameters.js create mode 100644 packages/dicom-image-loader/src/imageLoader/imageIdToURI.js create mode 100644 packages/dicom-image-loader/src/imageLoader/index-noWorkers.js create mode 100644 packages/dicom-image-loader/src/imageLoader/index.js create mode 100644 packages/dicom-image-loader/src/imageLoader/internal/index.js create mode 100644 packages/dicom-image-loader/src/imageLoader/internal/options.js create mode 100644 packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.js create mode 100644 packages/dicom-image-loader/src/imageLoader/isColorImage.js create mode 100644 packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.js create mode 100644 packages/dicom-image-loader/src/imageLoader/registerLoaders.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/index.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/loadImage.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/loadImage_test.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/metaData/index.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/register.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager_test.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/index.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/metaData/index.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/register.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.js create mode 100644 packages/dicom-image-loader/src/imageLoader/webWorkerManager.js create mode 100644 packages/dicom-image-loader/src/imageLoader/webWorkerManager_test.js create mode 100644 packages/dicom-image-loader/src/index.ts create mode 100644 packages/dicom-image-loader/src/shared/calculateMinMax.js create mode 100644 packages/dicom-image-loader/src/shared/calculateMinMax_test.js create mode 100644 packages/dicom-image-loader/src/shared/decodeImageFrame.js create mode 100644 packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.js create mode 100644 packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.js create mode 100644 packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.js create mode 100644 packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-wasm-not-yet-working.js create mode 100644 packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.js create mode 100644 packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.js create mode 100644 packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.js create mode 100644 packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.js create mode 100644 packages/dicom-image-loader/src/shared/decoders/decodeRLE.js create mode 100644 packages/dicom-image-loader/src/shared/getMinMax.js create mode 100644 packages/dicom-image-loader/src/shared/getMinMax_test.js create mode 100644 packages/dicom-image-loader/src/shared/scaling/scaleArray.js create mode 100644 packages/dicom-image-loader/src/webWorker/decodeTask.js create mode 100644 packages/dicom-image-loader/src/webWorker/index.worker.js create mode 100644 packages/dicom-image-loader/src/webWorker/webWorker.js create mode 100644 packages/dicom-image-loader/tsconfig.cjs.json create mode 100644 packages/dicom-image-loader/tsconfig.esm.json create mode 100644 packages/dicom-image-loader/tsconfig.json diff --git a/.webpack/webpack.base.js b/.webpack/webpack.base.js index 3524a48ec..c5966a46d 100644 --- a/.webpack/webpack.base.js +++ b/.webpack/webpack.base.js @@ -42,10 +42,10 @@ module.exports = (env, argv, { DIST_DIR }) => { resolve: { modules: [path.resolve(PROJECT_ROOT, './node_modules'), SRC_PATH], extensions: ['.ts', '.tsx', '.js', '.jsx'], - alias: { - 'cornerstone-wado-image-loader': - 'cornerstone-wado-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js', - }, + // alias: { + // ''@cornerstonejs/dicom-image-loader'': + // 'cornerstone-wado-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js', + // }, fallback: { fs: false, path: require.resolve('path-browserify'), @@ -70,7 +70,7 @@ module.exports = (env, argv, { DIST_DIR }) => { // Show build progress new webpack.ProgressPlugin(), // Clear dist between builds - new CleanWebpackPlugin() + new CleanWebpackPlugin(), ], }; diff --git a/api-extractor.json b/api-extractor.json index ce9888821..bb195ae29 100644 --- a/api-extractor.json +++ b/api-extractor.json @@ -46,7 +46,8 @@ "bundledPackages": [ "@cornerstonejs/core", "@cornerstonejs/tools", - "@cornerstonejs/streaming-image-volume-loader" + "@cornerstonejs/streaming-image-volume-loader", + "@cornerstonejs/dicom-image-loader" ], /** diff --git a/lerna.json b/lerna.json index 2b405f12b..9e65a608d 100644 --- a/lerna.json +++ b/lerna.json @@ -3,7 +3,8 @@ "packages": [ "packages/core", "packages/tools", - "packages/streaming-image-volume-loader" + "packages/streaming-image-volume-loader", + "packages/dicom-image-loader" ], "npmClient": "yarn", "useWorkspaces": true, diff --git a/package.json b/package.json index adfceb8b4..80e03428a 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "cssnano": "^4.1.11", "eslint": "7.32.0", "eslint-config-prettier": "^8.3.0", + "eslint-loader": "^4.0.2", "eslint-plugin-import": "^2.25.4", "eslint-plugin-jsx-a11y": "6.x", "eslint-plugin-prettier": "^3.4.1", diff --git a/packages/core/.webpack/webpack.dev.js b/packages/core/.webpack/webpack.dev.js index 9ba31e870..a20fea2a3 100644 --- a/packages/core/.webpack/webpack.dev.js +++ b/packages/core/.webpack/webpack.dev.js @@ -1,8 +1,36 @@ +const { merge } = require('webpack-merge'); const path = require('path'); const webpackCommon = require('./../../../.webpack/webpack.common.js'); const SRC_DIR = path.join(__dirname, '../src'); const DIST_DIR = path.join(__dirname, '../dist'); module.exports = (env, argv) => { - return webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); + const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); + + return merge(commonConfig, { + devtool: 'source-map', + entry: { + lib: path.join(__dirname, '../src/index.ts'), + }, + output: { + path: path.join(__dirname, '../dist/umd'), + library: 'cornerstone3D', + libraryTarget: 'umd', + filename: 'index.js', + }, + stats: { + colors: true, + hash: true, + timings: true, + assets: true, + chunks: false, + chunkModules: false, + modules: false, + children: false, + warnings: true, + }, + optimization: { + minimize: false, + }, + }); }; diff --git a/packages/core/src/cache/cache.ts b/packages/core/src/cache/cache.ts index caac77958..1a6b341b4 100644 --- a/packages/core/src/cache/cache.ts +++ b/packages/core/src/cache/cache.ts @@ -762,5 +762,6 @@ class Cache implements ICache { * */ const cache = new Cache(); +window.cache = cache; export default cache; export { Cache }; // for documentation diff --git a/packages/dicom-image-loader/.gitignore b/packages/dicom-image-loader/.gitignore new file mode 100644 index 000000000..849ddff3b --- /dev/null +++ b/packages/dicom-image-loader/.gitignore @@ -0,0 +1 @@ +dist/ diff --git a/packages/dicom-image-loader/.webpack/webpack-base.js b/packages/dicom-image-loader/.webpack/webpack-base.js new file mode 100644 index 000000000..fce51d91a --- /dev/null +++ b/packages/dicom-image-loader/.webpack/webpack-base.js @@ -0,0 +1,92 @@ +const path = require('path'); +const webpack = require('webpack'); +const rootPath = process.cwd(); +const context = path.join(rootPath, 'src'); +const codecs = path.join(rootPath, 'codecs'); +const outputPath = path.join(rootPath, 'dist'); + +const BundleAnalyzerPlugin = + require('webpack-bundle-analyzer').BundleAnalyzerPlugin; + +module.exports = { + mode: 'development', + context, + entry: { + cornerstoneWADOImageLoader: './imageLoader/index.js', + }, + target: 'web', + output: { + library: { + name: '[name]', + type: 'umd', + umdNamedDefine: true, + }, + globalObject: 'this', + path: outputPath, + publicPath: 'auto', + }, + devtool: 'source-map', + externals: { + 'dicom-parser': { + commonjs: 'dicom-parser', + commonjs2: 'dicom-parser', + amd: 'dicom-parser', + root: 'dicomParser', + }, + }, + resolve: { + fallback: { + fs: false, + path: false, + }, + }, + module: { + noParse: [/(codecs)/], + rules: [ + { + enforce: 'pre', + test: /\.js$/, + exclude: /(node_modules)|(codecs)/, + loader: 'eslint-loader', + options: { + failOnError: false, + }, + }, + { + test: /\.wasm/, + type: 'asset/resource', + }, + { + test: /\.worker\.js$/, + use: [ + { + loader: 'worker-loader', + }, + // { + // loader: 'babel-loader', + // }, + ], + }, + { + test: /\.js$/, + exclude: [/(node_modules)/, /(codecs)/], + use: { + loader: 'babel-loader', + }, + }, + { + test: path.join(codecs, 'jpeg.js'), + loader: 'exports-loader', + options: { + type: 'commonjs', + exports: 'JpegImage', + }, + }, + ], + }, + // experiments: { + // asyncWebAssembly: true, + // }, + plugins: [new webpack.ProgressPlugin()], + // plugins: [new webpack.ProgressPlugin(), new BundleAnalyzerPlugin()], +}; diff --git a/packages/dicom-image-loader/.webpack/webpack-dynamic-import.js b/packages/dicom-image-loader/.webpack/webpack-dynamic-import.js new file mode 100644 index 000000000..15659c04c --- /dev/null +++ b/packages/dicom-image-loader/.webpack/webpack-dynamic-import.js @@ -0,0 +1,32 @@ +const path = require('path'); +const { merge } = require('webpack-merge'); +const rootPath = process.cwd(); +const baseConfig = require('./webpack-base'); +const TerserPlugin = require('terser-webpack-plugin'); +const outputPath = path.join(rootPath, 'dist', 'dynamic-import'); + +const prodConfig = { + mode: 'production', + stats: { + children: true, + }, + output: { + /*library: { + //name: '[name]', + },*/ + path: outputPath, + libraryTarget: 'umd', + globalObject: 'this', + filename: '[name].min.js', + }, + optimization: { + // minimize: false, + minimizer: [ + new TerserPlugin({ + parallel: true, + }), + ], + }, +}; + +module.exports = merge(baseConfig, prodConfig); diff --git a/packages/dicom-image-loader/.webpack/webpack.dev.js b/packages/dicom-image-loader/.webpack/webpack.dev.js new file mode 100644 index 000000000..a20fea2a3 --- /dev/null +++ b/packages/dicom-image-loader/.webpack/webpack.dev.js @@ -0,0 +1,36 @@ +const { merge } = require('webpack-merge'); +const path = require('path'); +const webpackCommon = require('./../../../.webpack/webpack.common.js'); +const SRC_DIR = path.join(__dirname, '../src'); +const DIST_DIR = path.join(__dirname, '../dist'); + +module.exports = (env, argv) => { + const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); + + return merge(commonConfig, { + devtool: 'source-map', + entry: { + lib: path.join(__dirname, '../src/index.ts'), + }, + output: { + path: path.join(__dirname, '../dist/umd'), + library: 'cornerstone3D', + libraryTarget: 'umd', + filename: 'index.js', + }, + stats: { + colors: true, + hash: true, + timings: true, + assets: true, + chunks: false, + chunkModules: false, + modules: false, + children: false, + warnings: true, + }, + optimization: { + minimize: false, + }, + }); +}; diff --git a/packages/dicom-image-loader/.webpack/webpack.prod.js b/packages/dicom-image-loader/.webpack/webpack.prod.js new file mode 100644 index 000000000..b83e4c439 --- /dev/null +++ b/packages/dicom-image-loader/.webpack/webpack.prod.js @@ -0,0 +1,36 @@ +const { merge } = require('webpack-merge'); +const path = require('path'); +const webpackCommon = require('./../../../.webpack/webpack.common.js'); +const SRC_DIR = path.join(__dirname, '../src'); +const DIST_DIR = path.join(__dirname, '../dist'); + +module.exports = (env, argv) => { + const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); + + return merge(commonConfig, { + devtool: 'source-map', + entry: { + lib: path.join(__dirname, '../src/index.ts'), + }, + output: { + path: path.join(__dirname, '../dist/umd'), + library: 'cornerstone3D', + libraryTarget: 'umd', + filename: 'index.js', + }, + stats: { + colors: true, + hash: true, + timings: true, + assets: true, + chunks: false, + chunkModules: false, + modules: false, + children: false, + warnings: true, + }, + optimization: { + minimize: true, + }, + }); +}; diff --git a/packages/dicom-image-loader/CHANGELOG.md b/packages/dicom-image-loader/CHANGELOG.md new file mode 100644 index 000000000..933bfb1fe --- /dev/null +++ b/packages/dicom-image-loader/CHANGELOG.md @@ -0,0 +1,866 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.21.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.21.3...@cornerstonejs/core@0.21.4) (2022-11-21) + + +### Bug Fixes + +* annotation rendering engine on viewport removal ([#303](https://github.com/cornerstonejs/cornerstone3D-beta/issues/303)) ([aeb205e](https://github.com/cornerstonejs/cornerstone3D-beta/commit/aeb205e56e0d2068258c278863aa3d7447331a43)) + + + + + +## [0.21.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.21.2...@cornerstonejs/core@0.21.3) (2022-11-19) + + +### Bug Fixes + +* don't reset display pipeline when spacing is missing ([#301](https://github.com/cornerstonejs/cornerstone3D-beta/issues/301)) ([e12fcf3](https://github.com/cornerstonejs/cornerstone3D-beta/commit/e12fcf3c361db0f927fd5fdd448686fef8893b36)) + + + + + +## [0.21.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.21.1...@cornerstonejs/core@0.21.2) (2022-11-18) + + +### Bug Fixes + +* **worldToImage:** Not throw out of bounds in worldToImage ([#302](https://github.com/cornerstonejs/cornerstone3D-beta/issues/302)) ([ffb20f7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ffb20f715c768b8f590b103cd18acc2bc2068adf)) + + + + + +## [0.21.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.21.0...@cornerstonejs/core@0.21.1) (2022-11-17) + + +### Bug Fixes + +* adjust canvas, not only off screen renderer on resize ([#279](https://github.com/cornerstonejs/cornerstone3D-beta/issues/279)) ([1959ac7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/1959ac7866305510855753f054678eac95e9c015)) + + + + + +# [0.21.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.20.0...@cornerstonejs/core@0.21.0) (2022-11-11) + + +### Features + +* add reference lines tool ([#292](https://github.com/cornerstonejs/cornerstone3D-beta/issues/292)) ([c56df91](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c56df91a64ec005656f940dd3728f476152fa917)) + + + + + +# [0.20.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.19.2...@cornerstonejs/core@0.20.0) (2022-11-11) + + +### Features + +* Add segmentSpecificConfiguration and add outlineOpacity config for Segmentation ([#285](https://github.com/cornerstonejs/cornerstone3D-beta/issues/285)) ([92fb495](https://github.com/cornerstonejs/cornerstone3D-beta/commit/92fb49594cfc3219f761e905ba765acaddbe1e1a)) +* add stack synchronization within or across studies ([#291](https://github.com/cornerstonejs/cornerstone3D-beta/issues/291)) ([f38bec0](https://github.com/cornerstonejs/cornerstone3D-beta/commit/f38bec06713265cee361fc905539aa5ed841e707)) + + + + + +## [0.19.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.19.1...@cornerstonejs/core@0.19.2) (2022-11-09) + +**Note:** Version bump only for package @cornerstonejs/core + + + + + +## [0.19.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.19.0...@cornerstonejs/core@0.19.1) (2022-11-04) + + +### Bug Fixes + +* volume scaling should be returned in getImageData ([#282](https://github.com/cornerstonejs/cornerstone3D-beta/issues/282)) ([4df3f71](https://github.com/cornerstonejs/cornerstone3D-beta/commit/4df3f7110de1a12dbeb0fea1260e4bb9e85320fa)) + + + + + +# [0.19.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.18.1...@cornerstonejs/core@0.19.0) (2022-11-04) + + +### Features + +* rendering engine should not reset camera on resize ([#273](https://github.com/cornerstonejs/cornerstone3D-beta/issues/273)) ([f1fe501](https://github.com/cornerstonejs/cornerstone3D-beta/commit/f1fe5015eaac736d1a16670e53849ab3d19baddf)) + + + + + +## [0.18.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.18.0...@cornerstonejs/core@0.18.1) (2022-11-04) + + +### Bug Fixes + +* resetCamera and annotations for flipped viewports ([#278](https://github.com/cornerstonejs/cornerstone3D-beta/issues/278)) ([cabefce](https://github.com/cornerstonejs/cornerstone3D-beta/commit/cabefcefcba463abb1ea9bf346a2f755b2494aed)) + + + + + +# [0.18.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.17.0...@cornerstonejs/core@0.18.0) (2022-11-01) + + +### Features + +* flip viewports via camera api instead of actor ([#271](https://github.com/cornerstonejs/cornerstone3D-beta/issues/271)) ([7c99f76](https://github.com/cornerstonejs/cornerstone3D-beta/commit/7c99f76fe10f9dac2f2221f9cdc134c90ebbe115)) + + + + + +# [0.17.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.12...@cornerstonejs/core@0.17.0) (2022-10-31) + + +### Features + +* reset to center option for reset camera ([#269](https://github.com/cornerstonejs/cornerstone3D-beta/issues/269)) ([9539f6c](https://github.com/cornerstonejs/cornerstone3D-beta/commit/9539f6c56e2bd3b06f4c6b40fd6b4478d806bee3)) + + + + + +## [0.16.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.11...@cornerstonejs/core@0.16.12) (2022-10-28) + + +### Bug Fixes + +* viewRight was calculated wrong for tools ([#255](https://github.com/cornerstonejs/cornerstone3D-beta/issues/255)) ([cf536df](https://github.com/cornerstonejs/cornerstone3D-beta/commit/cf536df66c05b4c4385ad18ad814d1dac1c8ad77)) + + + + + +## [0.16.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.10...@cornerstonejs/core@0.16.11) (2022-10-27) + + +### Bug Fixes + +* volume viewport getCurrentImageId ([#265](https://github.com/cornerstonejs/cornerstone3D-beta/issues/265)) ([30e4a5d](https://github.com/cornerstonejs/cornerstone3D-beta/commit/30e4a5d812a9d800887dfdc940a73149e5687ab8)) + + + + + +## [0.16.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.9...@cornerstonejs/core@0.16.10) (2022-10-25) + +**Note:** Version bump only for package @cornerstonejs/core + + + + + +## [0.16.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.8...@cornerstonejs/core@0.16.9) (2022-10-25) + + +### Bug Fixes + +* fixes the memory leak for volumes ([#253](https://github.com/cornerstonejs/cornerstone3D-beta/issues/253)) ([c863126](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c863126fc1df3fa989e15da1a7eae43cf94b24d0)) + + + + + +## [0.16.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.7...@cornerstonejs/core@0.16.8) (2022-10-07) + +**Note:** Version bump only for package @cornerstonejs/core + + + + + +## [0.16.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.6...@cornerstonejs/core@0.16.7) (2022-10-06) + +**Note:** Version bump only for package @cornerstonejs/core + + + + + +## [0.16.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.5...@cornerstonejs/core@0.16.6) (2022-10-06) + +**Note:** Version bump only for package @cornerstonejs/core + + + + + +## [0.16.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.4...@cornerstonejs/core@0.16.5) (2022-10-05) + + +### Bug Fixes + +* resetCamera should reset the rotation as well ([#236](https://github.com/cornerstonejs/cornerstone3D-beta/issues/236)) ([a347c93](https://github.com/cornerstonejs/cornerstone3D-beta/commit/a347c9338252fb3843737b605d610f2d51b2c547)) + + + + + +## [0.16.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.3...@cornerstonejs/core@0.16.4) (2022-10-05) + + +### Bug Fixes + +* Add storeAsInitialCamera parameter to StackViewport.setCamera ([#228](https://github.com/cornerstonejs/cornerstone3D-beta/issues/228)) ([b951acc](https://github.com/cornerstonejs/cornerstone3D-beta/commit/b951acc2c893837d13ec78850e18b7d26dd32076)) + + + + + +## [0.16.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.2...@cornerstonejs/core@0.16.3) (2022-09-16) + + +### Bug Fixes + +* **rgba:** Handle rgba to rgb conversion based on length ([#220](https://github.com/cornerstonejs/cornerstone3D-beta/issues/220)) ([d56dd8a](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d56dd8a7b23579f2a87cd3487b6b73b40a89648b)) + + + + + +## [0.16.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.1...@cornerstonejs/core@0.16.2) (2022-09-14) + + +### Bug Fixes + +* annotation hidden on horizontal and vertical ([#205](https://github.com/cornerstonejs/cornerstone3D-beta/issues/205)) ([9e825fd](https://github.com/cornerstonejs/cornerstone3D-beta/commit/9e825fd3d37ecfdf1722da9cd2fd6a1a75995459)) + + + + + +## [0.16.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.0...@cornerstonejs/core@0.16.1) (2022-09-08) + + +### Bug Fixes + +* drag probe appearing unnecessarily on all viewports ([#204](https://github.com/cornerstonejs/cornerstone3D-beta/issues/204)) ([c292c05](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c292c05eecf17a6edbdcab5aa5a604304ef3d2e5)) + + + + + +# [0.16.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.15.3...@cornerstonejs/core@0.16.0) (2022-09-08) + + +### Features + +* orientation on volumeViewport can be optional ([#203](https://github.com/cornerstonejs/cornerstone3D-beta/issues/203)) ([749dcb5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/749dcb59414c1aff2dffdca582fb3df0e4ca5ed7)) + + + + + +## [0.15.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.15.2...@cornerstonejs/core@0.15.3) (2022-09-02) + + +### Bug Fixes + +* annotations throwing error when stack and volume viewports are converted ([#195](https://github.com/cornerstonejs/cornerstone3D-beta/issues/195)) ([ed23f05](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ed23f05b23063769942328f9e6797d792767ec49)) + + + + + +## [0.15.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.15.1...@cornerstonejs/core@0.15.2) (2022-08-26) + + +### Bug Fixes + +* revert the stack viewport setting of targetImageIndex ([#192](https://github.com/cornerstonejs/cornerstone3D-beta/issues/192)) ([0cf057e](https://github.com/cornerstonejs/cornerstone3D-beta/commit/0cf057ee45a7b154ecd5ac067c719ac52403f382)) + + + + + +## [0.15.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.15.0...@cornerstonejs/core@0.15.1) (2022-08-26) + + +### Bug Fixes + +* shadow for annotations and stack viewport targetImageIdIndex bug ([#189](https://github.com/cornerstonejs/cornerstone3D-beta/issues/189)) ([be70be7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/be70be70a543fffb18f7d05c69e16d5c0255a57e)) + + + + + +# [0.15.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.14.7...@cornerstonejs/core@0.15.0) (2022-08-23) + + +### Features + +* camera sync canvas relative ([#167](https://github.com/cornerstonejs/cornerstone3D-beta/issues/167)) ([2fd6c98](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2fd6c9830eb6e9da10960de0c25702b06716382a)) + + + + + +## [0.14.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.14.6...@cornerstonejs/core@0.14.7) (2022-08-23) + +**Note:** Version bump only for package @cornerstonejs/core + + + + + +## [0.14.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.14.5...@cornerstonejs/core@0.14.6) (2022-08-19) + + +### Bug Fixes + +* **demoData:** The URL was pointing to a private AWS account ([#175](https://github.com/cornerstonejs/cornerstone3D-beta/issues/175)) ([69dafea](https://github.com/cornerstonejs/cornerstone3D-beta/commit/69dafea902dcd224ea5d1d6d418d5e0c1cec2fe0)) + + + + + +## [0.14.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.14.4...@cornerstonejs/core@0.14.5) (2022-08-18) + + +### Bug Fixes + +* add extra missing exports and no static code block at build ([#179](https://github.com/cornerstonejs/cornerstone3D-beta/issues/179)) ([dfdc4bf](https://github.com/cornerstonejs/cornerstone3D-beta/commit/dfdc4bfbf331da40368a4976f3dc199bd355864a)) + + + + + +## [0.14.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.14.3...@cornerstonejs/core@0.14.4) (2022-08-15) + + +### Bug Fixes + +* default voi for volumes and webLoader ([#171](https://github.com/cornerstonejs/cornerstone3D-beta/issues/171)) ([81f07a6](https://github.com/cornerstonejs/cornerstone3D-beta/commit/81f07a6f9d2a27d9cd6bb78c7ee65d6ac4456724)) + + + + + +## [0.14.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.14.2...@cornerstonejs/core@0.14.3) (2022-08-04) + + +### Bug Fixes + +* make typescript strict true ([#162](https://github.com/cornerstonejs/cornerstone3D-beta/issues/162)) ([7c311f7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/7c311f77f0532372ae82b6be2027bcd25925fa0d)) + + + + + +## [0.14.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.14.1...@cornerstonejs/core@0.14.2) (2022-08-03) + + +### Bug Fixes + +* wadouri metadata was not using scaling parameters properly ([#159](https://github.com/cornerstonejs/cornerstone3D-beta/issues/159)) ([d21aba5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d21aba56f1e0a8730088d89a4dfde8358d978a60)) + + + + + +## [0.14.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.14.0...@cornerstonejs/core@0.14.1) (2022-08-03) + + +### Bug Fixes + +* Attempt to fix build issues [@haehn](https://github.com/haehn) has reported ([#144](https://github.com/cornerstonejs/cornerstone3D-beta/issues/144)) ([2a7ec92](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2a7ec9271e012929682aa5c0a860cd65d0d5c02d)) + + + + + +# [0.14.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.11...@cornerstonejs/core@0.14.0) (2022-07-29) + + +### Features + +* volume viewport api with setProperties ([#154](https://github.com/cornerstonejs/cornerstone3D-beta/issues/154)) ([fab3abe](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fab3abe907ddde1ee61bc121c40d4fc23d2dbfd7)) + + + + + +## [0.13.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.10...@cornerstonejs/core@0.13.11) (2022-07-27) + + +### Bug Fixes + +* convert RGBA to RGB for GPU rendering if cached ([#152](https://github.com/cornerstonejs/cornerstone3D-beta/issues/152)) ([fb8aa36](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fb8aa36374c4bdf06d9d6da1f2df128c68dbc7da)) + + + + + +## [0.13.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.9...@cornerstonejs/core@0.13.10) (2022-07-25) + + +### Bug Fixes + +* annotation unit hydration bug and more color image support ([#151](https://github.com/cornerstonejs/cornerstone3D-beta/issues/151)) ([4f157dc](https://github.com/cornerstonejs/cornerstone3D-beta/commit/4f157dc5d7a8d0d80abb5b68c35ed17cb5f349ed)) + + + + + +## [0.13.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.8...@cornerstonejs/core@0.13.9) (2022-06-24) + + +### Bug Fixes + +* Handle cases where row and column cosines are missing ([#139](https://github.com/cornerstonejs/cornerstone3D-beta/issues/139)) ([5bd0a70](https://github.com/cornerstonejs/cornerstone3D-beta/commit/5bd0a7062adf7efd4654b20b6f4c8daed236a2db)) + + + + + +## [0.13.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.7...@cornerstonejs/core@0.13.8) (2022-06-24) + + +### Bug Fixes + +* Pixel data array was the wrong length for color images ([#138](https://github.com/cornerstonejs/cornerstone3D-beta/issues/138)) ([e42419d](https://github.com/cornerstonejs/cornerstone3D-beta/commit/e42419d0f7be45ff0ba87cb51502017b53687171)) + + + + + +## [0.13.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.6...@cornerstonejs/core@0.13.7) (2022-06-20) + + +### Bug Fixes + +* Use maximum clipping range for StackViewport ([#136](https://github.com/cornerstonejs/cornerstone3D-beta/issues/136)) ([016eff6](https://github.com/cornerstonejs/cornerstone3D-beta/commit/016eff66a02e4b120fb8ed06f90faaa3b29a8024)) + + + + + +## [0.13.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.5...@cornerstonejs/core@0.13.6) (2022-06-20) + + +### Bug Fixes + +* Cleanup magnify canvas on mouse up ([#135](https://github.com/cornerstonejs/cornerstone3D-beta/issues/135)) ([6fd0c3f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/6fd0c3fe114586f9e7ac0ab1f448b6c5199d1f7a)) + + + + + +## [0.13.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.4...@cornerstonejs/core@0.13.5) (2022-06-20) + + +### Bug Fixes + +* Resizing off-screen canvas was broken due to devicePixelRatio ([#134](https://github.com/cornerstonejs/cornerstone3D-beta/issues/134)) ([7b8ac34](https://github.com/cornerstonejs/cornerstone3D-beta/commit/7b8ac340f4708d8b0d99951d2fa4e2c996514968)) + + + + + +## [0.13.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.3...@cornerstonejs/core@0.13.4) (2022-06-20) + + +### Bug Fixes + +* Fix event for camera modified firing with wrong values ([#133](https://github.com/cornerstonejs/cornerstone3D-beta/issues/133)) ([f16f994](https://github.com/cornerstonejs/cornerstone3D-beta/commit/f16f9947902a104568cb4a7be75c0d19dd4a0715)) + + + + + +## [0.13.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.2...@cornerstonejs/core@0.13.3) (2022-06-20) + + +### Bug Fixes + +* Address issues with CPU Flip ([#132](https://github.com/cornerstonejs/cornerstone3D-beta/issues/132)) ([62b2843](https://github.com/cornerstonejs/cornerstone3D-beta/commit/62b28430cb00fc90e212f1c9f3cb7f748dbadb84)) + + + + + +## [0.13.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.1...@cornerstonejs/core@0.13.2) (2022-06-17) + + +### Bug Fixes + +* Fix resize behaviour after devicePixelRatio changes ([#131](https://github.com/cornerstonejs/cornerstone3D-beta/issues/131)) ([2e9d686](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2e9d686d83e4a529cd71f1b4d0ea19e1137cee3a)) + + + + + +## [0.13.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.0...@cornerstonejs/core@0.13.1) (2022-06-17) + + +### Bug Fixes + +* large image rendering, missing metadata for StackViewport, high DPI devices ([#127](https://github.com/cornerstonejs/cornerstone3D-beta/issues/127)) ([d4bf1c8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d4bf1c80391bcecaee64d9eb086416c42aa406e2)) + + + + + +# [0.13.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.12.1...@cornerstonejs/core@0.13.0) (2022-06-14) + + +### Features + +* remove unnecessary event firing for annotations ([#123](https://github.com/cornerstonejs/cornerstone3D-beta/issues/123)) ([03551d9](https://github.com/cornerstonejs/cornerstone3D-beta/commit/03551d9f9269b7bfd3d828dad4f8f38ef51703d1)) + + + + + +## [0.12.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.12.0...@cornerstonejs/core@0.12.1) (2022-06-10) + + +### Bug Fixes + +* resetPan option in resetCamera was ignored for PolyData ([#125](https://github.com/cornerstonejs/cornerstone3D-beta/issues/125)) ([5f4f36d](https://github.com/cornerstonejs/cornerstone3D-beta/commit/5f4f36df1e70f25b379fccef7c08b86f8c80f3dc)) + + + + + +# [0.12.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.11.1...@cornerstonejs/core@0.12.0) (2022-06-06) + + +### Features + +* improved stack prefetch and zoom to mouse ([#121](https://github.com/cornerstonejs/cornerstone3D-beta/issues/121)) ([bc72d37](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bc72d37b10f5a9e3e2bc9ed1254a707047f04f45)) + + + + + +## [0.11.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.11.0...@cornerstonejs/core@0.11.1) (2022-06-01) + + +### Bug Fixes + +* toolGroup default cursor ([#120](https://github.com/cornerstonejs/cornerstone3D-beta/issues/120)) ([8c385c4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/8c385c4780cbaf40400fffc310fd1e3b86056767)) + + + + + +# [0.11.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.10.3...@cornerstonejs/core@0.11.0) (2022-05-31) + + +### Features + +* improved threshold volume API and refactored boundingBox utils ([#117](https://github.com/cornerstonejs/cornerstone3D-beta/issues/117)) ([adc308b](https://github.com/cornerstonejs/cornerstone3D-beta/commit/adc308bef0509852bc48c96114eb3268c3d100b9)) + + + + + +## [0.10.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.10.2...@cornerstonejs/core@0.10.3) (2022-05-27) + + +### Bug Fixes + +* scale factor for zoom in perspective mode and do not update clipping planes for non Volume Actors ([#116](https://github.com/cornerstonejs/cornerstone3D-beta/issues/116)) ([ce8c13e](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ce8c13e534a48392fc11dcb615d8d81275cd01d7)) + + + + + +## [0.10.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.10.1...@cornerstonejs/core@0.10.2) (2022-05-27) + + +### Bug Fixes + +* remove the need for slabThickness in volumeAPI for tools ([#113](https://github.com/cornerstonejs/cornerstone3D-beta/issues/113)) ([a5e431d](https://github.com/cornerstonejs/cornerstone3D-beta/commit/a5e431dee952281be340994aa773a593a85fad04)) + + + + + +## [0.10.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.10.0...@cornerstonejs/core@0.10.1) (2022-05-27) + +**Note:** Version bump only for package @cornerstonejs/core + + + + + +# [0.10.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.9.0...@cornerstonejs/core@0.10.0) (2022-05-24) + + +### Features + +* Add VOLUME_NEW_IMAGE event and Add jumpToSlice and default VOI for volume viewport ([#104](https://github.com/cornerstonejs/cornerstone3D-beta/issues/104)) ([d36a23a](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d36a23a4eaf5bafcc8dddc0ab796065098df616a)) + + + + + +# [0.9.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.8.1...@cornerstonejs/core@0.9.0) (2022-05-24) + + +### Features + +* Add Clipping planes for rendering ([#110](https://github.com/cornerstonejs/cornerstone3D-beta/issues/110)) ([1a6e4c7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/1a6e4c742a3b89a88b46fd98d6cbeca5c95918aa)) + + + + + +## [0.8.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.8.0...@cornerstonejs/core@0.8.1) (2022-05-11) + + +### Bug Fixes + +* Attempt to resolve incompatible peerDeps situation ([#98](https://github.com/cornerstonejs/cornerstone3D-beta/issues/98)) ([00f141b](https://github.com/cornerstonejs/cornerstone3D-beta/commit/00f141bfa9f9a4b37c016d726a6d31f2330e2e44)) + + + + + +# [0.8.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.7.0...@cornerstonejs/core@0.8.0) (2022-05-10) + + +### Features + +* Add AngleTool and MagnifyTool ([#97](https://github.com/cornerstonejs/cornerstone3D-beta/issues/97)) ([2c4c800](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2c4c800c4b3ba92164f728865b904933a2539210)) + + + + + +# [0.7.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.6.4...@cornerstonejs/core@0.7.0) (2022-04-27) + + +### Features + +* Add worldToImage and imageToWorld utilities ([#85](https://github.com/cornerstonejs/cornerstone3D-beta/issues/85)) ([54e1b7f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/54e1b7f718f9d23b4c9f98ebc02c523100c1ddb0)) + + + + + +## [0.6.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.6.3...@cornerstonejs/core@0.6.4) (2022-04-22) + + +### Bug Fixes + +* Camera events for flip and rotation changes ([#83](https://github.com/cornerstonejs/cornerstone3D-beta/issues/83)) ([82115ec](https://github.com/cornerstonejs/cornerstone3D-beta/commit/82115ec00bd924fb942473d04052473408b84eb7)) + + + + + +## [0.6.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.6.2...@cornerstonejs/core@0.6.3) (2022-04-21) + + +### Bug Fixes + +* selection API, requestPoolManager and VOI and Scaling ([#82](https://github.com/cornerstonejs/cornerstone3D-beta/issues/82)) ([bedd8dd](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bedd8ddfa356c2d52a6e72f74c7cb3bb660a86ef)) + + + + + +## [0.6.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.6.1...@cornerstonejs/core@0.6.2) (2022-04-20) + + +### Bug Fixes + +* windowLevel event trigger and initial voi range ([#81](https://github.com/cornerstonejs/cornerstone3D-beta/issues/81)) ([38307d4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/38307d40cec60f2b3b8497abda8aa4fa657fc179)) + + + + + +## [0.6.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.6.0...@cornerstonejs/core@0.6.1) (2022-04-19) + + +### Bug Fixes + +* jumpToSlice and scaling of images in renderToCanvas ([#78](https://github.com/cornerstonejs/cornerstone3D-beta/issues/78)) ([bbebf7f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bbebf7fbad28e670333783cd669e571ec2ae7358)) + + + + + +# [0.6.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.5.0...@cornerstonejs/core@0.6.0) (2022-04-14) + + +### Features + +* add scrollToSlice for element ([#76](https://github.com/cornerstonejs/cornerstone3D-beta/issues/76)) ([c43fe8f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c43fe8f955930a70be60015f2f6bc1d5bf9fffbb)) + + + + + +# [0.5.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.4.6...@cornerstonejs/core@0.5.0) (2022-04-13) + + +### Features + +* cachedStats to store imageId and volumeId ([#75](https://github.com/cornerstonejs/cornerstone3D-beta/issues/75)) ([a2404c4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/a2404c4f1cb15a3935ba3af58fa7fc556716458c)) + + + + + +## [0.4.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.4.5...@cornerstonejs/core@0.4.6) (2022-04-13) + + +### Bug Fixes + +* renderToCanvas to use CPU rendering ([#74](https://github.com/cornerstonejs/cornerstone3D-beta/issues/74)) ([97ba32f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/97ba32f629376960f45bfbc3f22552476f934198)) + + + + + +## [0.4.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.4.4...@cornerstonejs/core@0.4.5) (2022-04-12) + + +### Bug Fixes + +* Remove resemblejs from dependencies, add detect-gpu, clonedeep, CWIL ([#73](https://github.com/cornerstonejs/cornerstone3D-beta/issues/73)) ([db65d50](https://github.com/cornerstonejs/cornerstone3D-beta/commit/db65d50a5c7488f323ab2424cf9d750055b2e6d5)) + + + + + +## [0.4.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.4.3...@cornerstonejs/core@0.4.4) (2022-04-12) + + +### Bug Fixes + +* Only fire STACK_NEW_IMAGE event after we are certain this image will be displayed ([#72](https://github.com/cornerstonejs/cornerstone3D-beta/issues/72)) ([bfb8b91](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bfb8b91baafb3bd342239ab9f1c4da0a1bfdf12a)) + + + + + +## [0.4.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.4.2...@cornerstonejs/core@0.4.3) (2022-04-11) + + +### Bug Fixes + +* extract IRenderingEngine type, docs: add documentation search ([#70](https://github.com/cornerstonejs/cornerstone3D-beta/issues/70)) ([6a705a8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/6a705a8f3cb9e8463c0ab6fe4d59dd3bb8bf5ef2)) + + + + + +## [0.4.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.4.1...@cornerstonejs/core@0.4.2) (2022-04-04) + + +### Bug Fixes + +* change package.json 'module' field to use '.js' extension from '.ts' ([#65](https://github.com/cornerstonejs/cornerstone3D-beta/issues/65)) ([42f66c2](https://github.com/cornerstonejs/cornerstone3D-beta/commit/42f66c2c8887467036c55b07d3a7041db467efab)) + + + + + +## [0.4.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.4.0...@cornerstonejs/core@0.4.1) (2022-04-01) + + +### Bug Fixes + +* cleanup exports, add docs and more tutorials ([#39](https://github.com/cornerstonejs/cornerstone3D-beta/issues/39)) ([743dea8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/743dea89c7a726c29d396756bdd991c81e561105)) + + + + + +# [0.4.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.3.4...@cornerstonejs/core@0.4.0) (2022-03-31) + + +### Features + +* advanced examples ([#38](https://github.com/cornerstonejs/cornerstone3D-beta/issues/38)) ([27f26a1](https://github.com/cornerstonejs/cornerstone3D-beta/commit/27f26a12a1712b7542cc66ab1d077cfb0da50a86)) + + + + + +## [0.3.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.3.3...@cornerstonejs/core@0.3.4) (2022-03-31) + +**Note:** Version bump only for package @cornerstonejs/core + + + + + +## [0.3.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.3.2...@cornerstonejs/core@0.3.3) (2022-03-31) + +**Note:** Version bump only for package @cornerstonejs/core + + + + + +## [0.3.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.3.1...@cornerstonejs/core@0.3.2) (2022-03-30) + +**Note:** Version bump only for package @cornerstonejs/core + + + + + +## [0.3.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.3.0...@cornerstonejs/core@0.3.1) (2022-03-30) + +**Note:** Version bump only for package @cornerstonejs/core + +# [0.3.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.2.3...@cornerstonejs/core@0.3.0) (2022-03-30) + +### Features + +- segmentation examples ([#29](https://github.com/cornerstonejs/cornerstone3D-beta/issues/29)) ([fd95a12](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fd95a12910ffe87a201d5eb94cbae32e95a8be8f)) + +## [0.2.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.2.2...@cornerstonejs/core@0.2.3) (2022-03-30) + +**Note:** Version bump only for package @cornerstonejs/core + +## [0.2.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.2.1...@cornerstonejs/core@0.2.2) (2022-03-28) + +**Note:** Version bump only for package @cornerstonejs/core + +## [0.2.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.2.0...@cornerstonejs/core@0.2.1) (2022-03-28) + +**Note:** Version bump only for package @cornerstonejs/core + +# [0.2.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.1.4...@cornerstonejs/core@0.2.0) (2022-03-28) + +### Features + +- Segmentation state restructure to add main representation ([#19](https://github.com/cornerstonejs/cornerstone3D-beta/issues/19)) ([b6eda97](https://github.com/cornerstonejs/cornerstone3D-beta/commit/b6eda97ab77ec244fd2e3a8c7d164efe78a4516f)) + +## [0.1.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.1.3...@cornerstonejs/core@0.1.4) (2022-03-25) + +**Note:** Version bump only for package @cornerstonejs/core + +## [0.1.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.1.2...@cornerstonejs/core@0.1.3) (2022-03-24) + +**Note:** Version bump only for package @cornerstonejs/core + +## [0.1.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.1.1...@cornerstonejs/core@0.1.2) (2022-03-24) + +**Note:** Version bump only for package @cornerstonejs/core + +## 0.1.1 (2022-03-24) + +**Note:** Version bump only for package @cornerstonejs/core diff --git a/packages/dicom-image-loader/README.md b/packages/dicom-image-loader/README.md new file mode 100644 index 000000000..a8edf2c91 --- /dev/null +++ b/packages/dicom-image-loader/README.md @@ -0,0 +1,7 @@ +# @cornerstonejs/core + +Cornerstone is a set of JavaScript libraries that can be used to build web-based medical imaging applications. It provides a framework to build radiology applications such as the [OHIF Viewer](https://ohif.org/). + +This library, _@cornerstonejs/core_, provides CPU and GPU-based rendering support, image/volume loading API, and caching utilities. + +You can find the Cornerstone documentation [on the website](https://cornerstonejs.org/). diff --git a/packages/dicom-image-loader/api-extractor.json b/packages/dicom-image-loader/api-extractor.json new file mode 100644 index 000000000..f78ff35b5 --- /dev/null +++ b/packages/dicom-image-loader/api-extractor.json @@ -0,0 +1,9 @@ +{ + "extends": "../../api-extractor.json", + "projectFolder": ".", + "mainEntryPointFilePath": "/dist/cjs/index.d.ts", + "apiReport": { + "reportFileName": ".api.md", + "reportFolder": "../../common/reviews/api" + } +} diff --git a/packages/dicom-image-loader/babel.config.js b/packages/dicom-image-loader/babel.config.js new file mode 100644 index 000000000..325ca2a8e --- /dev/null +++ b/packages/dicom-image-loader/babel.config.js @@ -0,0 +1 @@ +module.exports = require('../../babel.config.js'); diff --git a/packages/dicom-image-loader/codecs/jpeg.js b/packages/dicom-image-loader/codecs/jpeg.js new file mode 100644 index 000000000..7e177e768 --- /dev/null +++ b/packages/dicom-image-loader/codecs/jpeg.js @@ -0,0 +1,1156 @@ +// jshint ignore: start + +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / + /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* + Copyright 2011 notmasteryet + + 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. + */ + +// - The JPEG specification can be found in the ITU CCITT Recommendation T.81 +// (www.w3.org/Graphics/JPEG/itu-t81.pdf) +// - The JFIF specification can be found in the JPEG File Interchange Format +// (www.w3.org/Graphics/JPEG/jfif3.pdf) +// - The Adobe Application-Specific JPEG markers in the Supporting the DCT Filters +// in PostScript Level 2, Technical Note #5116 +// (partners.adobe.com/public/developer/en/ps/sdk/5116.DCT_Filter.pdf) + +var ColorSpace = { Unkown: 0, Grayscale: 1, AdobeRGB: 2, RGB: 3, CYMK: 4 }; +var JpegImage = (function jpegImage() { + 'use strict'; + var dctZigZag = new Int32Array([ + 0, + 1, + 8, + 16, + 9, + 2, + 3, + 10, + 17, + 24, + 32, + 25, + 18, + 11, + 4, + 5, + 12, + 19, + 26, + 33, + 40, + 48, + 41, + 34, + 27, + 20, + 13, + 6, + 7, + 14, + 21, + 28, + 35, + 42, + 49, + 56, + 57, + 50, + 43, + 36, + 29, + 22, + 15, + 23, + 30, + 37, + 44, + 51, + 58, + 59, + 52, + 45, + 38, + 31, + 39, + 46, + 53, + 60, + 61, + 54, + 47, + 55, + 62, + 63, + ]); + + var dctCos1 = 4017; // cos(pi/16) + var dctSin1 = 799; // sin(pi/16) + var dctCos3 = 3406; // cos(3*pi/16) + var dctSin3 = 2276; // sin(3*pi/16) + var dctCos6 = 1567; // cos(6*pi/16) + var dctSin6 = 3784; // sin(6*pi/16) + var dctSqrt2 = 5793; // sqrt(2) + var dctSqrt1d2 = 2896; // sqrt(2) / 2 + + function constructor() {} + + function buildHuffmanTable(codeLengths, values) { + var k = 0, + code = [], + i, + j, + length = 16; + while (length > 0 && !codeLengths[length - 1]) length--; + code.push({ children: [], index: 0 }); + var p = code[0], + q; + for (i = 0; i < length; i++) { + for (j = 0; j < codeLengths[i]; j++) { + p = code.pop(); + p.children[p.index] = values[k]; + while (p.index > 0) { + p = code.pop(); + } + p.index++; + code.push(p); + while (code.length <= i) { + code.push((q = { children: [], index: 0 })); + p.children[p.index] = q.children; + p = q; + } + k++; + } + if (i + 1 < length) { + // p here points to last code + code.push((q = { children: [], index: 0 })); + p.children[p.index] = q.children; + p = q; + } + } + return code[0].children; + } + + function getBlockBufferOffset(component, row, col) { + return 64 * ((component.blocksPerLine + 1) * row + col); + } + + function decodeScan( + data, + offset, + frame, + components, + resetInterval, + spectralStart, + spectralEnd, + successivePrev, + successive + ) { + var precision = frame.precision; + var samplesPerLine = frame.samplesPerLine; + var scanLines = frame.scanLines; + var mcusPerLine = frame.mcusPerLine; + var progressive = frame.progressive; + var maxH = frame.maxH, + maxV = frame.maxV; + + var startOffset = offset, + bitsData = 0, + bitsCount = 0; + + function readBit() { + if (bitsCount > 0) { + bitsCount--; + return (bitsData >> bitsCount) & 1; + } + bitsData = data[offset++]; + if (bitsData == 0xff) { + var nextByte = data[offset++]; + if (nextByte) { + throw 'unexpected marker: ' + + ((bitsData << 8) | nextByte).toString(16); + } + // unstuff 0 + } + bitsCount = 7; + return bitsData >>> 7; + } + + function decodeHuffman(tree) { + var node = tree; + var bit; + while ((bit = readBit()) !== null) { + node = node[bit]; + if (typeof node === 'number') return node; + if (typeof node !== 'object') throw 'invalid huffman sequence'; + } + return null; + } + + function receive(length) { + var n = 0; + while (length > 0) { + var bit = readBit(); + if (bit === null) return; + n = (n << 1) | bit; + length--; + } + return n; + } + + function receiveAndExtend(length) { + var n = receive(length); + if (n >= 1 << (length - 1)) return n; + return n + (-1 << length) + 1; + } + + function decodeBaseline(component, offset) { + var t = decodeHuffman(component.huffmanTableDC); + var diff = t === 0 ? 0 : receiveAndExtend(t); + component.blockData[offset] = component.pred += diff; + var k = 1; + while (k < 64) { + var rs = decodeHuffman(component.huffmanTableAC); + var s = rs & 15, + r = rs >> 4; + if (s === 0) { + if (r < 15) break; + k += 16; + continue; + } + k += r; + var z = dctZigZag[k]; + component.blockData[offset + z] = receiveAndExtend(s); + k++; + } + } + + function decodeDCFirst(component, offset) { + var t = decodeHuffman(component.huffmanTableDC); + var diff = t === 0 ? 0 : receiveAndExtend(t) << successive; + component.blockData[offset] = component.pred += diff; + } + + function decodeDCSuccessive(component, offset) { + component.blockData[offset] |= readBit() << successive; + } + + var eobrun = 0; + function decodeACFirst(component, offset) { + if (eobrun > 0) { + eobrun--; + return; + } + var k = spectralStart, + e = spectralEnd; + while (k <= e) { + var rs = decodeHuffman(component.huffmanTableAC); + var s = rs & 15, + r = rs >> 4; + if (s === 0) { + if (r < 15) { + eobrun = receive(r) + (1 << r) - 1; + break; + } + k += 16; + continue; + } + k += r; + var z = dctZigZag[k]; + component.blockData[offset + z] = + receiveAndExtend(s) * (1 << successive); + k++; + } + } + + var successiveACState = 0, + successiveACNextValue; + function decodeACSuccessive(component, offset) { + var k = spectralStart, + e = spectralEnd, + r = 0; + while (k <= e) { + var z = dctZigZag[k]; + switch (successiveACState) { + case 0: // initial state + var rs = decodeHuffman(component.huffmanTableAC); + var s = rs & 15; + r = rs >> 4; + if (s === 0) { + if (r < 15) { + eobrun = receive(r) + (1 << r); + successiveACState = 4; + } else { + r = 16; + successiveACState = 1; + } + } else { + if (s !== 1) throw 'invalid ACn encoding'; + successiveACNextValue = receiveAndExtend(s); + successiveACState = r ? 2 : 3; + } + continue; + case 1: // skipping r zero items + case 2: + if (component.blockData[offset + z]) { + component.blockData[offset + z] += readBit() << successive; + } else { + r--; + if (r === 0) successiveACState = successiveACState == 2 ? 3 : 0; + } + break; + case 3: // set value for a zero item + if (component.blockData[offset + z]) { + component.blockData[offset + z] += readBit() << successive; + } else { + component.blockData[offset + z] = + successiveACNextValue << successive; + successiveACState = 0; + } + break; + case 4: // eob + if (component.blockData[offset + z]) { + component.blockData[offset + z] += readBit() << successive; + } + break; + } + k++; + } + if (successiveACState === 4) { + eobrun--; + if (eobrun === 0) successiveACState = 0; + } + } + + function decodeMcu(component, decode, mcu, row, col) { + var mcuRow = (mcu / mcusPerLine) | 0; + var mcuCol = mcu % mcusPerLine; + var blockRow = mcuRow * component.v + row; + var blockCol = mcuCol * component.h + col; + var offset = getBlockBufferOffset(component, blockRow, blockCol); + decode(component, offset); + } + + function decodeBlock(component, decode, mcu) { + var blockRow = (mcu / component.blocksPerLine) | 0; + var blockCol = mcu % component.blocksPerLine; + var offset = getBlockBufferOffset(component, blockRow, blockCol); + decode(component, offset); + } + + var componentsLength = components.length; + var component, i, j, k, n; + var decodeFn; + if (progressive) { + if (spectralStart === 0) + decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive; + else decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive; + } else { + decodeFn = decodeBaseline; + } + + var mcu = 0, + marker; + var mcuExpected; + if (componentsLength == 1) { + mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn; + } else { + mcuExpected = mcusPerLine * frame.mcusPerColumn; + } + if (!resetInterval) { + resetInterval = mcuExpected; + } + + var h, v; + while (mcu < mcuExpected) { + // reset interval stuff + for (i = 0; i < componentsLength; i++) { + components[i].pred = 0; + } + eobrun = 0; + + if (componentsLength == 1) { + component = components[0]; + for (n = 0; n < resetInterval; n++) { + decodeBlock(component, decodeFn, mcu); + mcu++; + } + } else { + for (n = 0; n < resetInterval; n++) { + for (i = 0; i < componentsLength; i++) { + component = components[i]; + h = component.h; + v = component.v; + for (j = 0; j < v; j++) { + for (k = 0; k < h; k++) { + decodeMcu(component, decodeFn, mcu, j, k); + } + } + } + mcu++; + } + } + + // find marker + bitsCount = 0; + marker = (data[offset] << 8) | data[offset + 1]; + if (marker <= 0xff00) { + throw 'marker was not found'; + } + + if (marker >= 0xffd0 && marker <= 0xffd7) { + // RSTx + offset += 2; + } else { + break; + } + } + + return offset - startOffset; + } + + // A port of poppler's IDCT method which in turn is taken from: + // Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, + // "Practical Fast 1-D DCT Algorithms with 11 Multiplications", + // IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989, + // 988-991. + function quantizeAndInverse(component, blockBufferOffset, p) { + var qt = component.quantizationTable; + var v0, v1, v2, v3, v4, v5, v6, v7, t; + var i; + + // dequant + for (i = 0; i < 64; i++) { + p[i] = component.blockData[blockBufferOffset + i] * qt[i]; + } + + // inverse DCT on rows + for (i = 0; i < 8; ++i) { + var row = 8 * i; + + // check for all-zero AC coefficients + if ( + p[1 + row] === 0 && + p[2 + row] === 0 && + p[3 + row] === 0 && + p[4 + row] === 0 && + p[5 + row] === 0 && + p[6 + row] === 0 && + p[7 + row] === 0 + ) { + t = (dctSqrt2 * p[0 + row] + 512) >> 10; + p[0 + row] = t; + p[1 + row] = t; + p[2 + row] = t; + p[3 + row] = t; + p[4 + row] = t; + p[5 + row] = t; + p[6 + row] = t; + p[7 + row] = t; + continue; + } + + // stage 4 + v0 = (dctSqrt2 * p[0 + row] + 128) >> 8; + v1 = (dctSqrt2 * p[4 + row] + 128) >> 8; + v2 = p[2 + row]; + v3 = p[6 + row]; + v4 = (dctSqrt1d2 * (p[1 + row] - p[7 + row]) + 128) >> 8; + v7 = (dctSqrt1d2 * (p[1 + row] + p[7 + row]) + 128) >> 8; + v5 = p[3 + row] << 4; + v6 = p[5 + row] << 4; + + // stage 3 + t = (v0 - v1 + 1) >> 1; + v0 = (v0 + v1 + 1) >> 1; + v1 = t; + t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8; + v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8; + v3 = t; + t = (v4 - v6 + 1) >> 1; + v4 = (v4 + v6 + 1) >> 1; + v6 = t; + t = (v7 + v5 + 1) >> 1; + v5 = (v7 - v5 + 1) >> 1; + v7 = t; + + // stage 2 + t = (v0 - v3 + 1) >> 1; + v0 = (v0 + v3 + 1) >> 1; + v3 = t; + t = (v1 - v2 + 1) >> 1; + v1 = (v1 + v2 + 1) >> 1; + v2 = t; + t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12; + v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12; + v7 = t; + t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12; + v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12; + v6 = t; + + // stage 1 + p[0 + row] = v0 + v7; + p[7 + row] = v0 - v7; + p[1 + row] = v1 + v6; + p[6 + row] = v1 - v6; + p[2 + row] = v2 + v5; + p[5 + row] = v2 - v5; + p[3 + row] = v3 + v4; + p[4 + row] = v3 - v4; + } + + // inverse DCT on columns + for (i = 0; i < 8; ++i) { + var col = i; + + // check for all-zero AC coefficients + if ( + p[1 * 8 + col] === 0 && + p[2 * 8 + col] === 0 && + p[3 * 8 + col] === 0 && + p[4 * 8 + col] === 0 && + p[5 * 8 + col] === 0 && + p[6 * 8 + col] === 0 && + p[7 * 8 + col] === 0 + ) { + t = (dctSqrt2 * p[i + 0] + 8192) >> 14; + p[0 * 8 + col] = t; + p[1 * 8 + col] = t; + p[2 * 8 + col] = t; + p[3 * 8 + col] = t; + p[4 * 8 + col] = t; + p[5 * 8 + col] = t; + p[6 * 8 + col] = t; + p[7 * 8 + col] = t; + continue; + } + + // stage 4 + v0 = (dctSqrt2 * p[0 * 8 + col] + 2048) >> 12; + v1 = (dctSqrt2 * p[4 * 8 + col] + 2048) >> 12; + v2 = p[2 * 8 + col]; + v3 = p[6 * 8 + col]; + v4 = (dctSqrt1d2 * (p[1 * 8 + col] - p[7 * 8 + col]) + 2048) >> 12; + v7 = (dctSqrt1d2 * (p[1 * 8 + col] + p[7 * 8 + col]) + 2048) >> 12; + v5 = p[3 * 8 + col]; + v6 = p[5 * 8 + col]; + + // stage 3 + t = (v0 - v1 + 1) >> 1; + v0 = (v0 + v1 + 1) >> 1; + v1 = t; + t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12; + v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12; + v3 = t; + t = (v4 - v6 + 1) >> 1; + v4 = (v4 + v6 + 1) >> 1; + v6 = t; + t = (v7 + v5 + 1) >> 1; + v5 = (v7 - v5 + 1) >> 1; + v7 = t; + + // stage 2 + t = (v0 - v3 + 1) >> 1; + v0 = (v0 + v3 + 1) >> 1; + v3 = t; + t = (v1 - v2 + 1) >> 1; + v1 = (v1 + v2 + 1) >> 1; + v2 = t; + t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12; + v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12; + v7 = t; + t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12; + v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12; + v6 = t; + + // stage 1 + p[0 * 8 + col] = v0 + v7; + p[7 * 8 + col] = v0 - v7; + p[1 * 8 + col] = v1 + v6; + p[6 * 8 + col] = v1 - v6; + p[2 * 8 + col] = v2 + v5; + p[5 * 8 + col] = v2 - v5; + p[3 * 8 + col] = v3 + v4; + p[4 * 8 + col] = v3 - v4; + } + + // convert to 8-bit integers + for (i = 0; i < 64; ++i) { + var index = blockBufferOffset + i; + var q = p[i]; + q = + q <= -2056 / component.bitConversion + ? 0 + : q >= 2024 / component.bitConversion + ? 255 / component.bitConversion + : (q + 2056 / component.bitConversion) >> 4; + component.blockData[index] = q; + } + } + + function buildComponentData(frame, component) { + var lines = []; + var blocksPerLine = component.blocksPerLine; + var blocksPerColumn = component.blocksPerColumn; + var samplesPerLine = blocksPerLine << 3; + var computationBuffer = new Int32Array(64); + + var i, + j, + ll = 0; + for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) { + for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) { + var offset = getBlockBufferOffset(component, blockRow, blockCol); + quantizeAndInverse(component, offset, computationBuffer); + } + } + return component.blockData; + } + + function clampToUint8(a) { + return a <= 0 ? 0 : a >= 255 ? 255 : a | 0; + } + + constructor.prototype = { + load: function load(path) { + var handleData = function(data) { + this.parse(data); + if (this.onload) this.onload(); + }.bind(this); + + if (path.indexOf('data:') > -1) { + var offset = path.indexOf('base64,') + 7; + var data = atob(path.substring(offset)); + var arr = new Uint8Array(data.length); + for (var i = data.length - 1; i >= 0; i--) { + arr[i] = data.charCodeAt(i); + } + handleData(data); + } else { + var xhr = new XMLHttpRequest(); + xhr.open('GET', path, true); + xhr.responseType = 'arraybuffer'; + xhr.onload = function() { + // TODO catch parse error + var data = new Uint8Array(xhr.response); + handleData(data); + }.bind(this); + xhr.send(null); + } + }, + parse: function parse(data) { + function readUint16() { + var value = (data[offset] << 8) | data[offset + 1]; + offset += 2; + return value; + } + + function readDataBlock() { + var length = readUint16(); + var array = data.subarray(offset, offset + length - 2); + offset += array.length; + return array; + } + + function prepareComponents(frame) { + var mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / frame.maxH); + var mcusPerColumn = Math.ceil(frame.scanLines / 8 / frame.maxV); + for (var i = 0; i < frame.components.length; i++) { + component = frame.components[i]; + var blocksPerLine = Math.ceil( + (Math.ceil(frame.samplesPerLine / 8) * component.h) / frame.maxH + ); + var blocksPerColumn = Math.ceil( + (Math.ceil(frame.scanLines / 8) * component.v) / frame.maxV + ); + var blocksPerLineForMcu = mcusPerLine * component.h; + var blocksPerColumnForMcu = mcusPerColumn * component.v; + + var blocksBufferSize = + 64 * blocksPerColumnForMcu * (blocksPerLineForMcu + 1); + component.blockData = new Int16Array(blocksBufferSize); + component.blocksPerLine = blocksPerLine; + component.blocksPerColumn = blocksPerColumn; + } + frame.mcusPerLine = mcusPerLine; + frame.mcusPerColumn = mcusPerColumn; + } + + var offset = 0, + length = data.length; + var jfif = null; + var adobe = null; + var pixels = null; + var frame, resetInterval; + var quantizationTables = []; + var huffmanTablesAC = [], + huffmanTablesDC = []; + var fileMarker = readUint16(); + if (fileMarker != 0xffd8) { + // SOI (Start of Image) + throw 'SOI not found'; + } + + fileMarker = readUint16(); + while (fileMarker != 0xffd9) { + // EOI (End of image) + var i, j, l; + switch (fileMarker) { + case 0xffe0: // APP0 (Application Specific) + case 0xffe1: // APP1 + case 0xffe2: // APP2 + case 0xffe3: // APP3 + case 0xffe4: // APP4 + case 0xffe5: // APP5 + case 0xffe6: // APP6 + case 0xffe7: // APP7 + case 0xffe8: // APP8 + case 0xffe9: // APP9 + case 0xffea: // APP10 + case 0xffeb: // APP11 + case 0xffec: // APP12 + case 0xffed: // APP13 + case 0xffee: // APP14 + case 0xffef: // APP15 + case 0xfffe: // COM (Comment) + var appData = readDataBlock(); + + if (fileMarker === 0xffe0) { + if ( + appData[0] === 0x4a && + appData[1] === 0x46 && + appData[2] === 0x49 && + appData[3] === 0x46 && + appData[4] === 0 + ) { + // 'JFIF\x00' + jfif = { + version: { major: appData[5], minor: appData[6] }, + densityUnits: appData[7], + xDensity: (appData[8] << 8) | appData[9], + yDensity: (appData[10] << 8) | appData[11], + thumbWidth: appData[12], + thumbHeight: appData[13], + thumbData: appData.subarray( + 14, + 14 + 3 * appData[12] * appData[13] + ), + }; + } + } + // TODO APP1 - Exif + if (fileMarker === 0xffee) { + if ( + appData[0] === 0x41 && + appData[1] === 0x64 && + appData[2] === 0x6f && + appData[3] === 0x62 && + appData[4] === 0x65 && + appData[5] === 0 + ) { + // 'Adobe\x00' + adobe = { + version: appData[6], + flags0: (appData[7] << 8) | appData[8], + flags1: (appData[9] << 8) | appData[10], + transformCode: appData[11], + }; + } + } + break; + + case 0xffdb: // DQT (Define Quantization Tables) + var quantizationTablesLength = readUint16(); + var quantizationTablesEnd = quantizationTablesLength + offset - 2; + while (offset < quantizationTablesEnd) { + var quantizationTableSpec = data[offset++]; + var tableData = new Int32Array(64); + if (quantizationTableSpec >> 4 === 0) { + // 8 bit values + for (j = 0; j < 64; j++) { + var z = dctZigZag[j]; + tableData[z] = data[offset++]; + } + } else if (quantizationTableSpec >> 4 === 1) { + //16 bit + for (j = 0; j < 64; j++) { + var zz = dctZigZag[j]; + tableData[zz] = readUint16(); + } + } else throw 'DQT: invalid table spec'; + quantizationTables[quantizationTableSpec & 15] = tableData; + } + break; + + case 0xffc0: // SOF0 (Start of Frame, Baseline DCT) + case 0xffc1: // SOF1 (Start of Frame, Extended DCT) + case 0xffc2: // SOF2 (Start of Frame, Progressive DCT) + if (frame) { + throw 'Only single frame JPEGs supported'; + } + readUint16(); // skip data length + frame = {}; + frame.extended = fileMarker === 0xffc1; + frame.progressive = fileMarker === 0xffc2; + frame.precision = data[offset++]; + frame.scanLines = readUint16(); + frame.samplesPerLine = readUint16(); + frame.components = []; + frame.componentIds = {}; + var componentsCount = data[offset++], + componentId; + var maxH = 0, + maxV = 0; + for (i = 0; i < componentsCount; i++) { + componentId = data[offset]; + var h = data[offset + 1] >> 4; + var v = data[offset + 1] & 15; + if (maxH < h) maxH = h; + if (maxV < v) maxV = v; + var qId = data[offset + 2]; + l = frame.components.push({ + h: h, + v: v, + quantizationTable: quantizationTables[qId], + quantizationTableId: qId, + bitConversion: 255 / ((1 << frame.precision) - 1), + }); + frame.componentIds[componentId] = l - 1; + offset += 3; + } + frame.maxH = maxH; + frame.maxV = maxV; + prepareComponents(frame); + break; + + case 0xffc4: // DHT (Define Huffman Tables) + var huffmanLength = readUint16(); + for (i = 2; i < huffmanLength; ) { + var huffmanTableSpec = data[offset++]; + var codeLengths = new Uint8Array(16); + var codeLengthSum = 0; + for (j = 0; j < 16; j++, offset++) + codeLengthSum += codeLengths[j] = data[offset]; + var huffmanValues = new Uint8Array(codeLengthSum); + for (j = 0; j < codeLengthSum; j++, offset++) + huffmanValues[j] = data[offset]; + i += 17 + codeLengthSum; + + (huffmanTableSpec >> 4 === 0 ? huffmanTablesDC : huffmanTablesAC)[ + huffmanTableSpec & 15 + ] = buildHuffmanTable(codeLengths, huffmanValues); + } + break; + + case 0xffdd: // DRI (Define Restart Interval) + readUint16(); // skip data length + resetInterval = readUint16(); + break; + + case 0xffda: // SOS (Start of Scan) + var scanLength = readUint16(); + var selectorsCount = data[offset++]; + var components = [], + component; + for (i = 0; i < selectorsCount; i++) { + var componentIndex = frame.componentIds[data[offset++]]; + component = frame.components[componentIndex]; + var tableSpec = data[offset++]; + component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4]; + component.huffmanTableAC = huffmanTablesAC[tableSpec & 15]; + components.push(component); + } + var spectralStart = data[offset++]; + var spectralEnd = data[offset++]; + var successiveApproximation = data[offset++]; + var processed = decodeScan( + data, + offset, + frame, + components, + resetInterval, + spectralStart, + spectralEnd, + successiveApproximation >> 4, + successiveApproximation & 15 + ); + offset += processed; + break; + case 0xffff: // Fill bytes + if (data[offset] !== 0xff) { + // Avoid skipping a valid marker. + offset--; + } + break; + default: + if ( + data[offset - 3] == 0xff && + data[offset - 2] >= 0xc0 && + data[offset - 2] <= 0xfe + ) { + // could be incorrect encoding -- last 0xFF byte of the previous + // block was eaten by the encoder + offset -= 3; + break; + } + throw 'unknown JPEG marker ' + fileMarker.toString(16); + } + fileMarker = readUint16(); + } + + this.width = frame.samplesPerLine; + this.height = frame.scanLines; + this.jfif = jfif; + this.adobe = adobe; + this.components = []; + switch (frame.components.length) { + case 1: + this.colorspace = ColorSpace.Grayscale; + break; + case 3: + if (this.adobe) this.colorspace = ColorSpace.AdobeRGB; + else this.colorspace = ColorSpace.RGB; + break; + case 4: + this.colorspace = ColorSpace.CYMK; + break; + default: + this.colorspace = ColorSpace.Unknown; + } + for (var i = 0; i < frame.components.length; i++) { + var component = frame.components[i]; + if ( + !component.quantizationTable && + component.quantizationTableId !== null + ) + component.quantizationTable = + quantizationTables[component.quantizationTableId]; + this.components.push({ + output: buildComponentData(frame, component), + scaleX: component.h / frame.maxH, + scaleY: component.v / frame.maxV, + blocksPerLine: component.blocksPerLine, + blocksPerColumn: component.blocksPerColumn, + bitConversion: component.bitConversion, + }); + } + }, + getData16: function getData16(width, height) { + if (this.components.length !== 1) throw 'Unsupported color mode'; + var scaleX = this.width / width, + scaleY = this.height / height; + + var component, componentScaleX, componentScaleY; + var x, y, i; + var offset = 0; + var numComponents = this.components.length; + var dataLength = width * height * numComponents; + var data = new Uint16Array(dataLength); + var componentLine; + + // lineData is reused for all components. Assume first component is + // the biggest + var lineData = new Uint16Array( + (this.components[0].blocksPerLine << 3) * + this.components[0].blocksPerColumn * + 8 + ); + + // First construct image data ... + for (i = 0; i < numComponents; i++) { + component = this.components[i]; + var blocksPerLine = component.blocksPerLine; + var blocksPerColumn = component.blocksPerColumn; + var samplesPerLine = blocksPerLine << 3; + + var j, + k, + ll = 0; + var lineOffset = 0; + for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) { + var scanLine = blockRow << 3; + for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) { + var bufferOffset = getBlockBufferOffset( + component, + blockRow, + blockCol + ); + var offset = 0, + sample = blockCol << 3; + for (j = 0; j < 8; j++) { + var lineOffset = (scanLine + j) * samplesPerLine; + for (k = 0; k < 8; k++) { + lineData[lineOffset + sample + k] = + component.output[bufferOffset + offset++]; + } + } + } + } + + componentScaleX = component.scaleX * scaleX; + componentScaleY = component.scaleY * scaleY; + offset = i; + + var cx, cy; + var index; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + cy = 0 | (y * componentScaleY); + cx = 0 | (x * componentScaleX); + index = cy * samplesPerLine + cx; + data[offset] = lineData[index]; + offset += numComponents; + } + } + } + return data; + }, + getData: function getData(width, height) { + var scaleX = this.width / width, + scaleY = this.height / height; + + var component, componentScaleX, componentScaleY; + var x, y, i; + var offset = 0; + var Y, Cb, Cr, K, C, M, Ye, R, G, B; + var colorTransform; + var numComponents = this.components.length; + var dataLength = width * height * numComponents; + var data = new Uint8Array(dataLength); + var componentLine; + + // lineData is reused for all components. Assume first component is + // the biggest + var lineData = new Uint8Array( + (this.components[0].blocksPerLine << 3) * + this.components[0].blocksPerColumn * + 8 + ); + + // First construct image data ... + for (i = 0; i < numComponents; i++) { + component = this.components[i]; + var blocksPerLine = component.blocksPerLine; + var blocksPerColumn = component.blocksPerColumn; + var samplesPerLine = blocksPerLine << 3; + + var j, + k, + ll = 0; + var lineOffset = 0; + for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) { + var scanLine = blockRow << 3; + for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) { + var bufferOffset = getBlockBufferOffset( + component, + blockRow, + blockCol + ); + var offset = 0, + sample = blockCol << 3; + for (j = 0; j < 8; j++) { + var lineOffset = (scanLine + j) * samplesPerLine; + for (k = 0; k < 8; k++) { + lineData[lineOffset + sample + k] = + component.output[bufferOffset + offset++] * + component.bitConversion; + } + } + } + } + + componentScaleX = component.scaleX * scaleX; + componentScaleY = component.scaleY * scaleY; + offset = i; + + var cx, cy; + var index; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + cy = 0 | (y * componentScaleY); + cx = 0 | (x * componentScaleX); + index = cy * samplesPerLine + cx; + data[offset] = lineData[index]; + offset += numComponents; + } + } + } + + // ... then transform colors, if necessary + switch (numComponents) { + case 1: + case 2: + break; + // no color conversion for one or two compoenents + + case 3: + // The default transform for three components is true + colorTransform = true; + // The adobe transform marker overrides any previous setting + if (this.adobe && this.adobe.transformCode) colorTransform = true; + else if (typeof this.colorTransform !== 'undefined') + colorTransform = !!this.colorTransform; + + if (colorTransform) { + for (i = 0; i < dataLength; i += numComponents) { + Y = data[i]; + Cb = data[i + 1]; + Cr = data[i + 2]; + + R = clampToUint8(Y - 179.456 + 1.402 * Cr); + G = clampToUint8(Y + 135.459 - 0.344 * Cb - 0.714 * Cr); + B = clampToUint8(Y - 226.816 + 1.772 * Cb); + + data[i] = R; + data[i + 1] = G; + data[i + 2] = B; + } + } + break; + case 4: + if (!this.adobe) throw 'Unsupported color mode (4 components)'; + // The default transform for four components is false + colorTransform = false; + // The adobe transform marker overrides any previous setting + if (this.adobe && this.adobe.transformCode) colorTransform = true; + else if (typeof this.colorTransform !== 'undefined') + colorTransform = !!this.colorTransform; + + if (colorTransform) { + for (i = 0; i < dataLength; i += numComponents) { + Y = data[i]; + Cb = data[i + 1]; + Cr = data[i + 2]; + + C = clampToUint8(434.456 - Y - 1.402 * Cr); + M = clampToUint8(119.541 - Y + 0.344 * Cb + 0.714 * Cr); + Y = clampToUint8(481.816 - Y - 1.772 * Cb); + + data[i] = C; + data[i + 1] = M; + data[i + 2] = Y; + // K is unchanged + } + } + break; + default: + throw 'Unsupported color mode'; + } + return data; + }, + }; + + return constructor; +})(); diff --git a/packages/dicom-image-loader/codecs/jpegLossless.js b/packages/dicom-image-loader/codecs/jpegLossless.js new file mode 100644 index 000000000..5bfe0d40c --- /dev/null +++ b/packages/dicom-image-loader/codecs/jpegLossless.js @@ -0,0 +1,1756 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.jpeg = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o> 4) !== 0x0FFC) || (current === 0xFFC4))) { // SOF 0~15 + switch (current) { + case 0xFFC4: // DHT + this.huffTable.read(this.stream, this.HuffTab); + break; + case 0xFFCC: // DAC + throw new Error("Program doesn't support arithmetic coding. (format throw new IOException)"); + case 0xFFDB: + this.quantTable.read(this.stream, jpeg.lossless.Decoder.TABLE); + break; + case 0xFFDD: + this.restartInterval = this.readNumber(); + break; + case 0xFFE0: + case 0xFFE1: + case 0xFFE2: + case 0xFFE3: + case 0xFFE4: + case 0xFFE5: + case 0xFFE6: + case 0xFFE7: + case 0xFFE8: + case 0xFFE9: + case 0xFFEA: + case 0xFFEB: + case 0xFFEC: + case 0xFFED: + case 0xFFEE: + case 0xFFEF: + this.readApp(); + break; + case 0xFFFE: + this.readComment(); + break; + default: + if ((current >> 8) !== 0xFF) { + throw new Error("ERROR: format throw new IOException! (decode)"); + } + } + + current = this.stream.get16(); + } + + if ((current < 0xFFC0) || (current > 0xFFC7)) { + throw new Error("ERROR: could not handle arithmetic code!"); + } + + this.frame.read(this.stream); + current = this.stream.get16(); + + do { + while (current !== 0x0FFDA) { // SOS + switch (current) { + case 0xFFC4: // DHT + this.huffTable.read(this.stream, this.HuffTab); + break; + case 0xFFCC: // DAC + throw new Error("Program doesn't support arithmetic coding. (format throw new IOException)"); + case 0xFFDB: + this.quantTable.read(this.stream, jpeg.lossless.Decoder.TABLE); + break; + case 0xFFDD: + this.restartInterval = this.readNumber(); + break; + case 0xFFE0: + case 0xFFE1: + case 0xFFE2: + case 0xFFE3: + case 0xFFE4: + case 0xFFE5: + case 0xFFE6: + case 0xFFE7: + case 0xFFE8: + case 0xFFE9: + case 0xFFEA: + case 0xFFEB: + case 0xFFEC: + case 0xFFED: + case 0xFFEE: + case 0xFFEF: + this.readApp(); + break; + case 0xFFFE: + this.readComment(); + break; + default: + if ((current >> 8) !== 0xFF) { + throw new Error("ERROR: format throw new IOException! (Parser.decode)"); + } + } + + current = this.stream.get16(); + } + + this.precision = this.frame.precision; + this.components = this.frame.components; + + if (!this.numBytes) { + this.numBytes = parseInt(Math.ceil(this.precision / 8)); + } + + if (this.numBytes == 1) { + this.mask = 0xFF; + } else { + this.mask = 0xFFFF; + } + + this.scan.read(this.stream); + this.numComp = this.scan.numComp; + this.selection = this.scan.selection; + + if (this.numBytes === 1) { + if (this.numComp === 3) { + this.getter = this.getValueRGB; + this.setter = this.setValueRGB; + this.output = this.outputRGB; + } else { + this.getter = this.getValue8; + this.setter = this.setValue8; + this.output = this.outputSingle; + } + } else { + this.getter = this.getValue16; + this.setter = this.setValue16; + this.output = this.outputSingle; + } + + switch (this.selection) { + case 2: + this.selector = this.select2; + break; + case 3: + this.selector = this.select3; + break; + case 4: + this.selector = this.select4; + break; + case 5: + this.selector = this.select5; + break; + case 6: + this.selector = this.select6; + break; + case 7: + this.selector = this.select7; + break; + default: + this.selector = this.select1; + break; + } + + this.scanComps = this.scan.components; + this.quantTables = this.quantTable.quantTables; + + for (i = 0; i < this.numComp; i+=1) { + compN = this.scanComps[i].scanCompSel; + this.qTab[i] = this.quantTables[this.components[compN].quantTableSel]; + this.nBlock[i] = this.components[compN].vSamp * this.components[compN].hSamp; + this.dcTab[i] = this.HuffTab[this.scanComps[i].dcTabSel][0]; + this.acTab[i] = this.HuffTab[this.scanComps[i].acTabSel][1]; + } + + this.xDim = this.frame.dimX; + this.yDim = this.frame.dimY; + if (this.numBytes == 1) { + this.outputData = new Uint8Array(new ArrayBuffer(this.xDim * this.yDim * this.numBytes * this.numComp)); + } else { + this.outputData = new Uint16Array(new ArrayBuffer(this.xDim * this.yDim * this.numBytes * this.numComp)); + } + + scanNum+=1; + + while (true) { // Decode one scan + temp[0] = 0; + index[0] = 0; + + for (i = 0; i < 10; i+=1) { + pred[i] = (1 << (this.precision - 1)); + } + + if (this.restartInterval === 0) { + current = this.decodeUnit(pred, temp, index); + + while ((current === 0) && ((this.xLoc < this.xDim) && (this.yLoc < this.yDim))) { + this.output(pred); + current = this.decodeUnit(pred, temp, index); + } + + break; //current=MARKER + } + + for (mcuNum = 0; mcuNum < this.restartInterval; mcuNum+=1) { + this.restarting = (mcuNum == 0); + current = this.decodeUnit(pred, temp, index); + this.output(pred); + + if (current !== 0) { + break; + } + } + + if (current === 0) { + if (this.markerIndex !== 0) { + current = (0xFF00 | this.marker); + this.markerIndex = 0; + } else { + current = this.stream.get16(); + } + } + + if (!((current >= jpeg.lossless.Decoder.RESTART_MARKER_BEGIN) && + (current <= jpeg.lossless.Decoder.RESTART_MARKER_END))) { + break; //current=MARKER + } + } + + if ((current === 0xFFDC) && (scanNum === 1)) { //DNL + this.readNumber(); + current = this.stream.get16(); + } + } while ((current !== 0xFFD9) && ((this.xLoc < this.xDim) && (this.yLoc < this.yDim)) && (scanNum === 0)); + + return this.outputData; + }; + + + + jpeg.lossless.Decoder.prototype.decodeUnit = function (prev, temp, index) { + if (this.numComp == 1) { + return this.decodeSingle(prev, temp, index); + } else if (this.numComp == 3) { + return this.decodeRGB(prev, temp, index); + } else { + return -1; + } + }; + + + + jpeg.lossless.Decoder.prototype.select1 = function (compOffset) { + return this.getPreviousX(compOffset); + }; + + + + jpeg.lossless.Decoder.prototype.select2 = function (compOffset) { + return this.getPreviousY(compOffset); + }; + + + + jpeg.lossless.Decoder.prototype.select3 = function (compOffset) { + return this.getPreviousXY(compOffset); + }; + + + + jpeg.lossless.Decoder.prototype.select4 = function (compOffset) { + return (this.getPreviousX(compOffset) + this.getPreviousY(compOffset)) - this.getPreviousXY(compOffset); + }; + + + + jpeg.lossless.Decoder.prototype.select5 = function (compOffset) { + return this.getPreviousX(compOffset) + ((this.getPreviousY(compOffset) - this.getPreviousXY(compOffset)) >> 1); + }; + + + + jpeg.lossless.Decoder.prototype.select6 = function (compOffset) { + return this.getPreviousY(compOffset) + ((this.getPreviousX(compOffset) - this.getPreviousXY(compOffset)) >> 1); + }; + + + + jpeg.lossless.Decoder.prototype.select7 = function (compOffset) { + return ((this.getPreviousX(compOffset) + this.getPreviousY(compOffset)) / 2); + }; + + + + jpeg.lossless.Decoder.prototype.decodeRGB = function (prev, temp, index) { + /*jslint bitwise: true */ + + var value, actab, dctab, qtab, ctrC, i, k, j; + + prev[0] = this.selector(0); + prev[1] = this.selector(1); + prev[2] = this.selector(2); + + for (ctrC = 0; ctrC < this.numComp; ctrC+=1) { + qtab = this.qTab[ctrC]; + actab = this.acTab[ctrC]; + dctab = this.dcTab[ctrC]; + for (i = 0; i < this.nBlock[ctrC]; i+=1) { + for (k = 0; k < this.IDCT_Source.length; k+=1) { + this.IDCT_Source[k] = 0; + } + + value = this.getHuffmanValue(dctab, temp, index); + + if (value >= 0xFF00) { + return value; + } + + prev[ctrC] = this.IDCT_Source[0] = prev[ctrC] + this.getn(index, value, temp, index); + this.IDCT_Source[0] *= qtab[0]; + + for (j = 1; j < 64; j+=1) { + value = this.getHuffmanValue(actab, temp, index); + + if (value >= 0xFF00) { + return value; + } + + j += (value >> 4); + + if ((value & 0x0F) === 0) { + if ((value >> 4) === 0) { + break; + } + } else { + this.IDCT_Source[jpeg.lossless.Decoder.IDCT_P[j]] = this.getn(index, value & 0x0F, temp, index) * qtab[j]; + } + } + } + } + + return 0; + }; + + + + jpeg.lossless.Decoder.prototype.decodeSingle = function (prev, temp, index) { + /*jslint bitwise: true */ + + var value, i, n, nRestart; + + if (this.restarting) { + this.restarting = false; + prev[0] = (1 << (this.frame.precision - 1)); + } else { + prev[0] = this.selector(); + } + + for (i = 0; i < this.nBlock[0]; i+=1) { + value = this.getHuffmanValue(this.dcTab[0], temp, index); + if (value >= 0xFF00) { + return value; + } + + n = this.getn(prev, value, temp, index); + nRestart = (n >> 8); + + if ((nRestart >= jpeg.lossless.Decoder.RESTART_MARKER_BEGIN) && (nRestart <= jpeg.lossless.Decoder.RESTART_MARKER_END)) { + return nRestart; + } + + prev[0] += n; + } + + return 0; + }; + + + + // Huffman table for fast search: (HuffTab) 8-bit Look up table 2-layer search architecture, 1st-layer represent 256 node (8 bits) if codeword-length > 8 + // bits, then the entry of 1st-layer = (# of 2nd-layer table) | MSB and it is stored in the 2nd-layer Size of tables in each layer are 256. + // HuffTab[*][*][0-256] is always the only 1st-layer table. + // + // An entry can be: (1) (# of 2nd-layer table) | MSB , for code length > 8 in 1st-layer (2) (Code length) << 8 | HuffVal + // + // HuffmanValue(table HuffTab[x][y] (ex) HuffmanValue(HuffTab[1][0],...) + // ): + // return: Huffman Value of table + // 0xFF?? if it receives a MARKER + // Parameter: table HuffTab[x][y] (ex) HuffmanValue(HuffTab[1][0],...) + // temp temp storage for remainded bits + // index index to bit of temp + // in FILE pointer + // Effect: + // temp store new remainded bits + // index change to new index + // in change to new position + // NOTE: + // Initial by temp=0; index=0; + // NOTE: (explain temp and index) + // temp: is always in the form at calling time or returning time + // | byte 4 | byte 3 | byte 2 | byte 1 | + // | 0 | 0 | 00000000 | 00000??? | if not a MARKER + // ^index=3 (from 0 to 15) + // 321 + // NOTE (marker and marker_index): + // If get a MARKER from 'in', marker=the low-byte of the MARKER + // and marker_index=9 + // If marker_index=9 then index is always > 8, or HuffmanValue() + // will not be called + jpeg.lossless.Decoder.prototype.getHuffmanValue = function (table, temp, index) { + /*jslint bitwise: true */ + + var code, input, mask; + mask = 0xFFFF; + + if (index[0] < 8) { + temp[0] <<= 8; + input = this.stream.get8(); + if (input === 0xFF) { + this.marker = this.stream.get8(); + if (this.marker !== 0) { + this.markerIndex = 9; + } + } + temp[0] |= input; + } else { + index[0] -= 8; + } + + code = table[temp[0] >> index[0]]; + + if ((code & jpeg.lossless.Decoder.MSB) !== 0) { + if (this.markerIndex !== 0) { + this.markerIndex = 0; + return 0xFF00 | this.marker; + } + + temp[0] &= (mask >> (16 - index[0])); + temp[0] <<= 8; + input = this.stream.get8(); + + if (input === 0xFF) { + this.marker = this.stream.get8(); + if (this.marker !== 0) { + this.markerIndex = 9; + } + } + + temp[0] |= input; + code = table[((code & 0xFF) * 256) + (temp[0] >> index[0])]; + index[0] += 8; + } + + index[0] += 8 - (code >> 8); + + if (index[0] < 0) { + throw new Error("index=" + index[0] + " temp=" + temp[0] + " code=" + code + " in HuffmanValue()"); + } + + if (index[0] < this.markerIndex) { + this.markerIndex = 0; + return 0xFF00 | this.marker; + } + + temp[0] &= (mask >> (16 - index[0])); + return code & 0xFF; + }; + + + + jpeg.lossless.Decoder.prototype.getn = function (PRED, n, temp, index) { + /*jslint bitwise: true */ + + var result, one, n_one, mask, input; + one = 1; + n_one = -1; + mask = 0xFFFF; + + if (n === 0) { + return 0; + } + + if (n === 16) { + if (PRED[0] >= 0) { + return -32768; + } else { + return 32768; + } + } + + index[0] -= n; + + if (index[0] >= 0) { + if ((index[0] < this.markerIndex) && !this.isLastPixel()) { // this was corrupting the last pixel in some cases + this.markerIndex = 0; + return (0xFF00 | this.marker) << 8; + } + + result = temp[0] >> index[0]; + temp[0] &= (mask >> (16 - index[0])); + } else { + temp[0] <<= 8; + input = this.stream.get8(); + + if (input === 0xFF) { + this.marker = this.stream.get8(); + if (this.marker !== 0) { + this.markerIndex = 9; + } + } + + temp[0] |= input; + index[0] += 8; + + if (index[0] < 0) { + if (this.markerIndex !== 0) { + this.markerIndex = 0; + return (0xFF00 | this.marker) << 8; + } + + temp[0] <<= 8; + input = this.stream.get8(); + + if (input === 0xFF) { + this.marker = this.stream.get8(); + if (this.marker !== 0) { + this.markerIndex = 9; + } + } + + temp[0] |= input; + index[0] += 8; + } + + if (index[0] < 0) { + throw new Error("index=" + index[0] + " in getn()"); + } + + if (index[0] < this.markerIndex) { + this.markerIndex = 0; + return (0xFF00 | this.marker) << 8; + } + + result = temp[0] >> index[0]; + temp[0] &= (mask >> (16 - index[0])); + } + + if (result < (one << (n - 1))) { + result += (n_one << n) + 1; + } + + return result; + }; + + + + jpeg.lossless.Decoder.prototype.getPreviousX = function (compOffset) { + /*jslint bitwise: true */ + + if (this.xLoc > 0) { + return this.getter((((this.yLoc * this.xDim) + this.xLoc) - 1), compOffset); + } else if (this.yLoc > 0) { + return this.getPreviousY(compOffset); + } else { + return (1 << (this.frame.precision - 1)); + } + }; + + + + jpeg.lossless.Decoder.prototype.getPreviousXY = function (compOffset) { + /*jslint bitwise: true */ + + if ((this.xLoc > 0) && (this.yLoc > 0)) { + return this.getter(((((this.yLoc - 1) * this.xDim) + this.xLoc) - 1), compOffset); + } else { + return this.getPreviousY(compOffset); + } + }; + + + + jpeg.lossless.Decoder.prototype.getPreviousY = function (compOffset) { + /*jslint bitwise: true */ + + if (this.yLoc > 0) { + return this.getter((((this.yLoc - 1) * this.xDim) + this.xLoc), compOffset); + } else { + return this.getPreviousX(compOffset); + } + }; + + + + jpeg.lossless.Decoder.prototype.isLastPixel = function () { + return (this.xLoc === (this.xDim - 1)) && (this.yLoc === (this.yDim - 1)); + }; + + + + jpeg.lossless.Decoder.prototype.outputSingle = function (PRED) { + if ((this.xLoc < this.xDim) && (this.yLoc < this.yDim)) { + this.setter((((this.yLoc * this.xDim) + this.xLoc)), this.mask & PRED[0]); + + this.xLoc+=1; + + if (this.xLoc >= this.xDim) { + this.yLoc+=1; + this.xLoc = 0; + } + } + }; + + + + jpeg.lossless.Decoder.prototype.outputRGB = function (PRED) { + var offset = ((this.yLoc * this.xDim) + this.xLoc); + + if ((this.xLoc < this.xDim) && (this.yLoc < this.yDim)) { + this.setter(offset, PRED[0], 0); + this.setter(offset, PRED[1], 1); + this.setter(offset, PRED[2], 2); + + this.xLoc+=1; + + if (this.xLoc >= this.xDim) { + this.yLoc+=1; + this.xLoc = 0; + } + } + }; + + jpeg.lossless.Decoder.prototype.setValue8 = function (index, val) { + this.outputData[index] = val; + }; + + jpeg.lossless.Decoder.prototype.getValue8 = function (index) { + return this.outputData[index]; // mask should not be necessary because outputData is either Int8Array or Int16Array + }; + + var littleEndian = (function() { + var buffer = new ArrayBuffer(2); + new DataView(buffer).setInt16(0, 256, true /* littleEndian */); + // Int16Array uses the platform's endianness. + return new Int16Array(buffer)[0] === 256; + })(); + + if (littleEndian) { + // just reading from an array is fine then. Int16Array will use platform endianness. + jpeg.lossless.Decoder.prototype.setValue16 = jpeg.lossless.Decoder.prototype.setValue8; + jpeg.lossless.Decoder.prototype.getValue16 = jpeg.lossless.Decoder.prototype.getValue8; + } + else { + // If platform is big-endian, we will need to convert to little-endian + jpeg.lossless.Decoder.prototype.setValue16 = function (index, val) { + this.outputData[index] = ((val & 0xFF) << 8) | ((val >> 8) & 0xFF); + }; + + jpeg.lossless.Decoder.prototype.getValue16 = function (index) { + var val = this.outputData[index]; + return ((val & 0xFF) << 8) | ((val >> 8) & 0xFF); + }; + } + + jpeg.lossless.Decoder.prototype.setValueRGB = function (index, val, compOffset) { + // this.outputData.setUint8(index * 3 + compOffset, val); + this.outputData[index * 3 + compOffset] = val; + }; + + jpeg.lossless.Decoder.prototype.getValueRGB = function (index, compOffset) { + // return this.outputData.getUint8(index * 3 + compOffset); + return this.outputData[index * 3 + compOffset]; + }; + + + + jpeg.lossless.Decoder.prototype.readApp = function() { + var count = 0, length = this.stream.get16(); + count += 2; + + while (count < length) { + this.stream.get8(); + count+=1; + } + + return length; + }; + + + + jpeg.lossless.Decoder.prototype.readComment = function () { + var sb = "", count = 0, length; + + length = this.stream.get16(); + count += 2; + + while (count < length) { + sb += this.stream.get8(); + count+=1; + } + + return sb; + }; + + + + jpeg.lossless.Decoder.prototype.readNumber = function() { + var Ld = this.stream.get16(); + + if (Ld !== 4) { + throw new Error("ERROR: Define number format throw new IOException [Ld!=4]"); + } + + return this.stream.get16(); + }; + + + + /*** Exports ***/ + + var moduleType = typeof module; + if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg.lossless.Decoder; + } + + },{"./data-stream.js":2,"./frame-header.js":4,"./huffman-table.js":5,"./quantization-table.js":7,"./scan-header.js":9,"./utils.js":10}],4:[function(require,module,exports){ + /* + * Copyright (C) 2015 Michael Martinez + * Changes: Added support for selection values 2-7, fixed minor bugs & + * warnings, split into multiple class files, and general clean up. + * + * 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT. + */ + + /* + * Copyright (C) Helmut Dersch + * + * 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. + */ + + /*jslint browser: true, node: true */ + /*global require, module */ + + "use strict"; + + /*** Imports ***/ + var jpeg = jpeg || {}; + jpeg.lossless = jpeg.lossless || {}; + jpeg.lossless.ComponentSpec = jpeg.lossless.ComponentSpec || ((typeof require !== 'undefined') ? require('./component-spec.js') : null); + jpeg.lossless.DataStream = jpeg.lossless.DataStream || ((typeof require !== 'undefined') ? require('./data-stream.js') : null); + + + /*** Constructor ***/ + jpeg.lossless.FrameHeader = jpeg.lossless.FrameHeader || function () { + this.components = []; // Components + this.dimX = 0; // Number of samples per line + this.dimY = 0; // Number of lines + this.numComp = 0; // Number of component in the frame + this.precision = 0; // Sample Precision (from the original image) + }; + + + + /*** Prototype Methods ***/ + + jpeg.lossless.FrameHeader.prototype.read = function (data) { + /*jslint bitwise: true */ + + var count = 0, length, i, c, temp; + + length = data.get16(); + count += 2; + + this.precision = data.get8(); + count+=1; + + this.dimY = data.get16(); + count += 2; + + this.dimX = data.get16(); + count += 2; + + this.numComp = data.get8(); + count+=1; + for (i = 1; i <= this.numComp; i+=1) { + if (count > length) { + throw new Error("ERROR: frame format error"); + } + + c = data.get8(); + count+=1; + + if (count >= length) { + throw new Error("ERROR: frame format error [c>=Lf]"); + } + + temp = data.get8(); + count+=1; + + if (!this.components[c]) { + this.components[c] = new jpeg.lossless.ComponentSpec(); + } + + this.components[c].hSamp = temp >> 4; + this.components[c].vSamp = temp & 0x0F; + this.components[c].quantTableSel = data.get8(); + count+=1; + } + + if (count !== length) { + throw new Error("ERROR: frame format error [Lf!=count]"); + } + + return 1; + }; + + + /*** Exports ***/ + + var moduleType = typeof module; + if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg.lossless.FrameHeader; + } + + },{"./component-spec.js":1,"./data-stream.js":2}],5:[function(require,module,exports){ + /* + * Copyright (C) 2015 Michael Martinez + * Changes: Added support for selection values 2-7, fixed minor bugs & + * warnings, split into multiple class files, and general clean up. + * + * 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT. + */ + + /* + * Copyright (C) Helmut Dersch + * + * 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. + */ + + /*jslint browser: true, node: true */ + /*global require, module */ + + "use strict"; + + /*** Imports ***/ + var jpeg = jpeg || {}; + jpeg.lossless = jpeg.lossless || {}; + jpeg.lossless.DataStream = jpeg.lossless.DataStream || ((typeof require !== 'undefined') ? require('./data-stream.js') : null); + jpeg.lossless.Utils = jpeg.lossless.Utils || ((typeof require !== 'undefined') ? require('./utils.js') : null); + + + /*** Constructor ***/ + jpeg.lossless.HuffmanTable = jpeg.lossless.HuffmanTable || function () { + this.l = jpeg.lossless.Utils.createArray(4, 2, 16); + this.th = []; + this.v = jpeg.lossless.Utils.createArray(4, 2, 16, 200); + this.tc = jpeg.lossless.Utils.createArray(4, 2); + + this.tc[0][0] = 0; + this.tc[1][0] = 0; + this.tc[2][0] = 0; + this.tc[3][0] = 0; + this.tc[0][1] = 0; + this.tc[1][1] = 0; + this.tc[2][1] = 0; + this.tc[3][1] = 0; + this.th[0] = 0; + this.th[1] = 0; + this.th[2] = 0; + this.th[3] = 0; + }; + + + + /*** Static Pseudo-constants ***/ + + jpeg.lossless.HuffmanTable.MSB = 0x80000000; + + + /*** Prototype Methods ***/ + + jpeg.lossless.HuffmanTable.prototype.read = function(data, HuffTab) { + /*jslint bitwise: true */ + + var count = 0, length, temp, t, c, i, j; + + length = data.get16(); + count += 2; + + while (count < length) { + temp = data.get8(); + count+=1; + t = temp & 0x0F; + if (t > 3) { + throw new Error("ERROR: Huffman table ID > 3"); + } + + c = temp >> 4; + if (c > 2) { + throw new Error("ERROR: Huffman table [Table class > 2 ]"); + } + + this.th[t] = 1; + this.tc[t][c] = 1; + + for (i = 0; i < 16; i+=1) { + this.l[t][c][i] = data.get8(); + count+=1; + } + + for (i = 0; i < 16; i+=1) { + for (j = 0; j < this.l[t][c][i]; j+=1) { + if (count > length) { + throw new Error("ERROR: Huffman table format error [count>Lh]"); + } + + this.v[t][c][i][j] = data.get8(); + count+=1; + } + } + } + + if (count !== length) { + throw new Error("ERROR: Huffman table format error [count!=Lf]"); + } + + for (i = 0; i < 4; i+=1) { + for (j = 0; j < 2; j+=1) { + if (this.tc[i][j] !== 0) { + this.buildHuffTable(HuffTab[i][j], this.l[i][j], this.v[i][j]); + } + } + } + + return 1; + }; + + + + // Build_HuffTab() + // Parameter: t table ID + // c table class ( 0 for DC, 1 for AC ) + // L[i] # of codewords which length is i + // V[i][j] Huffman Value (length=i) + // Effect: + // build up HuffTab[t][c] using L and V. + jpeg.lossless.HuffmanTable.prototype.buildHuffTable = function(tab, L, V) { + /*jslint bitwise: true */ + + var currentTable, temp, k, i, j, n; + temp = 256; + k = 0; + + for (i = 0; i < 8; i+=1) { // i+1 is Code length + for (j = 0; j < L[i]; j+=1) { + for (n = 0; n < (temp >> (i + 1)); n+=1) { + tab[k] = V[i][j] | ((i + 1) << 8); + k+=1; + } + } + } + + for (i = 1; k < 256; i+=1, k+=1) { + tab[k] = i | jpeg.lossless.HuffmanTable.MSB; + } + + currentTable = 1; + k = 0; + + for (i = 8; i < 16; i+=1) { // i+1 is Code length + for (j = 0; j < L[i]; j+=1) { + for (n = 0; n < (temp >> (i - 7)); n+=1) { + tab[(currentTable * 256) + k] = V[i][j] | ((i + 1) << 8); + k+=1; + } + + if (k >= 256) { + if (k > 256) { + throw new Error("ERROR: Huffman table error(1)!"); + } + + k = 0; + currentTable+=1; + } + } + } + }; + + + /*** Exports ***/ + + var moduleType = typeof module; + if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg.lossless.HuffmanTable; + } + + },{"./data-stream.js":2,"./utils.js":10}],6:[function(require,module,exports){ + /*jslint browser: true, node: true */ + /*global require, module */ + + "use strict"; + + /*** Imports ****/ + + /** + * jpeg + * @type {*|{}} + */ + var jpeg = jpeg || {}; + + /** + * jpeg.lossless + * @type {*|{}} + */ + jpeg.lossless = jpeg.lossless || {}; + + + jpeg.lossless.ComponentSpec = jpeg.lossless.ComponentSpec || ((typeof require !== 'undefined') ? require('./component-spec.js') : null); + jpeg.lossless.DataStream = jpeg.lossless.DataStream || ((typeof require !== 'undefined') ? require('./data-stream.js') : null); + jpeg.lossless.Decoder = jpeg.lossless.Decoder || ((typeof require !== 'undefined') ? require('./decoder.js') : null); + jpeg.lossless.FrameHeader = jpeg.lossless.FrameHeader || ((typeof require !== 'undefined') ? require('./frame-header.js') : null); + jpeg.lossless.HuffmanTable = jpeg.lossless.HuffmanTable || ((typeof require !== 'undefined') ? require('./huffman-table.js') : null); + jpeg.lossless.QuantizationTable = jpeg.lossless.QuantizationTable || ((typeof require !== 'undefined') ? require('./quantization-table.js') : null); + jpeg.lossless.ScanComponent = jpeg.lossless.ScanComponent || ((typeof require !== 'undefined') ? require('./scan-component.js') : null); + jpeg.lossless.ScanHeader = jpeg.lossless.ScanHeader || ((typeof require !== 'undefined') ? require('./scan-header.js') : null); + jpeg.lossless.Utils = jpeg.lossless.Utils || ((typeof require !== 'undefined') ? require('./utils.js') : null); + + + /*** Exports ***/ + var moduleType = typeof module; + if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg; + } + + },{"./component-spec.js":1,"./data-stream.js":2,"./decoder.js":3,"./frame-header.js":4,"./huffman-table.js":5,"./quantization-table.js":7,"./scan-component.js":8,"./scan-header.js":9,"./utils.js":10}],7:[function(require,module,exports){ + /* + * Copyright (C) 2015 Michael Martinez + * Changes: Added support for selection values 2-7, fixed minor bugs & + * warnings, split into multiple class files, and general clean up. + * + * 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT. + */ + + /* + * Copyright (C) Helmut Dersch + * + * 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. + */ + + /*jslint browser: true, node: true */ + /*global require, module */ + + "use strict"; + + /*** Imports ***/ + var jpeg = jpeg || {}; + jpeg.lossless = jpeg.lossless || {}; + jpeg.lossless.DataStream = jpeg.lossless.DataStream || ((typeof require !== 'undefined') ? require('./data-stream.js') : null); + jpeg.lossless.Utils = jpeg.lossless.Utils || ((typeof require !== 'undefined') ? require('./utils.js') : null); + + + /*** Constructor ***/ + jpeg.lossless.QuantizationTable = jpeg.lossless.QuantizationTable || function () { + this.precision = []; // Quantization precision 8 or 16 + this.tq = []; // 1: this table is presented + this.quantTables = jpeg.lossless.Utils.createArray(4, 64); // Tables + + this.tq[0] = 0; + this.tq[1] = 0; + this.tq[2] = 0; + this.tq[3] = 0; + }; + + + + /*** Static Methods ***/ + + jpeg.lossless.QuantizationTable.enhanceQuantizationTable = function(qtab, table) { + /*jslint bitwise: true */ + + var i; + + for (i = 0; i < 8; i+=1) { + qtab[table[(0 * 8) + i]] *= 90; + qtab[table[(4 * 8) + i]] *= 90; + qtab[table[(2 * 8) + i]] *= 118; + qtab[table[(6 * 8) + i]] *= 49; + qtab[table[(5 * 8) + i]] *= 71; + qtab[table[(1 * 8) + i]] *= 126; + qtab[table[(7 * 8) + i]] *= 25; + qtab[table[(3 * 8) + i]] *= 106; + } + + for (i = 0; i < 8; i+=1) { + qtab[table[0 + (8 * i)]] *= 90; + qtab[table[4 + (8 * i)]] *= 90; + qtab[table[2 + (8 * i)]] *= 118; + qtab[table[6 + (8 * i)]] *= 49; + qtab[table[5 + (8 * i)]] *= 71; + qtab[table[1 + (8 * i)]] *= 126; + qtab[table[7 + (8 * i)]] *= 25; + qtab[table[3 + (8 * i)]] *= 106; + } + + for (i = 0; i < 64; i+=1) { + qtab[i] >>= 6; + } + }; + + + /*** Prototype Methods ***/ + + jpeg.lossless.QuantizationTable.prototype.read = function (data, table) { + /*jslint bitwise: true */ + + var count = 0, length, temp, t, i; + + length = data.get16(); + count += 2; + + while (count < length) { + temp = data.get8(); + count+=1; + t = temp & 0x0F; + + if (t > 3) { + throw new Error("ERROR: Quantization table ID > 3"); + } + + this.precision[t] = temp >> 4; + + if (this.precision[t] === 0) { + this.precision[t] = 8; + } else if (this.precision[t] === 1) { + this.precision[t] = 16; + } else { + throw new Error("ERROR: Quantization table precision error"); + } + + this.tq[t] = 1; + + if (this.precision[t] === 8) { + for (i = 0; i < 64; i+=1) { + if (count > length) { + throw new Error("ERROR: Quantization table format error"); + } + + this.quantTables[t][i] = data.get8(); + count+=1; + } + + jpeg.lossless.QuantizationTable.enhanceQuantizationTable(this.quantTables[t], table); + } else { + for (i = 0; i < 64; i+=1) { + if (count > length) { + throw new Error("ERROR: Quantization table format error"); + } + + this.quantTables[t][i] = data.get16(); + count += 2; + } + + jpeg.lossless.QuantizationTable.enhanceQuantizationTable(this.quantTables[t], table); + } + } + + if (count !== length) { + throw new Error("ERROR: Quantization table error [count!=Lq]"); + } + + return 1; + }; + + + + /*** Exports ***/ + + var moduleType = typeof module; + if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg.lossless.QuantizationTable; + } + + },{"./data-stream.js":2,"./utils.js":10}],8:[function(require,module,exports){ + /* + * Copyright (C) 2015 Michael Martinez + * Changes: Added support for selection values 2-7, fixed minor bugs & + * warnings, split into multiple class files, and general clean up. + * + * 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT. + */ + + /* + * Copyright (C) Helmut Dersch + * + * 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. + */ + + /*jslint browser: true, node: true */ + /*global require, module */ + + "use strict"; + + /*** Imports ***/ + var jpeg = jpeg || {}; + jpeg.lossless = jpeg.lossless || {}; + + + /*** Constructor ***/ + jpeg.lossless.ScanComponent = jpeg.lossless.ScanComponent || function () { + this.acTabSel = 0; // AC table selector + this.dcTabSel = 0; // DC table selector + this.scanCompSel = 0; // Scan component selector + }; + + + + /*** Exports ***/ + + var moduleType = typeof module; + if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg.lossless.ScanComponent; + } + + },{}],9:[function(require,module,exports){ + /* + * Copyright (C) 2015 Michael Martinez + * Changes: Added support for selection values 2-7, fixed minor bugs & + * warnings, split into multiple class files, and general clean up. + * + * 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT. + */ + + /* + * Copyright (C) Helmut Dersch + * + * 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. + */ + + /*jslint browser: true, node: true */ + /*global require, module */ + + "use strict"; + + /*** Imports ***/ + var jpeg = jpeg || {}; + jpeg.lossless = jpeg.lossless || {}; + jpeg.lossless.DataStream = jpeg.lossless.DataStream || ((typeof require !== 'undefined') ? require('./data-stream.js') : null); + jpeg.lossless.ScanComponent = jpeg.lossless.ScanComponent || ((typeof require !== 'undefined') ? require('./scan-component.js') : null); + + + /*** Constructor ***/ + jpeg.lossless.ScanHeader = jpeg.lossless.ScanHeader || function () { + this.ah = 0; + this.al = 0; + this.numComp = 0; // Number of components in the scan + this.selection = 0; // Start of spectral or predictor selection + this.spectralEnd = 0; // End of spectral selection + this.components = []; + }; + + + /*** Prototype Methods ***/ + + jpeg.lossless.ScanHeader.prototype.read = function(data) { + /*jslint bitwise: true */ + + var count = 0, length, i, temp; + + length = data.get16(); + count += 2; + + this.numComp = data.get8(); + count+=1; + + for (i = 0; i < this.numComp; i+=1) { + this.components[i] = new jpeg.lossless.ScanComponent(); + + if (count > length) { + throw new Error("ERROR: scan header format error"); + } + + this.components[i].scanCompSel = data.get8(); + count+=1; + + temp = data.get8(); + count+=1; + + this.components[i].dcTabSel = (temp >> 4); + this.components[i].acTabSel = (temp & 0x0F); + } + + this.selection = data.get8(); + count+=1; + + this.spectralEnd = data.get8(); + count+=1; + + temp = data.get8(); + this.ah = (temp >> 4); + this.al = (temp & 0x0F); + count+=1; + + if (count !== length) { + throw new Error("ERROR: scan header format error [count!=Ns]"); + } + + return 1; + }; + + + + /*** Exports ***/ + + var moduleType = typeof module; + if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg.lossless.ScanHeader; + } + + },{"./data-stream.js":2,"./scan-component.js":8}],10:[function(require,module,exports){ + /* + * Copyright (C) 2015 Michael Martinez + * Changes: Added support for selection values 2-7, fixed minor bugs & + * warnings, split into multiple class files, and general clean up. + * + * 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT. + */ + + /* + * Copyright (C) Helmut Dersch + * + * 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. + */ + + /*jslint browser: true, node: true */ + /*global require, module */ + + "use strict"; + + /*** Imports ***/ + var jpeg = jpeg || {}; + jpeg.lossless = jpeg.lossless || {}; + + + /*** Constructor ***/ + jpeg.lossless.Utils = jpeg.lossless.Utils || {}; + + + /*** Static methods ***/ + + // http://stackoverflow.com/questions/966225/how-can-i-create-a-two-dimensional-array-in-javascript + jpeg.lossless.Utils.createArray = function (length) { + var arr = new Array(length || 0), + i = length; + + if (arguments.length > 1) { + var args = Array.prototype.slice.call(arguments, 1); + while(i--) arr[length-1 - i] = jpeg.lossless.Utils.createArray.apply(this, args); + } + + return arr; + }; + + + // http://stackoverflow.com/questions/18638900/javascript-crc32 + jpeg.lossless.Utils.makeCRCTable = function(){ + var c; + var crcTable = []; + for(var n =0; n < 256; n++){ + c = n; + for(var k =0; k < 8; k++){ + c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); + } + crcTable[n] = c; + } + return crcTable; + }; + + jpeg.lossless.Utils.crc32 = function(dataView) { + var uint8view = new Uint8Array(dataView.buffer); + var crcTable = jpeg.lossless.Utils.crcTable || (jpeg.lossless.Utils.crcTable = jpeg.lossless.Utils.makeCRCTable()); + var crc = 0 ^ (-1); + + for (var i = 0; i < uint8view.length; i++ ) { + crc = (crc >>> 8) ^ crcTable[(crc ^ uint8view[i]) & 0xFF]; + } + + return (crc ^ (-1)) >>> 0; + }; + + + /*** Exports ***/ + + var moduleType = typeof module; + if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg.lossless.Utils; + } + +},{}]},{},[6])(6) +}); diff --git a/packages/dicom-image-loader/package.json b/packages/dicom-image-loader/package.json new file mode 100644 index 000000000..81319eefc --- /dev/null +++ b/packages/dicom-image-loader/package.json @@ -0,0 +1,50 @@ +{ + "name": "@cornerstonejs/dicom-image-loader", + "version": "0.1.1", + "description": "", + "main": "dist/umd/index.js", + "types": "dist/esm/index.d.ts", + "module": "dist/esm/index.js", + "repository": "https://github.com/cornerstonejs/cornerstone3D-beta", + "files": [ + "dist/" + ], + "directories": { + "test": "test" + }, + "sideEffects": false, + "scripts": { + "build:cjs": "tsc --project ./tsconfig.cjs.json", + "build:esm": "tsc --project ./tsconfig.esm.json", + "build:umd": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js", + "build:all": "yarn run build:umd && yarn run build:cjs && yarn run build:esm", + "copy-dts": "copyfiles -u 1 \"src/**/*.d.ts\" dist/cjs && copyfiles -u 1 \"src/**/*.d.ts\" dist/esm", + "build": "yarn run build:all && yarn run copy-dts", + "api-check": "api-extractor --debug run", + "build:update-api": "yarn run build && api-extractor run --local", + "prepublishOnly": "yarn run build", + "example": "node ../../utils/ExampleRunner/example-runner-cli.js", + "webpack:dev": "webpack serve --progress --config ./.webpack/webpack-dev.js", + "webpack:dynamic-import": "webpack --progress --config ./.webpack/webpack-dynamic-import", + "webpack:bundle": "webpack --progress --config ./.webpack/webpack-bundle", + "webpack:dynamic-import:watch": "webpack --progress --watch --config ./.webpack/webpack-dynamic-import" + }, + "dependencies": { + "@cornerstonejs/codec-charls": "^0.1.1", + "@cornerstonejs/codec-libjpeg-turbo-8bit": "^0.0.7", + "@cornerstonejs/codec-openjpeg": "^0.1.0", + "dicom-parser": "^1.8.9", + "pako": "^2.0.4" + }, + "contributors": [ + { + "name": "Cornerstone.js Contributors", + "url": "https://github.com/orgs/cornerstonejs/people" + } + ], + "license": "MIT", + "funding": { + "type": "individual", + "url": "https://ohif.org/donate" + } +} diff --git a/packages/dicom-image-loader/src/externalModules.js b/packages/dicom-image-loader/src/externalModules.js new file mode 100644 index 000000000..2cde3fcef --- /dev/null +++ b/packages/dicom-image-loader/src/externalModules.js @@ -0,0 +1,47 @@ +/* eslint import/extensions:0 */ +import registerLoaders from './imageLoader/registerLoaders.js'; + +let cornerstone; + +let dicomParser; + +const external = { + set cornerstone(cs) { + cornerstone = cs; + + registerLoaders(cornerstone); + }, + get cornerstone() { + if (!cornerstone) { + if (window && window.cornerstone) { + cornerstone = window.cornerstone; + + registerLoaders(cornerstone); + } else { + throw new Error( + 'cornerstoneWADOImageLoader requires a copy of Cornerstone to work properly. Please add cornerstoneWADOImageLoader.external.cornerstone = cornerstone; to your application.' + ); + } + } + + return cornerstone; + }, + set dicomParser(dp) { + dicomParser = dp; + }, + get dicomParser() { + if (!dicomParser) { + if (window && window.dicomParser) { + dicomParser = window.dicomParser; + } else { + throw new Error( + 'cornerstoneWADOImageLoader requires a copy of dicomParser to work properly. Please add cornerstoneWADOImageLoader.external.dicomParser = dicomParser; to your application.' + ); + } + } + + return dicomParser; + }, +}; + +export default external; diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.js new file mode 100644 index 000000000..5a9b1f56f --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.js @@ -0,0 +1,77 @@ +/* eslint no-bitwise: 0 */ + +function convertLUTto8Bit(lut, shift) { + const numEntries = lut.length; + const cleanedLUT = new Uint8ClampedArray(numEntries); + + for (let i = 0; i < numEntries; ++i) { + cleanedLUT[i] = lut[i] >> shift; + } + + return cleanedLUT; +} + +/** + * Convert pixel data with PALETTE COLOR Photometric Interpretation to RGBA + * + * @param {ImageFrame} imageFrame + * @param {Uint8ClampedArray} colorBuffer + * @returns {void} + */ +export default function (imageFrame, colorBuffer, useRGBA) { + const numPixels = imageFrame.columns * imageFrame.rows; + const pixelData = imageFrame.pixelData; + const rData = imageFrame.redPaletteColorLookupTableData; + const gData = imageFrame.greenPaletteColorLookupTableData; + const bData = imageFrame.bluePaletteColorLookupTableData; + const len = imageFrame.redPaletteColorLookupTableData.length; + + let palIndex = 0; + + let bufferIndex = 0; + + const start = imageFrame.redPaletteColorLookupTableDescriptor[1]; + const shift = + imageFrame.redPaletteColorLookupTableDescriptor[2] === 8 ? 0 : 8; + + const rDataCleaned = convertLUTto8Bit(rData, shift); + const gDataCleaned = convertLUTto8Bit(gData, shift); + const bDataCleaned = convertLUTto8Bit(bData, shift); + + if (useRGBA) { + for (let i = 0; i < numPixels; ++i) { + let value = pixelData[palIndex++]; + + if (value < start) { + value = 0; + } else if (value > start + len - 1) { + value = len - 1; + } else { + value -= start; + } + + colorBuffer[bufferIndex++] = rDataCleaned[value]; + colorBuffer[bufferIndex++] = gDataCleaned[value]; + colorBuffer[bufferIndex++] = bDataCleaned[value]; + colorBuffer[bufferIndex++] = 255; + } + + return; + } + + for (let i = 0; i < numPixels; ++i) { + let value = pixelData[palIndex++]; + + if (value < start) { + value = 0; + } else if (value > start + len - 1) { + value = len - 1; + } else { + value -= start; + } + + colorBuffer[bufferIndex++] = rDataCleaned[value]; + colorBuffer[bufferIndex++] = gDataCleaned[value]; + colorBuffer[bufferIndex++] = bDataCleaned[value]; + } +} diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.js new file mode 100644 index 000000000..2222c1e3f --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.js @@ -0,0 +1,28 @@ +export default function (imageFrame, colorBuffer, useRGBA) { + if (imageFrame === undefined) { + throw new Error('decodeRGB: rgbBuffer must not be undefined'); + } + if (imageFrame.length % 3 !== 0) { + throw new Error('decodeRGB: rgbBuffer length must be divisible by 3'); + } + + const numPixels = imageFrame.length / 3; + + let rgbIndex = 0; + + let bufferIndex = 0; + + if (useRGBA) { + for (let i = 0; i < numPixels; i++) { + colorBuffer[bufferIndex++] = imageFrame[rgbIndex++]; // red + colorBuffer[bufferIndex++] = imageFrame[rgbIndex++]; // green + colorBuffer[bufferIndex++] = imageFrame[rgbIndex++]; // blue + colorBuffer[bufferIndex++] = 255; // alpha + } + + return; + } + + // if RGB buffer + colorBuffer.set(imageFrame); +} diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.js new file mode 100644 index 000000000..124d9ee03 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.js @@ -0,0 +1,32 @@ +export default function (imageFrame, colorBuffer, useRGBA) { + if (imageFrame === undefined) { + throw new Error('decodeRGB: rgbBuffer must not be undefined'); + } + if (imageFrame.length % 3 !== 0) { + throw new Error('decodeRGB: rgbBuffer length must be divisible by 3'); + } + + const numPixels = imageFrame.length / 3; + + let bufferIndex = 0; + + let rIndex = 0; + + let gIndex = numPixels; + + let bIndex = numPixels * 2; + + if (useRGBA) { + for (let i = 0; i < numPixels; i++) { + colorBuffer[bufferIndex++] = imageFrame[rIndex++]; // red + colorBuffer[bufferIndex++] = imageFrame[gIndex++]; // green + colorBuffer[bufferIndex++] = imageFrame[bIndex++]; // blue + colorBuffer[bufferIndex++] = 255; // alpha + } + + return; + } + + // if RGB buffer + colorBuffer.set(imageFrame); +} diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.js new file mode 100644 index 000000000..13cc124a5 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.js @@ -0,0 +1,54 @@ +export default function (imageFrame, colorBuffer, useRGBA) { + if (imageFrame === undefined) { + throw new Error('decodeRGB: ybrBuffer must not be undefined'); + } + if (imageFrame.length % 2 !== 0) { + throw new Error('decodeRGB: ybrBuffer length must be divisble by 3'); + } + + const numPixels = imageFrame.length / 2; + + let ybrIndex = 0; + + let bufferIndex = 0; + + if (useRGBA) { + for (let i = 0; i < numPixels; i += 2) { + const y1 = imageFrame[ybrIndex++]; + const y2 = imageFrame[ybrIndex++]; + const cb = imageFrame[ybrIndex++]; + const cr = imageFrame[ybrIndex++]; + + colorBuffer[bufferIndex++] = y1 + 1.402 * (cr - 128); // red + colorBuffer[bufferIndex++] = + y1 - 0.34414 * (cb - 128) - 0.71414 * (cr - 128); // green + colorBuffer[bufferIndex++] = y1 + 1.772 * (cb - 128); // blue + colorBuffer[bufferIndex++] = 255; // alpha + + colorBuffer[bufferIndex++] = y2 + 1.402 * (cr - 128); // red + colorBuffer[bufferIndex++] = + y2 - 0.34414 * (cb - 128) - 0.71414 * (cr - 128); // green + colorBuffer[bufferIndex++] = y2 + 1.772 * (cb - 128); // blue + colorBuffer[bufferIndex++] = 255; // alpha + } + + return; + } + + for (let i = 0; i < numPixels; i += 2) { + const y1 = imageFrame[ybrIndex++]; + const y2 = imageFrame[ybrIndex++]; + const cb = imageFrame[ybrIndex++]; + const cr = imageFrame[ybrIndex++]; + + colorBuffer[bufferIndex++] = y1 + 1.402 * (cr - 128); // red + colorBuffer[bufferIndex++] = + y1 - 0.34414 * (cb - 128) - 0.71414 * (cr - 128); // green + colorBuffer[bufferIndex++] = y1 + 1.772 * (cb - 128); // blue + + colorBuffer[bufferIndex++] = y2 + 1.402 * (cr - 128); // red + colorBuffer[bufferIndex++] = + y2 - 0.34414 * (cb - 128) - 0.71414 * (cr - 128); // green + colorBuffer[bufferIndex++] = y2 + 1.772 * (cb - 128); // blue + } +} diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.js new file mode 100644 index 000000000..dfd46fde9 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.js @@ -0,0 +1,41 @@ +export default function (imageFrame, colorBuffer, useRGBA) { + if (imageFrame === undefined) { + throw new Error('decodeRGB: ybrBuffer must not be undefined'); + } + if (imageFrame.length % 3 !== 0) { + throw new Error('decodeRGB: ybrBuffer length must be divisble by 3'); + } + + const numPixels = imageFrame.length / 3; + + let ybrIndex = 0; + + let bufferIndex = 0; + + if (useRGBA) { + for (let i = 0; i < numPixels; i++) { + const y = imageFrame[ybrIndex++]; + const cb = imageFrame[ybrIndex++]; + const cr = imageFrame[ybrIndex++]; + + colorBuffer[bufferIndex++] = y + 1.402 * (cr - 128); // red + colorBuffer[bufferIndex++] = + y - 0.34414 * (cb - 128) - 0.71414 * (cr - 128); // green + colorBuffer[bufferIndex++] = y + 1.772 * (cb - 128); // blue + colorBuffer[bufferIndex++] = 255; // alpha + } + + return; + } + + for (let i = 0; i < numPixels; i++) { + const y = imageFrame[ybrIndex++]; + const cb = imageFrame[ybrIndex++]; + const cr = imageFrame[ybrIndex++]; + + colorBuffer[bufferIndex++] = y + 1.402 * (cr - 128); // red + colorBuffer[bufferIndex++] = + y - 0.34414 * (cb - 128) - 0.71414 * (cr - 128); // green + colorBuffer[bufferIndex++] = y + 1.772 * (cb - 128); // blue + } +} diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.js new file mode 100644 index 000000000..ccac454b9 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.js @@ -0,0 +1,45 @@ +export default function (imageFrame, colorBuffer, useRGBA) { + if (imageFrame === undefined) { + throw new Error('decodeRGB: ybrBuffer must not be undefined'); + } + if (imageFrame.length % 3 !== 0) { + throw new Error('decodeRGB: ybrBuffer length must be divisble by 3'); + } + + const numPixels = imageFrame.length / 3; + + let bufferIndex = 0; + + let yIndex = 0; + + let cbIndex = numPixels; + + let crIndex = numPixels * 2; + + if (useRGBA) { + for (let i = 0; i < numPixels; i++) { + const y = imageFrame[yIndex++]; + const cb = imageFrame[cbIndex++]; + const cr = imageFrame[crIndex++]; + + colorBuffer[bufferIndex++] = y + 1.402 * (cr - 128); // red + colorBuffer[bufferIndex++] = + y - 0.34414 * (cb - 128) - 0.71414 * (cr - 128); // green + colorBuffer[bufferIndex++] = y + 1.772 * (cb - 128); // blue + colorBuffer[bufferIndex++] = 255; // alpha + } + + return; + } + + for (let i = 0; i < numPixels; i++) { + const y = imageFrame[yIndex++]; + const cb = imageFrame[cbIndex++]; + const cr = imageFrame[crIndex++]; + + colorBuffer[bufferIndex++] = y + 1.402 * (cr - 128); // red + colorBuffer[bufferIndex++] = + y - 0.34414 * (cb - 128) - 0.71414 * (cr - 128); // green + colorBuffer[bufferIndex++] = y + 1.772 * (cb - 128); // blue + } +} diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/index.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/index.js new file mode 100644 index 000000000..80c8bbd88 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/index.js @@ -0,0 +1,15 @@ +import { default as convertRGBColorByPixel } from './convertRGBColorByPixel.js'; +import { default as convertRGBColorByPlane } from './convertRGBColorByPlane.js'; +import { default as convertYBRFullByPixel } from './convertYBRFullByPixel.js'; +import { default as convertYBRFullByPlane } from './convertYBRFullByPlane.js'; +import { default as convertYBRFull422ByPixel } from './convertYBRFull422ByPixel.js'; +import { default as convertPALETTECOLOR } from './convertPALETTECOLOR.js'; + +export { + convertRGBColorByPixel, + convertRGBColorByPlane, + convertYBRFullByPixel, + convertYBRFullByPlane, + convertYBRFull422ByPixel, + convertPALETTECOLOR, +}; diff --git a/packages/dicom-image-loader/src/imageLoader/configure.js b/packages/dicom-image-loader/src/imageLoader/configure.js new file mode 100644 index 000000000..45c3515f5 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/configure.js @@ -0,0 +1,7 @@ +import { setOptions } from './internal/index.js'; + +function configure(options) { + setOptions(options); +} + +export default configure; diff --git a/packages/dicom-image-loader/src/imageLoader/convertColorSpace.js b/packages/dicom-image-loader/src/imageLoader/convertColorSpace.js new file mode 100644 index 000000000..bc53e21d2 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/convertColorSpace.js @@ -0,0 +1,45 @@ +import { + convertRGBColorByPixel, + convertRGBColorByPlane, + convertYBRFullByPixel, + convertYBRFull422ByPixel, + convertYBRFullByPlane, + convertPALETTECOLOR, +} from './colorSpaceConverters/index.js'; + +function convertRGB(imageFrame, colorBuffer, useRGBA) { + if (imageFrame.planarConfiguration === 0) { + convertRGBColorByPixel(imageFrame.pixelData, colorBuffer, useRGBA); + } else { + convertRGBColorByPlane(imageFrame.pixelData, colorBuffer, useRGBA); + } +} + +function convertYBRFull(imageFrame, colorBuffer, useRGBA) { + if (imageFrame.planarConfiguration === 0) { + convertYBRFullByPixel(imageFrame.pixelData, colorBuffer, useRGBA); + } else { + convertYBRFullByPlane(imageFrame.pixelData, colorBuffer, useRGBA); + } +} + +export default function convertColorSpace(imageFrame, colorBuffer, useRGBA) { + // convert based on the photometric interpretation + if (imageFrame.photometricInterpretation === 'RGB') { + convertRGB(imageFrame, colorBuffer, useRGBA); + } else if (imageFrame.photometricInterpretation === 'YBR_RCT') { + convertRGB(imageFrame, colorBuffer, useRGBA); + } else if (imageFrame.photometricInterpretation === 'YBR_ICT') { + convertRGB(imageFrame, colorBuffer, useRGBA); + } else if (imageFrame.photometricInterpretation === 'PALETTE COLOR') { + convertPALETTECOLOR(imageFrame, colorBuffer, useRGBA); + } else if (imageFrame.photometricInterpretation === 'YBR_FULL_422') { + convertYBRFull422ByPixel(imageFrame.pixelData, colorBuffer, useRGBA); + } else if (imageFrame.photometricInterpretation === 'YBR_FULL') { + convertYBRFull(imageFrame, colorBuffer, useRGBA); + } else { + throw new Error( + `No color space conversion for photometric interpretation ${imageFrame.photometricInterpretation}` + ); + } +} diff --git a/packages/dicom-image-loader/src/imageLoader/createImage.js b/packages/dicom-image-loader/src/imageLoader/createImage.js new file mode 100644 index 000000000..297a61853 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/createImage.js @@ -0,0 +1,390 @@ +import external from '../externalModules.js'; +import getImageFrame from './getImageFrame.js'; +import decodeImageFrame from './decodeImageFrame.js'; +import isColorImageFn from './isColorImage.js'; +import convertColorSpace from './convertColorSpace.js'; +import getMinMax from '../shared/getMinMax.js'; +import isJPEGBaseline8BitColor from './isJPEGBaseline8BitColor.js'; +import { getOptions } from './internal/options.js'; +import getScalingParameters from './getScalingParameters.js'; + +let lastImageIdDrawn = ''; + +function isModalityLUTForDisplay(sopClassUid) { + // special case for XA and XRF + // https://groups.google.com/forum/#!searchin/comp.protocols.dicom/Modality$20LUT$20XA/comp.protocols.dicom/UBxhOZ2anJ0/D0R_QP8V2wIJ + return ( + sopClassUid !== '1.2.840.10008.5.1.4.1.1.12.1' && // XA + sopClassUid !== '1.2.840.10008.5.1.4.1.1.12.2.1' + ); // XRF +} + +function convertToIntPixelData(floatPixelData) { + const floatMinMax = getMinMax(floatPixelData); + const floatRange = Math.abs(floatMinMax.max - floatMinMax.min); + const intRange = 65535; + const slope = floatRange / intRange; + const intercept = floatMinMax.min; + const numPixels = floatPixelData.length; + const intPixelData = new Uint16Array(numPixels); + + let min = 65535; + + let max = 0; + + for (let i = 0; i < numPixels; i++) { + const rescaledPixel = Math.floor((floatPixelData[i] - intercept) / slope); + + intPixelData[i] = rescaledPixel; + min = Math.min(min, rescaledPixel); + max = Math.max(max, rescaledPixel); + } + + return { + min, + max, + intPixelData, + slope, + intercept, + }; +} + +/** + * Helper function to set pixel data to the right typed array. This is needed because web workers + * can transfer array buffers but not typed arrays + * @param imageFrame + */ +function setPixelDataType(imageFrame) { + if (imageFrame.bitsAllocated === 32) { + imageFrame.pixelData = new Float32Array(imageFrame.pixelData); + } else if (imageFrame.bitsAllocated === 16) { + if (imageFrame.pixelRepresentation === 0) { + imageFrame.pixelData = new Uint16Array(imageFrame.pixelData); + } else { + imageFrame.pixelData = new Int16Array(imageFrame.pixelData); + } + } else { + imageFrame.pixelData = new Uint8Array(imageFrame.pixelData); + } +} + +/** + * Removes the A from RGBA to return RGB buffer, this is used when the + * decoding happens with browser API which results in RGBA, but if useRGBA flag + * is set to false, we want to return RGB + * + * @param imageFrame - decoded image in RGBA + * @param targetBuffer - target buffer to write to + */ +function removeAFromRGBA(imageFrame, targetBuffer) { + const numPixels = imageFrame.length / 4; + + let rgbIndex = 0; + + let bufferIndex = 0; + + for (let i = 0; i < numPixels; i++) { + targetBuffer[bufferIndex++] = imageFrame[rgbIndex++]; // red + targetBuffer[bufferIndex++] = imageFrame[rgbIndex++]; // green + targetBuffer[bufferIndex++] = imageFrame[rgbIndex++]; // blue + rgbIndex++; // skip alpha + } + + return targetBuffer; +} + +function createImage(imageId, pixelData, transferSyntax, options = {}) { + // whether to use RGBA for color images, default true as cs-legacy uses RGBA + // but we don't need RGBA in cs3d, and it's faster, and memory-efficient + // in cs3d + let useRGBA = true; + + if (options.useRGBA !== undefined) { + useRGBA = options.useRGBA; + } + + // always preScale the pixel array unless it is asked not to + options.preScale = { + enabled: + options.preScale && options.preScale.enabled !== undefined + ? options.preScale.enabled + : false, + }; + + if (!pixelData || !pixelData.length) { + return Promise.reject(new Error('The file does not contain image data.')); + } + + const { cornerstone } = external; + const canvas = document.createElement('canvas'); + const imageFrame = getImageFrame(imageId); + + // Get the scaling parameters from the metadata + if (options.preScale.enabled) { + const scalingParameters = getScalingParameters( + cornerstone.metaData, + imageId + ); + + if (scalingParameters) { + options.preScale = { + ...options.preScale, + scalingParameters, + }; + } + } + const decodePromise = decodeImageFrame( + imageFrame, + transferSyntax, + pixelData, + canvas, + options + ); + + const { decodeConfig } = getOptions(); + const { convertFloatPixelDataToInt } = decodeConfig; + + return new Promise((resolve, reject) => { + // eslint-disable-next-line complexity + decodePromise.then(function (imageFrame) { + // If we have a target buffer that was written to in the + // Decode task, point the image to it here. + // We can't have done it within the thread incase it was a SharedArrayBuffer. + let alreadyTyped = false; + + if (options.targetBuffer) { + let offset, length; + // If we have a target buffer, write to that instead. This helps reduce memory duplication. + + ({ offset, length } = options.targetBuffer); + const { arrayBuffer, type } = options.targetBuffer; + + let TypedArrayConstructor; + + if (length === null || length === undefined) { + length = imageFrame.pixelDataLength; + } + + if (offset === null || offset === undefined) { + offset = 0; + } + + switch (type) { + case 'Uint8Array': + TypedArrayConstructor = Uint8Array; + break; + case 'Uint16Array': + TypedArrayConstructor = Uint16Array; + break; + case 'Float32Array': + TypedArrayConstructor = Float32Array; + break; + default: + throw new Error( + 'target array for image does not have a valid type.' + ); + } + + if (length !== imageFrame.pixelDataLength) { + throw new Error( + 'target array for image does not have the same length as the decoded image length.' + ); + } + + // TypedArray.Set is api level and ~50x faster than copying elements even for + // Arrays of different types, which aren't simply memcpy ops. + let typedArray; + + if (arrayBuffer) { + typedArray = new TypedArrayConstructor(arrayBuffer, offset, length); + } else { + typedArray = new TypedArrayConstructor(imageFrame.pixelData); + } + + // If need to scale, need to scale correct array. + imageFrame.pixelData = typedArray; + alreadyTyped = true; + } + + if (!alreadyTyped) { + setPixelDataType(imageFrame); + } + + const imagePlaneModule = + cornerstone.metaData.get('imagePlaneModule', imageId) || {}; + const voiLutModule = + cornerstone.metaData.get('voiLutModule', imageId) || {}; + const modalityLutModule = + cornerstone.metaData.get('modalityLutModule', imageId) || {}; + const sopCommonModule = + cornerstone.metaData.get('sopCommonModule', imageId) || {}; + const isColorImage = isColorImageFn(imageFrame.photometricInterpretation); + + if (isColorImage) { + if (useRGBA) { + // JPEGBaseline (8 bits) is already returning the pixel data in the right format (rgba) + // because it's using a canvas to load and decode images. + if (!isJPEGBaseline8BitColor(imageFrame, transferSyntax)) { + canvas.height = imageFrame.rows; + canvas.width = imageFrame.columns; + + const context = canvas.getContext('2d'); + + const imageData = context.createImageData( + imageFrame.columns, + imageFrame.rows + ); + + convertColorSpace(imageFrame, imageData.data, useRGBA); + + imageFrame.imageData = imageData; + imageFrame.pixelData = imageData.data; + } + } else { + if (isJPEGBaseline8BitColor(imageFrame, transferSyntax)) { + // If we don't need the RGBA but the decoding is done with RGBA (the case + // for JPEG Baseline 8 bit color), AND the option specifies to use RGB (no RGBA) + // we need to remove the A channel from pixel data + const colorBuffer = new Uint8ClampedArray( + (imageFrame.pixelData.length / 4) * 3 + ); + + // remove the A from the RGBA of the imageFrame + imageFrame.pixelData = removeAFromRGBA( + imageFrame.pixelData, + colorBuffer + ); + } else if (imageFrame.photometricInterpretation === 'PALETTE COLOR') { + canvas.height = imageFrame.rows; + canvas.width = imageFrame.columns; + + const context = canvas.getContext('2d'); + + const imageData = context.createImageData( + imageFrame.columns, + imageFrame.rows + ); + + convertColorSpace(imageFrame, imageData.data, true); + + const colorBuffer = new imageData.data.constructor( + (imageData.data.length / 4) * 3 + ); + + // remove the A from the RGBA of the imageFrame + imageFrame.pixelData = removeAFromRGBA(imageData.data, colorBuffer); + } + } + + // calculate smallest and largest PixelValue of the converted pixelData + const minMax = getMinMax(imageFrame.pixelData); + + imageFrame.smallestPixelValue = minMax.min; + imageFrame.largestPixelValue = minMax.max; + } + + const image = { + imageId, + color: isColorImage, + columnPixelSpacing: imagePlaneModule.columnPixelSpacing, + columns: imageFrame.columns, + height: imageFrame.rows, + preScale: imageFrame.preScale, + intercept: modalityLutModule.rescaleIntercept + ? modalityLutModule.rescaleIntercept + : 0, + slope: modalityLutModule.rescaleSlope + ? modalityLutModule.rescaleSlope + : 1, + invert: imageFrame.photometricInterpretation === 'MONOCHROME1', + minPixelValue: imageFrame.smallestPixelValue, + maxPixelValue: imageFrame.largestPixelValue, + rowPixelSpacing: imagePlaneModule.rowPixelSpacing, + rows: imageFrame.rows, + sizeInBytes: imageFrame.pixelData.byteLength, + width: imageFrame.columns, + windowCenter: voiLutModule.windowCenter + ? voiLutModule.windowCenter[0] + : undefined, + windowWidth: voiLutModule.windowWidth + ? voiLutModule.windowWidth[0] + : undefined, + decodeTimeInMS: imageFrame.decodeTimeInMS, + floatPixelData: undefined, + imageFrame, + rgba: isColorImage && useRGBA, + }; + + // If pixel data is intrinsically floating 32 array, we convert it to int for + // display in cornerstone. For other cases when pixel data is typed as + // Float32Array for scaling; this conversion is not needed. + if ( + imageFrame.pixelData instanceof Float32Array && + convertFloatPixelDataToInt + ) { + const floatPixelData = imageFrame.pixelData; + const results = convertToIntPixelData(floatPixelData); + + image.minPixelValue = results.min; + image.maxPixelValue = results.max; + image.slope = results.slope; + image.intercept = results.intercept; + image.floatPixelData = floatPixelData; + image.getPixelData = () => results.intPixelData; + } else { + image.getPixelData = () => imageFrame.pixelData; + } + + if (image.color) { + image.getCanvas = function () { + if (lastImageIdDrawn === imageId) { + return canvas; + } + + canvas.height = image.rows; + canvas.width = image.columns; + const context = canvas.getContext('2d'); + + context.putImageData(imageFrame.imageData, 0, 0); + lastImageIdDrawn = imageId; + + return canvas; + }; + } + + // Modality LUT + if ( + modalityLutModule.modalityLUTSequence && + modalityLutModule.modalityLUTSequence.length > 0 && + isModalityLUTForDisplay(sopCommonModule.sopClassUID) + ) { + image.modalityLUT = modalityLutModule.modalityLUTSequence[0]; + } + + // VOI LUT + if ( + voiLutModule.voiLUTSequence && + voiLutModule.voiLUTSequence.length > 0 + ) { + image.voiLUT = voiLutModule.voiLUTSequence[0]; + } + + if (image.color) { + image.windowWidth = 255; + image.windowCenter = 127; + } + + // set the ww/wc to cover the dynamic range of the image if no values are supplied + if (image.windowCenter === undefined || image.windowWidth === undefined) { + const maxVoi = image.maxPixelValue * image.slope + image.intercept; + const minVoi = image.minPixelValue * image.slope + image.intercept; + + image.windowWidth = maxVoi - minVoi; + image.windowCenter = (maxVoi + minVoi) / 2; + } + resolve(image); + }, reject); + }); +} + +export default createImage; diff --git a/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.js b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.js new file mode 100644 index 000000000..d07a5d323 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.js @@ -0,0 +1,112 @@ +import { getOptions } from './internal/options.js'; +import decodeJPEGBaseline8BitColor from './decodeJPEGBaseline8BitColor.js'; + +import { default as decodeImageFrameHandler } from '../shared/decodeImageFrame.js'; +import calculateMinMax from '../shared/calculateMinMax.js'; + +function processDecodeTask(imageFrame, transferSyntax, pixelData, options) { + const loaderOptions = getOptions(); + const { strict, decodeConfig } = loaderOptions; + + return new Promise((resolve, reject) => { + try { + const callbackFn = (decodedImageFrame) => { + calculateMinMax(decodedImageFrame, strict); + resolve(decodedImageFrame); + }; + + const decodeArguments = [ + imageFrame, + transferSyntax, + pixelData, + decodeConfig, + options, + callbackFn, + ]; + + decodeImageFrameHandler(...decodeArguments); + } catch (error) { + console.error(error); + reject(error); + } + }); +} + +function decodeImageFrame( + imageFrame, + transferSyntax, + pixelData, + canvas, + options = {} +) { + switch (transferSyntax) { + case '1.2.840.10008.1.2': + // Implicit VR Little Endian + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.1': + // Explicit VR Little Endian + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.2': + // Explicit VR Big Endian (retired) + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.1.99': + // Deflate transfer syntax (deflated by dicomParser) + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.5': + // RLE Lossless + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.4.50': + // JPEG Baseline lossy process 1 (8 bit) + + // Handle 8-bit JPEG Baseline color images using the browser's built-in + // JPEG decoding + if ( + imageFrame.bitsAllocated === 8 && + (imageFrame.samplesPerPixel === 3 || imageFrame.samplesPerPixel === 4) + ) { + return decodeJPEGBaseline8BitColor(imageFrame, pixelData, canvas); + } + + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.4.51': + // JPEG Baseline lossy process 2 & 4 (12 bit) + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.4.57': + // JPEG Lossless, Nonhierarchical (Processes 14) + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.4.70': + // JPEG Lossless, Nonhierarchical (Processes 14 [Selection 1]) + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.4.80': + // JPEG-LS Lossless Image Compression + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.4.81': + // JPEG-LS Lossy (Near-Lossless) Image Compression + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.4.90': + // JPEG 2000 Lossless + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.4.91': + // JPEG 2000 Lossy + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + } + + /* Don't know if these work... + // JPEG 2000 Part 2 Multicomponent Image Compression (Lossless Only) + else if(transferSyntax === "1.2.840.10008.1.2.4.92") + { + return cornerstoneWADOImageLoader.decodeJPEG2000(dataSet, frame); + } + // JPEG 2000 Part 2 Multicomponent Image Compression + else if(transferSyntax === "1.2.840.10008.1.2.4.93") + { + return cornerstoneWADOImageLoader.decodeJPEG2000(dataSet, frame); + } + */ + + return Promise.reject( + new Error(`No decoder for transfer syntax ${transferSyntax}`) + ); +} + +export default decodeImageFrame; diff --git a/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.js b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.js new file mode 100644 index 000000000..191ac18a4 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.js @@ -0,0 +1,107 @@ +import webWorkerManager from './webWorkerManager.js'; +import decodeJPEGBaseline8BitColor from './decodeJPEGBaseline8BitColor.js'; + +// dicomParser requires pako for browser-side decoding of deflate transfer syntax +// We only need one function though, so lets import that so we don't make our bundle +// too large. +import { inflateRaw } from 'pako/lib/inflate.js'; + +window.pako = { inflateRaw }; + +function processDecodeTask(imageFrame, transferSyntax, pixelData, options) { + const priority = options.priority || undefined; + const transferList = options.transferPixelData + ? [pixelData.buffer] + : undefined; + + return webWorkerManager.addTask( + 'decodeTask', + { + imageFrame, + transferSyntax, + pixelData, + options, + }, + priority, + transferList + ).promise; +} + +function decodeImageFrame( + imageFrame, + transferSyntax, + pixelData, + canvas, + options = {} +) { + switch (transferSyntax) { + case '1.2.840.10008.1.2': + // Implicit VR Little Endian + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.1': + // Explicit VR Little Endian + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.2': + // Explicit VR Big Endian (retired) + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.1.99': + // Deflate transfer syntax (deflated by dicomParser) + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.5': + // RLE Lossless + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.4.50': + // JPEG Baseline lossy process 1 (8 bit) + + // Handle 8-bit JPEG Baseline color images using the browser's built-in + // JPEG decoding + if ( + imageFrame.bitsAllocated === 8 && + (imageFrame.samplesPerPixel === 3 || imageFrame.samplesPerPixel === 4) + ) { + return decodeJPEGBaseline8BitColor(imageFrame, pixelData, canvas); + } + + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.4.51': + // JPEG Baseline lossy process 2 & 4 (12 bit) + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.4.57': + // JPEG Lossless, Nonhierarchical (Processes 14) + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.4.70': + // JPEG Lossless, Nonhierarchical (Processes 14 [Selection 1]) + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.4.80': + // JPEG-LS Lossless Image Compression + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.4.81': + // JPEG-LS Lossy (Near-Lossless) Image Compression + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.4.90': + // JPEG 2000 Lossless + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + case '1.2.840.10008.1.2.4.91': + // JPEG 2000 Lossy + return processDecodeTask(imageFrame, transferSyntax, pixelData, options); + } + + /* Don't know if these work... + // JPEG 2000 Part 2 Multicomponent Image Compression (Lossless Only) + else if(transferSyntax === "1.2.840.10008.1.2.4.92") + { + return cornerstoneWADOImageLoader.decodeJPEG2000(dataSet, frame); + } + // JPEG 2000 Part 2 Multicomponent Image Compression + else if(transferSyntax === "1.2.840.10008.1.2.4.93") + { + return cornerstoneWADOImageLoader.decodeJPEG2000(dataSet, frame); + } + */ + + return Promise.reject( + new Error(`No decoder for transfer syntax ${transferSyntax}`) + ); +} + +export default decodeImageFrame; diff --git a/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.js b/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.js new file mode 100644 index 000000000..c08093593 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.js @@ -0,0 +1,89 @@ +import getMinMax from '../shared/getMinMax.js'; + +/** + * Special decoder for 8 bit jpeg that leverages the browser's built in JPEG decoder for increased performance + */ + +function arrayBufferToString(buffer) { + return binaryToString( + String.fromCharCode.apply( + null, + Array.prototype.slice.apply(new Uint8Array(buffer)) + ) + ); +} + +function binaryToString(binary) { + let error; + + try { + return decodeURIComponent(escape(binary)); + } catch (_error) { + error = _error; + if (error instanceof URIError) { + return binary; + } + throw error; + } +} + +function decodeJPEGBaseline8BitColor(imageFrame, pixelData, canvas) { + const start = new Date().getTime(); + const imgBlob = new Blob([pixelData], { type: 'image/jpeg' }); + + return new Promise((resolve, reject) => { + const fileReader = new FileReader(); + + if (fileReader.readAsBinaryString === undefined) { + fileReader.readAsArrayBuffer(imgBlob); + } else { + fileReader.readAsBinaryString(imgBlob); // doesn't work on IE11 + } + + fileReader.onload = function () { + const img = new Image(); + + img.onload = function () { + canvas.height = img.height; + canvas.width = img.width; + imageFrame.rows = img.height; + imageFrame.columns = img.width; + const context = canvas.getContext('2d'); + + context.drawImage(this, 0, 0); + const imageData = context.getImageData(0, 0, img.width, img.height); + const end = new Date().getTime(); + + imageFrame.pixelData = imageData.data; + imageFrame.imageData = imageData; + imageFrame.decodeTimeInMS = end - start; + + // calculate smallest and largest PixelValue + const minMax = getMinMax(imageFrame.pixelData); + + imageFrame.smallestPixelValue = minMax.min; + imageFrame.largestPixelValue = minMax.max; + + resolve(imageFrame); + }; + + img.onerror = function (error) { + reject(error); + }; + + if (fileReader.readAsBinaryString === undefined) { + img.src = `data:image/jpeg;base64,${window.btoa( + arrayBufferToString(fileReader.result) + )}`; + } else { + img.src = `data:image/jpeg;base64,${window.btoa(fileReader.result)}`; // doesn't work on IE11 + } + }; + + fileReader.onerror = (e) => { + reject(e); + }; + }); +} + +export default decodeJPEGBaseline8BitColor; diff --git a/packages/dicom-image-loader/src/imageLoader/getImageFrame.js b/packages/dicom-image-loader/src/imageLoader/getImageFrame.js new file mode 100644 index 000000000..613ff8502 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/getImageFrame.js @@ -0,0 +1,37 @@ +import external from '../externalModules.js'; + +function getImageFrame(imageId) { + const { cornerstone } = external; + const imagePixelModule = cornerstone.metaData.get( + 'imagePixelModule', + imageId + ); + + return { + samplesPerPixel: imagePixelModule.samplesPerPixel, + photometricInterpretation: imagePixelModule.photometricInterpretation, + planarConfiguration: imagePixelModule.planarConfiguration, + rows: imagePixelModule.rows, + columns: imagePixelModule.columns, + bitsAllocated: imagePixelModule.bitsAllocated, + bitsStored: imagePixelModule.bitsStored, + pixelRepresentation: imagePixelModule.pixelRepresentation, // 0 = unsigned, + smallestPixelValue: imagePixelModule.smallestPixelValue, + largestPixelValue: imagePixelModule.largestPixelValue, + redPaletteColorLookupTableDescriptor: + imagePixelModule.redPaletteColorLookupTableDescriptor, + greenPaletteColorLookupTableDescriptor: + imagePixelModule.greenPaletteColorLookupTableDescriptor, + bluePaletteColorLookupTableDescriptor: + imagePixelModule.bluePaletteColorLookupTableDescriptor, + redPaletteColorLookupTableData: + imagePixelModule.redPaletteColorLookupTableData, + greenPaletteColorLookupTableData: + imagePixelModule.greenPaletteColorLookupTableData, + bluePaletteColorLookupTableData: + imagePixelModule.bluePaletteColorLookupTableData, + pixelData: undefined, // populated later after decoding + }; +} + +export default getImageFrame; diff --git a/packages/dicom-image-loader/src/imageLoader/getMinMax.js b/packages/dicom-image-loader/src/imageLoader/getMinMax.js new file mode 100644 index 000000000..c59e817e4 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/getMinMax.js @@ -0,0 +1,22 @@ +export default function getMinMax(storedPixelData) { + // we always calculate the min max values since they are not always + // present in DICOM and we don't want to trust them anyway as cornerstone + // depends on us providing reliable values for these + let min = storedPixelData[0]; + + let max = storedPixelData[0]; + + let storedPixel; + const numPixels = storedPixelData.length; + + for (let index = 0; index < numPixels; index++) { + storedPixel = storedPixelData[index]; + min = Math.min(min, storedPixel); + max = Math.max(max, storedPixel); + } + + return { + min, + max, + }; +} diff --git a/packages/dicom-image-loader/src/imageLoader/getScalingParameters.js b/packages/dicom-image-loader/src/imageLoader/getScalingParameters.js new file mode 100644 index 000000000..38cadf19e --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/getScalingParameters.js @@ -0,0 +1,29 @@ +/** + * It returns the scaling parameters for the image with the given imageId. This can be + * used to get passed (as an option) to the imageLoader in order to apply scaling to the image inside + * the imageLoader. + * @param imageId - The imageId of the image + * @returns ScalingParameters + */ +export default function getScalingParameters(metaData, imageId) { + const modalityLutModule = metaData.get('modalityLutModule', imageId) || {}; + + const generalSeriesModule = + metaData.get('generalSeriesModule', imageId) || {}; + + const { modality } = generalSeriesModule; + + const scalingParameters = { + rescaleSlope: modalityLutModule.rescaleSlope, + rescaleIntercept: modalityLutModule.rescaleIntercept, + modality, + }; + + debugger; + const suvFactor = metaData.get('scalingModule', imageId) || {}; + + return { + ...scalingParameters, + ...(modality === 'PT' && { suvbw: suvFactor.suvbw }), + }; +} diff --git a/packages/dicom-image-loader/src/imageLoader/imageIdToURI.js b/packages/dicom-image-loader/src/imageLoader/imageIdToURI.js new file mode 100644 index 000000000..7be55b075 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/imageIdToURI.js @@ -0,0 +1,12 @@ +/** + * Removes the data loader scheme from the imageId + * + * @param {string} imageId Image ID + * @returns {string} imageId without the data loader scheme + * @memberof Cache + */ +export default function imageIdToURI(imageId) { + const colonIndex = imageId.indexOf(':'); + + return imageId.substring(colonIndex + 1); +} diff --git a/packages/dicom-image-loader/src/imageLoader/index-noWorkers.js b/packages/dicom-image-loader/src/imageLoader/index-noWorkers.js new file mode 100644 index 000000000..2a41c6e5e --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/index-noWorkers.js @@ -0,0 +1,73 @@ +import { + convertRGBColorByPixel, + convertRGBColorByPlane, + convertYBRFullByPixel, + convertYBRFullByPlane, + convertPALETTECOLOR, +} from './colorSpaceConverters/index.js'; + +import { default as wadouri } from './wadouri/index.js'; +import { default as wadors } from './wadors/index.js'; +import { default as configure } from './configure.js'; +import { default as convertColorSpace } from './convertColorSpace.js'; +import { default as createImage } from './createImage.js'; +import { default as decodeImageFrame } from './decodeImageFrame-noWorkers.js'; +import { default as decodeJPEGBaseline8BitColor } from './decodeJPEGBaseline8BitColor.js'; +import { default as getImageFrame } from './getImageFrame.js'; +import { default as getMinMax } from '../shared/getMinMax.js'; +import { default as isColorImage } from './isColorImage.js'; +import { default as isJPEGBaseline8BitColor } from './isJPEGBaseline8BitColor.js'; +import { default as webWorkerManager } from './webWorkerManager.js'; +import { default as getPixelData } from './wadors/getPixelData.js'; +import { internal } from './internal/index.js'; +import { default as external } from '../externalModules.js'; + +const cornerstoneWADOImageLoader = { + convertRGBColorByPixel, + convertRGBColorByPlane, + convertYBRFullByPixel, + convertYBRFullByPlane, + convertPALETTECOLOR, + wadouri, + wadors, + configure, + convertColorSpace, + createImage, + decodeImageFrame, + decodeJPEGBaseline8BitColor, + getImageFrame, + getPixelData, + getMinMax, + isColorImage, + isJPEGBaseline8BitColor, + webWorkerManager, + version, + internal, + external, +}; + +export { + convertRGBColorByPixel, + convertRGBColorByPlane, + convertYBRFullByPixel, + convertYBRFullByPlane, + convertPALETTECOLOR, + wadouri, + wadors, + configure, + convertColorSpace, + createImage, + decodeImageFrame, + decodeJPEGBaseline8BitColor, + getImageFrame, + getPixelData, + getMinMax, + isColorImage, + isJPEGBaseline8BitColor, + webWorkerManager, + version, + internal, + external, +}; + +export default cornerstoneWADOImageLoader; diff --git a/packages/dicom-image-loader/src/imageLoader/index.js b/packages/dicom-image-loader/src/imageLoader/index.js new file mode 100644 index 000000000..9e360c5a9 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/index.js @@ -0,0 +1,71 @@ +import { + convertRGBColorByPixel, + convertRGBColorByPlane, + convertYBRFullByPixel, + convertYBRFullByPlane, + convertPALETTECOLOR, +} from './colorSpaceConverters/index.js'; + +import { default as wadouri } from './wadouri/index.js'; +import { default as wadors } from './wadors/index.js'; +import { default as configure } from './configure.js'; +import { default as convertColorSpace } from './convertColorSpace.js'; +import { default as createImage } from './createImage.js'; +import { default as decodeImageFrame } from './decodeImageFrame.js'; +import { default as decodeJPEGBaseline8BitColor } from './decodeJPEGBaseline8BitColor.js'; +import { default as getImageFrame } from './getImageFrame.js'; +import { default as getMinMax } from '../shared/getMinMax.js'; +import { default as isColorImage } from './isColorImage.js'; +import { default as isJPEGBaseline8BitColor } from './isJPEGBaseline8BitColor.js'; +import { default as webWorkerManager } from './webWorkerManager.js'; +import { default as getPixelData } from './wadors/getPixelData.js'; +import { internal } from './internal/index.js'; +import { default as external } from '../externalModules.js'; + +const cornerstoneWADOImageLoader = { + convertRGBColorByPixel, + convertRGBColorByPlane, + convertYBRFullByPixel, + convertYBRFullByPlane, + convertPALETTECOLOR, + wadouri, + wadors, + configure, + convertColorSpace, + createImage, + decodeImageFrame, + decodeJPEGBaseline8BitColor, + getImageFrame, + getPixelData, + getMinMax, + isColorImage, + isJPEGBaseline8BitColor, + webWorkerManager, + internal, + external, +}; + +export { + convertRGBColorByPixel, + convertRGBColorByPlane, + convertYBRFullByPixel, + convertYBRFullByPlane, + convertPALETTECOLOR, + wadouri, + wadors, + configure, + convertColorSpace, + createImage, + decodeImageFrame, + decodeJPEGBaseline8BitColor, + getImageFrame, + getPixelData, + getMinMax, + isColorImage, + isJPEGBaseline8BitColor, + webWorkerManager, + internal, + external, +}; + +export default cornerstoneWADOImageLoader; diff --git a/packages/dicom-image-loader/src/imageLoader/internal/index.js b/packages/dicom-image-loader/src/imageLoader/internal/index.js new file mode 100644 index 000000000..7ebe5022d --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/internal/index.js @@ -0,0 +1,10 @@ +import { default as xhrRequest } from './xhrRequest.js'; +import { setOptions, getOptions } from './options.js'; + +const internal = { + xhrRequest, + setOptions, + getOptions, +}; + +export { setOptions, getOptions, xhrRequest, internal }; diff --git a/packages/dicom-image-loader/src/imageLoader/internal/options.js b/packages/dicom-image-loader/src/imageLoader/internal/options.js new file mode 100644 index 000000000..90cfe4fed --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/internal/options.js @@ -0,0 +1,22 @@ +let options = { + // callback allowing customization of the xhr (e.g. adding custom auth headers, cors, etc) + beforeSend(/* xhr, imageId */) {}, + // callback allowing modification of the xhr response before creating image objects + beforeProcessing(xhr) { + return Promise.resolve(xhr.response); + }, + // callback allowing modification of newly created image objects + imageCreated(/* image */) {}, + strict: false, + decodeConfig: { + convertFloatPixelDataToInt: true, + }, +}; + +export function setOptions(newOptions) { + options = Object.assign(options, newOptions); +} + +export function getOptions() { + return options; +} diff --git a/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.js b/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.js new file mode 100644 index 000000000..0eb50da9e --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.js @@ -0,0 +1,169 @@ +import external from '../../externalModules.js'; +import { getOptions } from './options.js'; + +function xhrRequest(url, imageId, defaultHeaders = {}, params = {}) { + const { cornerstone } = external; + const options = getOptions(); + + const errorInterceptor = (xhr) => { + if (typeof options.errorInterceptor === 'function') { + const error = new Error('request failed'); + + error.request = xhr; + error.response = xhr.response; + error.status = xhr.status; + options.errorInterceptor(error); + } + }; + + // Make the request for the DICOM P10 SOP Instance + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + + xhr.open('get', url, true); + const beforeSendHeaders = options.beforeSend( + xhr, + imageId, + defaultHeaders, + params + ); + + xhr.responseType = 'arraybuffer'; + + const headers = Object.assign({}, defaultHeaders, beforeSendHeaders); + + Object.keys(headers).forEach(function (key) { + if (headers[key] === null) { + return; + } + if (key === 'Accept' && url.indexOf('accept=') !== -1) { + return; + } + xhr.setRequestHeader(key, headers[key]); + }); + + params.deferred = { + resolve, + reject, + }; + params.url = url; + params.imageId = imageId; + + // Event triggered when downloading an image starts + xhr.onloadstart = function (event) { + // Action + if (options.onloadstart) { + options.onloadstart(event, params); + } + + // Event + const eventData = { + url, + imageId, + }; + + cornerstone.triggerEvent( + cornerstone.events, + 'cornerstoneimageloadstart', + eventData + ); + }; + + // Event triggered when downloading an image ends + xhr.onloadend = function (event) { + // Action + if (options.onloadend) { + options.onloadend(event, params); + } + + const eventData = { + url, + imageId, + }; + + // Event + cornerstone.triggerEvent( + cornerstone.events, + 'cornerstoneimageloadend', + eventData + ); + }; + + // handle response data + xhr.onreadystatechange = function (event) { + // Action + if (options.onreadystatechange) { + options.onreadystatechange(event, params); + + return; + } + + // Default action + // TODO: consider sending out progress messages here as we receive + // the pixel data + if (xhr.readyState === 4) { + if (xhr.status === 200) { + options + .beforeProcessing(xhr) + .then(resolve) + .catch(() => { + errorInterceptor(xhr); + // request failed, reject the Promise + reject(xhr); + }); + } else { + errorInterceptor(xhr); + // request failed, reject the Promise + reject(xhr); + } + } + }; + + // Event triggered when downloading an image progresses + xhr.onprogress = function (oProgress) { + // console.log('progress:',oProgress) + const loaded = oProgress.loaded; // evt.loaded the bytes browser receive + + let total; + + let percentComplete; + + if (oProgress.lengthComputable) { + total = oProgress.total; // evt.total the total bytes seted by the header + percentComplete = Math.round((loaded / total) * 100); + } + + // Action + if (options.onprogress) { + options.onprogress(oProgress, params); + } + + // Event + const eventData = { + url, + imageId, + loaded, + total, + percentComplete, + }; + + cornerstone.triggerEvent( + cornerstone.events, + cornerstone.EVENTS.IMAGE_LOAD_PROGRESS, + eventData + ); + }; + xhr.onerror = function () { + errorInterceptor(xhr); + reject(xhr); + }; + + xhr.onabort = function () { + errorInterceptor(xhr); + reject(xhr); + }; + xhr.send(); + }); +} + +export default xhrRequest; diff --git a/packages/dicom-image-loader/src/imageLoader/isColorImage.js b/packages/dicom-image-loader/src/imageLoader/isColorImage.js new file mode 100644 index 000000000..bc75fffaa --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/isColorImage.js @@ -0,0 +1,12 @@ +export default function (photoMetricInterpretation) { + return ( + photoMetricInterpretation === 'RGB' || + photoMetricInterpretation === 'PALETTE COLOR' || + photoMetricInterpretation === 'YBR_FULL' || + photoMetricInterpretation === 'YBR_FULL_422' || + photoMetricInterpretation === 'YBR_PARTIAL_422' || + photoMetricInterpretation === 'YBR_PARTIAL_420' || + photoMetricInterpretation === 'YBR_RCT' || + photoMetricInterpretation === 'YBR_ICT' + ); +} diff --git a/packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.js b/packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.js new file mode 100644 index 000000000..1b2bf5f16 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.js @@ -0,0 +1,13 @@ +function isJPEGBaseline8BitColor(imageFrame, transferSyntax) { + transferSyntax = transferSyntax || imageFrame.transferSyntax; + + if ( + imageFrame.bitsAllocated === 8 && + transferSyntax === '1.2.840.10008.1.2.4.50' && + (imageFrame.samplesPerPixel === 3 || imageFrame.samplesPerPixel === 4) + ) { + return true; + } +} + +export default isJPEGBaseline8BitColor; diff --git a/packages/dicom-image-loader/src/imageLoader/registerLoaders.js b/packages/dicom-image-loader/src/imageLoader/registerLoaders.js new file mode 100644 index 000000000..fda14faf3 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/registerLoaders.js @@ -0,0 +1,15 @@ +import wadors from './wadors/index.js'; +import wadouri from './wadouri/index.js'; + +/** + * Register the WADO-URI and WADO-RS image loaders and metaData providers + * with an instance of Cornerstone Core. + * + * @param cornerstone The Cornerstone Core library to register the image loaders with + */ +function registerLoaders(cornerstone) { + wadors.register(cornerstone); + wadouri.register(cornerstone); +} + +export default registerLoaders; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.js b/packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.js new file mode 100644 index 000000000..f703ecb66 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.js @@ -0,0 +1,43 @@ +function checkToken(token, data, dataOffset) { + if (dataOffset + token.length > data.length) { + return false; + } + + let endIndex = dataOffset; + + for (let i = 0; i < token.length; i++) { + if (token[i] !== data[endIndex++]) { + return false; + } + } + + return true; +} + +function stringToUint8Array(str) { + const uint = new Uint8Array(str.length); + + for (let i = 0, j = str.length; i < j; i++) { + uint[i] = str.charCodeAt(i); + } + + return uint; +} + +function findIndexOfString(data, str, offset) { + offset = offset || 0; + + const token = stringToUint8Array(str); + + for (let i = offset; i < data.length; i++) { + if (token[0] === data[i]) { + // console.log('match @', i); + if (checkToken(token, data, i)) { + return i; + } + } + } + + return -1; +} +export default findIndexOfString; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.js b/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.js new file mode 100644 index 000000000..afade1936 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.js @@ -0,0 +1,81 @@ +import { xhrRequest } from '../internal/index.js'; +import findIndexOfString from './findIndexOfString.js'; + +function findBoundary(header) { + for (let i = 0; i < header.length; i++) { + if (header[i].substr(0, 2) === '--') { + return header[i]; + } + } +} + +function findContentType(header) { + for (let i = 0; i < header.length; i++) { + if (header[i].substr(0, 13) === 'Content-Type:') { + return header[i].substr(13).trim(); + } + } +} + +function uint8ArrayToString(data, offset, length) { + offset = offset || 0; + length = length || data.length - offset; + let str = ''; + + for (let i = offset; i < offset + length; i++) { + str += String.fromCharCode(data[i]); + } + + return str; +} + +function getPixelData(uri, imageId, mediaType = 'application/octet-stream') { + const headers = { + Accept: mediaType, + }; + + return new Promise((resolve, reject) => { + const loadPromise = xhrRequest(uri, imageId, headers); + + loadPromise.then(function (imageFrameAsArrayBuffer /* , xhr*/) { + // request succeeded, Parse the multi-part mime response + const response = new Uint8Array(imageFrameAsArrayBuffer); + + // First look for the multipart mime header + const tokenIndex = findIndexOfString(response, '\r\n\r\n'); + + if (tokenIndex === -1) { + reject(new Error('invalid response - no multipart mime header')); + } + const header = uint8ArrayToString(response, 0, tokenIndex); + // Now find the boundary marker + const split = header.split('\r\n'); + const boundary = findBoundary(split); + + if (!boundary) { + reject(new Error('invalid response - no boundary marker')); + } + const offset = tokenIndex + 4; // skip over the \r\n\r\n + + // find the terminal boundary marker + const endIndex = findIndexOfString(response, boundary, offset); + + if (endIndex === -1) { + reject(new Error('invalid response - terminating boundary not found')); + } + + // Remove \r\n from the length + const length = endIndex - offset - 2; + + // return the info for this pixel data + resolve({ + contentType: findContentType(split), + imageFrame: { + pixelData: new Uint8Array(imageFrameAsArrayBuffer, offset, length), + }, + }); + }, reject); + }); +} + +export default getPixelData; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/index.js b/packages/dicom-image-loader/src/imageLoader/wadors/index.js new file mode 100644 index 000000000..07ec46c99 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/index.js @@ -0,0 +1,30 @@ +import { + getNumberString, + getNumberValue, + getNumberValues, + getValue, + metaDataProvider, +} from './metaData/index.js'; + +import findIndexOfString from './findIndexOfString.js'; +import getPixelData from './getPixelData.js'; +import metaDataManager from './metaDataManager.js'; +import loadImage from './loadImage.js'; +import register from './register.js'; + +const metaData = { + getNumberString, + getNumberValue, + getNumberValues, + getValue, + metaDataProvider, +}; + +export default { + metaData, + findIndexOfString, + getPixelData, + loadImage, + metaDataManager, + register, +}; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.js b/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.js new file mode 100644 index 000000000..9fd63a540 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.js @@ -0,0 +1,132 @@ +import external from '../../externalModules.js'; +import getPixelData from './getPixelData.js'; +import createImage from '../createImage.js'; + +/** + * Helper method to extract the transfer-syntax from the response of the server. + * @param {string} contentType The value of the content-type header as returned by the WADO-RS server. + * @return The transfer-syntax as announced by the server, or Implicit Little Endian by default. + */ +export function getTransferSyntaxForContentType(contentType) { + const defaultTransferSyntax = '1.2.840.10008.1.2'; // Default is Implicit Little Endian. + + if (!contentType) { + return defaultTransferSyntax; + } + + // Browse through the content type parameters + const parameters = contentType.split(';'); + const params = {}; + + parameters.forEach((parameter) => { + // Look for a transfer-syntax=XXXX pair + const parameterValues = parameter.split('='); + + if (parameterValues.length !== 2) { + return; + } + + const value = parameterValues[1].trim().replace(/"/g, ''); + + params[parameterValues[0].trim()] = value; + }); + + // This is useful if the PACS doesn't respond with a syntax + // in the content type. + // http://dicom.nema.org/medical/dicom/current/output/chtml/part18/chapter_6.html#table_6.1.1.8-3b + const defaultTransferSyntaxByType = { + 'image/jpeg': '1.2.840.10008.1.2.4.50', + 'image/x-dicom-rle': '1.2.840.10008.1.2.5', + 'image/x-jls': '1.2.840.10008.1.2.4.80', + 'image/jls': '1.2.840.10008.1.2.4.80', + 'image/jll': '1.2.840.10008.1.2.4.70', + 'image/jp2': '1.2.840.10008.1.2.4.90', + 'image/jpx': '1.2.840.10008.1.2.4.92', + }; + + if (params['transfer-syntax']) { + return params['transfer-syntax']; + } else if ( + contentType && + !Object.keys(params).length && + defaultTransferSyntaxByType[contentType] + ) { + // dcm4che seems to be reporting the content type as just 'image/jp2'? + return defaultTransferSyntaxByType[contentType]; + } else if (params.type && defaultTransferSyntaxByType[params.type]) { + return defaultTransferSyntaxByType[params.type]; + } + + return defaultTransferSyntax; +} + +function getImageRetrievalPool() { + return external.cornerstone.imageRetrievalPoolManager; +} + +function loadImage(imageId, options = {}) { + const imageRetrievalPool = getImageRetrievalPool(); + + const start = new Date().getTime(); + + const promise = new Promise((resolve, reject) => { + // TODO: load bulk data items that we might need + + // Uncomment this on to test jpegls codec in OHIF + // const mediaType = 'multipart/related; type="image/x-jls"'; + // const mediaType = 'multipart/related; type="application/octet-stream"; transfer-syntax="image/x-jls"'; + const mediaType = + 'multipart/related; type=application/octet-stream; transfer-syntax=*'; + // const mediaType = + // 'multipart/related; type="image/jpeg"; transfer-syntax=1.2.840.10008.1.2.4.50'; + + function sendXHR(imageURI, imageId, mediaType) { + // get the pixel data from the server + return getPixelData(imageURI, imageId, mediaType) + .then((result) => { + const transferSyntax = getTransferSyntaxForContentType( + result.contentType + ); + const pixelData = result.imageFrame.pixelData; + const imagePromise = createImage( + imageId, + pixelData, + transferSyntax, + options + ); + + imagePromise.then((image) => { + // add the loadTimeInMS property + const end = new Date().getTime(); + + image.loadTimeInMS = end - start; + resolve(image); + }, reject); + }, reject) + .catch((error) => { + reject(error); + }); + } + + const requestType = options.requestType || 'interaction'; + const additionalDetails = options.additionalDetails || { imageId }; + const priority = options.priority === undefined ? 5 : options.priority; + const addToBeginning = options.addToBeginning || false; + const uri = imageId.substring(7); + + imageRetrievalPool.addRequest( + sendXHR.bind(this, uri, imageId, mediaType), + requestType, + additionalDetails, + priority, + addToBeginning + ); + }); + + return { + promise, + cancelFn: undefined, + }; +} + +export default loadImage; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/loadImage_test.js b/packages/dicom-image-loader/src/imageLoader/wadors/loadImage_test.js new file mode 100644 index 000000000..f2648c379 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/loadImage_test.js @@ -0,0 +1,49 @@ +import { expect } from 'chai'; +import { getTransferSyntaxForContentType } from './loadImage.js'; + +const cases = [ + // Test default case for missing or unspecified TS + [undefined, '1.2.840.10008.1.2'], + [null, '1.2.840.10008.1.2'], + ['', '1.2.840.10008.1.2'], + ['multipart/related; type="application/octet-stream"', '1.2.840.10008.1.2'], + [ + 'multipart/related; type="application/octet-stream"; transfer-syntax= ', + '1.2.840.10008.1.2', + ], + // Test TS extraction + [ + 'multipart/related; type=image/dicom+jpeg; transfer-syntax=1.2.840.10008.1.2.4.70', + '1.2.840.10008.1.2.4.70', + ], + [ + 'multipart/related; image/dicom+jpx; transfer-syntax=1.2.840.10008.1.2.4.93', + '1.2.840.10008.1.2.4.93', + ], + [ + 'multipart/related; video/mpeg; transfer-syntax=1.2.840.10008.1.2.4.100', + '1.2.840.10008.1.2.4.100', + ], + // Test case where transfer-syntax is not explicitly provided + ['multipart/related; type="image/jpeg"', '1.2.840.10008.1.2.4.50'], + ['multipart/related; type="image/x-jls"', '1.2.840.10008.1.2.4.80'], + ['multipart/related; type="image/x-dicom-rle"', '1.2.840.10008.1.2.5'], + ['multipart/related; type="image/jp2"', '1.2.840.10008.1.2.4.90'], + ['multipart/related; type="image/jpx"', '1.2.840.10008.1.2.4.92'], +]; + +describe('#getTransferSyntaxForContentType', function () { + cases.forEach(function (testCase) { + const contentType = testCase[0]; + const expectedTransferSyntax = testCase[1]; + + it(`given a content type of ${contentType}, should return ${expectedTransferSyntax}`, () => { + const transferSyntax = getTransferSyntaxForContentType(contentType); + + console.log(transferSyntax); + console.log(expectedTransferSyntax); + + expect(transferSyntax).to.be.equal(expectedTransferSyntax); + }); + }); +}); diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.js new file mode 100644 index 000000000..c812af0b6 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.js @@ -0,0 +1,21 @@ +import getValue from './getValue.js'; + +/** + * Returns the first string value as a Javascript number + * + * @param element - The javascript object for the specified element in the metadata + * @param [index] - the index of the value in a multi-valued element, default is 0 + * @param [defaultValue] - The default value to return if the element does not exist + * @returns {*} + */ +function getNumberString(element, index, defaultValue) { + const value = getValue(element, index, defaultValue); + + if (value === undefined) { + return; + } + + return parseFloat(value); +} + +export default getNumberString; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.js new file mode 100644 index 000000000..ef1866b32 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.js @@ -0,0 +1,13 @@ +import getValue from './getValue.js'; + +function getNumberValue(element, index) { + const value = getValue(element, index); + + if (value === undefined) { + return; + } + + return parseFloat(value); +} + +export default getNumberValue; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.js new file mode 100644 index 000000000..8a1199598 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.js @@ -0,0 +1,30 @@ +/** + * Returns the values as an array of javascript numbers + * + * @param element - The javascript object for the specified element in the metadata + * @param [minimumLength] - the minimum number of values + * @returns {*} + */ +function getNumberValues(element, minimumLength) { + if (!element) { + return; + } + // Value is not present if the attribute has a zero length value + if (!element.Value) { + return; + } + // make sure we have the expected length + if (minimumLength && element.Value.length < minimumLength) { + return; + } + + const values = []; + + for (let i = 0; i < element.Value.length; i++) { + values.push(parseFloat(element.Value[i])); + } + + return values; +} + +export default getNumberValues; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.js new file mode 100644 index 000000000..ea31f4d73 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.js @@ -0,0 +1,48 @@ +import getValue from './getValue.js'; +import getNumberValue from './getNumberValue.js'; + +export default function getOverlayPlaneModule(metaData) { + const overlays = []; + + for (let overlayGroup = 0x00; overlayGroup <= 0x1e; overlayGroup += 0x02) { + let groupStr = `x60${overlayGroup.toString(16)}`; + + if (groupStr.length === 4) { + groupStr = `x600${overlayGroup.toString(16)}`; + } + + const data = getValue(metaData[`${groupStr}3000`]); + + if (!data) { + continue; + } + + const pixelData = []; + + for (let i = 0; i < data.length; i++) { + for (let k = 0; k < 8; k++) { + const byte_as_int = metaData.Value[data.dataOffset + i]; + + pixelData[i * 8 + k] = (byte_as_int >> k) & 0b1; // eslint-disable-line no-bitwise + } + } + + overlays.push({ + rows: getNumberValue(metaData[`${groupStr}0010`]), + columns: getNumberValue(metaData[`${groupStr}0011`]), + type: getValue(metaData[`${groupStr}0040`]), + x: getNumberValue(metaData[`${groupStr}0050`], 1) - 1, + y: getNumberValue(metaData[`${groupStr}0050`], 0) - 1, + pixelData, + description: getValue(metaData[`${groupStr}0022`]), + label: getValue(metaData[`${groupStr}1500`]), + roiArea: getValue(metaData[`${groupStr}1301`]), + roiMean: getValue(metaData[`${groupStr}1302`]), + roiStandardDeviation: getValue(metaData[`${groupStr}1303`]), + }); + } + + return { + overlays, + }; +} diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.js new file mode 100644 index 000000000..334b46e7b --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.js @@ -0,0 +1,26 @@ +/** + * Returns the raw value + * + * @param element - The javascript object for the specified element in the metadata + * @param [index] - the index of the value in a multi-valued element, default is 0 + * @param [defaultValue] - The default value to return if the element does not exist + * @returns {*} + */ +function getValue(element, index, defaultValue) { + index = index || 0; + if (!element) { + return defaultValue; + } + // Value is not present if the attribute has a zero length value + if (!element.Value) { + return defaultValue; + } + // make sure we have the specified index + if (element.Value.length <= index) { + return defaultValue; + } + + return element.Value[index]; +} + +export default getValue; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/index.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/index.js new file mode 100644 index 000000000..1bd07779c --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/index.js @@ -0,0 +1,5 @@ +export { default as getNumberString } from './getNumberString.js'; +export { default as getNumberValue } from './getNumberValue.js'; +export { default as getNumberValues } from './getNumberValues.js'; +export { default as getValue } from './getValue.js'; +export { default as metaDataProvider } from './metaDataProvider.js'; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.js new file mode 100644 index 000000000..7794634fc --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.js @@ -0,0 +1,170 @@ +import external from '../../../externalModules.js'; +import getNumberValues from './getNumberValues.js'; +import getValue from './getValue.js'; +import getNumberValue from './getNumberValue.js'; +import getOverlayPlaneModule from './getOverlayPlaneModule.js'; +import metaDataManager from '../metaDataManager.js'; + +function metaDataProvider(type, imageId) { + const { dicomParser } = external; + const metaData = metaDataManager.get(imageId); + + if (!metaData) { + return; + } + + if (type === 'generalSeriesModule') { + return { + modality: getValue(metaData['00080060']), + seriesInstanceUID: getValue(metaData['0020000E']), + seriesNumber: getNumberValue(metaData['00200011']), + studyInstanceUID: getValue(metaData['0020000D']), + seriesDate: dicomParser.parseDA(getValue(metaData['00080021'])), + seriesTime: dicomParser.parseTM(getValue(metaData['00080031'], 0, '')), + }; + } + + if (type === 'patientStudyModule') { + return { + patientAge: getNumberValue(metaData['00101010']), + patientSize: getNumberValue(metaData['00101020']), + patientWeight: getNumberValue(metaData['00101030']), + }; + } + + if (type === 'imagePlaneModule') { + const imageOrientationPatient = getNumberValues(metaData['00200037'], 6); + const imagePositionPatient = getNumberValues(metaData['00200032'], 3); + const pixelSpacing = getNumberValues(metaData['00280030'], 2); + + let columnPixelSpacing = null; + + let rowPixelSpacing = null; + + if (pixelSpacing) { + rowPixelSpacing = pixelSpacing[0]; + columnPixelSpacing = pixelSpacing[1]; + } + + let rowCosines = null; + + let columnCosines = null; + + if (imageOrientationPatient) { + rowCosines = [ + parseFloat(imageOrientationPatient[0]), + parseFloat(imageOrientationPatient[1]), + parseFloat(imageOrientationPatient[2]), + ]; + columnCosines = [ + parseFloat(imageOrientationPatient[3]), + parseFloat(imageOrientationPatient[4]), + parseFloat(imageOrientationPatient[5]), + ]; + } + + return { + frameOfReferenceUID: getValue(metaData['00200052']), + rows: getNumberValue(metaData['00280010']), + columns: getNumberValue(metaData['00280011']), + imageOrientationPatient, + rowCosines, + columnCosines, + imagePositionPatient, + sliceThickness: getNumberValue(metaData['00180050']), + sliceLocation: getNumberValue(metaData['00201041']), + pixelSpacing, + rowPixelSpacing, + columnPixelSpacing, + }; + } + + if (type === 'imagePixelModule') { + return { + samplesPerPixel: getNumberValue(metaData['00280002']), + photometricInterpretation: getValue(metaData['00280004']), + rows: getNumberValue(metaData['00280010']), + columns: getNumberValue(metaData['00280011']), + bitsAllocated: getNumberValue(metaData['00280100']), + bitsStored: getNumberValue(metaData['00280101']), + highBit: getValue(metaData['00280102']), + pixelRepresentation: getNumberValue(metaData['00280103']), + planarConfiguration: getNumberValue(metaData['00280006']), + pixelAspectRatio: getValue(metaData['00280034']), + smallestPixelValue: getNumberValue(metaData['00280106']), + largestPixelValue: getNumberValue(metaData['00280107']), + redPaletteColorLookupTableDescriptor: getNumberValues( + metaData['00281101'] + ), + greenPaletteColorLookupTableDescriptor: getNumberValues( + metaData['00281102'] + ), + bluePaletteColorLookupTableDescriptor: getNumberValues( + metaData['00281103'] + ), + redPaletteColorLookupTableData: getNumberValues(metaData['00281201']), + greenPaletteColorLookupTableData: getNumberValues(metaData['00281202']), + bluePaletteColorLookupTableData: getNumberValues(metaData['00281203']), + }; + } + + if (type === 'voiLutModule') { + return { + // TODO VOT LUT Sequence + windowCenter: getNumberValues(metaData['00281050'], 1), + windowWidth: getNumberValues(metaData['00281051'], 1), + }; + } + + if (type === 'modalityLutModule') { + return { + // TODO VOT LUT Sequence + rescaleIntercept: getNumberValue(metaData['00281052']), + rescaleSlope: getNumberValue(metaData['00281053']), + rescaleType: getValue(metaData['00281054']), + }; + } + + if (type === 'sopCommonModule') { + return { + sopClassUID: getValue(metaData['00080016']), + sopInstanceUID: getValue(metaData['00080018']), + }; + } + + if (type === 'petIsotopeModule') { + const radiopharmaceuticalInfo = getValue(metaData['00540016']); + + if (radiopharmaceuticalInfo === undefined) { + return; + } + + return { + radiopharmaceuticalInfo: { + radiopharmaceuticalStartTime: dicomParser.parseTM( + getValue(radiopharmaceuticalInfo['00181072'], 0, '') + ), + radionuclideTotalDose: getNumberValue( + radiopharmaceuticalInfo['00181074'] + ), + radionuclideHalfLife: getNumberValue( + radiopharmaceuticalInfo['00181075'] + ), + }, + }; + } + + if (type === 'overlayPlaneModule') { + return getOverlayPlaneModule(metaData); + } + + // Note: this is not a DICOM module, but a useful metadata that can be + // retrieved from the image + if (type === 'transferSyntax') { + return { + transferSyntaxUID: getValue(metaData['00020010']), + }; + } +} + +export default metaDataProvider; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.js new file mode 100644 index 000000000..468c3696d --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.js @@ -0,0 +1,32 @@ +import imageIdToURI from '../imageIdToURI.js'; + +let metadataByImageURI = []; + +function add(imageId, metadata) { + const imageURI = imageIdToURI(imageId); + + metadataByImageURI[imageURI] = metadata; +} + +function get(imageId) { + const imageURI = imageIdToURI(imageId); + + return metadataByImageURI[imageURI]; +} + +function remove(imageId) { + const imageURI = imageIdToURI(imageId); + + metadataByImageURI[imageURI] = undefined; +} + +function purge() { + metadataByImageURI = []; +} + +export default { + add, + get, + remove, + purge, +}; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/register.js b/packages/dicom-image-loader/src/imageLoader/wadors/register.js new file mode 100644 index 000000000..b1158fb94 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/register.js @@ -0,0 +1,8 @@ +import loadImage from './loadImage.js'; +import { metaDataProvider } from './metaData/index.js'; + +export default function (cornerstone) { + // register wadors scheme and metadata provider + cornerstone.registerImageLoader('wadors', loadImage); + cornerstone.metaData.addProvider(metaDataProvider); +} diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.js b/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.js new file mode 100644 index 000000000..2cc587ac6 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.js @@ -0,0 +1,142 @@ +import external from '../../externalModules.js'; +import { xhrRequest } from '../internal/index.js'; + +/** + * This object supports loading of DICOM P10 dataset from a uri and caching it so it can be accessed + * by the caller. This allows a caller to access the datasets without having to go through cornerstone's + * image loader mechanism. One reason a caller may need to do this is to determine the number of frames + * in a multiframe sop instance so it can create the imageId's correctly. + */ +let cacheSizeInBytes = 0; + +let loadedDataSets = {}; + +let promises = {}; + +// returns true if the wadouri for the specified index has been loaded +function isLoaded(uri) { + return loadedDataSets[uri] !== undefined; +} + +function get(uri) { + if (!loadedDataSets[uri]) { + return; + } + + return loadedDataSets[uri].dataSet; +} + +// loads the dicom dataset from the wadouri sp +function load(uri, loadRequest = xhrRequest, imageId) { + const { cornerstone, dicomParser } = external; + + // if already loaded return it right away + if (loadedDataSets[uri]) { + // console.log('using loaded dataset ' + uri); + return new Promise((resolve) => { + loadedDataSets[uri].cacheCount++; + resolve(loadedDataSets[uri].dataSet); + }); + } + + // if we are currently loading this uri, increment the cacheCount and return its promise + if (promises[uri]) { + // console.log('returning existing load promise for ' + uri); + promises[uri].cacheCount++; + + return promises[uri]; + } + + // This uri is not loaded or being loaded, load it via an xhrRequest + const loadDICOMPromise = loadRequest(uri, imageId); + + // handle success and failure of the XHR request load + const promise = new Promise((resolve, reject) => { + loadDICOMPromise + .then(function (dicomPart10AsArrayBuffer /* , xhr*/) { + const byteArray = new Uint8Array(dicomPart10AsArrayBuffer); + + // Reject the promise if parsing the dicom file fails + let dataSet; + + try { + dataSet = dicomParser.parseDicom(byteArray); + } catch (error) { + return reject(error); + } + + loadedDataSets[uri] = { + dataSet, + cacheCount: promise.cacheCount, + }; + cacheSizeInBytes += dataSet.byteArray.length; + resolve(dataSet); + + cornerstone.triggerEvent(cornerstone.events, 'datasetscachechanged', { + uri, + action: 'loaded', + cacheInfo: getInfo(), + }); + }, reject) + .then( + () => { + // Remove the promise if success + delete promises[uri]; + }, + () => { + // Remove the promise if failure + delete promises[uri]; + } + ); + }); + + promise.cacheCount = 1; + + promises[uri] = promise; + + return promise; +} + +// remove the cached/loaded dicom dataset for the specified wadouri to free up memory +function unload(uri) { + const { cornerstone } = external; + + // console.log('unload for ' + uri); + if (loadedDataSets[uri]) { + loadedDataSets[uri].cacheCount--; + if (loadedDataSets[uri].cacheCount === 0) { + // console.log('removing loaded dataset for ' + uri); + cacheSizeInBytes -= loadedDataSets[uri].dataSet.byteArray.length; + delete loadedDataSets[uri]; + + cornerstone.triggerEvent(cornerstone.events, 'datasetscachechanged', { + uri, + action: 'unloaded', + cacheInfo: getInfo(), + }); + } + } +} + +export function getInfo() { + return { + cacheSizeInBytes, + numberOfDataSetsCached: Object.keys(loadedDataSets).length, + }; +} + +// removes all cached datasets from memory +function purge() { + loadedDataSets = {}; + promises = {}; + cacheSizeInBytes = 0; +} + +export default { + isLoaded, + load, + unload, + getInfo, + purge, + get, +}; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager_test.js b/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager_test.js new file mode 100644 index 000000000..a0be8f611 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager_test.js @@ -0,0 +1,13 @@ +import { expect } from 'chai'; +import dataSetCacheManager from './dataSetCacheManager.js'; + +describe('#getInfo', () => { + it('should return cache info for an empty cache', function () { + dataSetCacheManager.purge(); + + const cacheInfo = dataSetCacheManager.getInfo(); + + expect(cacheInfo.cacheSizeInBytes).to.be.equal(0); + expect(cacheInfo.numberOfDataSetsCached).to.be.equal(0); + }); +}); diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.js b/packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.js new file mode 100644 index 000000000..6b9853bc2 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.js @@ -0,0 +1,26 @@ +let files = []; + +function add(file) { + const fileIndex = files.push(file); + + return `dicomfile:${fileIndex - 1}`; +} + +function get(index) { + return files[index]; +} + +function remove(index) { + files[index] = undefined; +} + +function purge() { + files = []; +} + +export default { + add, + get, + remove, + purge, +}; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.js b/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.js new file mode 100644 index 000000000..51828eab3 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.js @@ -0,0 +1,50 @@ +import external from '../../externalModules.js'; + +/** + * Function to deal with extracting an image frame from an encapsulated data set. + */ + +function framesAreFragmented(dataSet) { + const numberOfFrames = dataSet.intString('x00280008'); + const pixelDataElement = dataSet.elements.x7fe00010; + + return numberOfFrames !== pixelDataElement.fragments.length; +} + +export default function getEncapsulatedImageFrame(dataSet, frameIndex) { + const { dicomParser } = external; + + if ( + dataSet.elements.x7fe00010 && + dataSet.elements.x7fe00010.basicOffsetTable.length + ) { + // Basic Offset Table is not empty + return dicomParser.readEncapsulatedImageFrame( + dataSet, + dataSet.elements.x7fe00010, + frameIndex + ); + } + + // Empty basic offset table + + if (framesAreFragmented(dataSet)) { + const basicOffsetTable = dicomParser.createJPEGBasicOffsetTable( + dataSet, + dataSet.elements.x7fe00010 + ); + + return dicomParser.readEncapsulatedImageFrame( + dataSet, + dataSet.elements.x7fe00010, + frameIndex, + basicOffsetTable + ); + } + + return dicomParser.readEncapsulatedPixelDataFromFragments( + dataSet, + dataSet.elements.x7fe00010, + frameIndex + ); +} diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.js b/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.js new file mode 100644 index 000000000..8bce72e85 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.js @@ -0,0 +1,19 @@ +import getEncapsulatedImageFrame from './getEncapsulatedImageFrame.js'; +import getUncompressedImageFrame from './getUncompressedImageFrame.js'; + +function getPixelData(dataSet, frameIndex = 0) { + const pixelDataElement = + dataSet.elements.x7fe00010 || dataSet.elements.x7fe00008; + + if (!pixelDataElement) { + return null; + } + + if (pixelDataElement.encapsulatedPixelData) { + return getEncapsulatedImageFrame(dataSet, frameIndex); + } + + return getUncompressedImageFrame(dataSet, frameIndex); +} + +export default getPixelData; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.js b/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.js new file mode 100644 index 000000000..683276b4f --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.js @@ -0,0 +1,94 @@ +import unpackBinaryFrame from './unpackBinaryFrame.js'; + +/** + * Function to deal with extracting an image frame from an encapsulated data set. + */ + +function getUncompressedImageFrame(dataSet, frameIndex) { + const pixelDataElement = + dataSet.elements.x7fe00010 || dataSet.elements.x7fe00008; + const bitsAllocated = dataSet.uint16('x00280100'); + const rows = dataSet.uint16('x00280010'); + const columns = dataSet.uint16('x00280011'); + + let samplesPerPixel = dataSet.uint16('x00280002'); + + /** + * From: http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.6.3.html + * + * Though the chrominance channels are downsampled, there are still nominally + * three channels, hence Samples per Pixel (0028,0002) has a value of 3, not + * 2. I.e., for pixel data in a Native (uncompressed) format, the Value Length + * of Pixel Data (7FE0,0010) is not: + * + * Rows (0028,0010) * Columns (0028,0011) * Number of Frames (0028,0008) * + * Samples per Pixel (0028,0002) * (⌊(Bits Allocated (0028,0100)-1)/8⌋+1) + * + * padded to an even length, as it would otherwise be, but rather is: + * + * Rows (0028,0010) * Columns (0028,0011) * Number of Frames (0028,0008) * 2 * + * (⌊(Bits Allocated (0028,0100)-1)/8⌋+1) + * + * padded to an even length. + */ + const photometricInterpretation = dataSet.string('x00280004'); + + if (photometricInterpretation === 'YBR_FULL_422') { + samplesPerPixel = 2; + console.warn( + `Using SamplesPerPixel of 2 for YBR_FULL_422 photometric interpretation. + See http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.6.3.html for more information.` + ); + } + + const pixelDataOffset = pixelDataElement.dataOffset; + const pixelsPerFrame = rows * columns * samplesPerPixel; + + let frameOffset; + + if (bitsAllocated === 8) { + frameOffset = pixelDataOffset + frameIndex * pixelsPerFrame; + if (frameOffset >= dataSet.byteArray.length) { + throw new Error('frame exceeds size of pixelData'); + } + + return new Uint8Array( + dataSet.byteArray.buffer, + frameOffset, + pixelsPerFrame + ); + } else if (bitsAllocated === 16) { + frameOffset = pixelDataOffset + frameIndex * pixelsPerFrame * 2; + if (frameOffset >= dataSet.byteArray.length) { + throw new Error('frame exceeds size of pixelData'); + } + + return new Uint8Array( + dataSet.byteArray.buffer, + frameOffset, + pixelsPerFrame * 2 + ); + } else if (bitsAllocated === 1) { + frameOffset = pixelDataOffset + frameIndex * pixelsPerFrame * 0.125; + if (frameOffset >= dataSet.byteArray.length) { + throw new Error('frame exceeds size of pixelData'); + } + + return unpackBinaryFrame(dataSet.byteArray, frameOffset, pixelsPerFrame); + } else if (bitsAllocated === 32) { + frameOffset = pixelDataOffset + frameIndex * pixelsPerFrame * 4; + if (frameOffset >= dataSet.byteArray.length) { + throw new Error('frame exceeds size of pixelData'); + } + + return new Uint8Array( + dataSet.byteArray.buffer, + frameOffset, + pixelsPerFrame * 4 + ); + } + + throw new Error('unsupported pixel format'); +} + +export default getUncompressedImageFrame; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/index.js b/packages/dicom-image-loader/src/imageLoader/wadouri/index.js new file mode 100644 index 000000000..1c732d411 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/index.js @@ -0,0 +1,44 @@ +import { + getImagePixelModule, + getLUTs, + getModalityLUTOutputPixelRepresentation, + getNumberValues, + metaDataProvider, +} from './metaData/index.js'; + +import dataSetCacheManager from './dataSetCacheManager.js'; +import fileManager from './fileManager.js'; +import getEncapsulatedImageFrame from './getEncapsulatedImageFrame.js'; +import getUncompressedImageFrame from './getUncompressedImageFrame.js'; +import loadFileRequest from './loadFileRequest.js'; +import { + loadImageFromPromise, + getLoaderForScheme, + loadImage, +} from './loadImage.js'; +import parseImageId from './parseImageId.js'; +import unpackBinaryFrame from './unpackBinaryFrame.js'; +import register from './register.js'; + +const metaData = { + getImagePixelModule, + getLUTs, + getModalityLUTOutputPixelRepresentation, + getNumberValues, + metaDataProvider, +}; + +export default { + metaData, + dataSetCacheManager, + fileManager, + getEncapsulatedImageFrame, + getUncompressedImageFrame, + loadFileRequest, + loadImageFromPromise, + getLoaderForScheme, + loadImage, + parseImageId, + unpackBinaryFrame, + register, +}; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.js b/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.js new file mode 100644 index 000000000..1acf2a7a4 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.js @@ -0,0 +1,24 @@ +import parseImageId from './parseImageId.js'; +import fileManager from './fileManager.js'; + +function loadFileRequest(uri) { + const parsedImageId = parseImageId(uri); + const fileIndex = parseInt(parsedImageId.url, 10); + const file = fileManager.get(fileIndex); + + return new Promise((resolve, reject) => { + const fileReader = new FileReader(); + + fileReader.onload = (e) => { + const dicomPart10AsArrayBuffer = e.target.result; + + resolve(dicomPart10AsArrayBuffer); + }; + + fileReader.onerror = reject; + + fileReader.readAsArrayBuffer(file); + }); +} + +export default loadFileRequest; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.js b/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.js new file mode 100644 index 000000000..f077b3c8d --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.js @@ -0,0 +1,178 @@ +import createImage from '../createImage.js'; +import parseImageId from './parseImageId.js'; +import dataSetCacheManager from './dataSetCacheManager.js'; +import loadFileRequest from './loadFileRequest.js'; +import getPixelData from './getPixelData.js'; +import { xhrRequest } from '../internal/index.js'; + +// add a decache callback function to clear out our dataSetCacheManager +function addDecache(imageLoadObject, imageId) { + imageLoadObject.decache = function () { + // console.log('decache'); + const parsedImageId = parseImageId(imageId); + + dataSetCacheManager.unload(parsedImageId.url); + }; +} + +function loadImageFromPromise( + dataSetPromise, + imageId, + frame = 0, + sharedCacheKey, + options, + callbacks +) { + const start = new Date().getTime(); + const imageLoadObject = { + cancelFn: undefined, + }; + + imageLoadObject.promise = new Promise((resolve, reject) => { + dataSetPromise.then( + (dataSet /* , xhr*/) => { + const pixelData = getPixelData(dataSet, frame); + const transferSyntax = dataSet.string('x00020010'); + const loadEnd = new Date().getTime(); + const imagePromise = createImage( + imageId, + pixelData, + transferSyntax, + options + ); + + addDecache(imageLoadObject, imageId); + + imagePromise.then( + (image) => { + image.data = dataSet; + image.sharedCacheKey = sharedCacheKey; + const end = new Date().getTime(); + + image.loadTimeInMS = loadEnd - start; + image.totalTimeInMS = end - start; + if ( + callbacks !== undefined && + callbacks.imageDoneCallback !== undefined + ) { + callbacks.imageDoneCallback(image); + } + resolve(image); + }, + function (error) { + // Reject the error, and the dataSet + reject({ + error, + dataSet, + }); + } + ); + }, + function (error) { + // Reject the error + reject({ + error, + }); + } + ); + }); + + return imageLoadObject; +} + +function loadImageFromDataSet( + dataSet, + imageId, + frame = 0, + sharedCacheKey, + options +) { + const start = new Date().getTime(); + + const promise = new Promise((resolve, reject) => { + const loadEnd = new Date().getTime(); + + let imagePromise; + + try { + const pixelData = getPixelData(dataSet, frame); + const transferSyntax = dataSet.string('x00020010'); + + imagePromise = createImage(imageId, pixelData, transferSyntax, options); + } catch (error) { + // Reject the error, and the dataSet + reject({ + error, + dataSet, + }); + + return; + } + + imagePromise.then((image) => { + image.data = dataSet; + image.sharedCacheKey = sharedCacheKey; + const end = new Date().getTime(); + + image.loadTimeInMS = loadEnd - start; + image.totalTimeInMS = end - start; + resolve(image); + }, reject); + }); + + return { + promise, + cancelFn: undefined, + }; +} + +function getLoaderForScheme(scheme) { + if (scheme === 'dicomweb' || scheme === 'wadouri') { + return xhrRequest; + } else if (scheme === 'dicomfile') { + return loadFileRequest; + } +} + +function loadImage(imageId, options = {}) { + const parsedImageId = parseImageId(imageId); + + options = Object.assign({}, options); + let loader = options.loader; + + if (loader === undefined) { + loader = getLoaderForScheme(parsedImageId.scheme); + } else { + delete options.loader; + } + + // if the dataset for this url is already loaded, use it + if (dataSetCacheManager.isLoaded(parsedImageId.url)) { + const dataSet = dataSetCacheManager.get(parsedImageId.url, loader, imageId); + + return loadImageFromDataSet( + dataSet, + imageId, + parsedImageId.frame, + parsedImageId.url, + options + ); + } + + // load the dataSet via the dataSetCacheManager + const dataSetPromise = dataSetCacheManager.load( + parsedImageId.url, + loader, + imageId + ); + + return loadImageFromPromise( + dataSetPromise, + imageId, + parsedImageId.frame, + parsedImageId.url, + options + ); +} + +export { loadImageFromPromise, getLoaderForScheme, loadImage }; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.js new file mode 100644 index 000000000..27db277de --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.js @@ -0,0 +1,132 @@ +function getLutDescriptor(dataSet, tag) { + if (!dataSet.elements[tag] || dataSet.elements[tag].length !== 6) { + return; + } + + return [ + dataSet.uint16(tag, 0), + dataSet.uint16(tag, 1), + dataSet.uint16(tag, 2), + ]; +} + +function getLutData(lutDataSet, tag, lutDescriptor) { + const lut = []; + const lutData = lutDataSet.elements[tag]; + + for (let i = 0; i < lutDescriptor[0]; i++) { + // Output range is always unsigned + if (lutDescriptor[2] === 16) { + lut[i] = lutDataSet.uint16(tag, i); + } else { + lut[i] = lutDataSet.byteArray[i + lutData.dataOffset]; + } + } + + return lut; +} + +function populatePaletteColorLut(dataSet, imagePixelModule) { + imagePixelModule.redPaletteColorLookupTableDescriptor = getLutDescriptor( + dataSet, + 'x00281101' + ); + imagePixelModule.greenPaletteColorLookupTableDescriptor = getLutDescriptor( + dataSet, + 'x00281102' + ); + imagePixelModule.bluePaletteColorLookupTableDescriptor = getLutDescriptor( + dataSet, + 'x00281103' + ); + + // The first Palette Color Lookup Table Descriptor value is the number of entries in the lookup table. + // When the number of table entries is equal to 2ˆ16 then this value shall be 0. + // See http://dicom.nema.org/MEDICAL/DICOM/current/output/chtml/part03/sect_C.7.6.3.html#sect_C.7.6.3.1.5 + if (imagePixelModule.redPaletteColorLookupTableDescriptor[0] === 0) { + imagePixelModule.redPaletteColorLookupTableDescriptor[0] = 65536; + imagePixelModule.greenPaletteColorLookupTableDescriptor[0] = 65536; + imagePixelModule.bluePaletteColorLookupTableDescriptor[0] = 65536; + } + + // The third Palette Color Lookup Table Descriptor value specifies the number of bits for each entry in the Lookup Table Data. + // It shall take the value of 8 or 16. + // The LUT Data shall be stored in a format equivalent to 8 bits allocated when the number of bits for each entry is 8, and 16 bits allocated when the number of bits for each entry is 16, where in both cases the high bit is equal to bits allocated-1. + // The third value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. + // + // Note: Some implementations have encoded 8 bit entries with 16 bits allocated, padding the high bits; + // this can be detected by comparing the number of entries specified in the LUT Descriptor with the actual value length of the LUT Data entry. + // The value length in bytes should equal the number of entries if bits allocated is 8, and be twice as long if bits allocated is 16. + const numLutEntries = + imagePixelModule.redPaletteColorLookupTableDescriptor[0]; + const lutData = dataSet.elements.x00281201; + const lutBitsAllocated = lutData.length === numLutEntries ? 8 : 16; + + // If the descriptors do not appear to have the correct values, correct them + if ( + imagePixelModule.redPaletteColorLookupTableDescriptor[2] !== + lutBitsAllocated + ) { + imagePixelModule.redPaletteColorLookupTableDescriptor[2] = lutBitsAllocated; + imagePixelModule.greenPaletteColorLookupTableDescriptor[2] = + lutBitsAllocated; + imagePixelModule.bluePaletteColorLookupTableDescriptor[2] = + lutBitsAllocated; + } + + imagePixelModule.redPaletteColorLookupTableData = getLutData( + dataSet, + 'x00281201', + imagePixelModule.redPaletteColorLookupTableDescriptor + ); + imagePixelModule.greenPaletteColorLookupTableData = getLutData( + dataSet, + 'x00281202', + imagePixelModule.greenPaletteColorLookupTableDescriptor + ); + imagePixelModule.bluePaletteColorLookupTableData = getLutData( + dataSet, + 'x00281203', + imagePixelModule.bluePaletteColorLookupTableDescriptor + ); +} + +function populateSmallestLargestPixelValues(dataSet, imagePixelModule) { + const pixelRepresentation = dataSet.uint16('x00280103'); + + if (pixelRepresentation === 0) { + imagePixelModule.smallestPixelValue = dataSet.uint16('x00280106'); + imagePixelModule.largestPixelValue = dataSet.uint16('x00280107'); + } else { + imagePixelModule.smallestPixelValue = dataSet.int16('x00280106'); + imagePixelModule.largestPixelValue = dataSet.int16('x00280107'); + } +} + +function getImagePixelModule(dataSet) { + const imagePixelModule = { + samplesPerPixel: dataSet.uint16('x00280002'), + photometricInterpretation: dataSet.string('x00280004'), + rows: dataSet.uint16('x00280010'), + columns: dataSet.uint16('x00280011'), + bitsAllocated: dataSet.uint16('x00280100'), + bitsStored: dataSet.uint16('x00280101'), + highBit: dataSet.uint16('x00280102'), + pixelRepresentation: dataSet.uint16('x00280103'), + planarConfiguration: dataSet.uint16('x00280006'), + pixelAspectRatio: dataSet.string('x00280034'), + }; + + populateSmallestLargestPixelValues(dataSet, imagePixelModule); + + if ( + imagePixelModule.photometricInterpretation === 'PALETTE COLOR' && + dataSet.elements.x00281101 + ) { + populatePaletteColorLut(dataSet, imagePixelModule); + } + + return imagePixelModule; +} + +export default getImagePixelModule; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.js new file mode 100644 index 000000000..ebb761481 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.js @@ -0,0 +1,53 @@ +function getLUT(pixelRepresentation, lutDataSet) { + let numLUTEntries = lutDataSet.uint16('x00283002', 0); + + if (numLUTEntries === 0) { + numLUTEntries = 65535; + } + let firstValueMapped = 0; + + if (pixelRepresentation === 0) { + firstValueMapped = lutDataSet.uint16('x00283002', 1); + } else { + firstValueMapped = lutDataSet.int16('x00283002', 1); + } + const numBitsPerEntry = lutDataSet.uint16('x00283002', 2); + // console.log('LUT(', numLUTEntries, ',', firstValueMapped, ',', numBitsPerEntry, ')'); + const lut = { + id: '1', + firstValueMapped, + numBitsPerEntry, + lut: [], + }; + + // console.log("minValue=", minValue, "; maxValue=", maxValue); + for (let i = 0; i < numLUTEntries; i++) { + if (pixelRepresentation === 0) { + lut.lut[i] = lutDataSet.uint16('x00283006', i); + } else { + lut.lut[i] = lutDataSet.int16('x00283006', i); + } + } + + return lut; +} + +function getLUTs(pixelRepresentation, lutSequence) { + if (!lutSequence || !lutSequence.items || !lutSequence.items.length) { + return; + } + const luts = []; + + for (let i = 0; i < lutSequence.items.length; i++) { + const lutDataSet = lutSequence.items[i].dataSet; + const lut = getLUT(pixelRepresentation, lutDataSet); + + if (lut) { + luts.push(lut); + } + } + + return luts; +} + +export default getLUTs; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.js new file mode 100644 index 000000000..72f7cdedb --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.js @@ -0,0 +1,52 @@ +/* eslint no-bitwise: 0 */ + +function getMinStoredPixelValue(dataSet) { + const pixelRepresentation = dataSet.uint16('x00280103'); + const bitsStored = dataSet.uint16('x00280101'); + + if (pixelRepresentation === 0) { + return 0; + } + + return -1 << (bitsStored - 1); +} + +// 0 = unsigned / US, 1 = signed / SS +function getModalityLUTOutputPixelRepresentation(dataSet) { + // CT SOP Classes are always signed + const sopClassUID = dataSet.string('x00080016'); + + if ( + sopClassUID === '1.2.840.10008.5.1.4.1.1.2' || + sopClassUID === '1.2.840.10008.5.1.4.1.1.2.1' + ) { + return 1; + } + + // if rescale intercept and rescale slope are present, pass the minimum stored + // pixel value through them to see if we get a signed output range + const rescaleIntercept = dataSet.floatString('x00281052'); + const rescaleSlope = dataSet.floatString('x00281053'); + + if (rescaleIntercept !== undefined && rescaleSlope !== undefined) { + const minStoredPixelValue = getMinStoredPixelValue(dataSet); // + const minModalityLutValue = + minStoredPixelValue * rescaleSlope + rescaleIntercept; + + if (minModalityLutValue < 0) { + return 1; + } + + return 0; + } + + // Output of non linear modality lut is always unsigned + if (dataSet.elements.x00283000 && dataSet.elements.x00283000.length > 0) { + return 0; + } + + // If no modality lut transform, output is same as pixel representation + return dataSet.uint16('x00280103'); +} + +export default getModalityLUTOutputPixelRepresentation; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.js new file mode 100644 index 000000000..a2f9ee918 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.js @@ -0,0 +1,20 @@ +function getNumberValues(dataSet, tag, minimumLength) { + const values = []; + const valueAsString = dataSet.string(tag); + + if (!valueAsString) { + return; + } + const split = valueAsString.split('\\'); + + if (minimumLength && split.length < minimumLength) { + return; + } + for (let i = 0; i < split.length; i++) { + values.push(parseFloat(split[i])); + } + + return values; +} + +export default getNumberValues; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.js new file mode 100644 index 000000000..ecdce907d --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.js @@ -0,0 +1,45 @@ +export default function getOverlayPlaneModule(dataSet) { + const overlays = []; + + for (let overlayGroup = 0x00; overlayGroup <= 0x1e; overlayGroup += 0x02) { + let groupStr = `x60${overlayGroup.toString(16)}`; + + if (groupStr.length === 4) { + groupStr = `x600${overlayGroup.toString(16)}`; + } + + const data = dataSet.elements[`${groupStr}3000`]; + + if (!data) { + continue; + } + + const pixelData = []; + + for (let i = 0; i < data.length; i++) { + for (let k = 0; k < 8; k++) { + const byte_as_int = dataSet.byteArray[data.dataOffset + i]; + + pixelData[i * 8 + k] = (byte_as_int >> k) & 0b1; // eslint-disable-line no-bitwise + } + } + + overlays.push({ + rows: dataSet.uint16(`${groupStr}0010`), + columns: dataSet.uint16(`${groupStr}0011`), + type: dataSet.string(`${groupStr}0040`), + x: dataSet.int16(`${groupStr}0050`, 1) - 1, + y: dataSet.int16(`${groupStr}0050`, 0) - 1, + pixelData, + description: dataSet.string(`${groupStr}0022`), + label: dataSet.string(`${groupStr}1500`), + roiArea: dataSet.string(`${groupStr}1301`), + roiMean: dataSet.string(`${groupStr}1302`), + roiStandardDeviation: dataSet.string(`${groupStr}1303`), + }); + } + + return { + overlays, + }; +} diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/index.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/index.js new file mode 100644 index 000000000..e67d6b280 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/index.js @@ -0,0 +1,5 @@ +export { default as getImagePixelModule } from './getImagePixelModule.js'; +export { default as getLUTs } from './getLUTs.js'; +export { default as getModalityLUTOutputPixelRepresentation } from './getModalityLUTOutputPixelRepresentation.js'; +export { default as getNumberValues } from './getNumberValues.js'; +export { default as metaDataProvider } from './metaDataProvider.js'; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.js new file mode 100644 index 000000000..2418d8e85 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.js @@ -0,0 +1,159 @@ +import external from '../../../externalModules.js'; +import getNumberValues from './getNumberValues.js'; +import parseImageId from '../parseImageId.js'; +import dataSetCacheManager from '../dataSetCacheManager.js'; +import getImagePixelModule from './getImagePixelModule.js'; +import getOverlayPlaneModule from './getOverlayPlaneModule.js'; +import getLUTs from './getLUTs.js'; +import getModalityLUTOutputPixelRepresentation from './getModalityLUTOutputPixelRepresentation.js'; + +function metaDataProvider(type, imageId) { + const { dicomParser } = external; + const parsedImageId = parseImageId(imageId); + + const dataSet = dataSetCacheManager.get(parsedImageId.url); + + if (!dataSet) { + return; + } + + if (type === 'generalSeriesModule') { + return { + modality: dataSet.string('x00080060'), + seriesInstanceUID: dataSet.string('x0020000e'), + seriesNumber: dataSet.intString('x00200011'), + studyInstanceUID: dataSet.string('x0020000d'), + seriesDate: dicomParser.parseDA(dataSet.string('x00080021')), + seriesTime: dicomParser.parseTM(dataSet.string('x00080031') || ''), + }; + } + + if (type === 'patientStudyModule') { + return { + patientAge: dataSet.intString('x00101010'), + patientSize: dataSet.floatString('x00101020'), + patientWeight: dataSet.floatString('x00101030'), + }; + } + + if (type === 'imagePlaneModule') { + const imageOrientationPatient = getNumberValues(dataSet, 'x00200037', 6); + const imagePositionPatient = getNumberValues(dataSet, 'x00200032', 3); + const pixelSpacing = getNumberValues(dataSet, 'x00280030', 2); + + let columnPixelSpacing = null; + + let rowPixelSpacing = null; + + if (pixelSpacing) { + rowPixelSpacing = pixelSpacing[0]; + columnPixelSpacing = pixelSpacing[1]; + } + + let rowCosines = null; + + let columnCosines = null; + + if (imageOrientationPatient) { + rowCosines = [ + parseFloat(imageOrientationPatient[0]), + parseFloat(imageOrientationPatient[1]), + parseFloat(imageOrientationPatient[2]), + ]; + columnCosines = [ + parseFloat(imageOrientationPatient[3]), + parseFloat(imageOrientationPatient[4]), + parseFloat(imageOrientationPatient[5]), + ]; + } + + return { + frameOfReferenceUID: dataSet.string('x00200052'), + rows: dataSet.uint16('x00280010'), + columns: dataSet.uint16('x00280011'), + imageOrientationPatient, + rowCosines, + columnCosines, + imagePositionPatient, + sliceThickness: dataSet.floatString('x00180050'), + sliceLocation: dataSet.floatString('x00201041'), + pixelSpacing, + rowPixelSpacing, + columnPixelSpacing, + }; + } + + if (type === 'imagePixelModule') { + return getImagePixelModule(dataSet); + } + + if (type === 'modalityLutModule') { + return { + rescaleIntercept: dataSet.floatString('x00281052'), + rescaleSlope: dataSet.floatString('x00281053'), + rescaleType: dataSet.string('x00281054'), + modalityLUTSequence: getLUTs( + dataSet.uint16('x00280103'), + dataSet.elements.x00283000 + ), + }; + } + + if (type === 'voiLutModule') { + const modalityLUTOutputPixelRepresentation = + getModalityLUTOutputPixelRepresentation(dataSet); + + return { + windowCenter: getNumberValues(dataSet, 'x00281050', 1), + windowWidth: getNumberValues(dataSet, 'x00281051', 1), + voiLUTSequence: getLUTs( + modalityLUTOutputPixelRepresentation, + dataSet.elements.x00283010 + ), + }; + } + + if (type === 'sopCommonModule') { + return { + sopClassUID: dataSet.string('x00080016'), + sopInstanceUID: dataSet.string('x00080018'), + }; + } + + if (type === 'petIsotopeModule') { + const radiopharmaceuticalInfo = dataSet.elements.x00540016; + + if (radiopharmaceuticalInfo === undefined) { + return; + } + + const firstRadiopharmaceuticalInfoDataSet = + radiopharmaceuticalInfo.items[0].dataSet; + + return { + radiopharmaceuticalInfo: { + radiopharmaceuticalStartTime: dicomParser.parseTM( + firstRadiopharmaceuticalInfoDataSet.string('x00181072') || '' + ), + radionuclideTotalDose: + firstRadiopharmaceuticalInfoDataSet.floatString('x00181074'), + radionuclideHalfLife: + firstRadiopharmaceuticalInfoDataSet.floatString('x00181075'), + }, + }; + } + + if (type === 'overlayPlaneModule') { + return getOverlayPlaneModule(dataSet); + } + + // Note: this is not a DICOM module, but a useful metadata that can be + // retrieved from the image + if (type === 'transferSyntax') { + return { + transferSyntaxUID: dataSet.string('x00020010'), + }; + } +} + +export default metaDataProvider; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.js b/packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.js new file mode 100644 index 000000000..07e7e804e --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.js @@ -0,0 +1,24 @@ +function parseImageId(imageId) { + // build a url by parsing out the url scheme and frame index from the imageId + const firstColonIndex = imageId.indexOf(':'); + + let url = imageId.substring(firstColonIndex + 1); + const frameIndex = url.indexOf('frame='); + + let frame; + + if (frameIndex !== -1) { + const frameStr = url.substr(frameIndex + 6); + + frame = parseInt(frameStr, 10); + url = url.substr(0, frameIndex - 1); + } + + return { + scheme: imageId.substr(0, firstColonIndex), + url, + frame, + }; +} + +export default parseImageId; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/register.js b/packages/dicom-image-loader/src/imageLoader/wadouri/register.js new file mode 100644 index 000000000..8d1b2586d --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/register.js @@ -0,0 +1,12 @@ +import { loadImage } from './loadImage.js'; +import { metaDataProvider } from './metaData/index.js'; + +export default function (cornerstone) { + // register dicomweb and wadouri image loader prefixes + cornerstone.registerImageLoader('dicomweb', loadImage); + cornerstone.registerImageLoader('wadouri', loadImage); + cornerstone.registerImageLoader('dicomfile', loadImage); + + // add wadouri metadata provider + cornerstone.metaData.addProvider(metaDataProvider); +} diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.js b/packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.js new file mode 100644 index 000000000..22a5dbfb2 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.js @@ -0,0 +1,31 @@ +/* eslint no-bitwise: 0 */ + +function isBitSet(byte, bitPos) { + return byte & (1 << bitPos); +} + +/** + * Function to deal with unpacking a binary frame + */ +function unpackBinaryFrame(byteArray, frameOffset, pixelsPerFrame) { + // Create a new pixel array given the image size + const pixelData = new Uint8Array(pixelsPerFrame); + + for (let i = 0; i < pixelsPerFrame; i++) { + // Compute byte position + const bytePos = Math.floor(i / 8); + + // Get the current byte + const byte = byteArray[bytePos + frameOffset]; + + // Bit position (0-7) within byte + const bitPos = i % 8; + + // Check whether bit at bitpos is set + pixelData[i] = isBitSet(byte, bitPos) ? 1 : 0; + } + + return pixelData; +} + +export default unpackBinaryFrame; diff --git a/packages/dicom-image-loader/src/imageLoader/webWorkerManager.js b/packages/dicom-image-loader/src/imageLoader/webWorkerManager.js new file mode 100644 index 000000000..cbf05ae02 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/webWorkerManager.js @@ -0,0 +1,362 @@ +// Not sure why but webpack isn't splitting this out unless we explicitly use worker-loader! +// eslint-disable-next-line +// import cornerstoneWADOImageLoaderWebWorker from 'worker-loader!../webWorker/index.worker.js'; +import cornerstoneWADOImageLoaderWebWorker from '../webWorker/index.worker.js'; + +// This is for the Webpack 5 approch but it's currently broken +// so we will continue relying on worker-loader for now +// https://github.com/webpack/webpack/issues/13899 +/* const cornerstoneWADOImageLoaderWebWorkerPath = new URL( + '../webWorker/index.js', + import.meta.url +);*/ + +import { getOptions } from './internal/options.js'; + +// the taskId to assign to the next task added via addTask() +let nextTaskId = 0; + +// array of queued tasks sorted with highest priority task first +const tasks = []; + +// array of web workers to dispatch decode tasks to +const webWorkers = []; + +// The options for CornerstoneWADOImageLoader +const options = getOptions(); + +const defaultConfig = { + maxWebWorkers: navigator.hardwareConcurrency || 1, + startWebWorkersOnDemand: true, + webWorkerTaskPaths: [], + taskConfiguration: { + decodeTask: { + initializeCodecsOnStartup: false, + strict: options.strict, + }, + }, +}; + +let config; + +const statistics = { + maxWebWorkers: 0, + numWebWorkers: 0, + numTasksQueued: 0, + numTasksExecuting: 0, + numTasksCompleted: 0, + totalTaskTimeInMS: 0, + totalTimeDelayedInMS: 0, +}; + +/** + * Function to start a task on a web worker + */ +function startTaskOnWebWorker() { + // return immediately if no decode tasks to do + if (!tasks.length) { + return; + } + + // look for a web worker that is ready + for (let i = 0; i < webWorkers.length; i++) { + if (webWorkers[i].status === 'ready') { + // mark it as busy so tasks are not assigned to it + webWorkers[i].status = 'busy'; + + // get the highest priority task + const task = tasks.shift(); + + task.start = new Date().getTime(); + + // update stats with how long this task was delayed (waiting in queue) + const end = new Date().getTime(); + + statistics.totalTimeDelayedInMS += end - task.added; + + // assign this task to this web worker and send the web worker + // a message to execute it + webWorkers[i].task = task; + webWorkers[i].worker.postMessage( + { + taskType: task.taskType, + workerIndex: i, + data: task.data, + }, + task.transferList + ); + statistics.numTasksExecuting++; + + return; + } + } + + // if no available web workers and we haven't started max web workers, start a new one + if (webWorkers.length < config.maxWebWorkers) { + spawnWebWorker(); + } +} + +/** + * Function to handle a message from a web worker + * @param msg + */ +function handleMessageFromWorker(msg) { + // console.log('handleMessageFromWorker', msg.data); + if (msg.data.taskType === 'initialize') { + webWorkers[msg.data.workerIndex].status = 'ready'; + startTaskOnWebWorker(); + } else { + const start = webWorkers[msg.data.workerIndex].task.start; + + const action = msg.data.status === 'success' ? 'resolve' : 'reject'; + + webWorkers[msg.data.workerIndex].task.deferred[action](msg.data.result); + + webWorkers[msg.data.workerIndex].task = undefined; + + statistics.numTasksExecuting--; + webWorkers[msg.data.workerIndex].status = 'ready'; + statistics.numTasksCompleted++; + + const end = new Date().getTime(); + + statistics.totalTaskTimeInMS += end - start; + + startTaskOnWebWorker(); + } +} + +/** + * Spawns a new web worker + */ +function spawnWebWorker() { + // prevent exceeding maxWebWorkers + if (webWorkers.length >= config.maxWebWorkers) { + return; + } + + // spawn the webworker + const worker = new cornerstoneWADOImageLoaderWebWorker(); + + // This is for the Webpack 5 approach but it's currently broken + /* const worker = new Worker(cornerstoneWADOImageLoaderWebWorkerPath, { + name: `cornerstoneWADOImageLoaderWebWorkerPath-${webWorkers.length + 1}`, + type: 'module', + });*/ + + // const worker = new Worker( + // './cornerstoneWADOImageLoaderWebWorker.bundle.min.js', + // { + // name: `cornerstoneWADOImageLoaderWebWorkerPath-${webWorkers.length + 1}`, + // } + // ); + + webWorkers.push({ + worker, + status: 'initializing', + }); + worker.addEventListener('message', handleMessageFromWorker); + worker.postMessage({ + taskType: 'initialize', + workerIndex: webWorkers.length - 1, + config, + }); +} + +/** + * Initialization function for the web worker manager - spawns web workers + * @param configObject + */ +function initialize(configObject) { + configObject = configObject || defaultConfig; + + // prevent being initialized more than once + if (config) { + // throw new Error('WebWorkerManager already initialized'); + } + + config = configObject; + + config.maxWebWorkers = + config.maxWebWorkers || navigator.hardwareConcurrency || 1; + + // Spawn new web workers + if (!config.startWebWorkersOnDemand) { + for (let i = 0; i < config.maxWebWorkers; i++) { + spawnWebWorker(); + } + } +} + +/** + * Terminate all running web workers. + */ +function terminate() { + for (let i = 0; i < webWorkers.length; i++) { + webWorkers[i].worker.terminate(); + } + webWorkers.length = 0; + config = undefined; +} + +/** + * dynamically loads a web worker task + * @param sourcePath + * @param taskConfig + */ +function loadWebWorkerTask(sourcePath, taskConfig) { + // add it to the list of web worker tasks paths so on demand web workers + // load this properly + config.webWorkerTaskPaths.push(sourcePath); + + // if a task specific configuration is provided, merge it into the config + if (taskConfig) { + config.taskConfiguration = Object.assign( + config.taskConfiguration, + taskConfig + ); + } + + // tell each spawned web worker to load this task + for (let i = 0; i < webWorkers.length; i++) { + webWorkers[i].worker.postMessage({ + taskType: 'loadWebWorkerTask', + workerIndex: webWorkers.length - 1, + sourcePath, + config, + }); + } +} + +/** + * Function to add a decode task to be performed + * + * @param taskType - the taskType for this task + * @param data - data specific to the task + * @param priority - optional priority of the task (defaults to 0), > 0 is higher, < 0 is lower + * @param transferList - optional array of data to transfer to web worker + * @returns {*} + */ +function addTask(taskType, data, priority = 0, transferList) { + if (!config) { + initialize(); + } + + let deferred = {}; + const promise = new Promise((resolve, reject) => { + deferred = { + resolve, + reject, + }; + }); + + // find the right spot to insert this decode task (based on priority) + let i; + + for (i = 0; i < tasks.length; i++) { + if (tasks[i].priority < priority) { + break; + } + } + + const taskId = nextTaskId++; + + // insert the decode task at position i + tasks.splice(i, 0, { + taskId, + taskType, + status: 'ready', + added: new Date().getTime(), + data, + deferred, + priority, + transferList, + }); + + // try to start a task on the web worker since we just added a new task and a web worker may be available + startTaskOnWebWorker(); + + return { + taskId, + promise, + }; +} + +/** + * Changes the priority of a queued task + * @param taskId - the taskId to change the priority of + * @param priority - priority of the task (defaults to 0), > 0 is higher, < 0 is lower + * @returns boolean - true on success, false if taskId not found + */ +function setTaskPriority(taskId, priority = 0) { + // search for this taskId + for (let i = 0; i < tasks.length; i++) { + if (tasks[i].taskId === taskId) { + // taskId found, remove it + const task = tasks.splice(i, 1)[0]; + + // set its priority + task.priority = priority; + + // find the right spot to insert this decode task (based on priority) + for (i = 0; i < tasks.length; i++) { + if (tasks[i].priority < priority) { + break; + } + } + + // insert the decode task at position i + tasks.splice(i, 0, task); + + return true; + } + } + + return false; +} + +/** + * Cancels a queued task and rejects + * @param taskId - the taskId to cancel + * @param reason - optional reason the task was rejected + * @returns boolean - true on success, false if taskId not found + */ +function cancelTask(taskId, reason) { + // search for this taskId + for (let i = 0; i < tasks.length; i++) { + if (tasks[i].taskId === taskId) { + // taskId found, remove it + const task = tasks.splice(i, 1); + + task.deferred.reject(reason); + + return true; + } + } + + return false; +} + +/** + * Function to return the statistics on running web workers + * @returns object containing statistics + */ +function getStatistics() { + statistics.maxWebWorkers = config.maxWebWorkers; + statistics.numWebWorkers = webWorkers.length; + statistics.numTasksQueued = tasks.length; + + return statistics; +} + +export default { + initialize, + loadWebWorkerTask, + addTask, + getStatistics, + setTaskPriority, + cancelTask, + webWorkers, + terminate, +}; diff --git a/packages/dicom-image-loader/src/imageLoader/webWorkerManager_test.js b/packages/dicom-image-loader/src/imageLoader/webWorkerManager_test.js new file mode 100644 index 000000000..53f05798d --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/webWorkerManager_test.js @@ -0,0 +1,26 @@ +import { expect } from 'chai'; +import webWorkerManager from './webWorkerManager.js'; + +const config = { + maxWebWorkers: 2, + startWebWorkersOnDemand: true, + taskConfiguration: { + decodeTask: { + initializeCodecsOnStartup: false, + }, + }, +}; + +describe('config', function () { + it('should initialize', () => { + webWorkerManager.initialize(config); + expect(webWorkerManager.webWorkers.length === 2); + webWorkerManager.terminate(); + }); + + it('should have 0 running workers after .terminate()', () => { + webWorkerManager.initialize(config); + webWorkerManager.terminate(); + expect(webWorkerManager.webWorkers.length === 0); + }); +}); diff --git a/packages/dicom-image-loader/src/index.ts b/packages/dicom-image-loader/src/index.ts new file mode 100644 index 000000000..8d509ebd1 --- /dev/null +++ b/packages/dicom-image-loader/src/index.ts @@ -0,0 +1 @@ +export * from './imageLoader'; diff --git a/packages/dicom-image-loader/src/shared/calculateMinMax.js b/packages/dicom-image-loader/src/shared/calculateMinMax.js new file mode 100644 index 000000000..e3ce55ab4 --- /dev/null +++ b/packages/dicom-image-loader/src/shared/calculateMinMax.js @@ -0,0 +1,41 @@ +import getMinMax from './getMinMax.js'; + +/** + * Check the minimum and maximum values in the imageFrame pixel data + * match with the provided smallestPixelValue and largestPixelValue metaData. + * + * If 'strict' is true, log to the console a warning if these values do not match. + * Otherwise, correct them automatically. + * + * @param {Object} imageFrame + * @param {Boolean} strict If 'strict' is true, log to the console a warning if these values do not match. + * Otherwise, correct them automatically.Default is true. + */ +export default function calculateMinMax(imageFrame, strict = true) { + const minMax = getMinMax(imageFrame.pixelData); + const mustAssign = !( + isNumber(imageFrame.smallestPixelValue) && + isNumber(imageFrame.largestPixelValue) + ); + + if (strict === true && !mustAssign) { + if (imageFrame.smallestPixelValue !== minMax.min) { + console.warn( + 'Image smallestPixelValue tag is incorrect. Rendering performance will suffer considerably.' + ); + } + + if (imageFrame.largestPixelValue !== minMax.max) { + console.warn( + 'Image largestPixelValue tag is incorrect. Rendering performance will suffer considerably.' + ); + } + } else { + imageFrame.smallestPixelValue = minMax.min; + imageFrame.largestPixelValue = minMax.max; + } +} + +function isNumber(numValue) { + return typeof numValue === 'number'; +} diff --git a/packages/dicom-image-loader/src/shared/calculateMinMax_test.js b/packages/dicom-image-loader/src/shared/calculateMinMax_test.js new file mode 100644 index 000000000..fb42c225c --- /dev/null +++ b/packages/dicom-image-loader/src/shared/calculateMinMax_test.js @@ -0,0 +1,58 @@ +import { expect } from 'chai'; +import calculateMinMax from './calculateMinMax.js'; + +describe('#calculateMinMax', () => { + let imageFrame = {}; + + beforeEach(() => { + imageFrame = { + smallestPixelValue: -1, + largestPixelValue: 10, + pixelData: [7, 3, 9, 6, 8, 1, 4, 5, 2], + }; + }); + + it('should update the smallest and largest pixel values if strict is false', () => { + const strict = false; + + calculateMinMax(imageFrame, strict); + + expect(imageFrame.smallestPixelValue).to.be.equal(1); + expect(imageFrame.largestPixelValue).to.be.equal(9); + }); + + it('should not update the smallest and largest pixel values if strict is true', () => { + const strict = true; + + calculateMinMax(imageFrame, strict); + + expect(imageFrame.smallestPixelValue).to.be.equal(-1); + expect(imageFrame.largestPixelValue).to.be.equal(10); + }); + + it('should update the smallest and largest pixel values regardless of strict value', () => { + let strict = false; + + imageFrame.smallestPixelValue = undefined; + imageFrame.largestPixelValue = undefined; + + // ACT + calculateMinMax(imageFrame, strict); + + // ASSERT + expect(imageFrame.smallestPixelValue).to.be.equal(1); + expect(imageFrame.largestPixelValue).to.be.equal(9); + + strict = true; + + imageFrame.smallestPixelValue = undefined; + imageFrame.largestPixelValue = undefined; + + // ACT + calculateMinMax(imageFrame, strict); + + // ASSERT + expect(imageFrame.smallestPixelValue).to.be.equal(1); + expect(imageFrame.largestPixelValue).to.be.equal(9); + }); +}); diff --git a/packages/dicom-image-loader/src/shared/decodeImageFrame.js b/packages/dicom-image-loader/src/shared/decodeImageFrame.js new file mode 100644 index 000000000..4d9d2c3d0 --- /dev/null +++ b/packages/dicom-image-loader/src/shared/decodeImageFrame.js @@ -0,0 +1,263 @@ +/* eslint-disable complexity */ +import decodeLittleEndian from './decoders/decodeLittleEndian.js'; +import decodeBigEndian from './decoders/decodeBigEndian.js'; +import decodeRLE from './decoders/decodeRLE.js'; +import decodeJPEGBaseline8Bit from './decoders/decodeJPEGBaseline8Bit.js'; +// import decodeJPEGBaseline12Bit from './decoders/decodeJPEGBaseline12Bit.js'; +import decodeJPEGBaseline12Bit from './decoders/decodeJPEGBaseline12Bit-js.js'; +import decodeJPEGLossless from './decoders/decodeJPEGLossless.js'; +import decodeJPEGLS from './decoders/decodeJPEGLS.js'; +import decodeJPEG2000 from './decoders/decodeJPEG2000.js'; +import scaleArray from './scaling/scaleArray.js'; + +function decodeImageFrame( + imageFrame, + transferSyntax, + pixelData, + decodeConfig, + options, + callbackFn +) { + const start = new Date().getTime(); + + let decodePromise = null; + + let opts; + + switch (transferSyntax) { + case '1.2.840.10008.1.2': + // Implicit VR Little Endian + decodePromise = decodeLittleEndian(imageFrame, pixelData); + break; + case '1.2.840.10008.1.2.1': + // Explicit VR Little Endian + decodePromise = decodeLittleEndian(imageFrame, pixelData); + break; + case '1.2.840.10008.1.2.2': + // Explicit VR Big Endian (retired) + decodePromise = decodeBigEndian(imageFrame, pixelData); + break; + case '1.2.840.10008.1.2.1.99': + // Deflate transfer syntax (deflated by dicomParser) + decodePromise = decodeLittleEndian(imageFrame, pixelData); + break; + case '1.2.840.10008.1.2.5': + // RLE Lossless + decodePromise = decodeRLE(imageFrame, pixelData); + break; + case '1.2.840.10008.1.2.4.50': + // JPEG Baseline lossy process 1 (8 bit) + opts = { + ...imageFrame, + }; + + decodePromise = decodeJPEGBaseline8Bit(pixelData, opts); + break; + case '1.2.840.10008.1.2.4.51': + // JPEG Baseline lossy process 2 & 4 (12 bit) + // opts = { + // ...imageFrame, + // }; + // decodePromise = decodeJPEGBaseline12Bit(pixelData, opts); + //throw new Error('Currently unsupported: 1.2.840.10008.1.2.4.51'); + decodePromise = decodeJPEGBaseline12Bit(imageFrame, pixelData); + break; + case '1.2.840.10008.1.2.4.57': + // JPEG Lossless, Nonhierarchical (Processes 14) + decodePromise = decodeJPEGLossless(imageFrame, pixelData); + break; + case '1.2.840.10008.1.2.4.70': + // JPEG Lossless, Nonhierarchical (Processes 14 [Selection 1]) + decodePromise = decodeJPEGLossless(imageFrame, pixelData); + break; + case '1.2.840.10008.1.2.4.80': + // JPEG-LS Lossless Image Compression + opts = { + signed: imageFrame.pixelRepresentation === 1, // imageFrame.signed, + // shouldn't need... + bytesPerPixel: imageFrame.bitsAllocated <= 8 ? 1 : 2, + ...imageFrame, + }; + + decodePromise = decodeJPEGLS(pixelData, opts); + break; + case '1.2.840.10008.1.2.4.81': + // JPEG-LS Lossy (Near-Lossless) Image Compression + opts = { + signed: false, // imageFrame.signed, + // shouldn't need... + bytesPerPixel: imageFrame.bitsAllocated <= 8 ? 1 : 2, + ...imageFrame, + }; + + decodePromise = decodeJPEGLS(pixelData, opts); + break; + case '1.2.840.10008.1.2.4.90': + opts = { + ...imageFrame, + }; + + // JPEG 2000 Lossless + // imageFrame, pixelData, decodeConfig, options + decodePromise = decodeJPEG2000(pixelData, opts); + break; + case '1.2.840.10008.1.2.4.91': + // JPEG 2000 Lossy + opts = { + ...imageFrame, + }; + + // JPEG 2000 Lossy + // imageFrame, pixelData, decodeConfig, options + decodePromise = decodeJPEG2000(pixelData, opts); + break; + default: + throw new Error(`no decoder for transfer syntax ${transferSyntax}`); + } + + /* Don't know if these work... + // JPEG 2000 Part 2 Multicomponent Image Compression (Lossless Only) + else if(transferSyntax === "1.2.840.10008.1.2.4.92") + { + return decodeJPEG2000(dataSet, frame); + } + // JPEG 2000 Part 2 Multicomponent Image Compression + else if(transferSyntax === "1.2.840.10008.1.2.4.93") + { + return decodeJPEG2000(dataSet, frame); + } + */ + + if (!decodePromise) { + throw new Error('decodePromise not defined'); + } + + decodePromise + .then((imageFrame) => { + callbackFn(postProcessDecodedPixels(imageFrame, options, start)); + }) + .catch((err) => { + throw err; + }); +} + +function postProcessDecodedPixels(imageFrame, options, start) { + const shouldShift = + imageFrame.pixelRepresentation !== undefined && + imageFrame.pixelRepresentation === 1; + const shift = + shouldShift && imageFrame.bitsStored !== undefined + ? 32 - imageFrame.bitsStored + : undefined; + + if (shouldShift && shift !== undefined) { + for (let i = 0; i < imageFrame.pixelData.length; i++) { + // eslint-disable-next-line no-bitwise + imageFrame.pixelData[i] = (imageFrame.pixelData[i] << shift) >> shift; + } + } + + // Cache the pixelData reference quickly incase we want to set a targetBuffer _and_ scale. + let pixelDataArray = imageFrame.pixelData; + + imageFrame.pixelDataLength = imageFrame.pixelData.length; + + if (options.targetBuffer) { + let offset, length; + // If we have a target buffer, write to that instead. This helps reduce memory duplication. + + ({ offset, length } = options.targetBuffer); + const { arrayBuffer, type } = options.targetBuffer; + + let TypedArrayConstructor; + + if (offset === null || offset === undefined) { + offset = 0; + } + + if ((length === null || length === undefined) && offset !== 0) { + length = imageFrame.pixelDataLength - offset; + } else if (length === null || length === undefined) { + length = imageFrame.pixelDataLength; + } + + switch (type) { + case 'Uint8Array': + TypedArrayConstructor = Uint8Array; + break; + case 'Uint16Array': + TypedArrayConstructor = Uint16Array; + break; + case 'Float32Array': + TypedArrayConstructor = Float32Array; + break; + default: + throw new Error('target array for image does not have a valid type.'); + } + + const imageFramePixelData = imageFrame.pixelData; + + if (length !== imageFramePixelData.length) { + throw new Error( + 'target array for image does not have the same length as the decoded image length.' + ); + } + + // TypedArray.Set is api level and ~50x faster than copying elements even for + // Arrays of different types, which aren't simply memcpy ops. + let typedArray; + + if (arrayBuffer) { + typedArray = new TypedArrayConstructor(arrayBuffer, offset, length); + } else { + typedArray = new TypedArrayConstructor(length); + } + + typedArray.set(imageFramePixelData, 0); + + // If need to scale, need to scale correct array. + pixelDataArray = typedArray; + } + + if (options.preScale.enabled) { + debugger; + const scalingParameters = options.preScale.scalingParameters; + + if (!scalingParameters) { + throw new Error( + 'options.preScale.scalingParameters must be defined if preScale.enabled is true, and scalingParameters cannot be derived from the metadata providers.' + ); + } + + const { rescaleSlope, rescaleIntercept } = scalingParameters; + + if ( + typeof rescaleSlope === 'number' && + typeof rescaleIntercept === 'number' + ) { + if (scaleArray(pixelDataArray, scalingParameters)) { + imageFrame.preScale = { + ...options.preScale, + scaled: true, + }; + } + } + } + + // Handle cases where the targetBuffer is not backed by a SharedArrayBuffer + if ( + options.targetBuffer && + (!options.targetBuffer.arrayBuffer || + options.targetBuffer.arrayBuffer instanceof ArrayBuffer) + ) { + imageFrame.pixelData = pixelDataArray; + } + + const end = new Date().getTime(); + + imageFrame.decodeTimeInMS = end - start; + + return imageFrame; +} + +export default decodeImageFrame; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.js b/packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.js new file mode 100644 index 000000000..53cde8cd6 --- /dev/null +++ b/packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.js @@ -0,0 +1,36 @@ +/* eslint no-bitwise: 0 */ +function swap16(val) { + return ((val & 0xff) << 8) | ((val >> 8) & 0xff); +} + +async function decodeBigEndian(imageFrame, pixelData) { + if (imageFrame.bitsAllocated === 16) { + let arrayBuffer = pixelData.buffer; + + let offset = pixelData.byteOffset; + const length = pixelData.length; + // if pixel data is not aligned on even boundary, shift it so we can create the 16 bit array + // buffers on it + + if (offset % 2) { + arrayBuffer = arrayBuffer.slice(offset); + offset = 0; + } + + if (imageFrame.pixelRepresentation === 0) { + imageFrame.pixelData = new Uint16Array(arrayBuffer, offset, length / 2); + } else { + imageFrame.pixelData = new Int16Array(arrayBuffer, offset, length / 2); + } + // Do the byte swap + for (let i = 0; i < imageFrame.pixelData.length; i++) { + imageFrame.pixelData[i] = swap16(imageFrame.pixelData[i]); + } + } else if (imageFrame.bitsAllocated === 8) { + imageFrame.pixelData = pixelData; + } + + return imageFrame; +} + +export default decodeBigEndian; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.js new file mode 100644 index 000000000..649739f5c --- /dev/null +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.js @@ -0,0 +1,161 @@ +// https://emscripten.org/docs/api_reference/module.html +import openJpegFactory from '@cornerstonejs/codec-openjpeg/dist/openjpegwasm_decode.js'; + +// Webpack asset/resource copies this to our output folder + +// TODO: At some point maybe we can use this instead. +// This is closer to what Webpack 5 wants but it doesn't seem to work now +// const wasm = new URL('./blah.wasm', import.meta.url) +import openjpegWasm from '@cornerstonejs/codec-openjpeg/dist/openjpegwasm_decode.wasm'; + +const local = { + codec: undefined, + decoder: undefined, + decodeConfig: {}, +}; + +export function initialize(decodeConfig) { + local.decodeConfig = decodeConfig; + + if (local.codec) { + return Promise.resolve(); + } + + const openJpegModule = openJpegFactory({ + locateFile: (f) => { + if (f.endsWith('.wasm')) { + return openjpegWasm; + } + + return f; + }, + }); + + return new Promise((resolve, reject) => { + openJpegModule.then((instance) => { + local.codec = instance; + local.decoder = new instance.J2KDecoder(); + resolve(); + }, reject); + }); +} + +// https://github.com/chafey/openjpegjs/blob/master/test/browser/index.html +async function decodeAsync(compressedImageFrame, imageInfo) { + await initialize(); + const decoder = local.decoder; + + // get pointer to the source/encoded bit stream buffer in WASM memory + // that can hold the encoded bitstream + const encodedBufferInWASM = decoder.getEncodedBuffer( + compressedImageFrame.length + ); + + // copy the encoded bitstream into WASM memory buffer + encodedBufferInWASM.set(compressedImageFrame); + + // decode it + decoder.decode(); + // decoder.decodeSubResolution(decodeLevel, decodeLayer); + // const resolutionAtLevel = decoder.calculateSizeAtDecompositionLevel(decodeLevel); + + // get information about the decoded image + const frameInfo = decoder.getFrameInfo(); + // get the decoded pixels + const decodedBufferInWASM = decoder.getDecodedBuffer(); + const imageFrame = new Uint8Array(decodedBufferInWASM.length); + + imageFrame.set(decodedBufferInWASM); + + const imageOffset = `x: ${decoder.getImageOffset().x}, y: ${ + decoder.getImageOffset().y + }`; + const numDecompositions = decoder.getNumDecompositions(); + const numLayers = decoder.getNumLayers(); + const progessionOrder = ['unknown', 'LRCP', 'RLCP', 'RPCL', 'PCRL', 'CPRL'][ + decoder.getProgressionOrder() + 1 + ]; + const reversible = decoder.getIsReversible(); + const blockDimensions = `${decoder.getBlockDimensions().width} x ${ + decoder.getBlockDimensions().height + }`; + const tileSize = `${decoder.getTileSize().width} x ${ + decoder.getTileSize().height + }`; + const tileOffset = `${decoder.getTileOffset().x}, ${ + decoder.getTileOffset().y + }`; + const colorTransform = decoder.getColorSpace(); + + const decodedSize = `${decodedBufferInWASM.length.toLocaleString()} bytes`; + const compressionRatio = `${( + decodedBufferInWASM.length / encodedBufferInWASM.length + ).toFixed(2)}:1`; + + const encodedImageInfo = { + columns: frameInfo.width, + rows: frameInfo.height, + bitsPerPixel: frameInfo.bitsPerSample, + signed: frameInfo.isSigned, + bytesPerPixel: imageInfo.bytesPerPixel, + componentsPerPixel: frameInfo.componentCount, + }; + const pixelData = getPixelData(frameInfo, decodedBufferInWASM); + + const encodeOptions = { + imageOffset, + numDecompositions, + numLayers, + progessionOrder, + reversible, + blockDimensions, + tileSize, + tileOffset, + colorTransform, + decodedSize, + compressionRatio, + }; + + return { + ...imageInfo, + pixelData, + imageInfo: encodedImageInfo, + encodeOptions, + ...encodeOptions, + ...encodedImageInfo, + }; +} + +function getPixelData(frameInfo, decodedBuffer) { + if (frameInfo.bitsPerSample > 8) { + if (frameInfo.isSigned) { + return new Int16Array( + decodedBuffer.buffer, + decodedBuffer.byteOffset, + decodedBuffer.byteLength / 2 + ); + } + + return new Uint16Array( + decodedBuffer.buffer, + decodedBuffer.byteOffset, + decodedBuffer.byteLength / 2 + ); + } + + if (frameInfo.isSigned) { + return new Int8Array( + decodedBuffer.buffer, + decodedBuffer.byteOffset, + decodedBuffer.byteLength + ); + } + + return new Uint8Array( + decodedBuffer.buffer, + decodedBuffer.byteOffset, + decodedBuffer.byteLength + ); +} + +export default decodeAsync; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.js new file mode 100644 index 000000000..28659544f --- /dev/null +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.js @@ -0,0 +1,46 @@ +const local = { + JpegImage: undefined, + decodeConfig: {}, +}; + +export function initialize(decodeConfig) { + local.decodeConfig = decodeConfig; + + if (local.JpegImage) { + return Promise.resolve(); + } + + return new Promise((resolve, reject) => { + import('../../../codecs/jpeg.js').then(({ JpegImage }) => { + local.JpegImage = JpegImage; + resolve(); + }, reject); + }); +} + +async function decodeJPEGBaseline12BitAsync(imageFrame, pixelData) { + // check to make sure codec is loaded + await initialize(); + if (typeof local.JpegImage === 'undefined') { + throw new Error('No JPEG Baseline decoder loaded'); + } + const jpeg = new local.JpegImage(); + + jpeg.parse(pixelData); + + // Do not use the internal jpeg.js color transformation, + // since we will handle this afterwards + jpeg.colorTransform = false; + + if (imageFrame.bitsAllocated === 8) { + imageFrame.pixelData = jpeg.getData(imageFrame.columns, imageFrame.rows); + + return imageFrame; + } else if (imageFrame.bitsAllocated === 16) { + imageFrame.pixelData = jpeg.getData16(imageFrame.columns, imageFrame.rows); + + return imageFrame; + } +} + +export default decodeJPEGBaseline12BitAsync; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-wasm-not-yet-working.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-wasm-not-yet-working.js new file mode 100644 index 000000000..ee680f640 --- /dev/null +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-wasm-not-yet-working.js @@ -0,0 +1,105 @@ +import libjpegTurbo12Factory from '@cornerstonejs/codec-libjpeg-turbo-12bit/dist/libjpegturbo12wasm.js'; + +// Webpack asset/resource copies this to our output folder +import libjpegTurbo12Wasm from '@cornerstonejs/codec-libjpeg-turbo-12bit/dist/libjpegturbo12wasm.wasm'; + +const local = { + codec: undefined, + decoder: undefined, +}; + +function initLibjpegTurbo() { + if (local.codec) { + return Promise.resolve(); + } + + const libjpegTurboModule = libjpegTurbo12Factory({ + locateFile: (f) => { + if (f.endsWith('.wasm')) { + return libjpegTurbo12Wasm; + } + + return f; + }, + }); + + return new Promise((resolve, reject) => { + libjpegTurboModule.then((instance) => { + local.codec = instance; + local.decoder = new instance.JPEGDecoder(); + resolve(); + }, reject); + }); +} + +// imageFrame.pixelRepresentation === 1 <-- Signed +/** + * + * @param {*} compressedImageFrame + * @param {object} imageInfo + * @param {boolean} imageInfo.signed - + */ +async function decodeAsync(compressedImageFrame, imageInfo) { + await initLibjpegTurbo(); + const decoder = local.decoder; + + // get pointer to the source/encoded bit stream buffer in WASM memory + // that can hold the encoded bitstream + const encodedBufferInWASM = decoder.getEncodedBuffer( + compressedImageFrame.length + ); + + // copy the encoded bitstream into WASM memory buffer + encodedBufferInWASM.set(compressedImageFrame); + + // decode it + decoder.decode(); + + // get information about the decoded image + const frameInfo = decoder.getFrameInfo(); + + // get the decoded pixels + const decodedPixelsInWASM = decoder.getDecodedBuffer(); + + const encodedImageInfo = { + columns: frameInfo.width, + rows: frameInfo.height, + bitsPerPixel: frameInfo.bitsPerSample, + signed: imageInfo.signed, + bytesPerPixel: imageInfo.bytesPerPixel, + componentsPerPixel: frameInfo.componentCount, + }; + + const pixelData = getPixelData(frameInfo, decodedPixelsInWASM); + + const encodeOptions = { + frameInfo, + }; + + return { + ...imageInfo, + pixelData, + imageInfo: encodedImageInfo, + encodeOptions, + ...encodeOptions, + ...encodedImageInfo, + }; +} + +function getPixelData(frameInfo, decodedBuffer) { + if (frameInfo.isSigned) { + return new Int16Array( + decodedBuffer.buffer, + decodedBuffer.byteOffset, + decodedBuffer.byteLength / 2 + ); + } + + return new Uint16Array( + decodedBuffer.buffer, + decodedBuffer.byteOffset, + decodedBuffer.byteLength / 2 + ); +} + +export default decodeAsync; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.js new file mode 100644 index 000000000..9bf4d8b6c --- /dev/null +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.js @@ -0,0 +1,105 @@ +import libjpegTurboFactory from '@cornerstonejs/codec-libjpeg-turbo-8bit/dist/libjpegturbowasm_decode.js'; + +// Webpack asset/resource copies this to our output folder +import libjpegTurboWasm from '@cornerstonejs/codec-libjpeg-turbo-8bit/dist/libjpegturbowasm_decode.wasm'; + +const local = { + codec: undefined, + decoder: undefined, +}; + +function initLibjpegTurbo() { + if (local.codec) { + return Promise.resolve(); + } + + const libjpegTurboModule = libjpegTurboFactory({ + locateFile: (f) => { + if (f.endsWith('.wasm')) { + return libjpegTurboWasm; + } + + return f; + }, + }); + + return new Promise((resolve, reject) => { + libjpegTurboModule.then((instance) => { + local.codec = instance; + local.decoder = new instance.JPEGDecoder(); + resolve(); + }, reject); + }); +} + +// imageFrame.pixelRepresentation === 1 <-- Signed +/** + * + * @param {*} compressedImageFrame + * @param {object} imageInfo + * @param {boolean} imageInfo.signed - + */ +async function decodeAsync(compressedImageFrame, imageInfo) { + await initLibjpegTurbo(); + const decoder = local.decoder; + + // get pointer to the source/encoded bit stream buffer in WASM memory + // that can hold the encoded bitstream + const encodedBufferInWASM = decoder.getEncodedBuffer( + compressedImageFrame.length + ); + + // copy the encoded bitstream into WASM memory buffer + encodedBufferInWASM.set(compressedImageFrame); + + // decode it + decoder.decode(); + + // get information about the decoded image + const frameInfo = decoder.getFrameInfo(); + + // get the decoded pixels + const decodedPixelsInWASM = decoder.getDecodedBuffer(); + + const encodedImageInfo = { + columns: frameInfo.width, + rows: frameInfo.height, + bitsPerPixel: frameInfo.bitsPerSample, + signed: imageInfo.signed, + bytesPerPixel: imageInfo.bytesPerPixel, + componentsPerPixel: frameInfo.componentCount, + }; + + const pixelData = getPixelData(frameInfo, decodedPixelsInWASM); + + const encodeOptions = { + frameInfo, + }; + + return { + ...imageInfo, + pixelData, + imageInfo: encodedImageInfo, + encodeOptions, + ...encodeOptions, + ...encodedImageInfo, + }; +} + +function getPixelData(frameInfo, decodedBuffer) { + if (frameInfo.isSigned) { + return new Int8Array( + decodedBuffer.buffer, + decodedBuffer.byteOffset, + decodedBuffer.byteLength + ); + } + + return new Uint8Array( + decodedBuffer.buffer, + decodedBuffer.byteOffset, + decodedBuffer.byteLength + ); +} + +export default decodeAsync; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.js new file mode 100644 index 000000000..111f69578 --- /dev/null +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.js @@ -0,0 +1,148 @@ +import charlsFactory from '@cornerstonejs/codec-charls/dist/charlswasm_decode.js'; +// import charlsFactory from '@cornerstonejs/codec-charls/dist/debug/charlswasm.js'; + +// Webpack asset/resource copies this to our output folder +import charlsWasm from '@cornerstonejs/codec-charls/dist/charlswasm_decode.wasm'; +// import charlsWasm from '@cornerstonejs/codec-charls/dist/debug/charlswasm.wasm'; + +const local = { + codec: undefined, + decoder: undefined, + decodeConfig: {}, +}; + +function getExceptionMessage(exception) { + return typeof exception === 'number' + ? local.codec.getExceptionMessage(exception) + : exception; +} + +export function initialize(decodeConfig) { + local.decodeConfig = decodeConfig; + + if (local.codec) { + return Promise.resolve(); + } + + const charlsModule = charlsFactory({ + locateFile: (f) => { + if (f.endsWith('.wasm')) { + return charlsWasm; + } + + return f; + }, + }); + + return new Promise((resolve, reject) => { + charlsModule.then((instance) => { + local.codec = instance; + local.decoder = new instance.JpegLSDecoder(); + resolve(); + }, reject); + }); +} + +/** + * + * @param {*} compressedImageFrame + * @param {object} imageInfo + * @param {boolean} imageInfo.signed - (pixelRepresentation === 1) + */ +async function decodeAsync(compressedImageFrame, imageInfo) { + try { + await initialize(); + const decoder = local.decoder; + + // get pointer to the source/encoded bit stream buffer in WASM memory + // that can hold the encoded bitstream + const encodedBufferInWASM = decoder.getEncodedBuffer( + compressedImageFrame.length + ); + + // copy the encoded bitstream into WASM memory buffer + encodedBufferInWASM.set(compressedImageFrame); + + // decode it + decoder.decode(); + + // get information about the decoded image + const frameInfo = decoder.getFrameInfo(); + const interleaveMode = decoder.getInterleaveMode(); + const nearLossless = decoder.getNearLossless(); + + // get the decoded pixels + const decodedPixelsInWASM = decoder.getDecodedBuffer(); + + const encodedImageInfo = { + columns: frameInfo.width, + rows: frameInfo.height, + bitsPerPixel: frameInfo.bitsPerSample, + signed: imageInfo.signed, + bytesPerPixel: imageInfo.bytesPerPixel, + componentsPerPixel: frameInfo.componentCount, + }; + + const pixelData = getPixelData( + frameInfo, + decodedPixelsInWASM, + imageInfo.signed + ); + + const encodeOptions = { + nearLossless, + interleaveMode, + frameInfo, + }; + + // local.codec.doLeakCheck(); + + return { + ...imageInfo, + pixelData, + imageInfo: encodedImageInfo, + encodeOptions, + ...encodeOptions, + ...encodedImageInfo, + }; + } catch (error) { + // Handle cases where WASM throws an error internally, and it only gives JS a number + // See https://emscripten.org/docs/porting/Debugging.html#handling-c-exceptions-from-javascript + // TODO: Copy to other codecs as well + throw getExceptionMessage(error); + } +} + +function getPixelData(frameInfo, decodedBuffer, signed) { + if (frameInfo.bitsPerSample > 8) { + if (signed) { + return new Int16Array( + decodedBuffer.buffer, + decodedBuffer.byteOffset, + decodedBuffer.byteLength / 2 + ); + } + + return new Uint16Array( + decodedBuffer.buffer, + decodedBuffer.byteOffset, + decodedBuffer.byteLength / 2 + ); + } + + if (signed) { + return new Int8Array( + decodedBuffer.buffer, + decodedBuffer.byteOffset, + decodedBuffer.byteLength + ); + } + + return new Uint8Array( + decodedBuffer.buffer, + decodedBuffer.byteOffset, + decodedBuffer.byteLength + ); +} + +export default decodeAsync; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.js new file mode 100644 index 000000000..4d6df6c42 --- /dev/null +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.js @@ -0,0 +1,61 @@ +const local = { + jpeg: undefined, + decodeConfig: {}, +}; + +export function initialize(decodeConfig) { + local.decodeConfig = decodeConfig; + + if (local.jpeg) { + return Promise.resolve(); + } + + return new Promise((resolve, reject) => { + import('../../../codecs/jpegLossless.js').then((jpeg) => { + local.jpeg = jpeg; + resolve(); + }, reject); + }); +} + +async function decodeJPEGLossless(imageFrame, pixelData) { + await initialize(); + + // check to make sure codec is loaded + if ( + typeof local.jpeg === 'undefined' || + typeof local.jpeg.lossless === 'undefined' || + typeof local.jpeg.lossless.Decoder === 'undefined' + ) { + throw new Error('No JPEG Lossless decoder loaded'); + } + + const byteOutput = imageFrame.bitsAllocated <= 8 ? 1 : 2; + // console.time('jpeglossless'); + const buffer = pixelData.buffer; + const decoder = new local.jpeg.lossless.Decoder(); + const decompressedData = decoder.decode( + buffer, + pixelData.byteOffset, + pixelData.length, + byteOutput + ); + // console.timeEnd('jpeglossless'); + + if (imageFrame.pixelRepresentation === 0) { + if (imageFrame.bitsAllocated === 16) { + imageFrame.pixelData = new Uint16Array(decompressedData.buffer); + + return imageFrame; + } + // untested! + imageFrame.pixelData = new Uint8Array(decompressedData.buffer); + + return imageFrame; + } + imageFrame.pixelData = new Int16Array(decompressedData.buffer); + + return imageFrame; +} + +export default decodeJPEGLossless; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.js b/packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.js new file mode 100644 index 000000000..0930d8248 --- /dev/null +++ b/packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.js @@ -0,0 +1,35 @@ +async function decodeLittleEndian(imageFrame, pixelData) { + let arrayBuffer = pixelData.buffer; + + let offset = pixelData.byteOffset; + const length = pixelData.length; + + if (imageFrame.bitsAllocated === 16) { + // if pixel data is not aligned on even boundary, shift it so we can create the 16 bit array + // buffers on it + if (offset % 2) { + arrayBuffer = arrayBuffer.slice(offset); + offset = 0; + } + + if (imageFrame.pixelRepresentation === 0) { + imageFrame.pixelData = new Uint16Array(arrayBuffer, offset, length / 2); + } else { + imageFrame.pixelData = new Int16Array(arrayBuffer, offset, length / 2); + } + } else if (imageFrame.bitsAllocated === 8 || imageFrame.bitsAllocated === 1) { + imageFrame.pixelData = pixelData; + } else if (imageFrame.bitsAllocated === 32) { + // if pixel data is not aligned on even boundary, shift it + if (offset % 2) { + arrayBuffer = arrayBuffer.slice(offset); + offset = 0; + } + + imageFrame.pixelData = new Float32Array(arrayBuffer, offset, length / 4); + } + + return imageFrame; +} + +export default decodeLittleEndian; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeRLE.js b/packages/dicom-image-loader/src/shared/decoders/decodeRLE.js new file mode 100644 index 000000000..204bbb965 --- /dev/null +++ b/packages/dicom-image-loader/src/shared/decoders/decodeRLE.js @@ -0,0 +1,169 @@ +async function decodeRLE(imageFrame, pixelData) { + if (imageFrame.bitsAllocated === 8) { + if (imageFrame.planarConfiguration) { + return decode8Planar(imageFrame, pixelData); + } + + return decode8(imageFrame, pixelData); + } else if (imageFrame.bitsAllocated === 16) { + return decode16(imageFrame, pixelData); + } + + throw new Error('unsupported pixel format for RLE'); +} + +function decode8(imageFrame, pixelData) { + const frameData = pixelData; + const frameSize = imageFrame.rows * imageFrame.columns; + const outFrame = new ArrayBuffer(frameSize * imageFrame.samplesPerPixel); + const header = new DataView(frameData.buffer, frameData.byteOffset); + const data = new Int8Array(frameData.buffer, frameData.byteOffset); + const out = new Int8Array(outFrame); + + let outIndex = 0; + const numSegments = header.getInt32(0, true); + + for (let s = 0; s < numSegments; ++s) { + outIndex = s; + + let inIndex = header.getInt32((s + 1) * 4, true); + + let maxIndex = header.getInt32((s + 2) * 4, true); + + if (maxIndex === 0) { + maxIndex = frameData.length; + } + + const endOfSegment = frameSize * numSegments; + + while (inIndex < maxIndex) { + const n = data[inIndex++]; + + if (n >= 0 && n <= 127) { + // copy n bytes + for (let i = 0; i < n + 1 && outIndex < endOfSegment; ++i) { + out[outIndex] = data[inIndex++]; + outIndex += imageFrame.samplesPerPixel; + } + } else if (n <= -1 && n >= -127) { + const value = data[inIndex++]; + // run of n bytes + + for (let j = 0; j < -n + 1 && outIndex < endOfSegment; ++j) { + out[outIndex] = value; + outIndex += imageFrame.samplesPerPixel; + } + } /* else if (n === -128) { + + } // do nothing */ + } + } + imageFrame.pixelData = new Uint8Array(outFrame); + + return imageFrame; +} + +function decode8Planar(imageFrame, pixelData) { + const frameData = pixelData; + const frameSize = imageFrame.rows * imageFrame.columns; + const outFrame = new ArrayBuffer(frameSize * imageFrame.samplesPerPixel); + const header = new DataView(frameData.buffer, frameData.byteOffset); + const data = new Int8Array(frameData.buffer, frameData.byteOffset); + const out = new Int8Array(outFrame); + + let outIndex = 0; + const numSegments = header.getInt32(0, true); + + for (let s = 0; s < numSegments; ++s) { + outIndex = s * frameSize; + + let inIndex = header.getInt32((s + 1) * 4, true); + + let maxIndex = header.getInt32((s + 2) * 4, true); + + if (maxIndex === 0) { + maxIndex = frameData.length; + } + + const endOfSegment = frameSize * numSegments; + + while (inIndex < maxIndex) { + const n = data[inIndex++]; + + if (n >= 0 && n <= 127) { + // copy n bytes + for (let i = 0; i < n + 1 && outIndex < endOfSegment; ++i) { + out[outIndex] = data[inIndex++]; + outIndex++; + } + } else if (n <= -1 && n >= -127) { + const value = data[inIndex++]; + // run of n bytes + + for (let j = 0; j < -n + 1 && outIndex < endOfSegment; ++j) { + out[outIndex] = value; + outIndex++; + } + } /* else if (n === -128) { + + } // do nothing */ + } + } + imageFrame.pixelData = new Uint8Array(outFrame); + + return imageFrame; +} + +function decode16(imageFrame, pixelData) { + const frameData = pixelData; + const frameSize = imageFrame.rows * imageFrame.columns; + const outFrame = new ArrayBuffer(frameSize * imageFrame.samplesPerPixel * 2); + + const header = new DataView(frameData.buffer, frameData.byteOffset); + const data = new Int8Array(frameData.buffer, frameData.byteOffset); + const out = new Int8Array(outFrame); + + const numSegments = header.getInt32(0, true); + + for (let s = 0; s < numSegments; ++s) { + let outIndex = 0; + const highByte = s === 0 ? 1 : 0; + + let inIndex = header.getInt32((s + 1) * 4, true); + + let maxIndex = header.getInt32((s + 2) * 4, true); + + if (maxIndex === 0) { + maxIndex = frameData.length; + } + + while (inIndex < maxIndex) { + const n = data[inIndex++]; + + if (n >= 0 && n <= 127) { + for (let i = 0; i < n + 1 && outIndex < frameSize; ++i) { + out[outIndex * 2 + highByte] = data[inIndex++]; + outIndex++; + } + } else if (n <= -1 && n >= -127) { + const value = data[inIndex++]; + + for (let j = 0; j < -n + 1 && outIndex < frameSize; ++j) { + out[outIndex * 2 + highByte] = value; + outIndex++; + } + } /* else if (n === -128) { + + } // do nothing */ + } + } + if (imageFrame.pixelRepresentation === 0) { + imageFrame.pixelData = new Uint16Array(outFrame); + } else { + imageFrame.pixelData = new Int16Array(outFrame); + } + + return imageFrame; +} + +export default decodeRLE; diff --git a/packages/dicom-image-loader/src/shared/getMinMax.js b/packages/dicom-image-loader/src/shared/getMinMax.js new file mode 100644 index 000000000..a3d727399 --- /dev/null +++ b/packages/dicom-image-loader/src/shared/getMinMax.js @@ -0,0 +1,30 @@ +/** + * Calculate the minimum and maximum values in an Array + * + * @param {Number[]} storedPixelData + * @return {{min: Number, max: Number}} + */ +function getMinMax(storedPixelData) { + // we always calculate the min max values since they are not always + // present in DICOM and we don't want to trust them anyway as cornerstone + // depends on us providing reliable values for these + let min = storedPixelData[0]; + + let max = storedPixelData[0]; + + let storedPixel; + const numPixels = storedPixelData.length; + + for (let index = 1; index < numPixels; index++) { + storedPixel = storedPixelData[index]; + min = Math.min(min, storedPixel); + max = Math.max(max, storedPixel); + } + + return { + min, + max, + }; +} + +export default getMinMax; diff --git a/packages/dicom-image-loader/src/shared/getMinMax_test.js b/packages/dicom-image-loader/src/shared/getMinMax_test.js new file mode 100644 index 000000000..42ba8a3ec --- /dev/null +++ b/packages/dicom-image-loader/src/shared/getMinMax_test.js @@ -0,0 +1,11 @@ +import { expect } from 'chai'; +import getMinMax from './getMinMax.js'; + +describe('#getMinMax', () => { + it('should return the right min and max values', () => { + const result = getMinMax([7, 3, 9, 6, 8, 1, 4, 5, 2]); + + expect(result.min).to.be.equal(1); + expect(result.max).to.be.equal(9); + }); +}); diff --git a/packages/dicom-image-loader/src/shared/scaling/scaleArray.js b/packages/dicom-image-loader/src/shared/scaling/scaleArray.js new file mode 100644 index 000000000..545ef7879 --- /dev/null +++ b/packages/dicom-image-loader/src/shared/scaling/scaleArray.js @@ -0,0 +1,20 @@ +export default function scaleArray(array, scalingParameters) { + const arrayLength = array.length; + const { rescaleSlope, rescaleIntercept, suvbw } = scalingParameters; + + if (scalingParameters.modality === 'PT') { + if (typeof suvbw !== 'number') { + return; + } + + for (let i = 0; i < arrayLength; i++) { + array[i] = suvbw * (array[i] * rescaleSlope + rescaleIntercept); + } + } else { + for (let i = 0; i < arrayLength; i++) { + array[i] = array[i] * rescaleSlope + rescaleIntercept; + } + } + + return true; +} diff --git a/packages/dicom-image-loader/src/webWorker/decodeTask.js b/packages/dicom-image-loader/src/webWorker/decodeTask.js new file mode 100644 index 000000000..88a0ecb34 --- /dev/null +++ b/packages/dicom-image-loader/src/webWorker/decodeTask.js @@ -0,0 +1,81 @@ +import { initialize as initializeJPEG2000 } from '../shared/decoders/decodeJPEG2000.js'; +import { initialize as initializeJPEGLS } from '../shared/decoders/decodeJPEGLS.js'; +import calculateMinMax from '../shared/calculateMinMax.js'; +import decodeImageFrame from '../shared/decodeImageFrame.js'; + +// the configuration object for the decodeTask +let decodeConfig; + +/** + * Function to control loading and initializing the codecs + * @param config + */ +function loadCodecs(config) { + // Initialize the codecs + if (config.decodeTask.initializeCodecsOnStartup) { + initializeJPEG2000(config.decodeTask); + initializeJPEGLS(config.decodeTask); + } +} + +/** + * Task initialization function + */ +function initialize(config) { + decodeConfig = config; + + loadCodecs(config); +} + +/** + * Task handler function + */ +function handler(data, doneCallback) { + // Load the codecs if they aren't already loaded + loadCodecs(decodeConfig); + + const strict = + decodeConfig && decodeConfig.decodeTask && decodeConfig.decodeTask.strict; + + // convert pixel data from ArrayBuffer to Uint8Array since web workers support passing ArrayBuffers but + // not typed arrays + const pixelData = new Uint8Array(data.data.pixelData); + + // TODO switch to promise + function finishedCallback(imageFrame) { + if (!imageFrame.pixelData) { + throw new Error( + 'decodeTask: imageFrame.pixelData is undefined after decoding' + ); + } + + calculateMinMax(imageFrame, strict); + + // convert from TypedArray to ArrayBuffer since web workers support passing ArrayBuffers but not + // typed arrays + imageFrame.pixelData = imageFrame.pixelData.buffer; + + // invoke the callback with our result and pass the pixelData in the transferList to move it to + // UI thread without making a copy + + // ONLY USING setTIMEOUT for TESTING>.. REMOVE THIS + // setTimeout(() => { + doneCallback(imageFrame, [imageFrame.pixelData]); + // }, 100); + } + + decodeImageFrame( + data.data.imageFrame, + data.data.transferSyntax, + pixelData, + decodeConfig.decodeTask, + data.data.options, + finishedCallback + ); +} + +export default { + taskType: 'decodeTask', + handler, + initialize, +}; diff --git a/packages/dicom-image-loader/src/webWorker/index.worker.js b/packages/dicom-image-loader/src/webWorker/index.worker.js new file mode 100644 index 000000000..f693e1310 --- /dev/null +++ b/packages/dicom-image-loader/src/webWorker/index.worker.js @@ -0,0 +1,13 @@ +import { registerTaskHandler } from './webWorker.js'; +import decodeTask from './decodeTask.js'; + +// register our task +registerTaskHandler(decodeTask); + +const cornerstoneWADOImageLoaderWebWorker = { + registerTaskHandler, +}; + +export { registerTaskHandler }; + +export default cornerstoneWADOImageLoaderWebWorker; diff --git a/packages/dicom-image-loader/src/webWorker/webWorker.js b/packages/dicom-image-loader/src/webWorker/webWorker.js new file mode 100644 index 000000000..fc2bd20ab --- /dev/null +++ b/packages/dicom-image-loader/src/webWorker/webWorker.js @@ -0,0 +1,145 @@ +// an object of task handlers +const taskHandlers = {}; + +// Flag to ensure web worker is only initialized once +let initialized = false; + +// the configuration object passed in when the web worker manager is initialized +let config; + +/** + * Initialization function that loads additional web workers and initializes them + * @param data + */ +function initialize(data) { + // console.log('web worker initialize ', data.workerIndex); + // prevent initialization from happening more than once + if (initialized) { + return; + } + + // save the config data + config = data.config; + + // Additional web worker tasks can self-register by calling self.registerTaskHandler + self.registerTaskHandler = registerTaskHandler; + + // load any additional web worker tasks + if (data.config.webWorkerTaskPaths) { + for (let i = 0; i < data.config.webWorkerTaskPaths.length; i++) { + self.importScripts(data.config.webWorkerTaskPaths[i]); + } + } + + // initialize each task handler + Object.keys(taskHandlers).forEach(function (key) { + taskHandlers[key].initialize(config.taskConfiguration); + }); + + // tell main ui thread that we have completed initialization + self.postMessage({ + taskType: 'initialize', + status: 'success', + result: {}, + workerIndex: data.workerIndex, + }); + + initialized = true; +} + +/** + * Function exposed to web worker tasks to register themselves + * @param taskHandler + */ +export function registerTaskHandler(taskHandler) { + if (taskHandlers[taskHandler.taskType]) { + console.log( + 'attempt to register duplicate task handler "', + taskHandler.taskType, + '"' + ); + + return false; + } + taskHandlers[taskHandler.taskType] = taskHandler; + if (initialized) { + taskHandler.initialize(config.taskConfiguration); + } +} + +/** + * Function to load a new web worker task with updated configuration + * @param data + */ +function loadWebWorkerTask(data) { + config = data.config; + self.importScripts(data.sourcePath); +} + +/** + * Web worker message handler - dispatches messages to the registered task handlers + * @param msg + */ +self.onmessage = function (msg) { + if (!msg.data.taskType) { + console.log(msg.data); + + return; + } + + // console.log('web worker onmessage', msg.data); + + // handle initialize message + if (msg.data.taskType === 'initialize') { + initialize(msg.data); + + return; + } + + // handle loadWebWorkerTask message + if (msg.data.taskType === 'loadWebWorkerTask') { + loadWebWorkerTask(msg.data); + + return; + } + + // dispatch the message if there is a handler registered for it + if (taskHandlers[msg.data.taskType]) { + try { + taskHandlers[msg.data.taskType].handler( + msg.data, + function (result, transferList) { + self.postMessage( + { + taskType: msg.data.taskType, + status: 'success', + result, + workerIndex: msg.data.workerIndex, + }, + transferList + ); + } + ); + } catch (error) { + console.log(`task ${msg.data.taskType} failed - ${error.message}`); + self.postMessage({ + taskType: msg.data.taskType, + status: 'failed', + result: error.message, + workerIndex: msg.data.workerIndex, + }); + } + + return; + } + + // not task handler registered - send a failure message back to ui thread + console.log('no task handler for ', msg.data.taskType); + console.log(taskHandlers); + + self.postMessage({ + taskType: msg.data.taskType, + status: 'failed - no task handler registered', + workerIndex: msg.data.workerIndex, + }); +}; diff --git a/packages/dicom-image-loader/tsconfig.cjs.json b/packages/dicom-image-loader/tsconfig.cjs.json new file mode 100644 index 000000000..aebe09c10 --- /dev/null +++ b/packages/dicom-image-loader/tsconfig.cjs.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.cjs.json", + "compilerOptions": { + "outDir": "./dist/cjs" + }, + "include": ["src"] +} diff --git a/packages/dicom-image-loader/tsconfig.esm.json b/packages/dicom-image-loader/tsconfig.esm.json new file mode 100644 index 000000000..cc9297119 --- /dev/null +++ b/packages/dicom-image-loader/tsconfig.esm.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.esm.json", + "compilerOptions": { + "outDir": "./dist/esm" + }, + "include": ["src"] +} diff --git a/packages/dicom-image-loader/tsconfig.json b/packages/dicom-image-loader/tsconfig.json new file mode 100644 index 000000000..b29a7b46c --- /dev/null +++ b/packages/dicom-image-loader/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": {} +} diff --git a/packages/docs/package.json b/packages/docs/package.json index ef586868f..d928103ab 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -38,7 +38,7 @@ "@mdx-js/react": "^1.6.21", "@svgr/webpack": "^6.2.1", "clsx": "^1.1.1", - "cornerstone-wado-image-loader": "^4.2.1", + "@cornerstonejs/dicom-image-loader": "^0.1.1", "dcmjs": "0.19.2", "detect-gpu": "^4.0.45", "dicom-parser": "^1.8.11", diff --git a/packages/docs/webpackConfigurationPlugin.js b/packages/docs/webpackConfigurationPlugin.js index d572b1e00..125cac22d 100644 --- a/packages/docs/webpackConfigurationPlugin.js +++ b/packages/docs/webpackConfigurationPlugin.js @@ -41,7 +41,7 @@ const CopyPlugin = require('copy-webpack-plugin'); // ), // // We use this alias and the CopyPlugin to support using the dynamic-import version // // of WADO Image Loader -// 'cornerstone-wado-image-loader': 'cornerstone-wado-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js', +// ''@cornerstonejs/dicom-image-loader'': 'cornerstone-wado-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js', // }, // }, // devServer: { diff --git a/packages/streaming-image-volume-loader/.webpack/webpack.dev.js b/packages/streaming-image-volume-loader/.webpack/webpack.dev.js index 9ba31e870..a20fea2a3 100644 --- a/packages/streaming-image-volume-loader/.webpack/webpack.dev.js +++ b/packages/streaming-image-volume-loader/.webpack/webpack.dev.js @@ -1,8 +1,36 @@ +const { merge } = require('webpack-merge'); const path = require('path'); const webpackCommon = require('./../../../.webpack/webpack.common.js'); const SRC_DIR = path.join(__dirname, '../src'); const DIST_DIR = path.join(__dirname, '../dist'); module.exports = (env, argv) => { - return webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); + const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); + + return merge(commonConfig, { + devtool: 'source-map', + entry: { + lib: path.join(__dirname, '../src/index.ts'), + }, + output: { + path: path.join(__dirname, '../dist/umd'), + library: 'cornerstone3D', + libraryTarget: 'umd', + filename: 'index.js', + }, + stats: { + colors: true, + hash: true, + timings: true, + assets: true, + chunks: false, + chunkModules: false, + modules: false, + children: false, + warnings: true, + }, + optimization: { + minimize: false, + }, + }); }; diff --git a/packages/streaming-image-volume-loader/package.json b/packages/streaming-image-volume-loader/package.json index 335ffe25a..c57687ca7 100644 --- a/packages/streaming-image-volume-loader/package.json +++ b/packages/streaming-image-volume-loader/package.json @@ -27,14 +27,14 @@ }, "dependencies": { "@cornerstonejs/core": "^0.21.4", - "cornerstone-wado-image-loader": "^4.2.1" + "@cornerstonejs/dicom-image-loader": "^0.1.1" }, "peerDependencies": { "@cornerstonejs/calculate-suv": "1.0.2" }, "devDependencies": { "@cornerstonejs/calculate-suv": "1.0.2", - "cornerstone-wado-image-loader": "^4.2.1" + "@cornerstonejs/dicom-image-loader": "^0.1.1" }, "contributors": [ { diff --git a/packages/streaming-image-volume-loader/src/sharedArrayBufferImageLoader.ts b/packages/streaming-image-volume-loader/src/sharedArrayBufferImageLoader.ts index e6365286a..cf37d8ae1 100644 --- a/packages/streaming-image-volume-loader/src/sharedArrayBufferImageLoader.ts +++ b/packages/streaming-image-volume-loader/src/sharedArrayBufferImageLoader.ts @@ -4,7 +4,7 @@ import { decodeImageFrame, getImageFrame, external, -} from 'cornerstone-wado-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js'; +} from '@cornerstonejs/dicom-image-loader'; function getImageRetrievalPool() { return external.cornerstone.imageRetrievalPoolManager; diff --git a/packages/tools/.webpack/webpack.dev.js b/packages/tools/.webpack/webpack.dev.js index 9ba31e870..a20fea2a3 100644 --- a/packages/tools/.webpack/webpack.dev.js +++ b/packages/tools/.webpack/webpack.dev.js @@ -1,8 +1,36 @@ +const { merge } = require('webpack-merge'); const path = require('path'); const webpackCommon = require('./../../../.webpack/webpack.common.js'); const SRC_DIR = path.join(__dirname, '../src'); const DIST_DIR = path.join(__dirname, '../dist'); module.exports = (env, argv) => { - return webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); + const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); + + return merge(commonConfig, { + devtool: 'source-map', + entry: { + lib: path.join(__dirname, '../src/index.ts'), + }, + output: { + path: path.join(__dirname, '../dist/umd'), + library: 'cornerstone3D', + libraryTarget: 'umd', + filename: 'index.js', + }, + stats: { + colors: true, + hash: true, + timings: true, + assets: true, + chunks: false, + chunkModules: false, + modules: false, + children: false, + warnings: true, + }, + optimization: { + minimize: false, + }, + }); }; diff --git a/packages/tools/examples/local/index.ts b/packages/tools/examples/local/index.ts index e830ca5a5..51171fc5e 100644 --- a/packages/tools/examples/local/index.ts +++ b/packages/tools/examples/local/index.ts @@ -1,5 +1,5 @@ import { RenderingEngine, Types, Enums, metaData } from '@cornerstonejs/core'; -import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader'; +import cornerstoneWADOImageLoader from '@cornerstonejs/dicom-image-loader'; import * as cornerstoneTools from '@cornerstonejs/tools'; import htmlSetup from './htmlSetup'; import uids from './uids'; diff --git a/packages/tools/examples/localCPU/index.ts b/packages/tools/examples/localCPU/index.ts index bc3dc20a5..9b089f74e 100644 --- a/packages/tools/examples/localCPU/index.ts +++ b/packages/tools/examples/localCPU/index.ts @@ -1,5 +1,5 @@ import { RenderingEngine, Types, Enums, metaData } from '@cornerstonejs/core'; -import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader'; +import cornerstoneWADOImageLoader from '@cornerstonejs/dicom-image-loader'; import * as cornerstoneTools from '@cornerstonejs/tools'; import htmlSetup from '../local/htmlSetup'; import uids from '../local/uids'; diff --git a/packages/tools/examples/volumeAnnotationTools/index.ts b/packages/tools/examples/volumeAnnotationTools/index.ts index 38ad06ce0..4e5f21c18 100644 --- a/packages/tools/examples/volumeAnnotationTools/index.ts +++ b/packages/tools/examples/volumeAnnotationTools/index.ts @@ -122,10 +122,10 @@ async function run() { // Get Cornerstone imageIds and fetch metadata into RAM const imageIds = await createImageIdsAndCacheMetaData({ StudyInstanceUID: - '1.3.6.1.4.1.14519.5.2.1.7009.2403.334240657131972136850343327463', + '1.3.6.1.4.1.14519.5.2.1.7009.2403.871108593056125491804754960339', SeriesInstanceUID: - '1.3.6.1.4.1.14519.5.2.1.7009.2403.226151125820845824875394858561', - wadoRsRoot: 'https://d3t6nz73ql33tx.cloudfront.net/dicomweb', + '1.3.6.1.4.1.14519.5.2.1.7009.2403.367700692008930469189923116409', + wadoRsRoot: 'https://domvja9iplmyu.cloudfront.net/dicomweb', type: 'VOLUME', }); diff --git a/tsconfig.json b/tsconfig.json index ac82d6a94..9ea4e3808 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,8 @@ "streaming-image-volume-loader/src" ], "@cornerstonejs/core": ["core/src"], - "@cornerstonejs/tools": ["tools/src"] + "@cornerstonejs/tools": ["tools/src"], + "@cornerstonejs/dicom-image-loader": ["dicom-image-loader/src"] } } } diff --git a/utils/ExampleRunner/template-config.js b/utils/ExampleRunner/template-config.js index 361286d3a..a0084d648 100644 --- a/utils/ExampleRunner/template-config.js +++ b/utils/ExampleRunner/template-config.js @@ -34,29 +34,26 @@ module.exports = { plugins: [ new ESLintPlugin(), new HtmlWebpackPlugin({ - template: '${root.replace( - /\\/g, - '/' - )}/utils/ExampleRunner/template.html', + template: '${root.replace(/\\/g, '/')}/utils/ExampleRunner/template.html', }), new webpack.DefinePlugin({ __BASE_PATH__: "''", }), - new CopyPlugin({ - patterns: [ - { - from: - '../../../node_modules/cornerstone-wado-image-loader/dist/dynamic-import', - to: '${destPath.replace(/\\/g, '/')}', - }, - ], - }), + // new CopyPlugin({ + // patterns: [ + // { + // from: + // '../../../node_modules/cornerstone-wado-image-loader/dist/dynamic-import', + // to: '${destPath.replace(/\\/g, '/')}', + // }, + // ], + // }), // new BundleAnalyzerPlugin() ], - entry: path.join('${exampleBasePath.replace( + entry: path.join('${exampleBasePath.replace(/\\/g, '/')}', '${relPath.replace( /\\/g, '/' - )}', '${relPath.replace(/\\/g, '/')}'), + )}'), output: { path: '${destPath.replace(/\\/g, '/')}', filename: '${name}.js', @@ -74,7 +71,7 @@ module.exports = { )}', // We use this alias and the CopyPlugin to support using the dynamic-import version // of WADO Image Loader - 'cornerstone-wado-image-loader': 'cornerstone-wado-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js', + // ''@cornerstonejs/dicom-image-loader'': 'cornerstone-wado-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js', }, modules, extensions: ['.ts', '.tsx', '.js', '.jsx'], diff --git a/utils/ExampleRunner/template-multiexample-config.js b/utils/ExampleRunner/template-multiexample-config.js index 5a350b7f8..d587b2cd3 100644 --- a/utils/ExampleRunner/template-multiexample-config.js +++ b/utils/ExampleRunner/template-multiexample-config.js @@ -72,11 +72,11 @@ module.exports = { /\\/g, '/' )}" }, - { - from: - '../../../node_modules/cornerstone-wado-image-loader/dist/dynamic-import', - to: '${destPath.replace(/\\/g, '/')}', - }, + // { + // from: + // '../../../node_modules/cornerstone-wado-image-loader/dist/dynamic-import', + // to: '${destPath.replace(/\\/g, '/')}', + // }, ], }), ], @@ -100,7 +100,7 @@ module.exports = { )}', // We use this alias and the CopyPlugin to support using the dynamic-import version // of WADO Image Loader - 'cornerstone-wado-image-loader': 'cornerstone-wado-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js', + // ''@cornerstonejs/dicom-image-loader'': 'cornerstone-wado-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js', }, modules, extensions: ['.ts', '.tsx', '.js', '.jsx'], diff --git a/utils/demo/helpers/createImageIdsAndCacheMetaData.js b/utils/demo/helpers/createImageIdsAndCacheMetaData.js index c66eaa3b3..f054b327a 100644 --- a/utils/demo/helpers/createImageIdsAndCacheMetaData.js +++ b/utils/demo/helpers/createImageIdsAndCacheMetaData.js @@ -3,7 +3,7 @@ import dcmjs from 'dcmjs'; import { calculateSUVScalingFactors } from '@cornerstonejs/calculate-suv'; import { getPTImageIdInstanceMetadata } from './getPTImageIdInstanceMetadata'; import { utilities } from '@cornerstonejs/core'; -import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader'; +import cornerstoneWADOImageLoader from '@cornerstonejs/dicom-image-loader'; import WADORSHeaderProvider from './WADORSHeaderProvider'; import ptScalingMetaDataProvider from './ptScalingMetaDataProvider'; diff --git a/utils/demo/helpers/initCornerstoneWADOImageLoader.js b/utils/demo/helpers/initCornerstoneWADOImageLoader.js index dab790bca..14239413a 100644 --- a/utils/demo/helpers/initCornerstoneWADOImageLoader.js +++ b/utils/demo/helpers/initCornerstoneWADOImageLoader.js @@ -1,6 +1,6 @@ import dicomParser from 'dicom-parser'; import * as cornerstone from '@cornerstonejs/core'; -import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader'; +import cornerstoneWADOImageLoader from '@cornerstonejs/dicom-image-loader'; export default function initCornerstoneWADOImageLoader() { cornerstoneWADOImageLoader.external.cornerstone = cornerstone; diff --git a/yarn.lock b/yarn.lock index 6a59647d6..6ac379834 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8019,17 +8019,6 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cornerstone-wado-image-loader@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/cornerstone-wado-image-loader/-/cornerstone-wado-image-loader-4.2.1.tgz#ee37797fe8970dcb7e438a6d87b710e817066100" - integrity sha512-nRu+6GfHFERpZLytH/SCfymODCz1SC1NKRv/xn02pr3PEkzU6fvKI76sSxSFOozxDsYljupTRNi/qGMprfdBHA== - dependencies: - "@cornerstonejs/codec-charls" "^0.1.1" - "@cornerstonejs/codec-libjpeg-turbo-8bit" "^0.0.7" - "@cornerstonejs/codec-openjpeg" "^0.1.0" - dicom-parser "^1.8.9" - pako "^2.0.4" - cors@~2.8.5: version "2.8.5" resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" @@ -9795,6 +9784,17 @@ eslint-import-resolver-node@^0.3.6: debug "^3.2.7" resolve "^1.20.0" +eslint-loader@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/eslint-loader/-/eslint-loader-4.0.2.tgz#386a1e21bcb613b3cf2d252a3b708023ccfb41ec" + integrity sha512-EDpXor6lsjtTzZpLUn7KmXs02+nIjGcgees9BYjNkWra3jVq5vVa8IoCKgzT2M7dNNeoMBtaSG83Bd40N3poLw== + dependencies: + find-cache-dir "^3.3.1" + fs-extra "^8.1.0" + loader-utils "^2.0.0" + object-hash "^2.0.3" + schema-utils "^2.6.5" + eslint-module-utils@^2.7.3: version "2.7.3" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" @@ -10784,6 +10784,15 @@ fs-extra@^10.1.0: jsonfile "^6.0.1" universalify "^2.0.0" +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-extra@^9.0.0, fs-extra@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" @@ -15367,6 +15376,11 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" +object-hash@^2.0.3: + version "2.2.0" + resolved "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" + integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== + object-inspect@^1.12.0, object-inspect@^1.9.0: version "1.12.2" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" From c8e0bd9b59322346a9d4b5d8c8f9e6655ecc7f39 Mon Sep 17 00:00:00 2001 From: Alireza Date: Wed, 23 Nov 2022 23:08:53 -0500 Subject: [PATCH 02/14] it works --- .eslintrc.json | 1 + .webpack/webpack.base.js | 4 +- package.json | 1 + .../.webpack/webpack-base.js | 6 +-- .../dicom-image-loader/src/externalModules.js | 2 +- .../imageLoader/colorSpaceConverters/index.js | 12 ++--- .../src/imageLoader/configure.js | 2 +- .../src/imageLoader/convertColorSpace.js | 2 +- .../src/imageLoader/createImage.js | 18 ++++---- .../imageLoader/decodeImageFrame-noWorkers.js | 8 ++-- .../src/imageLoader/decodeImageFrame.js | 6 +-- .../decodeJPEGBaseline8BitColor.js | 2 +- .../src/imageLoader/getImageFrame.js | 2 +- .../src/imageLoader/getScalingParameters.js | 1 - .../src/imageLoader/index-noWorkers.js | 32 ++++++------- .../src/imageLoader/index.js | 32 ++++++------- .../src/imageLoader/internal/index.js | 4 +- .../src/imageLoader/internal/xhrRequest.js | 4 +- .../src/imageLoader/registerLoaders.js | 4 +- .../src/imageLoader/wadors/getPixelData.js | 4 +- .../src/imageLoader/wadors/index.js | 12 ++--- .../src/imageLoader/wadors/loadImage.js | 6 +-- .../src/imageLoader/wadors/loadImage_test.js | 2 +- .../wadors/metaData/getNumberString.js | 2 +- .../wadors/metaData/getNumberValue.js | 2 +- .../wadors/metaData/getOverlayPlaneModule.js | 4 +- .../src/imageLoader/wadors/metaData/index.js | 10 ++-- .../wadors/metaData/metaDataProvider.js | 12 ++--- .../src/imageLoader/wadors/metaDataManager.js | 2 +- .../src/imageLoader/wadors/register.js | 4 +- .../wadouri/dataSetCacheManager.js | 4 +- .../wadouri/dataSetCacheManager_test.js | 2 +- .../wadouri/getEncapsulatedImageFrame.js | 2 +- .../src/imageLoader/wadouri/getPixelData.js | 4 +- .../wadouri/getUncompressedImageFrame.js | 2 +- .../src/imageLoader/wadouri/index.js | 20 ++++---- .../imageLoader/wadouri/loadFileRequest.js | 4 +- .../src/imageLoader/wadouri/loadImage.js | 12 ++--- .../src/imageLoader/wadouri/metaData/index.js | 10 ++-- .../wadouri/metaData/metaDataProvider.js | 16 +++---- .../src/imageLoader/wadouri/register.js | 4 +- .../src/imageLoader/webWorkerManager.js | 10 ++-- .../src/imageLoader/webWorkerManager_test.js | 2 +- packages/dicom-image-loader/src/index.ts | 46 ++++++++++++++++++- .../src/shared/calculateMinMax.js | 2 +- .../src/shared/calculateMinMax_test.js | 2 +- .../src/shared/decodeImageFrame.js | 21 ++++----- .../src/shared/decoders/decodeJPEG2000.js | 2 +- .../decoders/decodeJPEGBaseline12Bit-js.js | 2 +- .../shared/decoders/decodeJPEGBaseline8Bit.js | 2 +- .../src/shared/decoders/decodeJPEGLS.js | 2 +- .../src/shared/decoders/decodeJPEGLossless.js | 2 +- .../src/shared/getMinMax_test.js | 2 +- .../src/webWorker/decodeTask.js | 8 ++-- .../src/webWorker/index.worker.js | 4 +- utils/ExampleRunner/template-config.js | 30 ++++++++---- .../template-multiexample-config.js | 14 +++++- yarn.lock | 7 +++ 58 files changed, 256 insertions(+), 185 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 897b62214..998bd609a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -55,6 +55,7 @@ "rules": { "tsdoc/syntax": "warn", "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/no-empty-function": "off", "no-console": [ "warn", { diff --git a/.webpack/webpack.base.js b/.webpack/webpack.base.js index c5966a46d..4efddbf94 100644 --- a/.webpack/webpack.base.js +++ b/.webpack/webpack.base.js @@ -43,8 +43,8 @@ module.exports = (env, argv, { DIST_DIR }) => { modules: [path.resolve(PROJECT_ROOT, './node_modules'), SRC_PATH], extensions: ['.ts', '.tsx', '.js', '.jsx'], // alias: { - // ''@cornerstonejs/dicom-image-loader'': - // 'cornerstone-wado-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js', + // '@cornerstonejs/dicom-image-loader': + // '@cornerstonejs/dicom-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js', // }, fallback: { fs: false, diff --git a/package.json b/package.json index 80e03428a..0661e020a 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "eslint-plugin-prettier": "^3.4.1", "eslint-plugin-tsdoc": "^0.2.14", "eslint-webpack-plugin": "^2.6.0", + "exports-loader": "^3.0.0", "file-loader": "^6.2.0", "html-webpack-plugin": "^5.5.0", "husky": "^4.3.8", diff --git a/packages/dicom-image-loader/.webpack/webpack-base.js b/packages/dicom-image-loader/.webpack/webpack-base.js index fce51d91a..689fc8f99 100644 --- a/packages/dicom-image-loader/.webpack/webpack-base.js +++ b/packages/dicom-image-loader/.webpack/webpack-base.js @@ -84,9 +84,9 @@ module.exports = { }, ], }, - // experiments: { - // asyncWebAssembly: true, - // }, + experiments: { + asyncWebAssembly: true, + }, plugins: [new webpack.ProgressPlugin()], // plugins: [new webpack.ProgressPlugin(), new BundleAnalyzerPlugin()], }; diff --git a/packages/dicom-image-loader/src/externalModules.js b/packages/dicom-image-loader/src/externalModules.js index 2cde3fcef..d494efb97 100644 --- a/packages/dicom-image-loader/src/externalModules.js +++ b/packages/dicom-image-loader/src/externalModules.js @@ -1,5 +1,5 @@ /* eslint import/extensions:0 */ -import registerLoaders from './imageLoader/registerLoaders.js'; +import registerLoaders from './imageLoader/registerLoaders'; let cornerstone; diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/index.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/index.js index 80c8bbd88..d36621a1e 100644 --- a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/index.js +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/index.js @@ -1,9 +1,9 @@ -import { default as convertRGBColorByPixel } from './convertRGBColorByPixel.js'; -import { default as convertRGBColorByPlane } from './convertRGBColorByPlane.js'; -import { default as convertYBRFullByPixel } from './convertYBRFullByPixel.js'; -import { default as convertYBRFullByPlane } from './convertYBRFullByPlane.js'; -import { default as convertYBRFull422ByPixel } from './convertYBRFull422ByPixel.js'; -import { default as convertPALETTECOLOR } from './convertPALETTECOLOR.js'; +import { default as convertRGBColorByPixel } from './convertRGBColorByPixel'; +import { default as convertRGBColorByPlane } from './convertRGBColorByPlane'; +import { default as convertYBRFullByPixel } from './convertYBRFullByPixel'; +import { default as convertYBRFullByPlane } from './convertYBRFullByPlane'; +import { default as convertYBRFull422ByPixel } from './convertYBRFull422ByPixel'; +import { default as convertPALETTECOLOR } from './convertPALETTECOLOR'; export { convertRGBColorByPixel, diff --git a/packages/dicom-image-loader/src/imageLoader/configure.js b/packages/dicom-image-loader/src/imageLoader/configure.js index 45c3515f5..0c6f20b69 100644 --- a/packages/dicom-image-loader/src/imageLoader/configure.js +++ b/packages/dicom-image-loader/src/imageLoader/configure.js @@ -1,4 +1,4 @@ -import { setOptions } from './internal/index.js'; +import { setOptions } from './internal/index'; function configure(options) { setOptions(options); diff --git a/packages/dicom-image-loader/src/imageLoader/convertColorSpace.js b/packages/dicom-image-loader/src/imageLoader/convertColorSpace.js index bc53e21d2..c209dc3a3 100644 --- a/packages/dicom-image-loader/src/imageLoader/convertColorSpace.js +++ b/packages/dicom-image-loader/src/imageLoader/convertColorSpace.js @@ -5,7 +5,7 @@ import { convertYBRFull422ByPixel, convertYBRFullByPlane, convertPALETTECOLOR, -} from './colorSpaceConverters/index.js'; +} from './colorSpaceConverters/index'; function convertRGB(imageFrame, colorBuffer, useRGBA) { if (imageFrame.planarConfiguration === 0) { diff --git a/packages/dicom-image-loader/src/imageLoader/createImage.js b/packages/dicom-image-loader/src/imageLoader/createImage.js index 297a61853..9523008bc 100644 --- a/packages/dicom-image-loader/src/imageLoader/createImage.js +++ b/packages/dicom-image-loader/src/imageLoader/createImage.js @@ -1,12 +1,12 @@ -import external from '../externalModules.js'; -import getImageFrame from './getImageFrame.js'; -import decodeImageFrame from './decodeImageFrame.js'; -import isColorImageFn from './isColorImage.js'; -import convertColorSpace from './convertColorSpace.js'; -import getMinMax from '../shared/getMinMax.js'; -import isJPEGBaseline8BitColor from './isJPEGBaseline8BitColor.js'; -import { getOptions } from './internal/options.js'; -import getScalingParameters from './getScalingParameters.js'; +import external from '../externalModules'; +import getImageFrame from './getImageFrame'; +import decodeImageFrame from './decodeImageFrame'; +import isColorImageFn from './isColorImage'; +import convertColorSpace from './convertColorSpace'; +import getMinMax from '../shared/getMinMax'; +import isJPEGBaseline8BitColor from './isJPEGBaseline8BitColor'; +import { getOptions } from './internal/options'; +import getScalingParameters from './getScalingParameters'; let lastImageIdDrawn = ''; diff --git a/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.js b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.js index d07a5d323..0438ab10b 100644 --- a/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.js +++ b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.js @@ -1,8 +1,8 @@ -import { getOptions } from './internal/options.js'; -import decodeJPEGBaseline8BitColor from './decodeJPEGBaseline8BitColor.js'; +import { getOptions } from './internal/options'; +import decodeJPEGBaseline8BitColor from './decodeJPEGBaseline8BitColor'; -import { default as decodeImageFrameHandler } from '../shared/decodeImageFrame.js'; -import calculateMinMax from '../shared/calculateMinMax.js'; +import { default as decodeImageFrameHandler } from '../shared/decodeImageFrame'; +import calculateMinMax from '../shared/calculateMinMax'; function processDecodeTask(imageFrame, transferSyntax, pixelData, options) { const loaderOptions = getOptions(); diff --git a/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.js b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.js index 191ac18a4..c5bcca2dd 100644 --- a/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.js +++ b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.js @@ -1,10 +1,10 @@ -import webWorkerManager from './webWorkerManager.js'; -import decodeJPEGBaseline8BitColor from './decodeJPEGBaseline8BitColor.js'; +import webWorkerManager from './webWorkerManager'; +import decodeJPEGBaseline8BitColor from './decodeJPEGBaseline8BitColor'; // dicomParser requires pako for browser-side decoding of deflate transfer syntax // We only need one function though, so lets import that so we don't make our bundle // too large. -import { inflateRaw } from 'pako/lib/inflate.js'; +import { inflateRaw } from 'pako/lib/inflate'; window.pako = { inflateRaw }; diff --git a/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.js b/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.js index c08093593..f34cbd345 100644 --- a/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.js +++ b/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.js @@ -1,4 +1,4 @@ -import getMinMax from '../shared/getMinMax.js'; +import getMinMax from '../shared/getMinMax'; /** * Special decoder for 8 bit jpeg that leverages the browser's built in JPEG decoder for increased performance diff --git a/packages/dicom-image-loader/src/imageLoader/getImageFrame.js b/packages/dicom-image-loader/src/imageLoader/getImageFrame.js index 613ff8502..5673263c2 100644 --- a/packages/dicom-image-loader/src/imageLoader/getImageFrame.js +++ b/packages/dicom-image-loader/src/imageLoader/getImageFrame.js @@ -1,4 +1,4 @@ -import external from '../externalModules.js'; +import external from '../externalModules'; function getImageFrame(imageId) { const { cornerstone } = external; diff --git a/packages/dicom-image-loader/src/imageLoader/getScalingParameters.js b/packages/dicom-image-loader/src/imageLoader/getScalingParameters.js index 38cadf19e..30372bc8e 100644 --- a/packages/dicom-image-loader/src/imageLoader/getScalingParameters.js +++ b/packages/dicom-image-loader/src/imageLoader/getScalingParameters.js @@ -19,7 +19,6 @@ export default function getScalingParameters(metaData, imageId) { modality, }; - debugger; const suvFactor = metaData.get('scalingModule', imageId) || {}; return { diff --git a/packages/dicom-image-loader/src/imageLoader/index-noWorkers.js b/packages/dicom-image-loader/src/imageLoader/index-noWorkers.js index 2a41c6e5e..b3d4e697e 100644 --- a/packages/dicom-image-loader/src/imageLoader/index-noWorkers.js +++ b/packages/dicom-image-loader/src/imageLoader/index-noWorkers.js @@ -4,23 +4,23 @@ import { convertYBRFullByPixel, convertYBRFullByPlane, convertPALETTECOLOR, -} from './colorSpaceConverters/index.js'; +} from './colorSpaceConverters/index'; -import { default as wadouri } from './wadouri/index.js'; -import { default as wadors } from './wadors/index.js'; -import { default as configure } from './configure.js'; -import { default as convertColorSpace } from './convertColorSpace.js'; -import { default as createImage } from './createImage.js'; -import { default as decodeImageFrame } from './decodeImageFrame-noWorkers.js'; -import { default as decodeJPEGBaseline8BitColor } from './decodeJPEGBaseline8BitColor.js'; -import { default as getImageFrame } from './getImageFrame.js'; -import { default as getMinMax } from '../shared/getMinMax.js'; -import { default as isColorImage } from './isColorImage.js'; -import { default as isJPEGBaseline8BitColor } from './isJPEGBaseline8BitColor.js'; -import { default as webWorkerManager } from './webWorkerManager.js'; -import { default as getPixelData } from './wadors/getPixelData.js'; -import { internal } from './internal/index.js'; -import { default as external } from '../externalModules.js'; +import { default as wadouri } from './wadouri/index'; +import { default as wadors } from './wadors/index'; +import { default as configure } from './configure'; +import { default as convertColorSpace } from './convertColorSpace'; +import { default as createImage } from './createImage'; +import { default as decodeImageFrame } from './decodeImageFrame-noWorkers'; +import { default as decodeJPEGBaseline8BitColor } from './decodeJPEGBaseline8BitColor'; +import { default as getImageFrame } from './getImageFrame'; +import { default as getMinMax } from '../shared/getMinMax'; +import { default as isColorImage } from './isColorImage'; +import { default as isJPEGBaseline8BitColor } from './isJPEGBaseline8BitColor'; +import { default as webWorkerManager } from './webWorkerManager'; +import { default as getPixelData } from './wadors/getPixelData'; +import { internal } from './internal/index'; +import { default as external } from '../externalModules'; const cornerstoneWADOImageLoader = { convertRGBColorByPixel, diff --git a/packages/dicom-image-loader/src/imageLoader/index.js b/packages/dicom-image-loader/src/imageLoader/index.js index 9e360c5a9..b8e080b24 100644 --- a/packages/dicom-image-loader/src/imageLoader/index.js +++ b/packages/dicom-image-loader/src/imageLoader/index.js @@ -4,23 +4,23 @@ import { convertYBRFullByPixel, convertYBRFullByPlane, convertPALETTECOLOR, -} from './colorSpaceConverters/index.js'; +} from './colorSpaceConverters/index'; -import { default as wadouri } from './wadouri/index.js'; -import { default as wadors } from './wadors/index.js'; -import { default as configure } from './configure.js'; -import { default as convertColorSpace } from './convertColorSpace.js'; -import { default as createImage } from './createImage.js'; -import { default as decodeImageFrame } from './decodeImageFrame.js'; -import { default as decodeJPEGBaseline8BitColor } from './decodeJPEGBaseline8BitColor.js'; -import { default as getImageFrame } from './getImageFrame.js'; -import { default as getMinMax } from '../shared/getMinMax.js'; -import { default as isColorImage } from './isColorImage.js'; -import { default as isJPEGBaseline8BitColor } from './isJPEGBaseline8BitColor.js'; -import { default as webWorkerManager } from './webWorkerManager.js'; -import { default as getPixelData } from './wadors/getPixelData.js'; -import { internal } from './internal/index.js'; -import { default as external } from '../externalModules.js'; +import { default as wadouri } from './wadouri/index'; +import { default as wadors } from './wadors/index'; +import { default as configure } from './configure'; +import { default as convertColorSpace } from './convertColorSpace'; +import { default as createImage } from './createImage'; +import { default as decodeImageFrame } from './decodeImageFrame'; +import { default as decodeJPEGBaseline8BitColor } from './decodeJPEGBaseline8BitColor'; +import { default as getImageFrame } from './getImageFrame'; +import { default as getMinMax } from '../shared/getMinMax'; +import { default as isColorImage } from './isColorImage'; +import { default as isJPEGBaseline8BitColor } from './isJPEGBaseline8BitColor'; +import { default as webWorkerManager } from './webWorkerManager'; +import { default as getPixelData } from './wadors/getPixelData'; +import { internal } from './internal/index'; +import { default as external } from '../externalModules'; const cornerstoneWADOImageLoader = { convertRGBColorByPixel, diff --git a/packages/dicom-image-loader/src/imageLoader/internal/index.js b/packages/dicom-image-loader/src/imageLoader/internal/index.js index 7ebe5022d..78d905ce6 100644 --- a/packages/dicom-image-loader/src/imageLoader/internal/index.js +++ b/packages/dicom-image-loader/src/imageLoader/internal/index.js @@ -1,5 +1,5 @@ -import { default as xhrRequest } from './xhrRequest.js'; -import { setOptions, getOptions } from './options.js'; +import { default as xhrRequest } from './xhrRequest'; +import { setOptions, getOptions } from './options'; const internal = { xhrRequest, diff --git a/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.js b/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.js index 0eb50da9e..928558430 100644 --- a/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.js +++ b/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.js @@ -1,5 +1,5 @@ -import external from '../../externalModules.js'; -import { getOptions } from './options.js'; +import external from '../../externalModules'; +import { getOptions } from './options'; function xhrRequest(url, imageId, defaultHeaders = {}, params = {}) { const { cornerstone } = external; diff --git a/packages/dicom-image-loader/src/imageLoader/registerLoaders.js b/packages/dicom-image-loader/src/imageLoader/registerLoaders.js index fda14faf3..4ecd98d94 100644 --- a/packages/dicom-image-loader/src/imageLoader/registerLoaders.js +++ b/packages/dicom-image-loader/src/imageLoader/registerLoaders.js @@ -1,5 +1,5 @@ -import wadors from './wadors/index.js'; -import wadouri from './wadouri/index.js'; +import wadors from './wadors/index'; +import wadouri from './wadouri/index'; /** * Register the WADO-URI and WADO-RS image loaders and metaData providers diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.js b/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.js index afade1936..6135a923d 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.js @@ -1,5 +1,5 @@ -import { xhrRequest } from '../internal/index.js'; -import findIndexOfString from './findIndexOfString.js'; +import { xhrRequest } from '../internal/index'; +import findIndexOfString from './findIndexOfString'; function findBoundary(header) { for (let i = 0; i < header.length; i++) { diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/index.js b/packages/dicom-image-loader/src/imageLoader/wadors/index.js index 07ec46c99..76458e97b 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/index.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/index.js @@ -4,13 +4,13 @@ import { getNumberValues, getValue, metaDataProvider, -} from './metaData/index.js'; +} from './metaData/index'; -import findIndexOfString from './findIndexOfString.js'; -import getPixelData from './getPixelData.js'; -import metaDataManager from './metaDataManager.js'; -import loadImage from './loadImage.js'; -import register from './register.js'; +import findIndexOfString from './findIndexOfString'; +import getPixelData from './getPixelData'; +import metaDataManager from './metaDataManager'; +import loadImage from './loadImage'; +import register from './register'; const metaData = { getNumberString, diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.js b/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.js index 9fd63a540..4adb88502 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.js @@ -1,6 +1,6 @@ -import external from '../../externalModules.js'; -import getPixelData from './getPixelData.js'; -import createImage from '../createImage.js'; +import external from '../../externalModules'; +import getPixelData from './getPixelData'; +import createImage from '../createImage'; /** * Helper method to extract the transfer-syntax from the response of the server. diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/loadImage_test.js b/packages/dicom-image-loader/src/imageLoader/wadors/loadImage_test.js index f2648c379..6bd55c208 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/loadImage_test.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/loadImage_test.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { getTransferSyntaxForContentType } from './loadImage.js'; +import { getTransferSyntaxForContentType } from './loadImage'; const cases = [ // Test default case for missing or unspecified TS diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.js index c812af0b6..aae181c53 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.js @@ -1,4 +1,4 @@ -import getValue from './getValue.js'; +import getValue from './getValue'; /** * Returns the first string value as a Javascript number diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.js index ef1866b32..ad1c39374 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.js @@ -1,4 +1,4 @@ -import getValue from './getValue.js'; +import getValue from './getValue'; function getNumberValue(element, index) { const value = getValue(element, index); diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.js index ea31f4d73..516a572ce 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.js @@ -1,5 +1,5 @@ -import getValue from './getValue.js'; -import getNumberValue from './getNumberValue.js'; +import getValue from './getValue'; +import getNumberValue from './getNumberValue'; export default function getOverlayPlaneModule(metaData) { const overlays = []; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/index.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/index.js index 1bd07779c..028b5f202 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/index.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/index.js @@ -1,5 +1,5 @@ -export { default as getNumberString } from './getNumberString.js'; -export { default as getNumberValue } from './getNumberValue.js'; -export { default as getNumberValues } from './getNumberValues.js'; -export { default as getValue } from './getValue.js'; -export { default as metaDataProvider } from './metaDataProvider.js'; +export { default as getNumberString } from './getNumberString'; +export { default as getNumberValue } from './getNumberValue'; +export { default as getNumberValues } from './getNumberValues'; +export { default as getValue } from './getValue'; +export { default as metaDataProvider } from './metaDataProvider'; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.js index 7794634fc..13db5d719 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.js @@ -1,9 +1,9 @@ -import external from '../../../externalModules.js'; -import getNumberValues from './getNumberValues.js'; -import getValue from './getValue.js'; -import getNumberValue from './getNumberValue.js'; -import getOverlayPlaneModule from './getOverlayPlaneModule.js'; -import metaDataManager from '../metaDataManager.js'; +import external from '../../../externalModules'; +import getNumberValues from './getNumberValues'; +import getValue from './getValue'; +import getNumberValue from './getNumberValue'; +import getOverlayPlaneModule from './getOverlayPlaneModule'; +import metaDataManager from '../metaDataManager'; function metaDataProvider(type, imageId) { const { dicomParser } = external; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.js index 468c3696d..1139e2699 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.js @@ -1,4 +1,4 @@ -import imageIdToURI from '../imageIdToURI.js'; +import imageIdToURI from '../imageIdToURI'; let metadataByImageURI = []; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/register.js b/packages/dicom-image-loader/src/imageLoader/wadors/register.js index b1158fb94..3451be2d5 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/register.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/register.js @@ -1,5 +1,5 @@ -import loadImage from './loadImage.js'; -import { metaDataProvider } from './metaData/index.js'; +import loadImage from './loadImage'; +import { metaDataProvider } from './metaData/index'; export default function (cornerstone) { // register wadors scheme and metadata provider diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.js b/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.js index 2cc587ac6..529383411 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.js @@ -1,5 +1,5 @@ -import external from '../../externalModules.js'; -import { xhrRequest } from '../internal/index.js'; +import external from '../../externalModules'; +import { xhrRequest } from '../internal/index'; /** * This object supports loading of DICOM P10 dataset from a uri and caching it so it can be accessed diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager_test.js b/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager_test.js index a0be8f611..2f3efa0f7 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager_test.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager_test.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import dataSetCacheManager from './dataSetCacheManager.js'; +import dataSetCacheManager from './dataSetCacheManager'; describe('#getInfo', () => { it('should return cache info for an empty cache', function () { diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.js b/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.js index 51828eab3..87869458e 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.js @@ -1,4 +1,4 @@ -import external from '../../externalModules.js'; +import external from '../../externalModules'; /** * Function to deal with extracting an image frame from an encapsulated data set. diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.js b/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.js index 8bce72e85..5afac52e1 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.js @@ -1,5 +1,5 @@ -import getEncapsulatedImageFrame from './getEncapsulatedImageFrame.js'; -import getUncompressedImageFrame from './getUncompressedImageFrame.js'; +import getEncapsulatedImageFrame from './getEncapsulatedImageFrame'; +import getUncompressedImageFrame from './getUncompressedImageFrame'; function getPixelData(dataSet, frameIndex = 0) { const pixelDataElement = diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.js b/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.js index 683276b4f..264ef71b8 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.js @@ -1,4 +1,4 @@ -import unpackBinaryFrame from './unpackBinaryFrame.js'; +import unpackBinaryFrame from './unpackBinaryFrame'; /** * Function to deal with extracting an image frame from an encapsulated data set. diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/index.js b/packages/dicom-image-loader/src/imageLoader/wadouri/index.js index 1c732d411..7ccfa60b9 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/index.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/index.js @@ -4,21 +4,21 @@ import { getModalityLUTOutputPixelRepresentation, getNumberValues, metaDataProvider, -} from './metaData/index.js'; +} from './metaData/index'; -import dataSetCacheManager from './dataSetCacheManager.js'; -import fileManager from './fileManager.js'; -import getEncapsulatedImageFrame from './getEncapsulatedImageFrame.js'; -import getUncompressedImageFrame from './getUncompressedImageFrame.js'; -import loadFileRequest from './loadFileRequest.js'; +import dataSetCacheManager from './dataSetCacheManager'; +import fileManager from './fileManager'; +import getEncapsulatedImageFrame from './getEncapsulatedImageFrame'; +import getUncompressedImageFrame from './getUncompressedImageFrame'; +import loadFileRequest from './loadFileRequest'; import { loadImageFromPromise, getLoaderForScheme, loadImage, -} from './loadImage.js'; -import parseImageId from './parseImageId.js'; -import unpackBinaryFrame from './unpackBinaryFrame.js'; -import register from './register.js'; +} from './loadImage'; +import parseImageId from './parseImageId'; +import unpackBinaryFrame from './unpackBinaryFrame'; +import register from './register'; const metaData = { getImagePixelModule, diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.js b/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.js index 1acf2a7a4..781fa704a 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.js @@ -1,5 +1,5 @@ -import parseImageId from './parseImageId.js'; -import fileManager from './fileManager.js'; +import parseImageId from './parseImageId'; +import fileManager from './fileManager'; function loadFileRequest(uri) { const parsedImageId = parseImageId(uri); diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.js b/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.js index f077b3c8d..785170c0f 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.js @@ -1,9 +1,9 @@ -import createImage from '../createImage.js'; -import parseImageId from './parseImageId.js'; -import dataSetCacheManager from './dataSetCacheManager.js'; -import loadFileRequest from './loadFileRequest.js'; -import getPixelData from './getPixelData.js'; -import { xhrRequest } from '../internal/index.js'; +import createImage from '../createImage'; +import parseImageId from './parseImageId'; +import dataSetCacheManager from './dataSetCacheManager'; +import loadFileRequest from './loadFileRequest'; +import getPixelData from './getPixelData'; +import { xhrRequest } from '../internal/index'; // add a decache callback function to clear out our dataSetCacheManager function addDecache(imageLoadObject, imageId) { diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/index.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/index.js index e67d6b280..67af79802 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/index.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/index.js @@ -1,5 +1,5 @@ -export { default as getImagePixelModule } from './getImagePixelModule.js'; -export { default as getLUTs } from './getLUTs.js'; -export { default as getModalityLUTOutputPixelRepresentation } from './getModalityLUTOutputPixelRepresentation.js'; -export { default as getNumberValues } from './getNumberValues.js'; -export { default as metaDataProvider } from './metaDataProvider.js'; +export { default as getImagePixelModule } from './getImagePixelModule'; +export { default as getLUTs } from './getLUTs'; +export { default as getModalityLUTOutputPixelRepresentation } from './getModalityLUTOutputPixelRepresentation'; +export { default as getNumberValues } from './getNumberValues'; +export { default as metaDataProvider } from './metaDataProvider'; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.js index 2418d8e85..6d7de0dd1 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.js @@ -1,11 +1,11 @@ -import external from '../../../externalModules.js'; -import getNumberValues from './getNumberValues.js'; -import parseImageId from '../parseImageId.js'; -import dataSetCacheManager from '../dataSetCacheManager.js'; -import getImagePixelModule from './getImagePixelModule.js'; -import getOverlayPlaneModule from './getOverlayPlaneModule.js'; -import getLUTs from './getLUTs.js'; -import getModalityLUTOutputPixelRepresentation from './getModalityLUTOutputPixelRepresentation.js'; +import external from '../../../externalModules'; +import getNumberValues from './getNumberValues'; +import parseImageId from '../parseImageId'; +import dataSetCacheManager from '../dataSetCacheManager'; +import getImagePixelModule from './getImagePixelModule'; +import getOverlayPlaneModule from './getOverlayPlaneModule'; +import getLUTs from './getLUTs'; +import getModalityLUTOutputPixelRepresentation from './getModalityLUTOutputPixelRepresentation'; function metaDataProvider(type, imageId) { const { dicomParser } = external; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/register.js b/packages/dicom-image-loader/src/imageLoader/wadouri/register.js index 8d1b2586d..ed24e59d1 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/register.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/register.js @@ -1,5 +1,5 @@ -import { loadImage } from './loadImage.js'; -import { metaDataProvider } from './metaData/index.js'; +import { loadImage } from './loadImage'; +import { metaDataProvider } from './metaData/index'; export default function (cornerstone) { // register dicomweb and wadouri image loader prefixes diff --git a/packages/dicom-image-loader/src/imageLoader/webWorkerManager.js b/packages/dicom-image-loader/src/imageLoader/webWorkerManager.js index cbf05ae02..8c099412b 100644 --- a/packages/dicom-image-loader/src/imageLoader/webWorkerManager.js +++ b/packages/dicom-image-loader/src/imageLoader/webWorkerManager.js @@ -1,17 +1,17 @@ // Not sure why but webpack isn't splitting this out unless we explicitly use worker-loader! // eslint-disable-next-line -// import cornerstoneWADOImageLoaderWebWorker from 'worker-loader!../webWorker/index.worker.js'; -import cornerstoneWADOImageLoaderWebWorker from '../webWorker/index.worker.js'; +// import cornerstoneWADOImageLoaderWebWorker from 'worker-loader!../webWorker/index.worker'; +import cornerstoneWADOImageLoaderWebWorker from '../webWorker/index.worker'; // This is for the Webpack 5 approch but it's currently broken // so we will continue relying on worker-loader for now // https://github.com/webpack/webpack/issues/13899 /* const cornerstoneWADOImageLoaderWebWorkerPath = new URL( - '../webWorker/index.js', + '../webWorker/index', import.meta.url );*/ -import { getOptions } from './internal/options.js'; +import { getOptions } from './internal/options'; // the taskId to assign to the next task added via addTask() let nextTaskId = 0; @@ -146,7 +146,7 @@ function spawnWebWorker() { });*/ // const worker = new Worker( - // './cornerstoneWADOImageLoaderWebWorker.bundle.min.js', + // './cornerstoneWADOImageLoaderWebWorker.bundle.min', // { // name: `cornerstoneWADOImageLoaderWebWorkerPath-${webWorkers.length + 1}`, // } diff --git a/packages/dicom-image-loader/src/imageLoader/webWorkerManager_test.js b/packages/dicom-image-loader/src/imageLoader/webWorkerManager_test.js index 53f05798d..7c54644ca 100644 --- a/packages/dicom-image-loader/src/imageLoader/webWorkerManager_test.js +++ b/packages/dicom-image-loader/src/imageLoader/webWorkerManager_test.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import webWorkerManager from './webWorkerManager.js'; +import webWorkerManager from './webWorkerManager'; const config = { maxWebWorkers: 2, diff --git a/packages/dicom-image-loader/src/index.ts b/packages/dicom-image-loader/src/index.ts index 8d509ebd1..68dcd1498 100644 --- a/packages/dicom-image-loader/src/index.ts +++ b/packages/dicom-image-loader/src/index.ts @@ -1 +1,45 @@ -export * from './imageLoader'; +import { + convertRGBColorByPixel, + convertRGBColorByPlane, + convertYBRFullByPixel, + convertYBRFullByPlane, + convertPALETTECOLOR, + wadouri, + wadors, + configure, + convertColorSpace, + createImage, + decodeImageFrame, + decodeJPEGBaseline8BitColor, + getImageFrame, + getPixelData, + getMinMax, + isColorImage, + isJPEGBaseline8BitColor, + webWorkerManager, + internal, + external, +} from './imageLoader'; + +export { + convertRGBColorByPixel, + convertRGBColorByPlane, + convertYBRFullByPixel, + convertYBRFullByPlane, + convertPALETTECOLOR, + wadouri, + wadors, + configure, + convertColorSpace, + createImage, + decodeImageFrame, + decodeJPEGBaseline8BitColor, + getImageFrame, + getPixelData, + getMinMax, + isColorImage, + isJPEGBaseline8BitColor, + webWorkerManager, + internal, + external, +}; diff --git a/packages/dicom-image-loader/src/shared/calculateMinMax.js b/packages/dicom-image-loader/src/shared/calculateMinMax.js index e3ce55ab4..51aed31ff 100644 --- a/packages/dicom-image-loader/src/shared/calculateMinMax.js +++ b/packages/dicom-image-loader/src/shared/calculateMinMax.js @@ -1,4 +1,4 @@ -import getMinMax from './getMinMax.js'; +import getMinMax from './getMinMax'; /** * Check the minimum and maximum values in the imageFrame pixel data diff --git a/packages/dicom-image-loader/src/shared/calculateMinMax_test.js b/packages/dicom-image-loader/src/shared/calculateMinMax_test.js index fb42c225c..461f79e2a 100644 --- a/packages/dicom-image-loader/src/shared/calculateMinMax_test.js +++ b/packages/dicom-image-loader/src/shared/calculateMinMax_test.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import calculateMinMax from './calculateMinMax.js'; +import calculateMinMax from './calculateMinMax'; describe('#calculateMinMax', () => { let imageFrame = {}; diff --git a/packages/dicom-image-loader/src/shared/decodeImageFrame.js b/packages/dicom-image-loader/src/shared/decodeImageFrame.js index 4d9d2c3d0..8904777c7 100644 --- a/packages/dicom-image-loader/src/shared/decodeImageFrame.js +++ b/packages/dicom-image-loader/src/shared/decodeImageFrame.js @@ -1,14 +1,14 @@ /* eslint-disable complexity */ -import decodeLittleEndian from './decoders/decodeLittleEndian.js'; -import decodeBigEndian from './decoders/decodeBigEndian.js'; -import decodeRLE from './decoders/decodeRLE.js'; -import decodeJPEGBaseline8Bit from './decoders/decodeJPEGBaseline8Bit.js'; -// import decodeJPEGBaseline12Bit from './decoders/decodeJPEGBaseline12Bit.js'; -import decodeJPEGBaseline12Bit from './decoders/decodeJPEGBaseline12Bit-js.js'; -import decodeJPEGLossless from './decoders/decodeJPEGLossless.js'; -import decodeJPEGLS from './decoders/decodeJPEGLS.js'; -import decodeJPEG2000 from './decoders/decodeJPEG2000.js'; -import scaleArray from './scaling/scaleArray.js'; +import decodeLittleEndian from './decoders/decodeLittleEndian'; +import decodeBigEndian from './decoders/decodeBigEndian'; +import decodeRLE from './decoders/decodeRLE'; +import decodeJPEGBaseline8Bit from './decoders/decodeJPEGBaseline8Bit'; +// import decodeJPEGBaseline12Bit from './decoders/decodeJPEGBaseline12Bit'; +import decodeJPEGBaseline12Bit from './decoders/decodeJPEGBaseline12Bit-js'; +import decodeJPEGLossless from './decoders/decodeJPEGLossless'; +import decodeJPEGLS from './decoders/decodeJPEGLS'; +import decodeJPEG2000 from './decoders/decodeJPEG2000'; +import scaleArray from './scaling/scaleArray'; function decodeImageFrame( imageFrame, @@ -220,7 +220,6 @@ function postProcessDecodedPixels(imageFrame, options, start) { } if (options.preScale.enabled) { - debugger; const scalingParameters = options.preScale.scalingParameters; if (!scalingParameters) { diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.js index 649739f5c..39dbdb7e6 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.js +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.js @@ -1,5 +1,5 @@ // https://emscripten.org/docs/api_reference/module.html -import openJpegFactory from '@cornerstonejs/codec-openjpeg/dist/openjpegwasm_decode.js'; +import openJpegFactory from '@cornerstonejs/codec-openjpeg/dist/openjpegwasm_decode'; // Webpack asset/resource copies this to our output folder diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.js index 28659544f..2a54b8c67 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.js +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.js @@ -11,7 +11,7 @@ export function initialize(decodeConfig) { } return new Promise((resolve, reject) => { - import('../../../codecs/jpeg.js').then(({ JpegImage }) => { + import('../../../codecs/jpeg').then(({ JpegImage }) => { local.JpegImage = JpegImage; resolve(); }, reject); diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.js index 9bf4d8b6c..1faa1f34c 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.js +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.js @@ -1,4 +1,4 @@ -import libjpegTurboFactory from '@cornerstonejs/codec-libjpeg-turbo-8bit/dist/libjpegturbowasm_decode.js'; +import libjpegTurboFactory from '@cornerstonejs/codec-libjpeg-turbo-8bit/dist/libjpegturbowasm_decode'; // Webpack asset/resource copies this to our output folder import libjpegTurboWasm from '@cornerstonejs/codec-libjpeg-turbo-8bit/dist/libjpegturbowasm_decode.wasm'; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.js index 111f69578..73b8656c8 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.js +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.js @@ -1,4 +1,4 @@ -import charlsFactory from '@cornerstonejs/codec-charls/dist/charlswasm_decode.js'; +import charlsFactory from '@cornerstonejs/codec-charls/dist/charlswasm_decode'; // import charlsFactory from '@cornerstonejs/codec-charls/dist/debug/charlswasm.js'; // Webpack asset/resource copies this to our output folder diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.js index 4d6df6c42..016ce6848 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.js +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.js @@ -11,7 +11,7 @@ export function initialize(decodeConfig) { } return new Promise((resolve, reject) => { - import('../../../codecs/jpegLossless.js').then((jpeg) => { + import('../../../codecs/jpegLossless').then((jpeg) => { local.jpeg = jpeg; resolve(); }, reject); diff --git a/packages/dicom-image-loader/src/shared/getMinMax_test.js b/packages/dicom-image-loader/src/shared/getMinMax_test.js index 42ba8a3ec..f61ed4cae 100644 --- a/packages/dicom-image-loader/src/shared/getMinMax_test.js +++ b/packages/dicom-image-loader/src/shared/getMinMax_test.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import getMinMax from './getMinMax.js'; +import getMinMax from './getMinMax'; describe('#getMinMax', () => { it('should return the right min and max values', () => { diff --git a/packages/dicom-image-loader/src/webWorker/decodeTask.js b/packages/dicom-image-loader/src/webWorker/decodeTask.js index 88a0ecb34..9ade7d214 100644 --- a/packages/dicom-image-loader/src/webWorker/decodeTask.js +++ b/packages/dicom-image-loader/src/webWorker/decodeTask.js @@ -1,7 +1,7 @@ -import { initialize as initializeJPEG2000 } from '../shared/decoders/decodeJPEG2000.js'; -import { initialize as initializeJPEGLS } from '../shared/decoders/decodeJPEGLS.js'; -import calculateMinMax from '../shared/calculateMinMax.js'; -import decodeImageFrame from '../shared/decodeImageFrame.js'; +import { initialize as initializeJPEG2000 } from '../shared/decoders/decodeJPEG2000'; +import { initialize as initializeJPEGLS } from '../shared/decoders/decodeJPEGLS'; +import calculateMinMax from '../shared/calculateMinMax'; +import decodeImageFrame from '../shared/decodeImageFrame'; // the configuration object for the decodeTask let decodeConfig; diff --git a/packages/dicom-image-loader/src/webWorker/index.worker.js b/packages/dicom-image-loader/src/webWorker/index.worker.js index f693e1310..c2b49a79a 100644 --- a/packages/dicom-image-loader/src/webWorker/index.worker.js +++ b/packages/dicom-image-loader/src/webWorker/index.worker.js @@ -1,5 +1,5 @@ -import { registerTaskHandler } from './webWorker.js'; -import decodeTask from './decodeTask.js'; +import { registerTaskHandler } from './webWorker'; +import decodeTask from './decodeTask'; // register our task registerTaskHandler(decodeTask); diff --git a/utils/ExampleRunner/template-config.js b/utils/ExampleRunner/template-config.js index a0084d648..fd1f60fb9 100644 --- a/utils/ExampleRunner/template-config.js +++ b/utils/ExampleRunner/template-config.js @@ -5,6 +5,9 @@ const csToolsBasePath = path.resolve('../tools/src/index'); const csStreamingBasePath = path.resolve( '../streaming-image-volume-loader/src/index' ); +const csDICOMImageLoader = path.resolve( + '../dicom-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js' +); module.exports = function buildConfig( name, @@ -39,15 +42,15 @@ module.exports = { new webpack.DefinePlugin({ __BASE_PATH__: "''", }), - // new CopyPlugin({ - // patterns: [ - // { - // from: - // '../../../node_modules/cornerstone-wado-image-loader/dist/dynamic-import', - // to: '${destPath.replace(/\\/g, '/')}', - // }, - // ], - // }), + new CopyPlugin({ + patterns: [ + { + from: + '../../../packages/dicom-image-loader/dist/dynamic-import', + to: '${destPath.replace(/\\/g, '/')}', + }, + ], + }), // new BundleAnalyzerPlugin() ], entry: path.join('${exampleBasePath.replace(/\\/g, '/')}', '${relPath.replace( @@ -71,7 +74,11 @@ module.exports = { )}', // We use this alias and the CopyPlugin to support using the dynamic-import version // of WADO Image Loader - // ''@cornerstonejs/dicom-image-loader'': 'cornerstone-wado-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js', + // '@cornerstonejs/dicom-image-loader': '@cornerstonejs/dicom-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js', + '@cornerstonejs/dicom-image-loader': '${csDICOMImageLoader.replace( + /\\/g, + '/' + )}', }, modules, extensions: ['.ts', '.tsx', '.js', '.jsx'], @@ -91,6 +98,9 @@ module.exports = { "Cross-Origin-Opener-Policy": "same-origin" } }, + experiments: { + asyncWebAssembly: true, + }, /*optimization: { minimize: false, usedExports: true, diff --git a/utils/ExampleRunner/template-multiexample-config.js b/utils/ExampleRunner/template-multiexample-config.js index d587b2cd3..7137883da 100644 --- a/utils/ExampleRunner/template-multiexample-config.js +++ b/utils/ExampleRunner/template-multiexample-config.js @@ -8,6 +8,9 @@ const csToolsBasePath = path.resolve('./packages/tools/src/index'); const csStreamingBasePath = path.resolve( './packages/streaming-image-volume-loader/src/index' ); +const csDICOMImageLoader = path.resolve( + '../dicom-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js' +); module.exports = function buildConfig(names, exampleBasePaths, destPath, root) { let multiExampleEntryPoints = ''; @@ -74,7 +77,7 @@ module.exports = { )}" }, // { // from: - // '../../../node_modules/cornerstone-wado-image-loader/dist/dynamic-import', + // '../../../node_modules/@cornerstonejs/dicom-image-loader/dist/dynamic-import', // to: '${destPath.replace(/\\/g, '/')}', // }, ], @@ -100,7 +103,11 @@ module.exports = { )}', // We use this alias and the CopyPlugin to support using the dynamic-import version // of WADO Image Loader - // ''@cornerstonejs/dicom-image-loader'': 'cornerstone-wado-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js', + // '@cornerstonejs/dicom-image-loader': '@cornerstonejs/dicom-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js', + '@cornerstonejs/dicom-image-loader': '${csDICOMImageLoader.replace( + /\\/g, + '/' + )}', }, modules, extensions: ['.ts', '.tsx', '.js', '.jsx'], @@ -120,6 +127,9 @@ module.exports = { "Cross-Origin-Opener-Policy": "same-origin" } }, + experiments: { + asyncWebAssembly: true, + }, optimization: { minimize: false }, diff --git a/yarn.lock b/yarn.lock index 6ac379834..4c0f125a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10119,6 +10119,13 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" +exports-loader@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/exports-loader/-/exports-loader-3.1.0.tgz#a68040b902da8ef24f9f6db716be904ac2455284" + integrity sha512-zkMR5OHDn8qHq2w5BLv6SnLmUK5QAtPkjTA7CNIYBB9kIxBFIeA+TA1GcMw3p/vn5Avnmq80L7MviA4tZclRmQ== + dependencies: + source-map "^0.6.1" + express-logging@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/express-logging/-/express-logging-1.1.1.tgz#62839618cbab5bb3610f1a1c1485352fe9d26c2a" From 1bed438cb27978cb087c1dcdf867091461baff26 Mon Sep 17 00:00:00 2001 From: Alireza Date: Thu, 24 Nov 2022 15:52:30 -0500 Subject: [PATCH 03/14] dont need the webpack watch anymore --- packages/core/src/enums/Events.ts | 2 +- .../.webpack/webpack-base.js | 21 ++++----- packages/dicom-image-loader/src/index.ts | 45 ------------------- utils/ExampleRunner/rules-examples.js | 18 ++++++++ utils/ExampleRunner/template-config.js | 17 +------ .../template-multiexample-config.js | 13 +----- 6 files changed, 30 insertions(+), 86 deletions(-) delete mode 100644 packages/dicom-image-loader/src/index.ts diff --git a/packages/core/src/enums/Events.ts b/packages/core/src/enums/Events.ts index d3316fece..3bb4dd7cf 100644 --- a/packages/core/src/enums/Events.ts +++ b/packages/core/src/enums/Events.ts @@ -162,7 +162,7 @@ enum Events { IMAGE_SPACING_CALIBRATED = 'CORNERSTONE_IMAGE_SPACING_CALIBRATED', /** * Triggers on the eventTarget when there is a progress in the image load process. Note: this event - * is being used in the Cornerstone-WADO-Image-Loader repository. See {@link https://github.com/cornerstonejs/cornerstoneWADOImageLoader/blob/master/src/imageLoader/internal/xhrRequest.js | here} + * is being used in the dicom-image-loader repository. See {@link https://github.com/cornerstonejs/cornerstoneWADOImageLoader/blob/master/src/imageLoader/internal/xhrRequest.js | here} * * Make use of {@link EventTypes.ImageLoadProgress | ImageLoadProgress Event Type } for typing your event listeners for IMAGE_LOAD_PROGRESS event, * and see what event detail is included in {@link EventTypes.ImageLoadProgressEventDetail | ImageLoadProgress Event Detail } diff --git a/packages/dicom-image-loader/.webpack/webpack-base.js b/packages/dicom-image-loader/.webpack/webpack-base.js index 689fc8f99..15fcb65ef 100644 --- a/packages/dicom-image-loader/.webpack/webpack-base.js +++ b/packages/dicom-image-loader/.webpack/webpack-base.js @@ -43,15 +43,15 @@ module.exports = { module: { noParse: [/(codecs)/], rules: [ - { - enforce: 'pre', - test: /\.js$/, - exclude: /(node_modules)|(codecs)/, - loader: 'eslint-loader', - options: { - failOnError: false, - }, - }, + // { + // enforce: 'pre', + // test: /\.js$/, + // exclude: /(node_modules)|(codecs)/, + // loader: 'eslint-loader', + // options: { + // failOnError: false, + // }, + // }, { test: /\.wasm/, type: 'asset/resource', @@ -84,9 +84,6 @@ module.exports = { }, ], }, - experiments: { - asyncWebAssembly: true, - }, plugins: [new webpack.ProgressPlugin()], // plugins: [new webpack.ProgressPlugin(), new BundleAnalyzerPlugin()], }; diff --git a/packages/dicom-image-loader/src/index.ts b/packages/dicom-image-loader/src/index.ts deleted file mode 100644 index 68dcd1498..000000000 --- a/packages/dicom-image-loader/src/index.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { - convertRGBColorByPixel, - convertRGBColorByPlane, - convertYBRFullByPixel, - convertYBRFullByPlane, - convertPALETTECOLOR, - wadouri, - wadors, - configure, - convertColorSpace, - createImage, - decodeImageFrame, - decodeJPEGBaseline8BitColor, - getImageFrame, - getPixelData, - getMinMax, - isColorImage, - isJPEGBaseline8BitColor, - webWorkerManager, - internal, - external, -} from './imageLoader'; - -export { - convertRGBColorByPixel, - convertRGBColorByPlane, - convertYBRFullByPixel, - convertYBRFullByPlane, - convertPALETTECOLOR, - wadouri, - wadors, - configure, - convertColorSpace, - createImage, - decodeImageFrame, - decodeJPEGBaseline8BitColor, - getImageFrame, - getPixelData, - getMinMax, - isColorImage, - isJPEGBaseline8BitColor, - webWorkerManager, - internal, - external, -}; diff --git a/utils/ExampleRunner/rules-examples.js b/utils/ExampleRunner/rules-examples.js index 36036f33b..e7d0e1741 100644 --- a/utils/ExampleRunner/rules-examples.js +++ b/utils/ExampleRunner/rules-examples.js @@ -15,6 +15,24 @@ module.exports = [ envName: 'development', }, }, + { + test: /\.wasm/, + // asset resource is used for assets that are not built but we want + // to copy to dist. Don't import .wasm, just treat it as a file and + // copy it to dist. + type: 'asset/resource', + }, + { + test: /\.worker\.js$/, + use: [ + { + loader: 'worker-loader', + }, + // { + // loader: 'babel-loader', + // }, + ], + }, { test: /\.css$/, exclude: /\.module\.css$/, diff --git a/utils/ExampleRunner/template-config.js b/utils/ExampleRunner/template-config.js index fd1f60fb9..e0465fbd5 100644 --- a/utils/ExampleRunner/template-config.js +++ b/utils/ExampleRunner/template-config.js @@ -6,7 +6,7 @@ const csStreamingBasePath = path.resolve( '../streaming-image-volume-loader/src/index' ); const csDICOMImageLoader = path.resolve( - '../dicom-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js' + '../dicom-image-loader/src/imageLoader/index' ); module.exports = function buildConfig( @@ -42,15 +42,6 @@ module.exports = { new webpack.DefinePlugin({ __BASE_PATH__: "''", }), - new CopyPlugin({ - patterns: [ - { - from: - '../../../packages/dicom-image-loader/dist/dynamic-import', - to: '${destPath.replace(/\\/g, '/')}', - }, - ], - }), // new BundleAnalyzerPlugin() ], entry: path.join('${exampleBasePath.replace(/\\/g, '/')}', '${relPath.replace( @@ -72,9 +63,6 @@ module.exports = { /\\/g, '//' )}', - // We use this alias and the CopyPlugin to support using the dynamic-import version - // of WADO Image Loader - // '@cornerstonejs/dicom-image-loader': '@cornerstonejs/dicom-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js', '@cornerstonejs/dicom-image-loader': '${csDICOMImageLoader.replace( /\\/g, '/' @@ -98,9 +86,6 @@ module.exports = { "Cross-Origin-Opener-Policy": "same-origin" } }, - experiments: { - asyncWebAssembly: true, - }, /*optimization: { minimize: false, usedExports: true, diff --git a/utils/ExampleRunner/template-multiexample-config.js b/utils/ExampleRunner/template-multiexample-config.js index 7137883da..203cad33f 100644 --- a/utils/ExampleRunner/template-multiexample-config.js +++ b/utils/ExampleRunner/template-multiexample-config.js @@ -9,7 +9,7 @@ const csStreamingBasePath = path.resolve( './packages/streaming-image-volume-loader/src/index' ); const csDICOMImageLoader = path.resolve( - '../dicom-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js' + '../dicom-image-loader/src/imageLoader/index' ); module.exports = function buildConfig(names, exampleBasePaths, destPath, root) { @@ -75,11 +75,6 @@ module.exports = { /\\/g, '/' )}" }, - // { - // from: - // '../../../node_modules/@cornerstonejs/dicom-image-loader/dist/dynamic-import', - // to: '${destPath.replace(/\\/g, '/')}', - // }, ], }), ], @@ -101,9 +96,6 @@ module.exports = { /\\/g, '/' )}', - // We use this alias and the CopyPlugin to support using the dynamic-import version - // of WADO Image Loader - // '@cornerstonejs/dicom-image-loader': '@cornerstonejs/dicom-image-loader/dist/dynamic-import/cornerstoneWADOImageLoader.min.js', '@cornerstonejs/dicom-image-loader': '${csDICOMImageLoader.replace( /\\/g, '/' @@ -127,9 +119,6 @@ module.exports = { "Cross-Origin-Opener-Policy": "same-origin" } }, - experiments: { - asyncWebAssembly: true, - }, optimization: { minimize: false }, From a10c16c735b9b23adfa73706ee7080b980606f13 Mon Sep 17 00:00:00 2001 From: Alireza Date: Thu, 24 Nov 2022 16:34:30 -0500 Subject: [PATCH 04/14] add previous webpack files --- packages/dicom-image-loader/.webpack/merge.js | 19 ++++ .../.webpack/webpack-base.js | 21 ++-- .../.webpack/webpack-bundle.js | 105 ++++++++++++++++++ .../.webpack/webpack-dev.js | 27 +++++ .../.webpack/webpack-dynamic-import.js | 2 +- .../.webpack/webpack-esm.js | 90 +++++++++++++++ .../.webpack/webpack.dev.js | 36 ------ .../.webpack/webpack.prod.js | 36 ------ packages/dicom-image-loader/package.json | 37 ++++-- .../src/imageLoader/index-noWorkers.js | 2 - packages/dicom-image-loader/src/version.js | 1 + 11 files changed, 281 insertions(+), 95 deletions(-) create mode 100644 packages/dicom-image-loader/.webpack/merge.js create mode 100644 packages/dicom-image-loader/.webpack/webpack-bundle.js create mode 100644 packages/dicom-image-loader/.webpack/webpack-dev.js create mode 100644 packages/dicom-image-loader/.webpack/webpack-esm.js delete mode 100644 packages/dicom-image-loader/.webpack/webpack.dev.js delete mode 100644 packages/dicom-image-loader/.webpack/webpack.prod.js create mode 100644 packages/dicom-image-loader/src/version.js diff --git a/packages/dicom-image-loader/.webpack/merge.js b/packages/dicom-image-loader/.webpack/merge.js new file mode 100644 index 000000000..2b6f358a8 --- /dev/null +++ b/packages/dicom-image-loader/.webpack/merge.js @@ -0,0 +1,19 @@ +const _ = require('lodash'); + +// Merge two objects +// Instead of merging array objects index by index (n-th source +// item with n-th object item) it concatenates both arrays +module.exports = function (object, source) { + const clone = _.cloneDeep(object); + const merged = _.mergeWith( + clone, + source, + function (objValue, srcValue, key, object, source, stack) { + if (objValue && srcValue && _.isArray(objValue) && _.isArray(srcValue)) { + return _.concat(objValue, srcValue); + } + } + ); + + return merged; +}; diff --git a/packages/dicom-image-loader/.webpack/webpack-base.js b/packages/dicom-image-loader/.webpack/webpack-base.js index 15fcb65ef..fce51d91a 100644 --- a/packages/dicom-image-loader/.webpack/webpack-base.js +++ b/packages/dicom-image-loader/.webpack/webpack-base.js @@ -43,15 +43,15 @@ module.exports = { module: { noParse: [/(codecs)/], rules: [ - // { - // enforce: 'pre', - // test: /\.js$/, - // exclude: /(node_modules)|(codecs)/, - // loader: 'eslint-loader', - // options: { - // failOnError: false, - // }, - // }, + { + enforce: 'pre', + test: /\.js$/, + exclude: /(node_modules)|(codecs)/, + loader: 'eslint-loader', + options: { + failOnError: false, + }, + }, { test: /\.wasm/, type: 'asset/resource', @@ -84,6 +84,9 @@ module.exports = { }, ], }, + // experiments: { + // asyncWebAssembly: true, + // }, plugins: [new webpack.ProgressPlugin()], // plugins: [new webpack.ProgressPlugin(), new BundleAnalyzerPlugin()], }; diff --git a/packages/dicom-image-loader/.webpack/webpack-bundle.js b/packages/dicom-image-loader/.webpack/webpack-bundle.js new file mode 100644 index 000000000..5f01476b6 --- /dev/null +++ b/packages/dicom-image-loader/.webpack/webpack-bundle.js @@ -0,0 +1,105 @@ +const path = require('path'); +const webpack = require('webpack'); +const rootPath = process.cwd(); +const context = path.join(rootPath, 'src'); +const codecs = path.join(rootPath, 'codecs'); +const outputPath = path.join(rootPath, 'dist'); +const TerserPlugin = require('terser-webpack-plugin'); + +const BundleAnalyzerPlugin = + require('webpack-bundle-analyzer').BundleAnalyzerPlugin; + +// The big difference between this and the dynamic-import version is that +// the dynamic import version does not bundle the WASM modules into the WebWorker file +module.exports = { + mode: 'production', + context, + entry: { + cornerstoneWADOImageLoader: './imageLoader/index.js', + cornerstoneWADOImageLoaderNoWebWorkers: './imageLoader/index-noWorkers.js', + }, + target: 'web', + output: { + library: { + name: 'cornerstoneWADOImageLoader', + type: 'umd', + umdNamedDefine: true, + }, + globalObject: 'this', + path: outputPath, + filename: '[name].bundle.min.js', + }, + devtool: 'source-map', + externals: { + 'dicom-parser': { + commonjs: 'dicom-parser', + commonjs2: 'dicom-parser', + amd: 'dicom-parser', + root: 'dicomParser', + }, + }, + resolve: { + fallback: { + fs: false, + path: false, + }, + }, + module: { + noParse: [/(codecs)/], + rules: [ + { + enforce: 'pre', + test: /\.js$/, + exclude: /(node_modules)|(codecs)/, + loader: 'eslint-loader', + options: { + failOnError: false, + }, + }, + { + test: /\.wasm/, + type: 'asset/inline', + }, + { + test: /\.worker\.js$/, + use: [ + { + loader: 'worker-loader', + options: { inline: 'fallback' }, + }, + { + loader: 'babel-loader', + }, + ], + }, + { + test: /\.js$/, + exclude: [/(node_modules)/, /(codecs)/], + use: { + loader: 'babel-loader', + }, + }, + { + test: path.join(codecs, 'jpeg.js'), + loader: 'exports-loader', + options: { + type: 'commonjs', + exports: 'JpegImage', + }, + }, + ], + }, + plugins: [new webpack.ProgressPlugin()], + experiments: { + asyncWebAssembly: true, + }, + optimization: { + // minimize: false, + minimizer: [ + new TerserPlugin({ + parallel: true, + }), + ], + }, + // plugins: [new webpack.ProgressPlugin(), new BundleAnalyzerPlugin()], +}; diff --git a/packages/dicom-image-loader/.webpack/webpack-dev.js b/packages/dicom-image-loader/.webpack/webpack-dev.js new file mode 100644 index 000000000..2ad276b79 --- /dev/null +++ b/packages/dicom-image-loader/.webpack/webpack-dev.js @@ -0,0 +1,27 @@ +const path = require('path'); +const merge = require('webpack-merge'); +const baseConfig = require('./webpack-base'); + +const devConfig = { + output: { + publicPath: '/dist/', + filename: '[name].bundle.min.js', + }, + devServer: { + hot: true, + open: true, + // Bundles; takes precedence over contentBase + // Static content + static: path.resolve(path.join(__dirname, './../../examples')), + port: 3000, + headers: { + 'Cross-Origin-Embedder-Policy': 'require-corp', + 'Cross-Origin-Opener-Policy': 'same-origin', + }, + }, + /*plugins: [ + new webpack.HotModuleReplacementPlugin({}) + ]*/ +}; + +module.exports = merge(baseConfig, devConfig); diff --git a/packages/dicom-image-loader/.webpack/webpack-dynamic-import.js b/packages/dicom-image-loader/.webpack/webpack-dynamic-import.js index 15659c04c..bf71a664c 100644 --- a/packages/dicom-image-loader/.webpack/webpack-dynamic-import.js +++ b/packages/dicom-image-loader/.webpack/webpack-dynamic-import.js @@ -1,5 +1,5 @@ const path = require('path'); -const { merge } = require('webpack-merge'); +const merge = require('./merge'); const rootPath = process.cwd(); const baseConfig = require('./webpack-base'); const TerserPlugin = require('terser-webpack-plugin'); diff --git a/packages/dicom-image-loader/.webpack/webpack-esm.js b/packages/dicom-image-loader/.webpack/webpack-esm.js new file mode 100644 index 000000000..354fbf052 --- /dev/null +++ b/packages/dicom-image-loader/.webpack/webpack-esm.js @@ -0,0 +1,90 @@ +// Not used for now due to issues with experimental output modules +const path = require('path'); +const webpack = require('webpack'); +const rootPath = process.cwd(); +const context = path.join(rootPath, 'src'); +const outputPath = path.join(rootPath, 'dist'); + +const BundleAnalyzerPlugin = + require('webpack-bundle-analyzer').BundleAnalyzerPlugin; + +const config = { + mode: 'development', + context, + entry: { + cornerstoneWADOImageLoader: './imageLoader/index.js', + }, + target: 'web', + output: { + path: outputPath, + filename: '[name].mjs', + library: { + type: 'module', + }, + module: true, + //libraryTarget: 'module', + //globalObject: 'this', + //chunkFormat: 'module', + }, + externals: { + 'dicom-parser': { + commonjs: 'dicom-parser', + commonjs2: 'dicom-parser', + amd: 'dicom-parser', + root: 'dicomParser', + }, + }, + resolve: { + fallback: { + fs: false, + path: false, + }, + }, + module: { + noParse: [/(codecs)/], + rules: [ + // { + // enforce: 'pre', + // test: /\.js$/, + // exclude: /(node_modules)|(codecs)/, + // loader: 'eslint-loader', + // options: { + // failOnError: false, + // }, + // }, + { + test: /\.wasm/, + type: 'asset/resource', + }, + { + test: /\.js$/, + exclude: [/(node_modules)/, /(codecs)/], + use: { + loader: 'babel-loader', + }, + }, + ], + }, + plugins: [new webpack.ProgressPlugin()], //, new BundleAnalyzerPlugin()], + optimization: { + //minimize: false, + /*minimizer: [ + new TerserPlugin({ + parallel: true, + }), + ],*/ + /*splitChunks: { + // include all types of chunks + chunks: 'all', + },*/ + //runtimeChunk: 'single', + usedExports: true, + concatenateModules: true, + }, + experiments: { + outputModule: true, + // asyncWebAssembly: true + }, +}; + +module.exports = config; diff --git a/packages/dicom-image-loader/.webpack/webpack.dev.js b/packages/dicom-image-loader/.webpack/webpack.dev.js deleted file mode 100644 index a20fea2a3..000000000 --- a/packages/dicom-image-loader/.webpack/webpack.dev.js +++ /dev/null @@ -1,36 +0,0 @@ -const { merge } = require('webpack-merge'); -const path = require('path'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); -const SRC_DIR = path.join(__dirname, '../src'); -const DIST_DIR = path.join(__dirname, '../dist'); - -module.exports = (env, argv) => { - const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); - - return merge(commonConfig, { - devtool: 'source-map', - entry: { - lib: path.join(__dirname, '../src/index.ts'), - }, - output: { - path: path.join(__dirname, '../dist/umd'), - library: 'cornerstone3D', - libraryTarget: 'umd', - filename: 'index.js', - }, - stats: { - colors: true, - hash: true, - timings: true, - assets: true, - chunks: false, - chunkModules: false, - modules: false, - children: false, - warnings: true, - }, - optimization: { - minimize: false, - }, - }); -}; diff --git a/packages/dicom-image-loader/.webpack/webpack.prod.js b/packages/dicom-image-loader/.webpack/webpack.prod.js deleted file mode 100644 index b83e4c439..000000000 --- a/packages/dicom-image-loader/.webpack/webpack.prod.js +++ /dev/null @@ -1,36 +0,0 @@ -const { merge } = require('webpack-merge'); -const path = require('path'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); -const SRC_DIR = path.join(__dirname, '../src'); -const DIST_DIR = path.join(__dirname, '../dist'); - -module.exports = (env, argv) => { - const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); - - return merge(commonConfig, { - devtool: 'source-map', - entry: { - lib: path.join(__dirname, '../src/index.ts'), - }, - output: { - path: path.join(__dirname, '../dist/umd'), - library: 'cornerstone3D', - libraryTarget: 'umd', - filename: 'index.js', - }, - stats: { - colors: true, - hash: true, - timings: true, - assets: true, - chunks: false, - chunkModules: false, - modules: false, - children: false, - warnings: true, - }, - optimization: { - minimize: true, - }, - }); -}; diff --git a/packages/dicom-image-loader/package.json b/packages/dicom-image-loader/package.json index 81319eefc..87b69fc07 100644 --- a/packages/dicom-image-loader/package.json +++ b/packages/dicom-image-loader/package.json @@ -14,20 +14,35 @@ }, "sideEffects": false, "scripts": { - "build:cjs": "tsc --project ./tsconfig.cjs.json", - "build:esm": "tsc --project ./tsconfig.esm.json", - "build:umd": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js", - "build:all": "yarn run build:umd && yarn run build:cjs && yarn run build:esm", - "copy-dts": "copyfiles -u 1 \"src/**/*.d.ts\" dist/cjs && copyfiles -u 1 \"src/**/*.d.ts\" dist/esm", - "build": "yarn run build:all && yarn run copy-dts", - "api-check": "api-extractor --debug run", - "build:update-api": "yarn run build && api-extractor run --local", - "prepublishOnly": "yarn run build", - "example": "node ../../utils/ExampleRunner/example-runner-cli.js", + "cm": "npx git-cz", + "build": "npm run webpack:bundle && npm run webpack:dynamic-import", + "clean": "npm run clean:dist && npm run clean:coverage", + "clean:dist": "shx rm -rf dist", + "clean:docs": "shx rm -rf documentation", + "clean:coverage": "shx rm -rf coverage", + "doc": "npm run doc:generate && opn documentation/index.html", + "doc:generate": "npm run clean:docs && jsdoc -c .jsdocrc", + "eslint": "eslint -c .eslintrc.js src", + "eslint-quiet": "eslint -c .eslintrc.js --quiet src", + "eslint-fix": "eslint -c .eslintrc.js --fix src", + "eslint-fix-test": "eslint -c .eslintrc.js --fix test", + "start": "npm run webpack:dev", + "start:dev": "webpack-dev-server --config ./.webpack/webpack-dev", + "test": "npm run test:chrome", + "test:ci": "karma start config/karma/karma-base.js --single-run", + "test:all": "npm run test && npm run test:chrome && npm run test:firefox", + "test:chrome": "karma start config/karma/karma-base.js", + "test:firefox": "karma start config/karma/karma-firefox.js", + "test:watch": "karma start config/karma/karma-watch.js", + "version": "node -p -e \"'export default \\'' + require('./package.json').version + '\\';'\" > src/version.js", + "watch": "npm run clean && shx mkdir dist && npm run webpack:watch", + "dev": "npm run webpack:dev", "webpack:dev": "webpack serve --progress --config ./.webpack/webpack-dev.js", "webpack:dynamic-import": "webpack --progress --config ./.webpack/webpack-dynamic-import", "webpack:bundle": "webpack --progress --config ./.webpack/webpack-bundle", - "webpack:dynamic-import:watch": "webpack --progress --watch --config ./.webpack/webpack-dynamic-import" + "webpack:dynamic-import:watch": "webpack --progress --watch --config ./.webpack/webpack-dynamic-import", + "webpack:watch": "webpack --progress --watch --config ./webpack", + "prepublishOnly": "npm run build && npm run test:ci && npm run doc:generate" }, "dependencies": { "@cornerstonejs/codec-charls": "^0.1.1", diff --git a/packages/dicom-image-loader/src/imageLoader/index-noWorkers.js b/packages/dicom-image-loader/src/imageLoader/index-noWorkers.js index b3d4e697e..ef0554c3a 100644 --- a/packages/dicom-image-loader/src/imageLoader/index-noWorkers.js +++ b/packages/dicom-image-loader/src/imageLoader/index-noWorkers.js @@ -41,7 +41,6 @@ const cornerstoneWADOImageLoader = { isColorImage, isJPEGBaseline8BitColor, webWorkerManager, - version, internal, external, }; @@ -65,7 +64,6 @@ export { isColorImage, isJPEGBaseline8BitColor, webWorkerManager, - version, internal, external, }; diff --git a/packages/dicom-image-loader/src/version.js b/packages/dicom-image-loader/src/version.js new file mode 100644 index 000000000..7007954a0 --- /dev/null +++ b/packages/dicom-image-loader/src/version.js @@ -0,0 +1 @@ +export default '0.1.1'; From 82da3f0c6d6e3752eb7249372081fae164072f1f Mon Sep 17 00:00:00 2001 From: James Manners Date: Wed, 7 Dec 2022 14:01:04 +1100 Subject: [PATCH 05/14] [wip] initial dicom-loader typescript conversion --- .../.webpack/webpack-base.js | 9 ++++---- .../.webpack/webpack-bundle.js | 11 +++++----- .../.webpack/webpack-esm.js | 5 +++-- ...{externalModules.js => externalModules.ts} | 22 ++++++++++--------- ...PALETTECOLOR.js => convertPALETTECOLOR.ts} | 0 ...orByPixel.js => convertRGBColorByPixel.ts} | 0 ...orByPlane.js => convertRGBColorByPlane.ts} | 0 ...ByPixel.js => convertYBRFull422ByPixel.ts} | 0 ...ullByPixel.js => convertYBRFullByPixel.ts} | 0 ...ullByPlane.js => convertYBRFullByPlane.ts} | 0 .../{index.js => index.ts} | 0 .../{configure.js => configure.ts} | 0 ...vertColorSpace.js => convertColorSpace.ts} | 0 .../{createImage.js => createImage.ts} | 0 ...rkers.js => decodeImageFrame-noWorkers.ts} | 0 ...ecodeImageFrame.js => decodeImageFrame.ts} | 0 ...olor.js => decodeJPEGBaseline8BitColor.ts} | 0 .../{getImageFrame.js => getImageFrame.ts} | 0 .../{getMinMax.js => getMinMax.ts} | 0 ...gParameters.js => getScalingParameters.ts} | 0 .../{imageIdToURI.js => imageIdToURI.ts} | 0 ...{index-noWorkers.js => index-noWorkers.ts} | 0 .../src/imageLoader/{index.js => index.ts} | 0 .../internal/{index.js => index.ts} | 0 .../internal/{options.js => options.ts} | 0 .../internal/{xhrRequest.js => xhrRequest.ts} | 0 .../{isColorImage.js => isColorImage.ts} | 0 ...BitColor.js => isJPEGBaseline8BitColor.ts} | 0 ...{registerLoaders.js => registerLoaders.ts} | 0 ...dIndexOfString.js => findIndexOfString.ts} | 0 .../{getPixelData.js => getPixelData.ts} | 0 .../imageLoader/wadors/{index.js => index.ts} | 0 .../wadors/{loadImage.js => loadImage.ts} | 0 .../{loadImage_test.js => loadImage_test.ts} | 0 ...{getNumberString.js => getNumberString.ts} | 0 .../{getNumberValue.js => getNumberValue.ts} | 0 ...{getNumberValues.js => getNumberValues.ts} | 0 ...laneModule.js => getOverlayPlaneModule.ts} | 0 .../metaData/{getValue.js => getValue.ts} | 0 .../wadors/metaData/{index.js => index.ts} | 0 ...etaDataProvider.js => metaDataProvider.ts} | 0 ...{metaDataManager.js => metaDataManager.ts} | 0 .../wadors/{register.js => register.ts} | 0 ...CacheManager.js => dataSetCacheManager.ts} | 0 ...er_test.js => dataSetCacheManager_test.ts} | 0 .../{fileManager.js => fileManager.ts} | 0 ...eFrame.js => getEncapsulatedImageFrame.ts} | 0 .../{getPixelData.js => getPixelData.ts} | 0 ...eFrame.js => getUncompressedImageFrame.ts} | 0 .../wadouri/{index.js => index.ts} | 0 ...{loadFileRequest.js => loadFileRequest.ts} | 0 .../wadouri/{loadImage.js => loadImage.ts} | 0 ...ePixelModule.js => getImagePixelModule.ts} | 0 .../metaData/{getLUTs.js => getLUTs.ts} | 0 ...etModalityLUTOutputPixelRepresentation.ts} | 0 ...{getNumberValues.js => getNumberValues.ts} | 0 ...laneModule.js => getOverlayPlaneModule.ts} | 0 .../wadouri/metaData/{index.js => index.ts} | 0 ...etaDataProvider.js => metaDataProvider.ts} | 0 .../{parseImageId.js => parseImageId.ts} | 0 .../wadouri/{register.js => register.ts} | 0 ...ackBinaryFrame.js => unpackBinaryFrame.ts} | 0 ...ebWorkerManager.js => webWorkerManager.ts} | 0 ...nager_test.js => webWorkerManager_test.ts} | 0 ...{calculateMinMax.js => calculateMinMax.ts} | 0 ...MinMax_test.js => calculateMinMax_test.ts} | 0 ...ecodeImageFrame.js => decodeImageFrame.ts} | 0 ...{decodeBigEndian.js => decodeBigEndian.ts} | 0 .../{decodeJPEG2000.js => decodeJPEG2000.ts} | 0 ...it-js.js => decodeJPEGBaseline12Bit-js.ts} | 0 ...JPEGBaseline12Bit-wasm-not-yet-working.ts} | 0 ...eline8Bit.js => decodeJPEGBaseline8Bit.ts} | 0 .../{decodeJPEGLS.js => decodeJPEGLS.ts} | 0 ...eJPEGLossless.js => decodeJPEGLossless.ts} | 0 ...eLittleEndian.js => decodeLittleEndian.ts} | 0 .../decoders/{decodeRLE.js => decodeRLE.ts} | 0 .../src/shared/{getMinMax.js => getMinMax.ts} | 0 .../{getMinMax_test.js => getMinMax_test.ts} | 0 .../scaling/{scaleArray.js => scaleArray.ts} | 0 .../src/{version.js => version.ts} | 0 .../{decodeTask.js => decodeTask.ts} | 0 .../{index.worker.js => index.worker.ts} | 0 .../webWorker/{webWorker.js => webWorker.ts} | 0 83 files changed, 26 insertions(+), 21 deletions(-) rename packages/dicom-image-loader/src/{externalModules.js => externalModules.ts} (59%) rename packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/{convertPALETTECOLOR.js => convertPALETTECOLOR.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/{convertRGBColorByPixel.js => convertRGBColorByPixel.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/{convertRGBColorByPlane.js => convertRGBColorByPlane.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/{convertYBRFull422ByPixel.js => convertYBRFull422ByPixel.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/{convertYBRFullByPixel.js => convertYBRFullByPixel.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/{convertYBRFullByPlane.js => convertYBRFullByPlane.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/{index.js => index.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{configure.js => configure.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{convertColorSpace.js => convertColorSpace.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{createImage.js => createImage.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{decodeImageFrame-noWorkers.js => decodeImageFrame-noWorkers.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{decodeImageFrame.js => decodeImageFrame.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{decodeJPEGBaseline8BitColor.js => decodeJPEGBaseline8BitColor.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{getImageFrame.js => getImageFrame.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{getMinMax.js => getMinMax.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{getScalingParameters.js => getScalingParameters.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{imageIdToURI.js => imageIdToURI.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{index-noWorkers.js => index-noWorkers.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{index.js => index.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/internal/{index.js => index.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/internal/{options.js => options.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/internal/{xhrRequest.js => xhrRequest.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{isColorImage.js => isColorImage.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{isJPEGBaseline8BitColor.js => isJPEGBaseline8BitColor.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{registerLoaders.js => registerLoaders.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadors/{findIndexOfString.js => findIndexOfString.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadors/{getPixelData.js => getPixelData.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadors/{index.js => index.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadors/{loadImage.js => loadImage.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadors/{loadImage_test.js => loadImage_test.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadors/metaData/{getNumberString.js => getNumberString.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadors/metaData/{getNumberValue.js => getNumberValue.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadors/metaData/{getNumberValues.js => getNumberValues.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadors/metaData/{getOverlayPlaneModule.js => getOverlayPlaneModule.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadors/metaData/{getValue.js => getValue.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadors/metaData/{index.js => index.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadors/metaData/{metaDataProvider.js => metaDataProvider.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadors/{metaDataManager.js => metaDataManager.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadors/{register.js => register.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{dataSetCacheManager.js => dataSetCacheManager.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{dataSetCacheManager_test.js => dataSetCacheManager_test.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{fileManager.js => fileManager.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{getEncapsulatedImageFrame.js => getEncapsulatedImageFrame.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{getPixelData.js => getPixelData.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{getUncompressedImageFrame.js => getUncompressedImageFrame.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{index.js => index.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{loadFileRequest.js => loadFileRequest.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{loadImage.js => loadImage.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/metaData/{getImagePixelModule.js => getImagePixelModule.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/metaData/{getLUTs.js => getLUTs.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/metaData/{getModalityLUTOutputPixelRepresentation.js => getModalityLUTOutputPixelRepresentation.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/metaData/{getNumberValues.js => getNumberValues.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/metaData/{getOverlayPlaneModule.js => getOverlayPlaneModule.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/metaData/{index.js => index.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/metaData/{metaDataProvider.js => metaDataProvider.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{parseImageId.js => parseImageId.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{register.js => register.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{unpackBinaryFrame.js => unpackBinaryFrame.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{webWorkerManager.js => webWorkerManager.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{webWorkerManager_test.js => webWorkerManager_test.ts} (100%) rename packages/dicom-image-loader/src/shared/{calculateMinMax.js => calculateMinMax.ts} (100%) rename packages/dicom-image-loader/src/shared/{calculateMinMax_test.js => calculateMinMax_test.ts} (100%) rename packages/dicom-image-loader/src/shared/{decodeImageFrame.js => decodeImageFrame.ts} (100%) rename packages/dicom-image-loader/src/shared/decoders/{decodeBigEndian.js => decodeBigEndian.ts} (100%) rename packages/dicom-image-loader/src/shared/decoders/{decodeJPEG2000.js => decodeJPEG2000.ts} (100%) rename packages/dicom-image-loader/src/shared/decoders/{decodeJPEGBaseline12Bit-js.js => decodeJPEGBaseline12Bit-js.ts} (100%) rename packages/dicom-image-loader/src/shared/decoders/{decodeJPEGBaseline12Bit-wasm-not-yet-working.js => decodeJPEGBaseline12Bit-wasm-not-yet-working.ts} (100%) rename packages/dicom-image-loader/src/shared/decoders/{decodeJPEGBaseline8Bit.js => decodeJPEGBaseline8Bit.ts} (100%) rename packages/dicom-image-loader/src/shared/decoders/{decodeJPEGLS.js => decodeJPEGLS.ts} (100%) rename packages/dicom-image-loader/src/shared/decoders/{decodeJPEGLossless.js => decodeJPEGLossless.ts} (100%) rename packages/dicom-image-loader/src/shared/decoders/{decodeLittleEndian.js => decodeLittleEndian.ts} (100%) rename packages/dicom-image-loader/src/shared/decoders/{decodeRLE.js => decodeRLE.ts} (100%) rename packages/dicom-image-loader/src/shared/{getMinMax.js => getMinMax.ts} (100%) rename packages/dicom-image-loader/src/shared/{getMinMax_test.js => getMinMax_test.ts} (100%) rename packages/dicom-image-loader/src/shared/scaling/{scaleArray.js => scaleArray.ts} (100%) rename packages/dicom-image-loader/src/{version.js => version.ts} (100%) rename packages/dicom-image-loader/src/webWorker/{decodeTask.js => decodeTask.ts} (100%) rename packages/dicom-image-loader/src/webWorker/{index.worker.js => index.worker.ts} (100%) rename packages/dicom-image-loader/src/webWorker/{webWorker.js => webWorker.ts} (100%) diff --git a/packages/dicom-image-loader/.webpack/webpack-base.js b/packages/dicom-image-loader/.webpack/webpack-base.js index fce51d91a..f6aed0257 100644 --- a/packages/dicom-image-loader/.webpack/webpack-base.js +++ b/packages/dicom-image-loader/.webpack/webpack-base.js @@ -12,7 +12,7 @@ module.exports = { mode: 'development', context, entry: { - cornerstoneWADOImageLoader: './imageLoader/index.js', + cornerstoneWADOImageLoader: './imageLoader/index.ts', }, target: 'web', output: { @@ -35,6 +35,7 @@ module.exports = { }, }, resolve: { + extensions: ['.ts', '.js'], fallback: { fs: false, path: false, @@ -45,7 +46,7 @@ module.exports = { rules: [ { enforce: 'pre', - test: /\.js$/, + test: /\.(mjs|js|ts)$/, exclude: /(node_modules)|(codecs)/, loader: 'eslint-loader', options: { @@ -57,7 +58,7 @@ module.exports = { type: 'asset/resource', }, { - test: /\.worker\.js$/, + test: /\.worker\.(mjs|js|ts)$/, use: [ { loader: 'worker-loader', @@ -68,7 +69,7 @@ module.exports = { ], }, { - test: /\.js$/, + test: /\.(mjs|js|ts)$/, exclude: [/(node_modules)/, /(codecs)/], use: { loader: 'babel-loader', diff --git a/packages/dicom-image-loader/.webpack/webpack-bundle.js b/packages/dicom-image-loader/.webpack/webpack-bundle.js index 5f01476b6..531706b23 100644 --- a/packages/dicom-image-loader/.webpack/webpack-bundle.js +++ b/packages/dicom-image-loader/.webpack/webpack-bundle.js @@ -15,8 +15,8 @@ module.exports = { mode: 'production', context, entry: { - cornerstoneWADOImageLoader: './imageLoader/index.js', - cornerstoneWADOImageLoaderNoWebWorkers: './imageLoader/index-noWorkers.js', + cornerstoneWADOImageLoader: './imageLoader/index.ts', + cornerstoneWADOImageLoaderNoWebWorkers: './imageLoader/index-noWorkers.ts', }, target: 'web', output: { @@ -39,6 +39,7 @@ module.exports = { }, }, resolve: { + extensions: ['.ts', '.js'], fallback: { fs: false, path: false, @@ -49,7 +50,7 @@ module.exports = { rules: [ { enforce: 'pre', - test: /\.js$/, + test: /\.(mjs|js|ts)$/, exclude: /(node_modules)|(codecs)/, loader: 'eslint-loader', options: { @@ -61,7 +62,7 @@ module.exports = { type: 'asset/inline', }, { - test: /\.worker\.js$/, + test: /\.worker\.(mjs|js|ts)$/, use: [ { loader: 'worker-loader', @@ -73,7 +74,7 @@ module.exports = { ], }, { - test: /\.js$/, + test: /\.(mjs|js|ts)$/, exclude: [/(node_modules)/, /(codecs)/], use: { loader: 'babel-loader', diff --git a/packages/dicom-image-loader/.webpack/webpack-esm.js b/packages/dicom-image-loader/.webpack/webpack-esm.js index 354fbf052..2a34322e0 100644 --- a/packages/dicom-image-loader/.webpack/webpack-esm.js +++ b/packages/dicom-image-loader/.webpack/webpack-esm.js @@ -12,7 +12,7 @@ const config = { mode: 'development', context, entry: { - cornerstoneWADOImageLoader: './imageLoader/index.js', + cornerstoneWADOImageLoader: './imageLoader/index.ts', }, target: 'web', output: { @@ -35,6 +35,7 @@ const config = { }, }, resolve: { + extensions: ['.ts', '.js'], fallback: { fs: false, path: false, @@ -57,7 +58,7 @@ const config = { type: 'asset/resource', }, { - test: /\.js$/, + test: /\.(mjs|js|ts)$/, exclude: [/(node_modules)/, /(codecs)/], use: { loader: 'babel-loader', diff --git a/packages/dicom-image-loader/src/externalModules.js b/packages/dicom-image-loader/src/externalModules.ts similarity index 59% rename from packages/dicom-image-loader/src/externalModules.js rename to packages/dicom-image-loader/src/externalModules.ts index d494efb97..18d332f45 100644 --- a/packages/dicom-image-loader/src/externalModules.js +++ b/packages/dicom-image-loader/src/externalModules.ts @@ -1,20 +1,22 @@ /* eslint import/extensions:0 */ import registerLoaders from './imageLoader/registerLoaders'; +import * as cornerstoneImport from '@cornerstonejs/core'; +import * as dicomParserImport from 'dicom-parser'; -let cornerstone; +let cornerstone: typeof cornerstoneImport; -let dicomParser; +let dicomParser: typeof dicomParserImport; const external = { - set cornerstone(cs) { + set cornerstone(cs: typeof cornerstoneImport) { cornerstone = cs; registerLoaders(cornerstone); }, - get cornerstone() { + get cornerstone(): typeof cornerstoneImport { if (!cornerstone) { - if (window && window.cornerstone) { - cornerstone = window.cornerstone; + if (window && (window as any).cornerstone) { + cornerstone = (window as any).cornerstone; registerLoaders(cornerstone); } else { @@ -26,13 +28,13 @@ const external = { return cornerstone; }, - set dicomParser(dp) { + set dicomParser(dp: typeof dicomParserImport) { dicomParser = dp; }, - get dicomParser() { + get dicomParser(): typeof dicomParserImport { if (!dicomParser) { - if (window && window.dicomParser) { - dicomParser = window.dicomParser; + if (window && (window as any).dicomParser) { + dicomParser = (window as any).dicomParser; } else { throw new Error( 'cornerstoneWADOImageLoader requires a copy of dicomParser to work properly. Please add cornerstoneWADOImageLoader.external.dicomParser = dicomParser; to your application.' diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.js rename to packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.ts diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.js rename to packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.ts diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.js rename to packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.ts diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.js rename to packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.ts diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.js rename to packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.ts diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.js rename to packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.ts diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/index.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/index.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/index.js rename to packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/index.ts diff --git a/packages/dicom-image-loader/src/imageLoader/configure.js b/packages/dicom-image-loader/src/imageLoader/configure.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/configure.js rename to packages/dicom-image-loader/src/imageLoader/configure.ts diff --git a/packages/dicom-image-loader/src/imageLoader/convertColorSpace.js b/packages/dicom-image-loader/src/imageLoader/convertColorSpace.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/convertColorSpace.js rename to packages/dicom-image-loader/src/imageLoader/convertColorSpace.ts diff --git a/packages/dicom-image-loader/src/imageLoader/createImage.js b/packages/dicom-image-loader/src/imageLoader/createImage.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/createImage.js rename to packages/dicom-image-loader/src/imageLoader/createImage.ts diff --git a/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.js b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.js rename to packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.ts diff --git a/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.js b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/decodeImageFrame.js rename to packages/dicom-image-loader/src/imageLoader/decodeImageFrame.ts diff --git a/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.js b/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.js rename to packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.ts diff --git a/packages/dicom-image-loader/src/imageLoader/getImageFrame.js b/packages/dicom-image-loader/src/imageLoader/getImageFrame.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/getImageFrame.js rename to packages/dicom-image-loader/src/imageLoader/getImageFrame.ts diff --git a/packages/dicom-image-loader/src/imageLoader/getMinMax.js b/packages/dicom-image-loader/src/imageLoader/getMinMax.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/getMinMax.js rename to packages/dicom-image-loader/src/imageLoader/getMinMax.ts diff --git a/packages/dicom-image-loader/src/imageLoader/getScalingParameters.js b/packages/dicom-image-loader/src/imageLoader/getScalingParameters.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/getScalingParameters.js rename to packages/dicom-image-loader/src/imageLoader/getScalingParameters.ts diff --git a/packages/dicom-image-loader/src/imageLoader/imageIdToURI.js b/packages/dicom-image-loader/src/imageLoader/imageIdToURI.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/imageIdToURI.js rename to packages/dicom-image-loader/src/imageLoader/imageIdToURI.ts diff --git a/packages/dicom-image-loader/src/imageLoader/index-noWorkers.js b/packages/dicom-image-loader/src/imageLoader/index-noWorkers.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/index-noWorkers.js rename to packages/dicom-image-loader/src/imageLoader/index-noWorkers.ts diff --git a/packages/dicom-image-loader/src/imageLoader/index.js b/packages/dicom-image-loader/src/imageLoader/index.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/index.js rename to packages/dicom-image-loader/src/imageLoader/index.ts diff --git a/packages/dicom-image-loader/src/imageLoader/internal/index.js b/packages/dicom-image-loader/src/imageLoader/internal/index.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/internal/index.js rename to packages/dicom-image-loader/src/imageLoader/internal/index.ts diff --git a/packages/dicom-image-loader/src/imageLoader/internal/options.js b/packages/dicom-image-loader/src/imageLoader/internal/options.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/internal/options.js rename to packages/dicom-image-loader/src/imageLoader/internal/options.ts diff --git a/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.js b/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.js rename to packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.ts diff --git a/packages/dicom-image-loader/src/imageLoader/isColorImage.js b/packages/dicom-image-loader/src/imageLoader/isColorImage.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/isColorImage.js rename to packages/dicom-image-loader/src/imageLoader/isColorImage.ts diff --git a/packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.js b/packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.js rename to packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.ts diff --git a/packages/dicom-image-loader/src/imageLoader/registerLoaders.js b/packages/dicom-image-loader/src/imageLoader/registerLoaders.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/registerLoaders.js rename to packages/dicom-image-loader/src/imageLoader/registerLoaders.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.js b/packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.js rename to packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.js b/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.js rename to packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/index.js b/packages/dicom-image-loader/src/imageLoader/wadors/index.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/index.js rename to packages/dicom-image-loader/src/imageLoader/wadors/index.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.js b/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/loadImage.js rename to packages/dicom-image-loader/src/imageLoader/wadors/loadImage.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/loadImage_test.js b/packages/dicom-image-loader/src/imageLoader/wadors/loadImage_test.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/loadImage_test.js rename to packages/dicom-image-loader/src/imageLoader/wadors/loadImage_test.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.js rename to packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.js rename to packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.js rename to packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.js rename to packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.js rename to packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/index.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/index.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/metaData/index.js rename to packages/dicom-image-loader/src/imageLoader/wadors/metaData/index.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.js rename to packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.js rename to packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/register.js b/packages/dicom-image-loader/src/imageLoader/wadors/register.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/register.js rename to packages/dicom-image-loader/src/imageLoader/wadors/register.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.js b/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager_test.js b/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager_test.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager_test.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager_test.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.js b/packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.js b/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.js b/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.js b/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/index.js b/packages/dicom-image-loader/src/imageLoader/wadouri/index.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/index.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/index.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.js b/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.js b/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/index.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/index.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/metaData/index.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/metaData/index.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.js b/packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/register.js b/packages/dicom-image-loader/src/imageLoader/wadouri/register.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/register.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/register.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.js b/packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.ts diff --git a/packages/dicom-image-loader/src/imageLoader/webWorkerManager.js b/packages/dicom-image-loader/src/imageLoader/webWorkerManager.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/webWorkerManager.js rename to packages/dicom-image-loader/src/imageLoader/webWorkerManager.ts diff --git a/packages/dicom-image-loader/src/imageLoader/webWorkerManager_test.js b/packages/dicom-image-loader/src/imageLoader/webWorkerManager_test.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/webWorkerManager_test.js rename to packages/dicom-image-loader/src/imageLoader/webWorkerManager_test.ts diff --git a/packages/dicom-image-loader/src/shared/calculateMinMax.js b/packages/dicom-image-loader/src/shared/calculateMinMax.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/calculateMinMax.js rename to packages/dicom-image-loader/src/shared/calculateMinMax.ts diff --git a/packages/dicom-image-loader/src/shared/calculateMinMax_test.js b/packages/dicom-image-loader/src/shared/calculateMinMax_test.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/calculateMinMax_test.js rename to packages/dicom-image-loader/src/shared/calculateMinMax_test.ts diff --git a/packages/dicom-image-loader/src/shared/decodeImageFrame.js b/packages/dicom-image-loader/src/shared/decodeImageFrame.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/decodeImageFrame.js rename to packages/dicom-image-loader/src/shared/decodeImageFrame.ts diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.js b/packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.js rename to packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.ts diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.js rename to packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.ts diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.js rename to packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.ts diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-wasm-not-yet-working.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-wasm-not-yet-working.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-wasm-not-yet-working.js rename to packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-wasm-not-yet-working.ts diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.js rename to packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.ts diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.js rename to packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.ts diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.js rename to packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.ts diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.js b/packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.js rename to packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.ts diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeRLE.js b/packages/dicom-image-loader/src/shared/decoders/decodeRLE.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/decoders/decodeRLE.js rename to packages/dicom-image-loader/src/shared/decoders/decodeRLE.ts diff --git a/packages/dicom-image-loader/src/shared/getMinMax.js b/packages/dicom-image-loader/src/shared/getMinMax.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/getMinMax.js rename to packages/dicom-image-loader/src/shared/getMinMax.ts diff --git a/packages/dicom-image-loader/src/shared/getMinMax_test.js b/packages/dicom-image-loader/src/shared/getMinMax_test.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/getMinMax_test.js rename to packages/dicom-image-loader/src/shared/getMinMax_test.ts diff --git a/packages/dicom-image-loader/src/shared/scaling/scaleArray.js b/packages/dicom-image-loader/src/shared/scaling/scaleArray.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/scaling/scaleArray.js rename to packages/dicom-image-loader/src/shared/scaling/scaleArray.ts diff --git a/packages/dicom-image-loader/src/version.js b/packages/dicom-image-loader/src/version.ts similarity index 100% rename from packages/dicom-image-loader/src/version.js rename to packages/dicom-image-loader/src/version.ts diff --git a/packages/dicom-image-loader/src/webWorker/decodeTask.js b/packages/dicom-image-loader/src/webWorker/decodeTask.ts similarity index 100% rename from packages/dicom-image-loader/src/webWorker/decodeTask.js rename to packages/dicom-image-loader/src/webWorker/decodeTask.ts diff --git a/packages/dicom-image-loader/src/webWorker/index.worker.js b/packages/dicom-image-loader/src/webWorker/index.worker.ts similarity index 100% rename from packages/dicom-image-loader/src/webWorker/index.worker.js rename to packages/dicom-image-loader/src/webWorker/index.worker.ts diff --git a/packages/dicom-image-loader/src/webWorker/webWorker.js b/packages/dicom-image-loader/src/webWorker/webWorker.ts similarity index 100% rename from packages/dicom-image-loader/src/webWorker/webWorker.js rename to packages/dicom-image-loader/src/webWorker/webWorker.ts From edb3eb5bcd49d980124d9b76f06d388fcbbb07c2 Mon Sep 17 00:00:00 2001 From: James Manners Date: Wed, 7 Dec 2022 15:14:05 +1100 Subject: [PATCH 06/14] [wip] initial typescript conversion --- .../convertPALETTECOLOR.ts | 11 +- .../convertRGBColorByPixel.ts | 8 +- .../convertRGBColorByPlane.ts | 8 +- .../convertYBRFull422ByPixel.ts | 8 +- .../convertYBRFullByPixel.ts | 8 +- .../convertYBRFullByPlane.ts | 8 +- .../src/imageLoader/configure.ts | 3 +- .../src/imageLoader/createImage.ts | 64 ++++++--- .../imageLoader/decodeImageFrame-noWorkers.ts | 23 +-- .../src/imageLoader/decodeImageFrame.ts | 26 ++-- .../decodeJPEGBaseline8BitColor.ts | 23 ++- .../src/imageLoader/getImageFrame.ts | 10 +- .../src/imageLoader/getMinMax.ts | 5 +- .../src/imageLoader/getScalingParameters.ts | 10 +- .../src/imageLoader/imageIdToURI.ts | 2 +- .../src/imageLoader/internal/options.ts | 38 ++++- .../src/imageLoader/internal/xhrRequest.ts | 43 ++++-- .../src/imageLoader/isColorImage.ts | 2 +- .../imageLoader/isJPEGBaseline8BitColor.ts | 10 +- .../src/imageLoader/registerLoaders.ts | 3 +- .../src/imageLoader/wado-loader.ts | 18 +++ .../imageLoader/wadors/findIndexOfString.ts | 10 +- .../src/imageLoader/wadors/getPixelData.ts | 18 ++- .../src/imageLoader/wadors/loadImage.ts | 135 ++++++++++-------- .../wadors/metaData/getNumberString.ts | 7 +- .../wadors/metaData/getNumberValue.ts | 6 +- .../wadors/metaData/getNumberValues.ts | 11 +- .../wadors/metaData/getOverlayPlaneModule.ts | 3 +- .../imageLoader/wadors/metaData/getValue.ts | 8 +- .../wadors/metaData/metaDataProvider.ts | 16 +-- .../src/imageLoader/wadors/metaDataManager.ts | 11 +- .../src/imageLoader/wadors/register.ts | 3 +- .../imageLoader/wadors/wado-rs-metadata.ts | 5 + .../wadouri/dataSetCacheManager.ts | 127 +++++++++------- .../src/imageLoader/wadouri/fileManager.ts | 10 +- .../wadouri/getEncapsulatedImageFrame.ts | 8 +- .../src/imageLoader/wadouri/getPixelData.ts | 3 +- .../wadouri/getUncompressedImageFrame.ts | 6 +- .../imageLoader/wadouri/loadFileRequest.ts | 6 +- .../src/imageLoader/wadouri/loadImage.ts | 109 ++++++++------ .../wadouri/metaData/getImagePixelModule.ts | 23 ++- .../imageLoader/wadouri/metaData/getLUTs.ts | 21 ++- ...getModalityLUTOutputPixelRepresentation.ts | 6 +- .../wadouri/metaData/getNumberValues.ts | 8 +- .../wadouri/metaData/getOverlayPlaneModule.ts | 4 +- .../wadouri/metaData/metaDataProvider.ts | 60 ++++++-- .../src/imageLoader/wadouri/parseImageId.ts | 8 +- .../src/imageLoader/wadouri/register.ts | 3 +- .../imageLoader/wadouri/unpackBinaryFrame.ts | 10 +- .../src/imageLoader/webWorkerManager.ts | 92 +++++++++--- .../src/shared/decodeImageFrame.ts | 20 ++- .../src/shared/decoders/decodeBigEndian.ts | 8 +- .../src/shared/decoders/decodeJPEG2000.ts | 13 +- .../decoders/decodeJPEGBaseline12Bit-js.ts | 15 +- .../shared/decoders/decodeJPEGBaseline8Bit.ts | 11 +- .../src/shared/decoders/decodeJPEGLS.ts | 16 ++- .../src/shared/decoders/decodeJPEGLossless.ts | 15 +- .../src/shared/decoders/decodeLittleEndian.ts | 8 +- .../src/shared/decoders/decodeRLE.ts | 17 ++- .../src/shared/getMinMax.ts | 4 +- .../src/shared/image-frame.ts | 30 ++++ .../src/shared/scaling/scaleArray.ts | 5 +- .../src/shared/types/load-image-options.ts | 17 +++ .../src/shared/types/load-request-function.ts | 6 + .../src/shared/types/metadata-modules.ts | 81 +++++++++++ .../src/webWorker/decodeTask.ts | 26 ++-- .../src/webWorker/webWorker.ts | 45 +++++- .../src/webWorker/webworker-messages.ts | 46 ++++++ 68 files changed, 1096 insertions(+), 355 deletions(-) create mode 100644 packages/dicom-image-loader/src/imageLoader/wado-loader.ts create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/wado-rs-metadata.ts create mode 100644 packages/dicom-image-loader/src/shared/image-frame.ts create mode 100644 packages/dicom-image-loader/src/shared/types/load-image-options.ts create mode 100644 packages/dicom-image-loader/src/shared/types/load-request-function.ts create mode 100644 packages/dicom-image-loader/src/shared/types/metadata-modules.ts create mode 100644 packages/dicom-image-loader/src/webWorker/webworker-messages.ts diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.ts b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.ts index 5a9b1f56f..fd7d4f455 100644 --- a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.ts +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.ts @@ -1,6 +1,9 @@ /* eslint no-bitwise: 0 */ -function convertLUTto8Bit(lut, shift) { +import { CornerstoneWadoImageFrame } from 'dicom-image-loader/src/shared/image-frame'; +import { ByteArray } from 'dicom-parser'; + +function convertLUTto8Bit(lut: number[], shift: number) { const numEntries = lut.length; const cleanedLUT = new Uint8ClampedArray(numEntries); @@ -18,7 +21,11 @@ function convertLUTto8Bit(lut, shift) { * @param {Uint8ClampedArray} colorBuffer * @returns {void} */ -export default function (imageFrame, colorBuffer, useRGBA) { +export default function ( + imageFrame: CornerstoneWadoImageFrame, + colorBuffer: ByteArray, + useRGBA: boolean +): void { const numPixels = imageFrame.columns * imageFrame.rows; const pixelData = imageFrame.pixelData; const rData = imageFrame.redPaletteColorLookupTableData; diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.ts b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.ts index 2222c1e3f..0b149aef1 100644 --- a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.ts +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.ts @@ -1,4 +1,10 @@ -export default function (imageFrame, colorBuffer, useRGBA) { +import { ByteArray } from 'dicom-parser'; + +export default function ( + imageFrame: ByteArray, + colorBuffer: ByteArray, + useRGBA: boolean +): void { if (imageFrame === undefined) { throw new Error('decodeRGB: rgbBuffer must not be undefined'); } diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.ts b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.ts index 124d9ee03..2e5f22fce 100644 --- a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.ts +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.ts @@ -1,4 +1,10 @@ -export default function (imageFrame, colorBuffer, useRGBA) { +import { ByteArray } from 'dicom-parser'; + +export default function ( + imageFrame: ByteArray, + colorBuffer: ByteArray, + useRGBA: boolean +): void { if (imageFrame === undefined) { throw new Error('decodeRGB: rgbBuffer must not be undefined'); } diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.ts b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.ts index 13cc124a5..1083abad0 100644 --- a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.ts +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.ts @@ -1,4 +1,10 @@ -export default function (imageFrame, colorBuffer, useRGBA) { +import { ByteArray } from 'dicom-parser'; + +export default function ( + imageFrame: ByteArray, + colorBuffer: ByteArray, + useRGBA: boolean +): void { if (imageFrame === undefined) { throw new Error('decodeRGB: ybrBuffer must not be undefined'); } diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.ts b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.ts index dfd46fde9..2ca53110c 100644 --- a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.ts +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.ts @@ -1,4 +1,10 @@ -export default function (imageFrame, colorBuffer, useRGBA) { +import { ByteArray } from 'dicom-parser'; + +export default function ( + imageFrame: ByteArray, + colorBuffer: ByteArray, + useRGBA: boolean +): void { if (imageFrame === undefined) { throw new Error('decodeRGB: ybrBuffer must not be undefined'); } diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.ts b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.ts index ccac454b9..389b6c73c 100644 --- a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.ts +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.ts @@ -1,4 +1,10 @@ -export default function (imageFrame, colorBuffer, useRGBA) { +import { ByteArray } from 'dicom-parser'; + +export default function ( + imageFrame: ByteArray, + colorBuffer: ByteArray, + useRGBA: boolean +): void { if (imageFrame === undefined) { throw new Error('decodeRGB: ybrBuffer must not be undefined'); } diff --git a/packages/dicom-image-loader/src/imageLoader/configure.ts b/packages/dicom-image-loader/src/imageLoader/configure.ts index 0c6f20b69..3fa07a5c1 100644 --- a/packages/dicom-image-loader/src/imageLoader/configure.ts +++ b/packages/dicom-image-loader/src/imageLoader/configure.ts @@ -1,6 +1,7 @@ import { setOptions } from './internal/index'; +import { CornerstoneWadoLoaderOptions } from './internal/options'; -function configure(options) { +function configure(options: CornerstoneWadoLoaderOptions): void { setOptions(options); } diff --git a/packages/dicom-image-loader/src/imageLoader/createImage.ts b/packages/dicom-image-loader/src/imageLoader/createImage.ts index 9523008bc..4361c0c6e 100644 --- a/packages/dicom-image-loader/src/imageLoader/createImage.ts +++ b/packages/dicom-image-loader/src/imageLoader/createImage.ts @@ -1,16 +1,24 @@ +import { ByteArray } from 'dicom-parser'; import external from '../externalModules'; -import getImageFrame from './getImageFrame'; +import getMinMax from '../shared/getMinMax'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; +import { + CornerstoneMetadataImagePlaneModule, + CornerstoneMetadataSopCommonModule, +} from '../shared/types/metadata-modules'; +import convertColorSpace from './convertColorSpace'; +import { CornerstoneLoadImageOptions } from '../shared/types/load-image-options'; import decodeImageFrame from './decodeImageFrame'; +import getImageFrame from './getImageFrame'; +import getScalingParameters from './getScalingParameters'; +import { getOptions } from './internal/options'; import isColorImageFn from './isColorImage'; -import convertColorSpace from './convertColorSpace'; -import getMinMax from '../shared/getMinMax'; import isJPEGBaseline8BitColor from './isJPEGBaseline8BitColor'; -import { getOptions } from './internal/options'; -import getScalingParameters from './getScalingParameters'; +import { CornerstoneWadoLoaderIImage } from './wado-loader'; let lastImageIdDrawn = ''; -function isModalityLUTForDisplay(sopClassUid) { +function isModalityLUTForDisplay(sopClassUid: string): boolean { // special case for XA and XRF // https://groups.google.com/forum/#!searchin/comp.protocols.dicom/Modality$20LUT$20XA/comp.protocols.dicom/UBxhOZ2anJ0/D0R_QP8V2wIJ return ( @@ -54,7 +62,7 @@ function convertToIntPixelData(floatPixelData) { * can transfer array buffers but not typed arrays * @param imageFrame */ -function setPixelDataType(imageFrame) { +function setPixelDataType(imageFrame: CornerstoneWadoImageFrame) { if (imageFrame.bitsAllocated === 32) { imageFrame.pixelData = new Float32Array(imageFrame.pixelData); } else if (imageFrame.bitsAllocated === 16) { @@ -76,7 +84,15 @@ function setPixelDataType(imageFrame) { * @param imageFrame - decoded image in RGBA * @param targetBuffer - target buffer to write to */ -function removeAFromRGBA(imageFrame, targetBuffer) { +function removeAFromRGBA( + imageFrame: + | Float32Array // populated later after decoding + | Int16Array + | Uint16Array + | Uint8Array + | Uint8ClampedArray, + targetBuffer: Uint8ClampedArray +) { const numPixels = imageFrame.length / 4; let rgbIndex = 0; @@ -93,7 +109,12 @@ function removeAFromRGBA(imageFrame, targetBuffer) { return targetBuffer; } -function createImage(imageId, pixelData, transferSyntax, options = {}) { +function createImage( + imageId: string, + pixelData: ByteArray, + transferSyntax: string, + options: CornerstoneLoadImageOptions = {} +): Promise { // whether to use RGBA for color images, default true as cs-legacy uses RGBA // but we don't need RGBA in cs3d, and it's faster, and memory-efficient // in cs3d @@ -144,7 +165,7 @@ function createImage(imageId, pixelData, transferSyntax, options = {}) { const { decodeConfig } = getOptions(); const { convertFloatPixelDataToInt } = decodeConfig; - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { // eslint-disable-next-line complexity decodePromise.then(function (imageFrame) { // If we have a target buffer that was written to in the @@ -153,7 +174,7 @@ function createImage(imageId, pixelData, transferSyntax, options = {}) { let alreadyTyped = false; if (options.targetBuffer) { - let offset, length; + let offset: number, length: number; // If we have a target buffer, write to that instead. This helps reduce memory duplication. ({ offset, length } = options.targetBuffer); @@ -210,13 +231,13 @@ function createImage(imageId, pixelData, transferSyntax, options = {}) { setPixelDataType(imageFrame); } - const imagePlaneModule = + const imagePlaneModule: CornerstoneMetadataImagePlaneModule = cornerstone.metaData.get('imagePlaneModule', imageId) || {}; const voiLutModule = cornerstone.metaData.get('voiLutModule', imageId) || {}; const modalityLutModule = cornerstone.metaData.get('modalityLutModule', imageId) || {}; - const sopCommonModule = + const sopCommonModule: CornerstoneMetadataSopCommonModule = cornerstone.metaData.get('sopCommonModule', imageId) || {}; const isColorImage = isColorImageFn(imageFrame.photometricInterpretation); @@ -267,7 +288,8 @@ function createImage(imageId, pixelData, transferSyntax, options = {}) { convertColorSpace(imageFrame, imageData.data, true); - const colorBuffer = new imageData.data.constructor( + /** @todo check as any */ + const colorBuffer = new (imageData.data as any).constructor( (imageData.data.length / 4) * 3 ); @@ -276,14 +298,15 @@ function createImage(imageId, pixelData, transferSyntax, options = {}) { } } + /** @todo check as any */ // calculate smallest and largest PixelValue of the converted pixelData - const minMax = getMinMax(imageFrame.pixelData); + const minMax = getMinMax(imageFrame.pixelData as any); imageFrame.smallestPixelValue = minMax.min; imageFrame.largestPixelValue = minMax.max; } - const image = { + const image: CornerstoneWadoLoaderIImage = { imageId, color: isColorImage, columnPixelSpacing: imagePlaneModule.columnPixelSpacing, @@ -313,6 +336,9 @@ function createImage(imageId, pixelData, transferSyntax, options = {}) { floatPixelData: undefined, imageFrame, rgba: isColorImage && useRGBA, + getPixelData: undefined, + getCanvas: undefined, + numComps: undefined, }; // If pixel data is intrinsically floating 32 array, we convert it to int for @@ -330,9 +356,11 @@ function createImage(imageId, pixelData, transferSyntax, options = {}) { image.slope = results.slope; image.intercept = results.intercept; image.floatPixelData = floatPixelData; - image.getPixelData = () => results.intPixelData; + /** @todo check as any */ + image.getPixelData = () => results.intPixelData as any; } else { - image.getPixelData = () => imageFrame.pixelData; + /** @todo check as any */ + image.getPixelData = () => imageFrame.pixelData as any; } if (image.color) { diff --git a/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.ts b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.ts index 0438ab10b..9c7f6369b 100644 --- a/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.ts +++ b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.ts @@ -1,10 +1,17 @@ -import { getOptions } from './internal/options'; import decodeJPEGBaseline8BitColor from './decodeJPEGBaseline8BitColor'; +import { getOptions } from './internal/options'; -import { default as decodeImageFrameHandler } from '../shared/decodeImageFrame'; +import { ByteArray } from 'dicom-parser'; import calculateMinMax from '../shared/calculateMinMax'; +import { default as decodeImageFrameHandler } from '../shared/decodeImageFrame'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; -function processDecodeTask(imageFrame, transferSyntax, pixelData, options) { +function processDecodeTask( + imageFrame: CornerstoneWadoImageFrame, + transferSyntax: string, + pixelData: ByteArray, + options +): Promise { const loaderOptions = getOptions(); const { strict, decodeConfig } = loaderOptions; @@ -33,12 +40,12 @@ function processDecodeTask(imageFrame, transferSyntax, pixelData, options) { } function decodeImageFrame( - imageFrame, - transferSyntax, - pixelData, - canvas, + imageFrame: CornerstoneWadoImageFrame, + transferSyntax: string, + pixelData: ByteArray, + canvas: HTMLCanvasElement, options = {} -) { +): Promise { switch (transferSyntax) { case '1.2.840.10008.1.2': // Implicit VR Little Endian diff --git a/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.ts b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.ts index c5bcca2dd..2248eecfb 100644 --- a/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.ts +++ b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.ts @@ -5,16 +5,26 @@ import decodeJPEGBaseline8BitColor from './decodeJPEGBaseline8BitColor'; // We only need one function though, so lets import that so we don't make our bundle // too large. import { inflateRaw } from 'pako/lib/inflate'; +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; -window.pako = { inflateRaw }; +/** + * @todo check any + */ +(window as any).pako = { inflateRaw }; -function processDecodeTask(imageFrame, transferSyntax, pixelData, options) { +function processDecodeTask( + imageFrame: CornerstoneWadoImageFrame, + transferSyntax: string, + pixelData: ByteArray, + options +): Promise { const priority = options.priority || undefined; const transferList = options.transferPixelData ? [pixelData.buffer] : undefined; - return webWorkerManager.addTask( + return webWorkerManager.addTask( 'decodeTask', { imageFrame, @@ -28,12 +38,12 @@ function processDecodeTask(imageFrame, transferSyntax, pixelData, options) { } function decodeImageFrame( - imageFrame, - transferSyntax, - pixelData, - canvas, + imageFrame: CornerstoneWadoImageFrame, + transferSyntax: string, + pixelData: ByteArray, + canvas: HTMLCanvasElement, options = {} -) { +): Promise { switch (transferSyntax) { case '1.2.840.10008.1.2': // Implicit VR Little Endian diff --git a/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.ts b/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.ts index f34cbd345..663e7555e 100644 --- a/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.ts +++ b/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.ts @@ -1,10 +1,12 @@ +import { ByteArray } from 'dicom-parser'; import getMinMax from '../shared/getMinMax'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; /** * Special decoder for 8 bit jpeg that leverages the browser's built in JPEG decoder for increased performance */ -function arrayBufferToString(buffer) { +function arrayBufferToString(buffer: ArrayBuffer) { return binaryToString( String.fromCharCode.apply( null, @@ -13,7 +15,7 @@ function arrayBufferToString(buffer) { ); } -function binaryToString(binary) { +function binaryToString(binary: string) { let error; try { @@ -27,7 +29,11 @@ function binaryToString(binary) { } } -function decodeJPEGBaseline8BitColor(imageFrame, pixelData, canvas) { +function decodeJPEGBaseline8BitColor( + imageFrame: CornerstoneWadoImageFrame, + pixelData: ByteArray, + canvas: HTMLCanvasElement +): Promise { const start = new Date().getTime(); const imgBlob = new Blob([pixelData], { type: 'image/jpeg' }); @@ -50,7 +56,10 @@ function decodeJPEGBaseline8BitColor(imageFrame, pixelData, canvas) { imageFrame.columns = img.width; const context = canvas.getContext('2d'); - context.drawImage(this, 0, 0); + /** + * @todo check this context + */ + context.drawImage(this as any, 0, 0); const imageData = context.getImageData(0, 0, img.width, img.height); const end = new Date().getTime(); @@ -73,10 +82,12 @@ function decodeJPEGBaseline8BitColor(imageFrame, pixelData, canvas) { if (fileReader.readAsBinaryString === undefined) { img.src = `data:image/jpeg;base64,${window.btoa( - arrayBufferToString(fileReader.result) + arrayBufferToString(fileReader.result as ArrayBuffer) )}`; } else { - img.src = `data:image/jpeg;base64,${window.btoa(fileReader.result)}`; // doesn't work on IE11 + img.src = `data:image/jpeg;base64,${window.btoa( + fileReader.result as string + )}`; // doesn't work on IE11 } }; diff --git a/packages/dicom-image-loader/src/imageLoader/getImageFrame.ts b/packages/dicom-image-loader/src/imageLoader/getImageFrame.ts index 5673263c2..1c313812a 100644 --- a/packages/dicom-image-loader/src/imageLoader/getImageFrame.ts +++ b/packages/dicom-image-loader/src/imageLoader/getImageFrame.ts @@ -1,11 +1,11 @@ import external from '../externalModules'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; +import { CornerstoneMetadataImagePixelModule } from '../shared/types/metadata-modules'; -function getImageFrame(imageId) { +function getImageFrame(imageId: string): CornerstoneWadoImageFrame { const { cornerstone } = external; - const imagePixelModule = cornerstone.metaData.get( - 'imagePixelModule', - imageId - ); + const imagePixelModule: CornerstoneMetadataImagePixelModule = + cornerstone.metaData.get('imagePixelModule', imageId); return { samplesPerPixel: imagePixelModule.samplesPerPixel, diff --git a/packages/dicom-image-loader/src/imageLoader/getMinMax.ts b/packages/dicom-image-loader/src/imageLoader/getMinMax.ts index c59e817e4..b63f021f7 100644 --- a/packages/dicom-image-loader/src/imageLoader/getMinMax.ts +++ b/packages/dicom-image-loader/src/imageLoader/getMinMax.ts @@ -1,4 +1,7 @@ -export default function getMinMax(storedPixelData) { +export default function getMinMax(storedPixelData: ArrayLike): { + min: number; + max: number; +} { // we always calculate the min max values since they are not always // present in DICOM and we don't want to trust them anyway as cornerstone // depends on us providing reliable values for these diff --git a/packages/dicom-image-loader/src/imageLoader/getScalingParameters.ts b/packages/dicom-image-loader/src/imageLoader/getScalingParameters.ts index 30372bc8e..418e3b61a 100644 --- a/packages/dicom-image-loader/src/imageLoader/getScalingParameters.ts +++ b/packages/dicom-image-loader/src/imageLoader/getScalingParameters.ts @@ -1,3 +1,6 @@ +import { CornerstoneMetadataGeneralSeriesModule } from '../shared/types/metadata-modules'; +import type * as cornerstoneImport from '@cornerstonejs/core'; + /** * It returns the scaling parameters for the image with the given imageId. This can be * used to get passed (as an option) to the imageLoader in order to apply scaling to the image inside @@ -5,10 +8,13 @@ * @param imageId - The imageId of the image * @returns ScalingParameters */ -export default function getScalingParameters(metaData, imageId) { +export default function getScalingParameters( + metaData: typeof cornerstoneImport.metaData, + imageId: string +) { const modalityLutModule = metaData.get('modalityLutModule', imageId) || {}; - const generalSeriesModule = + const generalSeriesModule: CornerstoneMetadataGeneralSeriesModule = metaData.get('generalSeriesModule', imageId) || {}; const { modality } = generalSeriesModule; diff --git a/packages/dicom-image-loader/src/imageLoader/imageIdToURI.ts b/packages/dicom-image-loader/src/imageLoader/imageIdToURI.ts index 7be55b075..4813c2c5f 100644 --- a/packages/dicom-image-loader/src/imageLoader/imageIdToURI.ts +++ b/packages/dicom-image-loader/src/imageLoader/imageIdToURI.ts @@ -5,7 +5,7 @@ * @returns {string} imageId without the data loader scheme * @memberof Cache */ -export default function imageIdToURI(imageId) { +export default function imageIdToURI(imageId: string): string { const colonIndex = imageId.indexOf(':'); return imageId.substring(colonIndex + 1); diff --git a/packages/dicom-image-loader/src/imageLoader/internal/options.ts b/packages/dicom-image-loader/src/imageLoader/internal/options.ts index 90cfe4fed..18bc505ab 100644 --- a/packages/dicom-image-loader/src/imageLoader/internal/options.ts +++ b/packages/dicom-image-loader/src/imageLoader/internal/options.ts @@ -1,9 +1,37 @@ -let options = { +import { + CornerstoneWadoLoaderXhrRequestError, + CornerstoneWadoLoaderXhrRequestParams, +} from './xhrRequest'; + +export interface CornerstoneWadoLoaderOptions { + // callback allowing customization of the xhr (e.g. adding custom auth headers, cors, etc) + beforeSend: ( + xhr: XMLHttpRequest, + imageId: string, + defaultHeaders: Record, + params: CornerstoneWadoLoaderXhrRequestParams + ) => Record | void; + // callback allowing modification of the xhr response before creating image objects + beforeProcessing: (xhr: XMLHttpRequest) => Promise; + // callback allowing modification of newly created image objects + imageCreated: (...args: any[]) => void; + onloadstart?: (event: ProgressEvent, params: any) => void; + onloadend?: (event: ProgressEvent, params: any) => void; + onreadystatechange?: (event: Event, params: any) => void; + onprogress?: (event: ProgressEvent, params: any) => void; + errorInterceptor?: (error: CornerstoneWadoLoaderXhrRequestError) => void; + strict: boolean; + decodeConfig: { + convertFloatPixelDataToInt: boolean; + }; +} + +let options: CornerstoneWadoLoaderOptions = { // callback allowing customization of the xhr (e.g. adding custom auth headers, cors, etc) beforeSend(/* xhr, imageId */) {}, // callback allowing modification of the xhr response before creating image objects - beforeProcessing(xhr) { - return Promise.resolve(xhr.response); + beforeProcessing(xhr: XMLHttpRequest) { + return Promise.resolve(xhr.response as ArrayBuffer); }, // callback allowing modification of newly created image objects imageCreated(/* image */) {}, @@ -13,10 +41,10 @@ let options = { }, }; -export function setOptions(newOptions) { +export function setOptions(newOptions: CornerstoneWadoLoaderOptions): void { options = Object.assign(options, newOptions); } -export function getOptions() { +export function getOptions(): CornerstoneWadoLoaderOptions { return options; } diff --git a/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.ts b/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.ts index 928558430..dc5fdf7da 100644 --- a/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.ts +++ b/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.ts @@ -1,13 +1,38 @@ import external from '../../externalModules'; import { getOptions } from './options'; -function xhrRequest(url, imageId, defaultHeaders = {}, params = {}) { +export interface CornerstoneWadoLoaderXhrRequestError extends Error { + request: XMLHttpRequest; + response: any; + status: number; +} + +/** + * @description mutable object + */ +export interface CornerstoneWadoLoaderXhrRequestParams { + url?: string; + deferred?: { + resolve: (value: ArrayBuffer | PromiseLike) => void; + reject: (reason?: any) => void; + }; + imageId?: string; +} + +function xhrRequest( + url: string, + imageId: string, + defaultHeaders: Record = {}, + params: CornerstoneWadoLoaderXhrRequestParams = {} +): Promise { const { cornerstone } = external; const options = getOptions(); - const errorInterceptor = (xhr) => { + const errorInterceptor = (xhr: XMLHttpRequest) => { if (typeof options.errorInterceptor === 'function') { - const error = new Error('request failed'); + const error = new Error( + 'request failed' + ) as CornerstoneWadoLoaderXhrRequestError; error.request = xhr; error.response = xhr.response; @@ -17,7 +42,7 @@ function xhrRequest(url, imageId, defaultHeaders = {}, params = {}) { }; // Make the request for the DICOM P10 SOP Instance - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('get', url, true); @@ -63,7 +88,7 @@ function xhrRequest(url, imageId, defaultHeaders = {}, params = {}) { }; cornerstone.triggerEvent( - cornerstone.events, + (cornerstone as any).events, 'cornerstoneimageloadstart', eventData ); @@ -83,7 +108,7 @@ function xhrRequest(url, imageId, defaultHeaders = {}, params = {}) { // Event cornerstone.triggerEvent( - cornerstone.events, + (cornerstone as any).events, 'cornerstoneimageloadend', eventData ); @@ -124,9 +149,9 @@ function xhrRequest(url, imageId, defaultHeaders = {}, params = {}) { // console.log('progress:',oProgress) const loaded = oProgress.loaded; // evt.loaded the bytes browser receive - let total; + let total: number; - let percentComplete; + let percentComplete: number; if (oProgress.lengthComputable) { total = oProgress.total; // evt.total the total bytes seted by the header @@ -148,7 +173,7 @@ function xhrRequest(url, imageId, defaultHeaders = {}, params = {}) { }; cornerstone.triggerEvent( - cornerstone.events, + (cornerstone as any).events, cornerstone.EVENTS.IMAGE_LOAD_PROGRESS, eventData ); diff --git a/packages/dicom-image-loader/src/imageLoader/isColorImage.ts b/packages/dicom-image-loader/src/imageLoader/isColorImage.ts index bc75fffaa..e6edfa634 100644 --- a/packages/dicom-image-loader/src/imageLoader/isColorImage.ts +++ b/packages/dicom-image-loader/src/imageLoader/isColorImage.ts @@ -1,4 +1,4 @@ -export default function (photoMetricInterpretation) { +export default function (photoMetricInterpretation: string): boolean { return ( photoMetricInterpretation === 'RGB' || photoMetricInterpretation === 'PALETTE COLOR' || diff --git a/packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.ts b/packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.ts index 1b2bf5f16..f9a19994a 100644 --- a/packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.ts +++ b/packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.ts @@ -1,5 +1,11 @@ -function isJPEGBaseline8BitColor(imageFrame, transferSyntax) { - transferSyntax = transferSyntax || imageFrame.transferSyntax; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; + +function isJPEGBaseline8BitColor( + imageFrame: CornerstoneWadoImageFrame, + transferSyntax: string +): boolean { + /** @todo check as any */ + transferSyntax = transferSyntax || (imageFrame as any).transferSyntax; if ( imageFrame.bitsAllocated === 8 && diff --git a/packages/dicom-image-loader/src/imageLoader/registerLoaders.ts b/packages/dicom-image-loader/src/imageLoader/registerLoaders.ts index 4ecd98d94..67722ef89 100644 --- a/packages/dicom-image-loader/src/imageLoader/registerLoaders.ts +++ b/packages/dicom-image-loader/src/imageLoader/registerLoaders.ts @@ -1,5 +1,6 @@ import wadors from './wadors/index'; import wadouri from './wadouri/index'; +import * as cornerstoneImport from '@cornerstonejs/core'; /** * Register the WADO-URI and WADO-RS image loaders and metaData providers @@ -7,7 +8,7 @@ import wadouri from './wadouri/index'; * * @param cornerstone The Cornerstone Core library to register the image loaders with */ -function registerLoaders(cornerstone) { +function registerLoaders(cornerstone: typeof cornerstoneImport): void { wadors.register(cornerstone); wadouri.register(cornerstone); } diff --git a/packages/dicom-image-loader/src/imageLoader/wado-loader.ts b/packages/dicom-image-loader/src/imageLoader/wado-loader.ts new file mode 100644 index 000000000..b9a53234b --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wado-loader.ts @@ -0,0 +1,18 @@ +import type { Types } from '@cornerstonejs/core'; +import { ByteArray, DataSet } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; + +export interface CornerstoneWadoLoaderIImage extends Types.IImage { + decodeTimeInMS: number; + floatPixelData?: ByteArray | Float32Array; + loadTimeInMS?: number; + totalTimeInMS?: number; + data?: DataSet; + imageFrame?: CornerstoneWadoImageFrame; +} + +export interface CornerstoneWadoLoaderIImageLoadObject + extends Types.IImageLoadObject { + promise: Promise; + decache?: () => void; +} diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.ts b/packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.ts index f703ecb66..f5bbd3583 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.ts @@ -1,4 +1,4 @@ -function checkToken(token, data, dataOffset) { +function checkToken(token, data, dataOffset): boolean { if (dataOffset + token.length > data.length) { return false; } @@ -14,7 +14,7 @@ function checkToken(token, data, dataOffset) { return true; } -function stringToUint8Array(str) { +function stringToUint8Array(str: string): Uint8Array { const uint = new Uint8Array(str.length); for (let i = 0, j = str.length; i < j; i++) { @@ -24,7 +24,11 @@ function stringToUint8Array(str) { return uint; } -function findIndexOfString(data, str, offset) { +function findIndexOfString( + data: Uint8Array, + str: string, + offset?: number +): number { offset = offset || 0; const token = stringToUint8Array(str); diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.ts b/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.ts index 6135a923d..3fa4e64a0 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.ts @@ -1,7 +1,7 @@ import { xhrRequest } from '../internal/index'; import findIndexOfString from './findIndexOfString'; -function findBoundary(header) { +function findBoundary(header: string[]): string { for (let i = 0; i < header.length; i++) { if (header[i].substr(0, 2) === '--') { return header[i]; @@ -9,7 +9,7 @@ function findBoundary(header) { } } -function findContentType(header) { +function findContentType(header: string[]): string { for (let i = 0; i < header.length; i++) { if (header[i].substr(0, 13) === 'Content-Type:') { return header[i].substr(13).trim(); @@ -29,12 +29,22 @@ function uint8ArrayToString(data, offset, length) { return str; } -function getPixelData(uri, imageId, mediaType = 'application/octet-stream') { +export interface GetPixelDataResponse { + contentType: string; + imageFrame: { + pixelData: Uint8Array; + }; +} +function getPixelData( + uri: string, + imageId: string, + mediaType = 'application/octet-stream' +): Promise { const headers = { Accept: mediaType, }; - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const loadPromise = xhrRequest(uri, imageId, headers); loadPromise.then(function (imageFrameAsArrayBuffer /* , xhr*/) { diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.ts b/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.ts index 4adb88502..c18168b52 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.ts @@ -1,13 +1,18 @@ +import { CornerstoneLoadImageOptions } from 'dicom-image-loader/src/shared/types/load-image-options'; import external from '../../externalModules'; -import getPixelData from './getPixelData'; import createImage from '../createImage'; +import { + CornerstoneWadoLoaderIImage, + CornerstoneWadoLoaderIImageLoadObject, +} from '../wado-loader'; +import getPixelData from './getPixelData'; /** * Helper method to extract the transfer-syntax from the response of the server. * @param {string} contentType The value of the content-type header as returned by the WADO-RS server. * @return The transfer-syntax as announced by the server, or Implicit Little Endian by default. */ -export function getTransferSyntaxForContentType(contentType) { +export function getTransferSyntaxForContentType(contentType: string): string { const defaultTransferSyntax = '1.2.840.10008.1.2'; // Default is Implicit Little Endian. if (!contentType) { @@ -16,7 +21,7 @@ export function getTransferSyntaxForContentType(contentType) { // Browse through the content type parameters const parameters = contentType.split(';'); - const params = {}; + const params: Record = {}; parameters.forEach((parameter) => { // Look for a transfer-syntax=XXXX pair @@ -64,64 +69,82 @@ function getImageRetrievalPool() { return external.cornerstone.imageRetrievalPoolManager; } -function loadImage(imageId, options = {}) { +export interface CornerstoneWadoRsLoaderOptions + extends CornerstoneLoadImageOptions { + requestType?: string; + additionalDetails?: { + imageId: string; + }; + priority?: number; + addToBeginning?: boolean; +} + +function loadImage( + imageId: string, + options: CornerstoneWadoRsLoaderOptions = {} +): CornerstoneWadoLoaderIImageLoadObject { const imageRetrievalPool = getImageRetrievalPool(); const start = new Date().getTime(); - const promise = new Promise((resolve, reject) => { - // TODO: load bulk data items that we might need - - // Uncomment this on to test jpegls codec in OHIF - // const mediaType = 'multipart/related; type="image/x-jls"'; - // const mediaType = 'multipart/related; type="application/octet-stream"; transfer-syntax="image/x-jls"'; - const mediaType = - 'multipart/related; type=application/octet-stream; transfer-syntax=*'; - // const mediaType = - // 'multipart/related; type="image/jpeg"; transfer-syntax=1.2.840.10008.1.2.4.50'; - - function sendXHR(imageURI, imageId, mediaType) { - // get the pixel data from the server - return getPixelData(imageURI, imageId, mediaType) - .then((result) => { - const transferSyntax = getTransferSyntaxForContentType( - result.contentType - ); - const pixelData = result.imageFrame.pixelData; - const imagePromise = createImage( - imageId, - pixelData, - transferSyntax, - options - ); - - imagePromise.then((image) => { - // add the loadTimeInMS property - const end = new Date().getTime(); - - image.loadTimeInMS = end - start; - resolve(image); - }, reject); - }, reject) - .catch((error) => { - reject(error); - }); + const promise = new Promise( + (resolve, reject) => { + // TODO: load bulk data items that we might need + + // Uncomment this on to test jpegls codec in OHIF + // const mediaType = 'multipart/related; type="image/x-jls"'; + // const mediaType = 'multipart/related; type="application/octet-stream"; transfer-syntax="image/x-jls"'; + const mediaType = + 'multipart/related; type=application/octet-stream; transfer-syntax=*'; + // const mediaType = + // 'multipart/related; type="image/jpeg"; transfer-syntax=1.2.840.10008.1.2.4.50'; + + function sendXHR(imageURI: string, imageId: string, mediaType: string) { + // get the pixel data from the server + return getPixelData(imageURI, imageId, mediaType) + .then((result) => { + const transferSyntax = getTransferSyntaxForContentType( + result.contentType + ); + const pixelData = result.imageFrame.pixelData; + const imagePromise = createImage( + imageId, + pixelData, + transferSyntax, + options + ); + + imagePromise.then((image) => { + // add the loadTimeInMS property + const end = new Date().getTime(); + + image.loadTimeInMS = end - start; + resolve(image); + }, reject); + }, reject) + .catch((error) => { + reject(error); + }); + } + + const requestType = options.requestType || 'interaction'; + const additionalDetails = options.additionalDetails || { imageId }; + const priority = options.priority === undefined ? 5 : options.priority; + const addToBeginning = options.addToBeginning || false; + const uri = imageId.substring(7); + + /** + * @todo check arguments + */ + imageRetrievalPool.addRequest( + sendXHR.bind(this, uri, imageId, mediaType), + requestType, + additionalDetails, + priority, + addToBeginning + ); } - - const requestType = options.requestType || 'interaction'; - const additionalDetails = options.additionalDetails || { imageId }; - const priority = options.priority === undefined ? 5 : options.priority; - const addToBeginning = options.addToBeginning || false; - const uri = imageId.substring(7); - - imageRetrievalPool.addRequest( - sendXHR.bind(this, uri, imageId, mediaType), - requestType, - additionalDetails, - priority, - addToBeginning - ); - }); + ); return { promise, diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.ts b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.ts index aae181c53..8c3ed5d01 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.ts @@ -1,3 +1,4 @@ +import { WadoRsMetaDataElement } from '../wado-rs-metadata'; import getValue from './getValue'; /** @@ -8,7 +9,11 @@ import getValue from './getValue'; * @param [defaultValue] - The default value to return if the element does not exist * @returns {*} */ -function getNumberString(element, index, defaultValue) { +function getNumberString( + element: WadoRsMetaDataElement, + index: number, + defaultValue +) { const value = getValue(element, index, defaultValue); if (value === undefined) { diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.ts b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.ts index ad1c39374..a76e038d7 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.ts @@ -1,6 +1,10 @@ +import { WadoRsMetaDataElement } from '../wado-rs-metadata'; import getValue from './getValue'; -function getNumberValue(element, index) { +function getNumberValue( + element: WadoRsMetaDataElement, + index?: number +): number { const value = getValue(element, index); if (value === undefined) { diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.ts b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.ts index 8a1199598..983831953 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.ts @@ -1,3 +1,5 @@ +import { WadoRsMetaDataElement } from '../wado-rs-metadata'; + /** * Returns the values as an array of javascript numbers * @@ -5,7 +7,10 @@ * @param [minimumLength] - the minimum number of values * @returns {*} */ -function getNumberValues(element, minimumLength) { +function getNumberValues( + element: WadoRsMetaDataElement, + minimumLength?: number +): number[] { if (!element) { return; } @@ -18,10 +23,10 @@ function getNumberValues(element, minimumLength) { return; } - const values = []; + const values: number[] = []; for (let i = 0; i < element.Value.length; i++) { - values.push(parseFloat(element.Value[i])); + values.push(parseFloat(element.Value[i] as string)); } return values; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.ts b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.ts index 516a572ce..e460f5c07 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.ts @@ -1,7 +1,8 @@ import getValue from './getValue'; import getNumberValue from './getNumberValue'; +import { WadoRsMetaData } from '../wado-rs-metadata'; -export default function getOverlayPlaneModule(metaData) { +export default function getOverlayPlaneModule(metaData: WadoRsMetaData) { const overlays = []; for (let overlayGroup = 0x00; overlayGroup <= 0x1e; overlayGroup += 0x02) { diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.ts b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.ts index 334b46e7b..816a6b8ec 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.ts @@ -1,3 +1,5 @@ +import { WadoRsMetaDataElement } from '../wado-rs-metadata'; + /** * Returns the raw value * @@ -6,7 +8,11 @@ * @param [defaultValue] - The default value to return if the element does not exist * @returns {*} */ -function getValue(element, index, defaultValue) { +function getValue( + element: WadoRsMetaDataElement, + index?: number, + defaultValue?: number | string +) { index = index || 0; if (!element) { return defaultValue; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.ts b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.ts index 13db5d719..1a4d0d2b4 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.ts @@ -5,7 +5,7 @@ import getNumberValue from './getNumberValue'; import getOverlayPlaneModule from './getOverlayPlaneModule'; import metaDataManager from '../metaDataManager'; -function metaDataProvider(type, imageId) { +function metaDataProvider(type: string, imageId: string) { const { dicomParser } = external; const metaData = metaDataManager.get(imageId); @@ -52,14 +52,14 @@ function metaDataProvider(type, imageId) { if (imageOrientationPatient) { rowCosines = [ - parseFloat(imageOrientationPatient[0]), - parseFloat(imageOrientationPatient[1]), - parseFloat(imageOrientationPatient[2]), + parseFloat(imageOrientationPatient[0] as any), + parseFloat(imageOrientationPatient[1] as any), + parseFloat(imageOrientationPatient[2] as any), ]; columnCosines = [ - parseFloat(imageOrientationPatient[3]), - parseFloat(imageOrientationPatient[4]), - parseFloat(imageOrientationPatient[5]), + parseFloat(imageOrientationPatient[3] as any), + parseFloat(imageOrientationPatient[4] as any), + parseFloat(imageOrientationPatient[5] as any), ]; } @@ -142,7 +142,7 @@ function metaDataProvider(type, imageId) { return { radiopharmaceuticalInfo: { radiopharmaceuticalStartTime: dicomParser.parseTM( - getValue(radiopharmaceuticalInfo['00181072'], 0, '') + getValue(radiopharmaceuticalInfo['00181072'], 0, '') as string ), radionuclideTotalDose: getNumberValue( radiopharmaceuticalInfo['00181074'] diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.ts b/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.ts index 1139e2699..c84369cb6 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.ts @@ -1,26 +1,27 @@ import imageIdToURI from '../imageIdToURI'; +import { WadoRsMetaData } from './wado-rs-metadata'; -let metadataByImageURI = []; +let metadataByImageURI: WadoRsMetaData[] = []; -function add(imageId, metadata) { +function add(imageId: string, metadata: WadoRsMetaData): void { const imageURI = imageIdToURI(imageId); metadataByImageURI[imageURI] = metadata; } -function get(imageId) { +function get(imageId: string): WadoRsMetaData { const imageURI = imageIdToURI(imageId); return metadataByImageURI[imageURI]; } -function remove(imageId) { +function remove(imageId: string): void { const imageURI = imageIdToURI(imageId); metadataByImageURI[imageURI] = undefined; } -function purge() { +function purge(): void { metadataByImageURI = []; } diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/register.ts b/packages/dicom-image-loader/src/imageLoader/wadors/register.ts index 3451be2d5..913dd9079 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/register.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadors/register.ts @@ -1,7 +1,8 @@ +import * as cornerstoneImport from '@cornerstonejs/core'; import loadImage from './loadImage'; import { metaDataProvider } from './metaData/index'; -export default function (cornerstone) { +export default function (cornerstone: typeof cornerstoneImport): void { // register wadors scheme and metadata provider cornerstone.registerImageLoader('wadors', loadImage); cornerstone.metaData.addProvider(metaDataProvider); diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/wado-rs-metadata.ts b/packages/dicom-image-loader/src/imageLoader/wadors/wado-rs-metadata.ts new file mode 100644 index 000000000..f455c724c --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/wado-rs-metadata.ts @@ -0,0 +1,5 @@ +export interface WadoRsMetaDataElement { + Value: string[] | number[]; +} + +export type WadoRsMetaData = Record; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.ts b/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.ts index 529383411..5728b8aa6 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.ts @@ -1,5 +1,7 @@ +import { DataSet } from 'dicom-parser'; import external from '../../externalModules'; import { xhrRequest } from '../internal/index'; +import { CornerstoneWadoLoaderLoadRequestFunction } from '../../shared/types/load-request-function'; /** * This object supports loading of DICOM P10 dataset from a uri and caching it so it can be accessed @@ -9,16 +11,21 @@ import { xhrRequest } from '../internal/index'; */ let cacheSizeInBytes = 0; -let loadedDataSets = {}; +let loadedDataSets: Record = + {}; -let promises = {}; +let promises: Record = {}; + +export interface CornerstoneWadoLoaderCachedPromise extends Promise { + cacheCount?: number; +} // returns true if the wadouri for the specified index has been loaded -function isLoaded(uri) { +function isLoaded(uri: string): boolean { return loadedDataSets[uri] !== undefined; } -function get(uri) { +function get(uri: string): DataSet { if (!loadedDataSets[uri]) { return; } @@ -27,7 +34,11 @@ function get(uri) { } // loads the dicom dataset from the wadouri sp -function load(uri, loadRequest = xhrRequest, imageId) { +function load( + uri: string, + loadRequest: CornerstoneWadoLoaderLoadRequestFunction = xhrRequest, + imageId: string +): CornerstoneWadoLoaderCachedPromise { const { cornerstone, dicomParser } = external; // if already loaded return it right away @@ -51,44 +62,50 @@ function load(uri, loadRequest = xhrRequest, imageId) { const loadDICOMPromise = loadRequest(uri, imageId); // handle success and failure of the XHR request load - const promise = new Promise((resolve, reject) => { - loadDICOMPromise - .then(function (dicomPart10AsArrayBuffer /* , xhr*/) { - const byteArray = new Uint8Array(dicomPart10AsArrayBuffer); - - // Reject the promise if parsing the dicom file fails - let dataSet; - - try { - dataSet = dicomParser.parseDicom(byteArray); - } catch (error) { - return reject(error); - } - - loadedDataSets[uri] = { - dataSet, - cacheCount: promise.cacheCount, - }; - cacheSizeInBytes += dataSet.byteArray.length; - resolve(dataSet); - - cornerstone.triggerEvent(cornerstone.events, 'datasetscachechanged', { - uri, - action: 'loaded', - cacheInfo: getInfo(), - }); - }, reject) - .then( - () => { - // Remove the promise if success - delete promises[uri]; - }, - () => { - // Remove the promise if failure - delete promises[uri]; - } - ); - }); + const promise: CornerstoneWadoLoaderCachedPromise = new Promise( + (resolve, reject) => { + loadDICOMPromise + .then(function (dicomPart10AsArrayBuffer /* , xhr*/) { + const byteArray = new Uint8Array(dicomPart10AsArrayBuffer); + + // Reject the promise if parsing the dicom file fails + let dataSet; + + try { + dataSet = dicomParser.parseDicom(byteArray); + } catch (error) { + return reject(error); + } + + loadedDataSets[uri] = { + dataSet, + cacheCount: promise.cacheCount, + }; + cacheSizeInBytes += dataSet.byteArray.length; + resolve(dataSet); + + cornerstone.triggerEvent( + (cornerstone as any).events, + 'datasetscachechanged', + { + uri, + action: 'loaded', + cacheInfo: getInfo(), + } + ); + }, reject) + .then( + () => { + // Remove the promise if success + delete promises[uri]; + }, + () => { + // Remove the promise if failure + delete promises[uri]; + } + ); + } + ); promise.cacheCount = 1; @@ -98,7 +115,7 @@ function load(uri, loadRequest = xhrRequest, imageId) { } // remove the cached/loaded dicom dataset for the specified wadouri to free up memory -function unload(uri) { +function unload(uri: string): void { const { cornerstone } = external; // console.log('unload for ' + uri); @@ -109,16 +126,24 @@ function unload(uri) { cacheSizeInBytes -= loadedDataSets[uri].dataSet.byteArray.length; delete loadedDataSets[uri]; - cornerstone.triggerEvent(cornerstone.events, 'datasetscachechanged', { - uri, - action: 'unloaded', - cacheInfo: getInfo(), - }); + cornerstone.triggerEvent( + (cornerstone as any).events, + 'datasetscachechanged', + { + uri, + action: 'unloaded', + cacheInfo: getInfo(), + } + ); } } } -export function getInfo() { +export interface CornerstoneWadoLoaderCacheManagerInfoResponse { + cacheSizeInBytes: number; + numberOfDataSetsCached: number; +} +export function getInfo(): CornerstoneWadoLoaderCacheManagerInfoResponse { return { cacheSizeInBytes, numberOfDataSetsCached: Object.keys(loadedDataSets).length, @@ -126,7 +151,7 @@ export function getInfo() { } // removes all cached datasets from memory -function purge() { +function purge(): void { loadedDataSets = {}; promises = {}; cacheSizeInBytes = 0; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.ts b/packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.ts index 6b9853bc2..10fbc9aa7 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.ts @@ -1,20 +1,20 @@ -let files = []; +let files: Blob[] = []; -function add(file) { +function add(file: Blob): string { const fileIndex = files.push(file); return `dicomfile:${fileIndex - 1}`; } -function get(index) { +function get(index: number): Blob { return files[index]; } -function remove(index) { +function remove(index: number): void { files[index] = undefined; } -function purge() { +function purge(): void { files = []; } diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.ts b/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.ts index 87869458e..0c14ea70f 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.ts @@ -1,17 +1,21 @@ +import { ByteArray, DataSet } from 'dicom-parser'; import external from '../../externalModules'; /** * Function to deal with extracting an image frame from an encapsulated data set. */ -function framesAreFragmented(dataSet) { +function framesAreFragmented(dataSet: DataSet) { const numberOfFrames = dataSet.intString('x00280008'); const pixelDataElement = dataSet.elements.x7fe00010; return numberOfFrames !== pixelDataElement.fragments.length; } -export default function getEncapsulatedImageFrame(dataSet, frameIndex) { +export default function getEncapsulatedImageFrame( + dataSet: DataSet, + frameIndex: number +): ByteArray { const { dicomParser } = external; if ( diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.ts b/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.ts index 5afac52e1..a2748b73c 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.ts @@ -1,7 +1,8 @@ +import { ByteArray, DataSet } from 'dicom-parser'; import getEncapsulatedImageFrame from './getEncapsulatedImageFrame'; import getUncompressedImageFrame from './getUncompressedImageFrame'; -function getPixelData(dataSet, frameIndex = 0) { +function getPixelData(dataSet: DataSet, frameIndex = 0): ByteArray { const pixelDataElement = dataSet.elements.x7fe00010 || dataSet.elements.x7fe00008; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.ts b/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.ts index 264ef71b8..10d1eeee8 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.ts @@ -1,10 +1,14 @@ +import { DataSet } from 'dicom-parser'; import unpackBinaryFrame from './unpackBinaryFrame'; /** * Function to deal with extracting an image frame from an encapsulated data set. */ -function getUncompressedImageFrame(dataSet, frameIndex) { +function getUncompressedImageFrame( + dataSet: DataSet, + frameIndex: number +): Uint8Array { const pixelDataElement = dataSet.elements.x7fe00010 || dataSet.elements.x7fe00008; const bitsAllocated = dataSet.uint16('x00280100'); diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.ts b/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.ts index 781fa704a..20d5a8c0e 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.ts @@ -1,16 +1,16 @@ import parseImageId from './parseImageId'; import fileManager from './fileManager'; -function loadFileRequest(uri) { +function loadFileRequest(uri: string): Promise { const parsedImageId = parseImageId(uri); const fileIndex = parseInt(parsedImageId.url, 10); const file = fileManager.get(fileIndex); - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const fileReader = new FileReader(); fileReader.onload = (e) => { - const dicomPart10AsArrayBuffer = e.target.result; + const dicomPart10AsArrayBuffer = e.target.result as ArrayBuffer; resolve(dicomPart10AsArrayBuffer); }; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.ts b/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.ts index 785170c0f..624ae2a82 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.ts @@ -1,12 +1,22 @@ +import { CornerstoneLoadImageOptions } from 'dicom-image-loader/src/shared/types/load-image-options'; +import { DataSet } from 'dicom-parser'; import createImage from '../createImage'; -import parseImageId from './parseImageId'; +import { xhrRequest } from '../internal/index'; +import { + CornerstoneWadoLoaderIImage, + CornerstoneWadoLoaderIImageLoadObject, +} from '../wado-loader'; import dataSetCacheManager from './dataSetCacheManager'; -import loadFileRequest from './loadFileRequest'; +import { CornerstoneWadoLoaderLoadRequestFunction } from '../../shared/types/load-request-function'; import getPixelData from './getPixelData'; -import { xhrRequest } from '../internal/index'; +import loadFileRequest from './loadFileRequest'; +import parseImageId from './parseImageId'; // add a decache callback function to clear out our dataSetCacheManager -function addDecache(imageLoadObject, imageId) { +function addDecache( + imageLoadObject: CornerstoneWadoLoaderIImageLoadObject, + imageId: string +) { imageLoadObject.decache = function () { // console.log('decache'); const parsedImageId = parseImageId(imageId); @@ -16,16 +26,19 @@ function addDecache(imageLoadObject, imageId) { } function loadImageFromPromise( - dataSetPromise, - imageId, + dataSetPromise: Promise, + imageId: string, frame = 0, - sharedCacheKey, - options, - callbacks -) { + sharedCacheKey: string, + options: CornerstoneLoadImageOptions, + callbacks?: { + imageDoneCallback: (image: CornerstoneWadoLoaderIImage) => void; + } +): CornerstoneWadoLoaderIImageLoadObject { const start = new Date().getTime(); - const imageLoadObject = { + const imageLoadObject: CornerstoneWadoLoaderIImageLoadObject = { cancelFn: undefined, + promise: undefined, }; imageLoadObject.promise = new Promise((resolve, reject) => { @@ -82,43 +95,45 @@ function loadImageFromPromise( function loadImageFromDataSet( dataSet, - imageId, + imageId: string, frame = 0, - sharedCacheKey, + sharedCacheKey: string, options -) { +): CornerstoneWadoLoaderIImageLoadObject { const start = new Date().getTime(); - const promise = new Promise((resolve, reject) => { - const loadEnd = new Date().getTime(); + const promise = new Promise( + (resolve, reject) => { + const loadEnd = new Date().getTime(); - let imagePromise; + let imagePromise: Promise; - try { - const pixelData = getPixelData(dataSet, frame); - const transferSyntax = dataSet.string('x00020010'); + try { + const pixelData = getPixelData(dataSet, frame); + const transferSyntax = dataSet.string('x00020010'); - imagePromise = createImage(imageId, pixelData, transferSyntax, options); - } catch (error) { - // Reject the error, and the dataSet - reject({ - error, - dataSet, - }); + imagePromise = createImage(imageId, pixelData, transferSyntax, options); + } catch (error) { + // Reject the error, and the dataSet + reject({ + error, + dataSet, + }); - return; - } + return; + } - imagePromise.then((image) => { - image.data = dataSet; - image.sharedCacheKey = sharedCacheKey; - const end = new Date().getTime(); + imagePromise.then((image) => { + image.data = dataSet; + image.sharedCacheKey = sharedCacheKey; + const end = new Date().getTime(); - image.loadTimeInMS = loadEnd - start; - image.totalTimeInMS = end - start; - resolve(image); - }, reject); - }); + image.loadTimeInMS = loadEnd - start; + image.totalTimeInMS = end - start; + resolve(image); + }, reject); + } + ); return { promise, @@ -126,7 +141,9 @@ function loadImageFromDataSet( }; } -function getLoaderForScheme(scheme) { +function getLoaderForScheme( + scheme: string +): CornerstoneWadoLoaderLoadRequestFunction { if (scheme === 'dicomweb' || scheme === 'wadouri') { return xhrRequest; } else if (scheme === 'dicomfile') { @@ -134,7 +151,10 @@ function getLoaderForScheme(scheme) { } } -function loadImage(imageId, options = {}) { +function loadImage( + imageId: string, + options: CornerstoneLoadImageOptions = {} +): CornerstoneWadoLoaderIImageLoadObject { const parsedImageId = parseImageId(imageId); options = Object.assign({}, options); @@ -148,7 +168,14 @@ function loadImage(imageId, options = {}) { // if the dataset for this url is already loaded, use it if (dataSetCacheManager.isLoaded(parsedImageId.url)) { - const dataSet = dataSetCacheManager.get(parsedImageId.url, loader, imageId); + /** + * @todo The arguments to the dataSetCacheManager below are incorrect. + */ + const dataSet: DataSet = (dataSetCacheManager as any).get( + parsedImageId.url, + loader, + imageId + ); return loadImageFromDataSet( dataSet, diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.ts b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.ts index 27db277de..e19512edb 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.ts @@ -1,4 +1,7 @@ -function getLutDescriptor(dataSet, tag) { +import { CornerstoneMetadataImagePixelModule } from 'dicom-image-loader/src/shared/types/metadata-modules'; +import { DataSet } from 'dicom-parser'; + +function getLutDescriptor(dataSet: DataSet, tag: string) { if (!dataSet.elements[tag] || dataSet.elements[tag].length !== 6) { return; } @@ -10,7 +13,7 @@ function getLutDescriptor(dataSet, tag) { ]; } -function getLutData(lutDataSet, tag, lutDescriptor) { +function getLutData(lutDataSet: DataSet, tag: string, lutDescriptor): number[] { const lut = []; const lutData = lutDataSet.elements[tag]; @@ -26,7 +29,10 @@ function getLutData(lutDataSet, tag, lutDescriptor) { return lut; } -function populatePaletteColorLut(dataSet, imagePixelModule) { +function populatePaletteColorLut( + dataSet: DataSet, + imagePixelModule: CornerstoneMetadataImagePixelModule +) { imagePixelModule.redPaletteColorLookupTableDescriptor = getLutDescriptor( dataSet, 'x00281101' @@ -91,7 +97,10 @@ function populatePaletteColorLut(dataSet, imagePixelModule) { ); } -function populateSmallestLargestPixelValues(dataSet, imagePixelModule) { +function populateSmallestLargestPixelValues( + dataSet: DataSet, + imagePixelModule: CornerstoneMetadataImagePixelModule +) { const pixelRepresentation = dataSet.uint16('x00280103'); if (pixelRepresentation === 0) { @@ -103,7 +112,9 @@ function populateSmallestLargestPixelValues(dataSet, imagePixelModule) { } } -function getImagePixelModule(dataSet) { +function getImagePixelModule( + dataSet: DataSet +): CornerstoneMetadataImagePixelModule { const imagePixelModule = { samplesPerPixel: dataSet.uint16('x00280002'), photometricInterpretation: dataSet.string('x00280004'), @@ -115,7 +126,7 @@ function getImagePixelModule(dataSet) { pixelRepresentation: dataSet.uint16('x00280103'), planarConfiguration: dataSet.uint16('x00280006'), pixelAspectRatio: dataSet.string('x00280034'), - }; + } as CornerstoneMetadataImagePixelModule; populateSmallestLargestPixelValues(dataSet, imagePixelModule); diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.ts b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.ts index ebb761481..6dd0281b5 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.ts @@ -1,4 +1,16 @@ -function getLUT(pixelRepresentation, lutDataSet) { +import { DataSet, Element } from 'dicom-parser'; + +export interface CornerstoneWadoLoaderLut { + id: string; + firstValueMapped: number; + numBitsPerEntry: number; + lut: number[]; +} + +function getLUT( + pixelRepresentation: number, + lutDataSet: DataSet +): CornerstoneWadoLoaderLut { let numLUTEntries = lutDataSet.uint16('x00283002', 0); if (numLUTEntries === 0) { @@ -32,11 +44,14 @@ function getLUT(pixelRepresentation, lutDataSet) { return lut; } -function getLUTs(pixelRepresentation, lutSequence) { +function getLUTs( + pixelRepresentation: number, + lutSequence: Element +): CornerstoneWadoLoaderLut[] { if (!lutSequence || !lutSequence.items || !lutSequence.items.length) { return; } - const luts = []; + const luts: CornerstoneWadoLoaderLut[] = []; for (let i = 0; i < lutSequence.items.length; i++) { const lutDataSet = lutSequence.items[i].dataSet; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.ts b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.ts index 72f7cdedb..d42b78896 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.ts @@ -1,6 +1,8 @@ /* eslint no-bitwise: 0 */ -function getMinStoredPixelValue(dataSet) { +import { DataSet } from 'dicom-parser'; + +function getMinStoredPixelValue(dataSet: DataSet) { const pixelRepresentation = dataSet.uint16('x00280103'); const bitsStored = dataSet.uint16('x00280101'); @@ -12,7 +14,7 @@ function getMinStoredPixelValue(dataSet) { } // 0 = unsigned / US, 1 = signed / SS -function getModalityLUTOutputPixelRepresentation(dataSet) { +function getModalityLUTOutputPixelRepresentation(dataSet: DataSet) { // CT SOP Classes are always signed const sopClassUID = dataSet.string('x00080016'); diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.ts b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.ts index a2f9ee918..e429ddfc9 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.ts @@ -1,4 +1,10 @@ -function getNumberValues(dataSet, tag, minimumLength) { +import { DataSet } from 'dicom-parser'; + +function getNumberValues( + dataSet: DataSet, + tag: string, + minimumLength: number +): number[] { const values = []; const valueAsString = dataSet.string(tag); diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.ts b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.ts index ecdce907d..b5a000ffe 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.ts @@ -1,4 +1,6 @@ -export default function getOverlayPlaneModule(dataSet) { +import { DataSet } from 'dicom-parser'; + +export default function getOverlayPlaneModule(dataSet: DataSet) { const overlays = []; for (let overlayGroup = 0x00; overlayGroup <= 0x1e; overlayGroup += 0x02) { diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.ts b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.ts index 6d7de0dd1..8dedb279a 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.ts @@ -1,13 +1,49 @@ +import { + CornerstoneMetadataGeneralSeriesModule, + CornerstoneMetadataImagePixelModule, + CornerstoneMetadataImagePlaneModule, + CornerstoneMetadataPatientStudyModule, + CornerstoneMetadataSopCommonModule, + CornerstoneMetadataTransferSyntax, + CornerstoneMetaDataTypes, +} from 'dicom-image-loader/src/shared/types/metadata-modules'; import external from '../../../externalModules'; -import getNumberValues from './getNumberValues'; -import parseImageId from '../parseImageId'; import dataSetCacheManager from '../dataSetCacheManager'; +import parseImageId from '../parseImageId'; import getImagePixelModule from './getImagePixelModule'; -import getOverlayPlaneModule from './getOverlayPlaneModule'; import getLUTs from './getLUTs'; import getModalityLUTOutputPixelRepresentation from './getModalityLUTOutputPixelRepresentation'; +import getNumberValues from './getNumberValues'; +import getOverlayPlaneModule from './getOverlayPlaneModule'; -function metaDataProvider(type, imageId) { +function metaDataProvider( + type: 'generalSeriesModule', + imageId: string +): CornerstoneMetadataGeneralSeriesModule; +function metaDataProvider( + type: 'patientStudyModule', + imageId: string +): CornerstoneMetadataPatientStudyModule; +function metaDataProvider( + type: 'imagePlaneModule', + imageId: string +): CornerstoneMetadataImagePlaneModule; +function metaDataProvider( + type: 'imagePixelModule', + imageId: string +): CornerstoneMetadataImagePixelModule; +function metaDataProvider( + type: 'transferSyntax', + imageId: string +): CornerstoneMetadataTransferSyntax; +function metaDataProvider( + type: 'sopCommonModule', + imageId: string +): CornerstoneMetadataSopCommonModule; +function metaDataProvider( + type: CornerstoneMetaDataTypes, + imageId: string +): any { const { dicomParser } = external; const parsedImageId = parseImageId(imageId); @@ -41,9 +77,9 @@ function metaDataProvider(type, imageId) { const imagePositionPatient = getNumberValues(dataSet, 'x00200032', 3); const pixelSpacing = getNumberValues(dataSet, 'x00280030', 2); - let columnPixelSpacing = null; + let columnPixelSpacing: number = null; - let rowPixelSpacing = null; + let rowPixelSpacing: number = null; if (pixelSpacing) { rowPixelSpacing = pixelSpacing[0]; @@ -56,14 +92,14 @@ function metaDataProvider(type, imageId) { if (imageOrientationPatient) { rowCosines = [ - parseFloat(imageOrientationPatient[0]), - parseFloat(imageOrientationPatient[1]), - parseFloat(imageOrientationPatient[2]), + parseFloat(imageOrientationPatient[0] as any), + parseFloat(imageOrientationPatient[1] as any), + parseFloat(imageOrientationPatient[2] as any), ]; columnCosines = [ - parseFloat(imageOrientationPatient[3]), - parseFloat(imageOrientationPatient[4]), - parseFloat(imageOrientationPatient[5]), + parseFloat(imageOrientationPatient[3] as any), + parseFloat(imageOrientationPatient[4] as any), + parseFloat(imageOrientationPatient[5] as any), ]; } diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.ts b/packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.ts index 07e7e804e..9fcd71a07 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.ts @@ -1,4 +1,10 @@ -function parseImageId(imageId) { +export interface CornerstoneImageUrl { + scheme: string; + url: string; + frame: number; +} + +function parseImageId(imageId: string): CornerstoneImageUrl { // build a url by parsing out the url scheme and frame index from the imageId const firstColonIndex = imageId.indexOf(':'); diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/register.ts b/packages/dicom-image-loader/src/imageLoader/wadouri/register.ts index ed24e59d1..e5c477a49 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/register.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/register.ts @@ -1,7 +1,8 @@ +import * as cornerstoneImport from '@cornerstonejs/core'; import { loadImage } from './loadImage'; import { metaDataProvider } from './metaData/index'; -export default function (cornerstone) { +export default function (cornerstone: typeof cornerstoneImport): void { // register dicomweb and wadouri image loader prefixes cornerstone.registerImageLoader('dicomweb', loadImage); cornerstone.registerImageLoader('wadouri', loadImage); diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.ts b/packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.ts index 22a5dbfb2..e416ec2db 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.ts +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.ts @@ -1,13 +1,19 @@ /* eslint no-bitwise: 0 */ -function isBitSet(byte, bitPos) { +import { ByteArray } from 'dicom-parser'; + +function isBitSet(byte: number, bitPos: number) { return byte & (1 << bitPos); } /** * Function to deal with unpacking a binary frame */ -function unpackBinaryFrame(byteArray, frameOffset, pixelsPerFrame) { +function unpackBinaryFrame( + byteArray: ByteArray, + frameOffset: number, + pixelsPerFrame: number +): Uint8Array { // Create a new pixel array given the image size const pixelData = new Uint8Array(pixelsPerFrame); diff --git a/packages/dicom-image-loader/src/imageLoader/webWorkerManager.ts b/packages/dicom-image-loader/src/imageLoader/webWorkerManager.ts index 8c099412b..301cd1420 100644 --- a/packages/dicom-image-loader/src/imageLoader/webWorkerManager.ts +++ b/packages/dicom-image-loader/src/imageLoader/webWorkerManager.ts @@ -2,6 +2,10 @@ // eslint-disable-next-line // import cornerstoneWADOImageLoaderWebWorker from 'worker-loader!../webWorker/index.worker'; import cornerstoneWADOImageLoaderWebWorker from '../webWorker/index.worker'; +import { + CornerstoneWadoWebWorkerDecodeTaskData, + CornerstoneWadoWebWorkerResponse, +} from '../webWorker/webworker-messages'; // This is for the Webpack 5 approch but it's currently broken // so we will continue relying on worker-loader for now @@ -16,16 +20,56 @@ import { getOptions } from './internal/options'; // the taskId to assign to the next task added via addTask() let nextTaskId = 0; +export interface CornerstoneWadoWebWorkerDecodeConfig { + initializeCodecsOnStartup: boolean; + strict: boolean; +} + +export interface CornerstoneWadoWebWorkerTaskOptions { + decodeTask: CornerstoneWadoWebWorkerDecodeConfig; +} + +interface CornerstoneWebWorkerDeferredObject { + resolve: (arg: T | PromiseLike) => void; + reject: (err: any) => void; +} +export type CornerstoneWadoWorkerTaskTypes = + | 'decodeTask' + | 'loadWebWorkerTask' + | 'initialize'; + // array of queued tasks sorted with highest priority task first -const tasks = []; +export interface CornerstoneWorkerTask { + taskId: number; + taskType: CornerstoneWadoWorkerTaskTypes; + status: 'ready' | 'success' | 'failed'; + added: number; + start?: number; + data: CornerstoneWadoWebWorkerDecodeTaskData; + deferred: CornerstoneWebWorkerDeferredObject; + priority: number; + transferList: Transferable[]; +} +const tasks: CornerstoneWorkerTask[] = []; // array of web workers to dispatch decode tasks to -const webWorkers = []; +const webWorkers: { + worker: Worker; + status: 'ready' | 'busy' | 'initializing'; + task?: CornerstoneWorkerTask; +}[] = []; // The options for CornerstoneWADOImageLoader const options = getOptions(); -const defaultConfig = { +export interface CornerstoneWadoWebWorkerOptions { + maxWebWorkers?: number; + startWebWorkersOnDemand?: boolean; + webWorkerTaskPaths?: string[]; + taskConfiguration?: CornerstoneWadoWebWorkerTaskOptions; +} + +const defaultConfig: CornerstoneWadoWebWorkerOptions = { maxWebWorkers: navigator.hardwareConcurrency || 1, startWebWorkersOnDemand: true, webWorkerTaskPaths: [], @@ -37,7 +81,7 @@ const defaultConfig = { }, }; -let config; +let config: CornerstoneWadoWebWorkerOptions; const statistics = { maxWebWorkers: 0, @@ -101,7 +145,9 @@ function startTaskOnWebWorker() { * Function to handle a message from a web worker * @param msg */ -function handleMessageFromWorker(msg) { +function handleMessageFromWorker( + msg: MessageEvent +) { // console.log('handleMessageFromWorker', msg.data); if (msg.data.taskType === 'initialize') { webWorkers[msg.data.workerIndex].status = 'ready'; @@ -137,7 +183,7 @@ function spawnWebWorker() { } // spawn the webworker - const worker = new cornerstoneWADOImageLoaderWebWorker(); + const worker: Worker = new (cornerstoneWADOImageLoaderWebWorker as any)(); // This is for the Webpack 5 approach but it's currently broken /* const worker = new Worker(cornerstoneWADOImageLoaderWebWorkerPath, { @@ -168,7 +214,7 @@ function spawnWebWorker() { * Initialization function for the web worker manager - spawns web workers * @param configObject */ -function initialize(configObject) { +function initialize(configObject?: CornerstoneWadoWebWorkerOptions): void { configObject = configObject || defaultConfig; // prevent being initialized more than once @@ -192,7 +238,7 @@ function initialize(configObject) { /** * Terminate all running web workers. */ -function terminate() { +function terminate(): void { for (let i = 0; i < webWorkers.length; i++) { webWorkers[i].worker.terminate(); } @@ -205,7 +251,7 @@ function terminate() { * @param sourcePath * @param taskConfig */ -function loadWebWorkerTask(sourcePath, taskConfig) { +function loadWebWorkerTask(sourcePath: string, taskConfig): void { // add it to the list of web worker tasks paths so on demand web workers // load this properly config.webWorkerTaskPaths.push(sourcePath); @@ -238,13 +284,21 @@ function loadWebWorkerTask(sourcePath, taskConfig) { * @param transferList - optional array of data to transfer to web worker * @returns {*} */ -function addTask(taskType, data, priority = 0, transferList) { +function addTask( + taskType: CornerstoneWadoWorkerTaskTypes, + data: CornerstoneWadoWebWorkerDecodeTaskData, + priority = 0, + transferList: Transferable[] +): { taskId: number; promise: Promise } { if (!config) { initialize(); } - let deferred = {}; - const promise = new Promise((resolve, reject) => { + let deferred: CornerstoneWebWorkerDeferredObject = { + resolve: undefined, + reject: undefined, + }; + const promise = new Promise((resolve, reject) => { deferred = { resolve, reject, @@ -252,7 +306,7 @@ function addTask(taskType, data, priority = 0, transferList) { }); // find the right spot to insert this decode task (based on priority) - let i; + let i: number; for (i = 0; i < tasks.length; i++) { if (tasks[i].priority < priority) { @@ -289,7 +343,7 @@ function addTask(taskType, data, priority = 0, transferList) { * @param priority - priority of the task (defaults to 0), > 0 is higher, < 0 is lower * @returns boolean - true on success, false if taskId not found */ -function setTaskPriority(taskId, priority = 0) { +function setTaskPriority(taskId: number, priority = 0): boolean { // search for this taskId for (let i = 0; i < tasks.length; i++) { if (tasks[i].taskId === taskId) { @@ -322,14 +376,18 @@ function setTaskPriority(taskId, priority = 0) { * @param reason - optional reason the task was rejected * @returns boolean - true on success, false if taskId not found */ -function cancelTask(taskId, reason) { +function cancelTask(taskId: number, reason: string): boolean { // search for this taskId for (let i = 0; i < tasks.length; i++) { if (tasks[i].taskId === taskId) { // taskId found, remove it + /** + * @todo Check if this is a bug. Splice returns an array but task is + * treated as a single task object + */ const task = tasks.splice(i, 1); - task.deferred.reject(reason); + (task as any).deferred.reject(reason); return true; } @@ -342,7 +400,7 @@ function cancelTask(taskId, reason) { * Function to return the statistics on running web workers * @returns object containing statistics */ -function getStatistics() { +function getStatistics(): typeof config { statistics.maxWebWorkers = config.maxWebWorkers; statistics.numWebWorkers = webWorkers.length; statistics.numTasksQueued = tasks.length; diff --git a/packages/dicom-image-loader/src/shared/decodeImageFrame.ts b/packages/dicom-image-loader/src/shared/decodeImageFrame.ts index 8904777c7..ee90e5445 100644 --- a/packages/dicom-image-loader/src/shared/decodeImageFrame.ts +++ b/packages/dicom-image-loader/src/shared/decodeImageFrame.ts @@ -9,18 +9,20 @@ import decodeJPEGLossless from './decoders/decodeJPEGLossless'; import decodeJPEGLS from './decoders/decodeJPEGLS'; import decodeJPEG2000 from './decoders/decodeJPEG2000'; import scaleArray from './scaling/scaleArray'; +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from './image-frame'; function decodeImageFrame( - imageFrame, - transferSyntax, - pixelData, + imageFrame: CornerstoneWadoImageFrame, + transferSyntax: string, + pixelData: ByteArray, decodeConfig, options, - callbackFn -) { + callbackFn: (...args: any[]) => void +): void { const start = new Date().getTime(); - let decodePromise = null; + let decodePromise: Promise = null; let opts; @@ -141,7 +143,11 @@ function decodeImageFrame( }); } -function postProcessDecodedPixels(imageFrame, options, start) { +function postProcessDecodedPixels( + imageFrame: CornerstoneWadoImageFrame, + options, + start: number +) { const shouldShift = imageFrame.pixelRepresentation !== undefined && imageFrame.pixelRepresentation === 1; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.ts b/packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.ts index 53cde8cd6..771b85b5d 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.ts +++ b/packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.ts @@ -1,9 +1,15 @@ +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../image-frame'; + /* eslint no-bitwise: 0 */ function swap16(val) { return ((val & 0xff) << 8) | ((val >> 8) & 0xff); } -async function decodeBigEndian(imageFrame, pixelData) { +async function decodeBigEndian( + imageFrame: CornerstoneWadoImageFrame, + pixelData: ByteArray +): Promise { if (imageFrame.bitsAllocated === 16) { let arrayBuffer = pixelData.buffer; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.ts b/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.ts index 39dbdb7e6..c74bcb3a1 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.ts +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.ts @@ -7,14 +7,18 @@ import openJpegFactory from '@cornerstonejs/codec-openjpeg/dist/openjpegwasm_dec // This is closer to what Webpack 5 wants but it doesn't seem to work now // const wasm = new URL('./blah.wasm', import.meta.url) import openjpegWasm from '@cornerstonejs/codec-openjpeg/dist/openjpegwasm_decode.wasm'; +import { CornerstoneWadoWebWorkerDecodeConfig } from 'dicom-image-loader/src/imageLoader/webWorkerManager'; +import { CornerstoneWadoImageFrame } from '../image-frame'; const local = { codec: undefined, decoder: undefined, - decodeConfig: {}, + decodeConfig: {} as CornerstoneWadoWebWorkerDecodeConfig, }; -export function initialize(decodeConfig) { +export function initialize( + decodeConfig?: CornerstoneWadoWebWorkerDecodeConfig +): Promise { local.decodeConfig = decodeConfig; if (local.codec) { @@ -41,7 +45,10 @@ export function initialize(decodeConfig) { } // https://github.com/chafey/openjpegjs/blob/master/test/browser/index.html -async function decodeAsync(compressedImageFrame, imageInfo) { +async function decodeAsync( + compressedImageFrame, + imageInfo +): Promise { await initialize(); const decoder = local.decoder; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.ts b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.ts index 2a54b8c67..aea807db8 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.ts +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.ts @@ -1,9 +1,15 @@ +import { CornerstoneWadoWebWorkerDecodeConfig } from 'dicom-image-loader/src/imageLoader/webWorkerManager'; +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../image-frame'; + const local = { JpegImage: undefined, - decodeConfig: {}, + decodeConfig: {} as CornerstoneWadoWebWorkerDecodeConfig, }; -export function initialize(decodeConfig) { +export function initialize( + decodeConfig?: CornerstoneWadoWebWorkerDecodeConfig +): Promise { local.decodeConfig = decodeConfig; if (local.JpegImage) { @@ -18,7 +24,10 @@ export function initialize(decodeConfig) { }); } -async function decodeJPEGBaseline12BitAsync(imageFrame, pixelData) { +async function decodeJPEGBaseline12BitAsync( + imageFrame: CornerstoneWadoImageFrame, + pixelData: ByteArray +): Promise { // check to make sure codec is loaded await initialize(); if (typeof local.JpegImage === 'undefined') { diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.ts b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.ts index 1faa1f34c..4c0d348a2 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.ts +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.ts @@ -2,13 +2,15 @@ import libjpegTurboFactory from '@cornerstonejs/codec-libjpeg-turbo-8bit/dist/li // Webpack asset/resource copies this to our output folder import libjpegTurboWasm from '@cornerstonejs/codec-libjpeg-turbo-8bit/dist/libjpegturbowasm_decode.wasm'; +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../image-frame'; const local = { codec: undefined, decoder: undefined, }; -function initLibjpegTurbo() { +function initLibjpegTurbo(): Promise { if (local.codec) { return Promise.resolve(); } @@ -39,7 +41,10 @@ function initLibjpegTurbo() { * @param {object} imageInfo * @param {boolean} imageInfo.signed - */ -async function decodeAsync(compressedImageFrame, imageInfo) { +async function decodeAsync( + compressedImageFrame, + imageInfo +): Promise { await initLibjpegTurbo(); const decoder = local.decoder; @@ -86,7 +91,7 @@ async function decodeAsync(compressedImageFrame, imageInfo) { }; } -function getPixelData(frameInfo, decodedBuffer) { +function getPixelData(frameInfo, decodedBuffer: ByteArray) { if (frameInfo.isSigned) { return new Int8Array( decodedBuffer.buffer, diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.ts b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.ts index 73b8656c8..d2b54bf1e 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.ts +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.ts @@ -3,12 +3,15 @@ import charlsFactory from '@cornerstonejs/codec-charls/dist/charlswasm_decode'; // Webpack asset/resource copies this to our output folder import charlsWasm from '@cornerstonejs/codec-charls/dist/charlswasm_decode.wasm'; +import { CornerstoneWadoWebWorkerDecodeConfig } from 'dicom-image-loader/src/imageLoader/webWorkerManager'; +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../image-frame'; // import charlsWasm from '@cornerstonejs/codec-charls/dist/debug/charlswasm.wasm'; const local = { codec: undefined, decoder: undefined, - decodeConfig: {}, + decodeConfig: {} as CornerstoneWadoWebWorkerDecodeConfig, }; function getExceptionMessage(exception) { @@ -17,7 +20,9 @@ function getExceptionMessage(exception) { : exception; } -export function initialize(decodeConfig) { +export function initialize( + decodeConfig?: CornerstoneWadoWebWorkerDecodeConfig +): Promise { local.decodeConfig = decodeConfig; if (local.codec) { @@ -49,7 +54,10 @@ export function initialize(decodeConfig) { * @param {object} imageInfo * @param {boolean} imageInfo.signed - (pixelRepresentation === 1) */ -async function decodeAsync(compressedImageFrame, imageInfo) { +async function decodeAsync( + compressedImageFrame, + imageInfo +): Promise { try { await initialize(); const decoder = local.decoder; @@ -113,7 +121,7 @@ async function decodeAsync(compressedImageFrame, imageInfo) { } } -function getPixelData(frameInfo, decodedBuffer, signed) { +function getPixelData(frameInfo, decodedBuffer: ByteArray, signed: boolean) { if (frameInfo.bitsPerSample > 8) { if (signed) { return new Int16Array( diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.ts b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.ts index 016ce6848..92bb3fe5e 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.ts +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.ts @@ -1,9 +1,15 @@ +import { CornerstoneWadoWebWorkerDecodeConfig } from 'dicom-image-loader/src/imageLoader/webWorkerManager'; +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../image-frame'; + const local = { jpeg: undefined, - decodeConfig: {}, + decodeConfig: {} as CornerstoneWadoWebWorkerDecodeConfig, }; -export function initialize(decodeConfig) { +export function initialize( + decodeConfig?: CornerstoneWadoWebWorkerDecodeConfig +): Promise { local.decodeConfig = decodeConfig; if (local.jpeg) { @@ -18,7 +24,10 @@ export function initialize(decodeConfig) { }); } -async function decodeJPEGLossless(imageFrame, pixelData) { +async function decodeJPEGLossless( + imageFrame: CornerstoneWadoImageFrame, + pixelData: ByteArray +): Promise { await initialize(); // check to make sure codec is loaded diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.ts b/packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.ts index 0930d8248..9e3727413 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.ts +++ b/packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.ts @@ -1,4 +1,10 @@ -async function decodeLittleEndian(imageFrame, pixelData) { +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../image-frame'; + +async function decodeLittleEndian( + imageFrame: CornerstoneWadoImageFrame, + pixelData: ByteArray +): Promise { let arrayBuffer = pixelData.buffer; let offset = pixelData.byteOffset; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeRLE.ts b/packages/dicom-image-loader/src/shared/decoders/decodeRLE.ts index 204bbb965..db622cf6c 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeRLE.ts +++ b/packages/dicom-image-loader/src/shared/decoders/decodeRLE.ts @@ -1,4 +1,10 @@ -async function decodeRLE(imageFrame, pixelData) { +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../image-frame'; + +async function decodeRLE( + imageFrame: CornerstoneWadoImageFrame, + pixelData: ByteArray +): Promise { if (imageFrame.bitsAllocated === 8) { if (imageFrame.planarConfiguration) { return decode8Planar(imageFrame, pixelData); @@ -12,7 +18,7 @@ async function decodeRLE(imageFrame, pixelData) { throw new Error('unsupported pixel format for RLE'); } -function decode8(imageFrame, pixelData) { +function decode8(imageFrame: CornerstoneWadoImageFrame, pixelData: ByteArray) { const frameData = pixelData; const frameSize = imageFrame.rows * imageFrame.columns; const outFrame = new ArrayBuffer(frameSize * imageFrame.samplesPerPixel); @@ -63,7 +69,10 @@ function decode8(imageFrame, pixelData) { return imageFrame; } -function decode8Planar(imageFrame, pixelData) { +function decode8Planar( + imageFrame: CornerstoneWadoImageFrame, + pixelData: ByteArray +) { const frameData = pixelData; const frameSize = imageFrame.rows * imageFrame.columns; const outFrame = new ArrayBuffer(frameSize * imageFrame.samplesPerPixel); @@ -114,7 +123,7 @@ function decode8Planar(imageFrame, pixelData) { return imageFrame; } -function decode16(imageFrame, pixelData) { +function decode16(imageFrame: CornerstoneWadoImageFrame, pixelData: ByteArray) { const frameData = pixelData; const frameSize = imageFrame.rows * imageFrame.columns; const outFrame = new ArrayBuffer(frameSize * imageFrame.samplesPerPixel * 2); diff --git a/packages/dicom-image-loader/src/shared/getMinMax.ts b/packages/dicom-image-loader/src/shared/getMinMax.ts index a3d727399..17c46148b 100644 --- a/packages/dicom-image-loader/src/shared/getMinMax.ts +++ b/packages/dicom-image-loader/src/shared/getMinMax.ts @@ -1,10 +1,12 @@ +import { ByteArray } from 'dicom-parser'; + /** * Calculate the minimum and maximum values in an Array * * @param {Number[]} storedPixelData * @return {{min: Number, max: Number}} */ -function getMinMax(storedPixelData) { +function getMinMax(storedPixelData: ByteArray): { min: number; max: number } { // we always calculate the min max values since they are not always // present in DICOM and we don't want to trust them anyway as cornerstone // depends on us providing reliable values for these diff --git a/packages/dicom-image-loader/src/shared/image-frame.ts b/packages/dicom-image-loader/src/shared/image-frame.ts new file mode 100644 index 000000000..b9293dec1 --- /dev/null +++ b/packages/dicom-image-loader/src/shared/image-frame.ts @@ -0,0 +1,30 @@ +export interface CornerstoneWadoImageFrame { + samplesPerPixel: number; + photometricInterpretation: string; + planarConfiguration: number; + rows: number; + columns: number; + bitsAllocated: number; + bitsStored: number; + pixelRepresentation: number; + smallestPixelValue: number; + largestPixelValue: number; + redPaletteColorLookupTableDescriptor: number[]; + greenPaletteColorLookupTableDescriptor: number[]; + bluePaletteColorLookupTableDescriptor: number[]; + redPaletteColorLookupTableData: number[]; + greenPaletteColorLookupTableData: number[]; + bluePaletteColorLookupTableData: number[]; + // populated later after decoding + pixelData: + | Float32Array + | Int16Array + | Uint16Array + | Uint8Array + | Uint8ClampedArray + | undefined; + imageData?: ImageData; + decodeTimeInMS?: number; + pixelDataLength?: number; + preScale?: any; +} diff --git a/packages/dicom-image-loader/src/shared/scaling/scaleArray.ts b/packages/dicom-image-loader/src/shared/scaling/scaleArray.ts index 545ef7879..d3f89c0be 100644 --- a/packages/dicom-image-loader/src/shared/scaling/scaleArray.ts +++ b/packages/dicom-image-loader/src/shared/scaling/scaleArray.ts @@ -1,4 +1,7 @@ -export default function scaleArray(array, scalingParameters) { +export default function scaleArray( + array: number[], + scalingParameters +): boolean { const arrayLength = array.length; const { rescaleSlope, rescaleIntercept, suvbw } = scalingParameters; diff --git a/packages/dicom-image-loader/src/shared/types/load-image-options.ts b/packages/dicom-image-loader/src/shared/types/load-image-options.ts new file mode 100644 index 000000000..b5c263b3f --- /dev/null +++ b/packages/dicom-image-loader/src/shared/types/load-image-options.ts @@ -0,0 +1,17 @@ +import { Types } from '@cornerstonejs/core'; +import { CornerstoneWadoLoaderLoadRequestFunction } from 'dicom-image-loader/src/shared/types/load-request-function'; + +export interface CornerstoneLoadImageOptions { + useRGBA?: boolean; + preScale?: { + enabled: boolean; + scalingParameters?: Types.ScalingParameters; + }; + targetBuffer?: { + type: 'Uint8Array' | 'Uint16Array' | 'Float32Array'; + arrayBuffer: ArrayBufferLike; + length: number; + offset: number; + }; + loader?: CornerstoneWadoLoaderLoadRequestFunction; +} diff --git a/packages/dicom-image-loader/src/shared/types/load-request-function.ts b/packages/dicom-image-loader/src/shared/types/load-request-function.ts new file mode 100644 index 000000000..130936f3b --- /dev/null +++ b/packages/dicom-image-loader/src/shared/types/load-request-function.ts @@ -0,0 +1,6 @@ + +export type CornerstoneWadoLoaderLoadRequestFunction = ( + url: string, + imageId: string, + ...args: any[] +) => Promise; diff --git a/packages/dicom-image-loader/src/shared/types/metadata-modules.ts b/packages/dicom-image-loader/src/shared/types/metadata-modules.ts new file mode 100644 index 000000000..207fc190c --- /dev/null +++ b/packages/dicom-image-loader/src/shared/types/metadata-modules.ts @@ -0,0 +1,81 @@ +export type CornerstoneMetaDataTypes = + | 'generalSeriesModule' + | 'patientStudyModule' + | 'imagePlaneModule' + | 'imagePixelModule' + | 'transferSyntax' + | 'sopCommonModule' + | string; + +export interface DicomDateObject { + year: number; + month: number; + day: number; +} + +export interface DicomTimeObject { + hours: number; + minutes?: number; + seconds?: number; + fractionalSeconds?: number; +} + +export interface CornerstoneMetadataGeneralSeriesModule { + modality: string; + seriesInstanceUID: string; + seriesNumber: number; + studyInstanceUID: string; + seriesDate: DicomDateObject; + seriesTime: DicomTimeObject; +} + +export interface CornerstoneMetadataPatientStudyModule { + patientAge: number; + patientSize: number; + patientWeight: number; +} + +export interface CornerstoneMetadataImagePlaneModule { + frameOfReferenceUID: string; + rows: string; + columns: string; + imageOrientationPatient: number[]; + rowCosines: number[]; + columnCosines: number[]; + imagePositionPatient: number[]; + sliceThickness: string; + sliceLocation: string; + pixelSpacing: number[]; + rowPixelSpacing: number | null; + columnPixelSpacing: number | null; +} + +export interface CornerstoneMetadataImagePixelModule { + samplesPerPixel: number; + photometricInterpretation: string; + rows: number; + columns: number; + bitsAllocated: number; + bitsStored: number; + highBit: number; + pixelRepresentation: number; + planarConfiguration: number; + pixelAspectRatio: string; + redPaletteColorLookupTableDescriptor: number[]; + greenPaletteColorLookupTableDescriptor: number[]; + bluePaletteColorLookupTableDescriptor: number[]; + redPaletteColorLookupTableData: number[]; + greenPaletteColorLookupTableData: number[]; + bluePaletteColorLookupTableData: number[]; + smallestPixelValue?: number; + largestPixelValue?: number; +} + +export interface CornerstoneMetadataSopCommonModule { + sopClassUID: string; + sopInstanceUID: string; +} + +export interface CornerstoneMetadataTransferSyntax { + transferSyntaxUID: string; +} diff --git a/packages/dicom-image-loader/src/webWorker/decodeTask.ts b/packages/dicom-image-loader/src/webWorker/decodeTask.ts index 9ade7d214..33918dca7 100644 --- a/packages/dicom-image-loader/src/webWorker/decodeTask.ts +++ b/packages/dicom-image-loader/src/webWorker/decodeTask.ts @@ -1,16 +1,19 @@ -import { initialize as initializeJPEG2000 } from '../shared/decoders/decodeJPEG2000'; -import { initialize as initializeJPEGLS } from '../shared/decoders/decodeJPEGLS'; +import { CornerstoneWadoWebWorkerTaskOptions } from '../imageLoader/webWorkerManager'; import calculateMinMax from '../shared/calculateMinMax'; import decodeImageFrame from '../shared/decodeImageFrame'; +import { initialize as initializeJPEG2000 } from '../shared/decoders/decodeJPEG2000'; +import { initialize as initializeJPEGLS } from '../shared/decoders/decodeJPEGLS'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; +import { CornerstoneWadoWebWorkerDecodeData } from './webworker-messages'; // the configuration object for the decodeTask -let decodeConfig; +let decodeConfig: CornerstoneWadoWebWorkerTaskOptions; /** * Function to control loading and initializing the codecs * @param config */ -function loadCodecs(config) { +function loadCodecs(config: CornerstoneWadoWebWorkerTaskOptions) { // Initialize the codecs if (config.decodeTask.initializeCodecsOnStartup) { initializeJPEG2000(config.decodeTask); @@ -21,7 +24,7 @@ function loadCodecs(config) { /** * Task initialization function */ -function initialize(config) { +function initialize(config: CornerstoneWadoWebWorkerTaskOptions): void { decodeConfig = config; loadCodecs(config); @@ -30,7 +33,13 @@ function initialize(config) { /** * Task handler function */ -function handler(data, doneCallback) { +function handler( + data: CornerstoneWadoWebWorkerDecodeData, + doneCallback: ( + imageFrame: CornerstoneWadoImageFrame, + pixelData: Transferable[] + ) => void +): void { // Load the codecs if they aren't already loaded loadCodecs(decodeConfig); @@ -42,7 +51,7 @@ function handler(data, doneCallback) { const pixelData = new Uint8Array(data.data.pixelData); // TODO switch to promise - function finishedCallback(imageFrame) { + function finishedCallback(imageFrame: CornerstoneWadoImageFrame) { if (!imageFrame.pixelData) { throw new Error( 'decodeTask: imageFrame.pixelData is undefined after decoding' @@ -51,9 +60,10 @@ function handler(data, doneCallback) { calculateMinMax(imageFrame, strict); + /** @todo check as any */ // convert from TypedArray to ArrayBuffer since web workers support passing ArrayBuffers but not // typed arrays - imageFrame.pixelData = imageFrame.pixelData.buffer; + imageFrame.pixelData = imageFrame.pixelData.buffer as any; // invoke the callback with our result and pass the pixelData in the transferList to move it to // UI thread without making a copy diff --git a/packages/dicom-image-loader/src/webWorker/webWorker.ts b/packages/dicom-image-loader/src/webWorker/webWorker.ts index fc2bd20ab..2dd64fe21 100644 --- a/packages/dicom-image-loader/src/webWorker/webWorker.ts +++ b/packages/dicom-image-loader/src/webWorker/webWorker.ts @@ -1,17 +1,43 @@ +/// + +import { + CornerstoneWadoWebWorkerOptions, + CornerstoneWadoWebWorkerTaskOptions, + CornerstoneWadoWorkerTaskTypes, +} from '../imageLoader/webWorkerManager'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; +import { + CornerstoneWadoWebWorkerData, + CornerstoneWadoWebWorkerDecodeData, + CornerstoneWadoWebWorkerInitializeData, +} from './webworker-messages'; + +interface CornerstoneWadoWebWorkerTaskHandler { + taskType: CornerstoneWadoWorkerTaskTypes; + handler: ( + data: CornerstoneWadoWebWorkerDecodeData, + cb: ( + result: CornerstoneWadoImageFrame, + transferables: Transferable[] + ) => void + ) => void; + initialize: (config: CornerstoneWadoWebWorkerTaskOptions) => void; +} + // an object of task handlers -const taskHandlers = {}; +const taskHandlers: Record = {}; // Flag to ensure web worker is only initialized once let initialized = false; // the configuration object passed in when the web worker manager is initialized -let config; +let config: CornerstoneWadoWebWorkerOptions; /** * Initialization function that loads additional web workers and initializes them * @param data */ -function initialize(data) { +function initialize(data: CornerstoneWadoWebWorkerInitializeData) { // console.log('web worker initialize ', data.workerIndex); // prevent initialization from happening more than once if (initialized) { @@ -21,8 +47,11 @@ function initialize(data) { // save the config data config = data.config; + /** + * @todo review any + */ // Additional web worker tasks can self-register by calling self.registerTaskHandler - self.registerTaskHandler = registerTaskHandler; + (self as any).registerTaskHandler = registerTaskHandler; // load any additional web worker tasks if (data.config.webWorkerTaskPaths) { @@ -51,7 +80,9 @@ function initialize(data) { * Function exposed to web worker tasks to register themselves * @param taskHandler */ -export function registerTaskHandler(taskHandler) { +export function registerTaskHandler( + taskHandler: CornerstoneWadoWebWorkerTaskHandler +): false | void { if (taskHandlers[taskHandler.taskType]) { console.log( 'attempt to register duplicate task handler "', @@ -80,7 +111,7 @@ function loadWebWorkerTask(data) { * Web worker message handler - dispatches messages to the registered task handlers * @param msg */ -self.onmessage = function (msg) { +self.onmessage = function (msg: MessageEvent) { if (!msg.data.taskType) { console.log(msg.data); @@ -120,7 +151,7 @@ self.onmessage = function (msg) { ); } ); - } catch (error) { + } catch (error: any) { console.log(`task ${msg.data.taskType} failed - ${error.message}`); self.postMessage({ taskType: msg.data.taskType, diff --git a/packages/dicom-image-loader/src/webWorker/webworker-messages.ts b/packages/dicom-image-loader/src/webWorker/webworker-messages.ts new file mode 100644 index 000000000..5735dca87 --- /dev/null +++ b/packages/dicom-image-loader/src/webWorker/webworker-messages.ts @@ -0,0 +1,46 @@ +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoLoaderOptions } from '../imageLoader/internal/options'; +import { + CornerstoneWadoWebWorkerOptions, + CornerstoneWadoWorkerTaskTypes, +} from '../imageLoader/webWorkerManager'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; + +export interface CornerstoneWadoWebWorkerDecodeTaskData { + imageFrame: CornerstoneWadoImageFrame; + transferSyntax: string; + pixelData: ByteArray; + options: CornerstoneWadoLoaderOptions; +} + +export interface CornerstoneWadoWebWorkerDecodeData { + taskType: 'decodeTask'; + workerIndex: number; + data: CornerstoneWadoWebWorkerDecodeTaskData; +} + +export interface CornerstoneWadoWebWorkerLoadData { + taskType: 'loadWebWorkerTask'; + workerIndex: number; + sourcePath: string; + config: CornerstoneWadoWebWorkerOptions; +} + +export interface CornerstoneWadoWebWorkerInitializeData { + taskType: 'initialize'; + workerIndex: number; + config: CornerstoneWadoWebWorkerOptions; +} + +export type CornerstoneWadoWebWorkerData = + | CornerstoneWadoWebWorkerDecodeData + | CornerstoneWadoWebWorkerLoadData + | CornerstoneWadoWebWorkerInitializeData; + +export interface CornerstoneWadoWebWorkerResponse { + taskType: CornerstoneWadoWorkerTaskTypes; + status: 'failed' | 'success'; + workerIndex: number; + data?: CornerstoneWadoImageFrame; + result: string | CornerstoneWadoImageFrame; +} From 09ca22fd29dc527f19ea9e4bd1e9711616d6b686 Mon Sep 17 00:00:00 2001 From: James Manners Date: Wed, 7 Dec 2022 15:27:20 +1100 Subject: [PATCH 07/14] [wip] update types for tests --- packages/dicom-image-loader/package.json | 7 +++++++ .../dicom-image-loader/src/imageLoader/webWorkerManager.ts | 2 +- .../dicom-image-loader/src/shared/calculateMinMax_test.ts | 2 +- packages/dicom-image-loader/src/shared/getMinMax.ts | 5 ++++- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/dicom-image-loader/package.json b/packages/dicom-image-loader/package.json index 87b69fc07..131525bf6 100644 --- a/packages/dicom-image-loader/package.json +++ b/packages/dicom-image-loader/package.json @@ -51,6 +51,13 @@ "dicom-parser": "^1.8.9", "pako": "^2.0.4" }, + "devDependencies": { + "@types/chai": "^4.3.4", + "@types/mocha": "^9.1.1", + "chai": "^4.3.4", + "mocha": "^9.1.1" + + }, "contributors": [ { "name": "Cornerstone.js Contributors", diff --git a/packages/dicom-image-loader/src/imageLoader/webWorkerManager.ts b/packages/dicom-image-loader/src/imageLoader/webWorkerManager.ts index 301cd1420..e8814b6c9 100644 --- a/packages/dicom-image-loader/src/imageLoader/webWorkerManager.ts +++ b/packages/dicom-image-loader/src/imageLoader/webWorkerManager.ts @@ -22,7 +22,7 @@ let nextTaskId = 0; export interface CornerstoneWadoWebWorkerDecodeConfig { initializeCodecsOnStartup: boolean; - strict: boolean; + strict?: boolean; } export interface CornerstoneWadoWebWorkerTaskOptions { diff --git a/packages/dicom-image-loader/src/shared/calculateMinMax_test.ts b/packages/dicom-image-loader/src/shared/calculateMinMax_test.ts index 461f79e2a..2f669b341 100644 --- a/packages/dicom-image-loader/src/shared/calculateMinMax_test.ts +++ b/packages/dicom-image-loader/src/shared/calculateMinMax_test.ts @@ -2,7 +2,7 @@ import { expect } from 'chai'; import calculateMinMax from './calculateMinMax'; describe('#calculateMinMax', () => { - let imageFrame = {}; + let imageFrame: any = {}; beforeEach(() => { imageFrame = { diff --git a/packages/dicom-image-loader/src/shared/getMinMax.ts b/packages/dicom-image-loader/src/shared/getMinMax.ts index 17c46148b..02eb142a2 100644 --- a/packages/dicom-image-loader/src/shared/getMinMax.ts +++ b/packages/dicom-image-loader/src/shared/getMinMax.ts @@ -6,7 +6,10 @@ import { ByteArray } from 'dicom-parser'; * @param {Number[]} storedPixelData * @return {{min: Number, max: Number}} */ -function getMinMax(storedPixelData: ByteArray): { min: number; max: number } { +function getMinMax(storedPixelData: ByteArray | number[]): { + min: number; + max: number; +} { // we always calculate the min max values since they are not always // present in DICOM and we don't want to trust them anyway as cornerstone // depends on us providing reliable values for these From f6efcca759f3df0edc591d90f91256375312c026 Mon Sep 17 00:00:00 2001 From: James Manners Date: Thu, 8 Dec 2022 08:23:14 +1100 Subject: [PATCH 08/14] Dicom Loader Typescript Conversion (#330) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: mouse-up should not unhighlight annotations (#305) * fix: annotation highlighted and tooling for ellipticalROI * update build * fix tests * chore(release): publish [skip ci] - docs@0.7.8 - @cornerstonejs/tools@0.29.7 * fix: stack viewport flip scroll (#304) * fix: use focal point for pan cache for stack viewport * fix: pan dir with flip * fix pan values while flipped * update build * apply review comments * fix build * chore(release): publish [skip ci] - @cornerstonejs/core@0.21.5 - docs@0.7.9 - @cornerstonejs/streaming-image-volume-loader@0.6.6 - @cornerstonejs/tools@0.29.8 * feat: add referenceCursors tool (#275) * added basic cursorCrosshairSync tool with example, TODO: for now cursorSync is displayed regardless of distance, create configurable distance and also sync the position of all viewports over which the mouse is not to scroll to a slice that is close to the currentMousePosition in 3d space * addde stack syncing for StackViewport and syncing for volumeViewport on imageChange events, added configuration for max display distance * refactored tool functions * added comment to possible bug * added configuration options to example * changed look of crosshair to 4 lines with central space * undid local tsconfig change * undid yarn.lock changes * added tool to example-info.json * removed from example-runner because it broke build * readded example and fixed typo * readded example-info and changed example to trigger rebuild * added cleanup for mouseoverElement when tool is disabled * added cleanup when tool gets disabled, this does not get called when toolGroup gets destroyed, might cause remaining listeners * applied naming changes, reworked adding annotation logic * removed event listeners and moved logic to check for stack scrolling into rendering logic * added planeDistanceToPoint to planar utilities * added getClosestStackImageIndexForPoint * rewrote logic to use onCameraModified * updated example-info * fixed bug with 0 being falsey * added logic to remove cursor if wanted * modified toolGroup so that setting a tool active only changes the cursor to default if there is no primary mouse cursor * fixed bug not updating disable cursor * fixed missing parentheses from merge * readded scrollWheel scrolling and api changes * fixed typos * chore(release): publish [skip ci] - @cornerstonejs/core@0.22.0 - docs@0.7.10 - @cornerstonejs/streaming-image-volume-loader@0.6.7 - @cornerstonejs/tools@0.30.0 * fix: ZoomTool fix for polyData actors with no imageData (#308) * chore(release): publish [skip ci] - docs@0.7.11 - @cornerstonejs/tools@0.30.1 * fix: If planar annotation is not visible, filter it (#318) Co-authored-by: edward65 * fix: filter planarFreeHandeROI based on parallel normals instead of equal normals. (#315) Co-authored-by: Ramon Emiliani * fix: get correct imageData with targetId in BaseTool (#294) * limit disabled element not need to render * Update BaseTool.ts fix: get correct viewport when there are multiple viewport with same stack data Co-authored-by: chendingmiao * chore(release): publish [skip ci] - docs@0.7.12 - @cornerstonejs/tools@0.30.2 * fix: htj2k and keymodifier (#313) * fix(htj2k):Support htj2k in the streaming volume loader * fix(decodeImage):Fix htj2k image decode and mouse key modifiers * Update for PR * update ci build * chore(release): publish [skip ci] - docs@0.7.13 - @cornerstonejs/streaming-image-volume-loader@0.6.8 - @cornerstonejs/tools@0.30.3 * fix: coronal view should not be flipped (#321) * chore(release): publish [skip ci] - @cornerstonejs/core@0.22.1 - docs@0.7.14 - @cornerstonejs/streaming-image-volume-loader@0.6.9 - @cornerstonejs/tools@0.30.4 * fix: bidirectional tool when short and long axis changes (#309) * fix rotation for handles * fix: short axis movement * fix: bidirectional tool incorrect interaction * chore(release): publish [skip ci] - @cornerstonejs/core@0.22.2 - docs@0.7.15 - @cornerstonejs/streaming-image-volume-loader@0.6.10 - @cornerstonejs/tools@0.30.5 * fix(volumeViewport): Add optional scaling as the volume can be undefined (#323) While trying to get the volume from the cache, it can be undefined so getting the scaling attribute would throw an error in that case. This is a quick fix * chore(release): publish [skip ci] - @cornerstonejs/core@0.22.3 - docs@0.7.16 - @cornerstonejs/streaming-image-volume-loader@0.6.11 - @cornerstonejs/tools@0.30.6 * fix: Use queryselector instead of firstChild to get svg-layer (#268) * chore(release): publish [skip ci] - docs@0.7.17 - @cornerstonejs/tools@0.30.7 * [wip] initial dicom-loader typescript conversion * [wip] initial typescript conversion * [wip] update types for tests Co-authored-by: Alireza Co-authored-by: ohif-bot Co-authored-by: Niclas do <32524613+doepnern@users.noreply.github.com> Co-authored-by: Neil Co-authored-by: Edward Son Co-authored-by: edward65 Co-authored-by: ramonemiliani93 Co-authored-by: Ramon Emiliani Co-authored-by: 陈定苗 <359650098@qq.com> Co-authored-by: chendingmiao Co-authored-by: Bill Wallace Co-authored-by: Gabriel Lebaudy Co-authored-by: Mustafa ÇİNÄ° Co-authored-by: James Manners --- common/reviews/api/core.api.md | 20 +- common/reviews/api/tools.api.md | 84 +- package.json | 4 +- packages/core/CHANGELOG.md | 521 ++------- packages/core/package.json | 2 +- .../core/src/RenderingEngine/StackViewport.ts | 59 +- packages/core/src/RenderingEngine/Viewport.ts | 81 +- .../src/RenderingEngine/VolumeViewport.ts | 2 +- .../core/src/constants/mprCameraValues.ts | 2 +- .../getClosestStackImageIndexForPoint.ts | 116 ++ packages/core/src/utilities/index.ts | 4 + packages/core/src/utilities/planar.ts | 27 +- ...eURI_100_100_10_1_1_1_0_coronal_linear.png | Bin 24301 -> 25355 bytes ...URI_100_100_10_1_1_1_0_coronal_nearest.png | Bin 21485 -> 22063 bytes .../.webpack/webpack-base.js | 9 +- .../.webpack/webpack-bundle.js | 11 +- .../.webpack/webpack-esm.js | 5 +- packages/dicom-image-loader/package.json | 7 + ...{externalModules.js => externalModules.ts} | 22 +- ...PALETTECOLOR.js => convertPALETTECOLOR.ts} | 11 +- ...orByPixel.js => convertRGBColorByPixel.ts} | 8 +- ...orByPlane.js => convertRGBColorByPlane.ts} | 8 +- ...ByPixel.js => convertYBRFull422ByPixel.ts} | 8 +- ...ullByPixel.js => convertYBRFullByPixel.ts} | 8 +- ...ullByPlane.js => convertYBRFullByPlane.ts} | 8 +- .../{index.js => index.ts} | 0 .../src/imageLoader/configure.js | 7 - .../src/imageLoader/configure.ts | 8 + ...vertColorSpace.js => convertColorSpace.ts} | 0 .../{createImage.js => createImage.ts} | 64 +- ...rkers.js => decodeImageFrame-noWorkers.ts} | 23 +- ...ecodeImageFrame.js => decodeImageFrame.ts} | 26 +- ...olor.js => decodeJPEGBaseline8BitColor.ts} | 23 +- .../{getImageFrame.js => getImageFrame.ts} | 10 +- .../{getMinMax.js => getMinMax.ts} | 5 +- ...gParameters.js => getScalingParameters.ts} | 10 +- .../{imageIdToURI.js => imageIdToURI.ts} | 2 +- ...{index-noWorkers.js => index-noWorkers.ts} | 0 .../src/imageLoader/{index.js => index.ts} | 0 .../internal/{index.js => index.ts} | 0 .../src/imageLoader/internal/options.js | 22 - .../src/imageLoader/internal/options.ts | 50 + .../internal/{xhrRequest.js => xhrRequest.ts} | 43 +- .../{isColorImage.js => isColorImage.ts} | 2 +- .../imageLoader/isJPEGBaseline8BitColor.js | 13 - .../imageLoader/isJPEGBaseline8BitColor.ts | 19 + ...{registerLoaders.js => registerLoaders.ts} | 3 +- .../src/imageLoader/wado-loader.ts | 18 + ...dIndexOfString.js => findIndexOfString.ts} | 10 +- .../{getPixelData.js => getPixelData.ts} | 18 +- .../imageLoader/wadors/{index.js => index.ts} | 0 .../src/imageLoader/wadors/loadImage.js | 132 --- .../src/imageLoader/wadors/loadImage.ts | 155 +++ .../{loadImage_test.js => loadImage_test.ts} | 0 ...{getNumberString.js => getNumberString.ts} | 7 +- .../{getNumberValue.js => getNumberValue.ts} | 6 +- ...{getNumberValues.js => getNumberValues.ts} | 11 +- ...laneModule.js => getOverlayPlaneModule.ts} | 3 +- .../metaData/{getValue.js => getValue.ts} | 8 +- .../wadors/metaData/{index.js => index.ts} | 0 ...etaDataProvider.js => metaDataProvider.ts} | 16 +- ...{metaDataManager.js => metaDataManager.ts} | 11 +- .../wadors/{register.js => register.ts} | 3 +- .../imageLoader/wadors/wado-rs-metadata.ts | 5 + ...CacheManager.js => dataSetCacheManager.ts} | 127 ++- ...er_test.js => dataSetCacheManager_test.ts} | 0 .../{fileManager.js => fileManager.ts} | 10 +- ...eFrame.js => getEncapsulatedImageFrame.ts} | 8 +- .../{getPixelData.js => getPixelData.ts} | 3 +- ...eFrame.js => getUncompressedImageFrame.ts} | 6 +- .../wadouri/{index.js => index.ts} | 0 ...{loadFileRequest.js => loadFileRequest.ts} | 6 +- .../wadouri/{loadImage.js => loadImage.ts} | 109 +- ...ePixelModule.js => getImagePixelModule.ts} | 23 +- .../metaData/{getLUTs.js => getLUTs.ts} | 21 +- ...etModalityLUTOutputPixelRepresentation.ts} | 6 +- ...{getNumberValues.js => getNumberValues.ts} | 8 +- ...laneModule.js => getOverlayPlaneModule.ts} | 4 +- .../wadouri/metaData/{index.js => index.ts} | 0 ...etaDataProvider.js => metaDataProvider.ts} | 60 +- .../{parseImageId.js => parseImageId.ts} | 8 +- .../wadouri/{register.js => register.ts} | 3 +- ...ackBinaryFrame.js => unpackBinaryFrame.ts} | 10 +- ...ebWorkerManager.js => webWorkerManager.ts} | 92 +- ...nager_test.js => webWorkerManager_test.ts} | 0 ...{calculateMinMax.js => calculateMinMax.ts} | 0 ...MinMax_test.js => calculateMinMax_test.ts} | 2 +- ...ecodeImageFrame.js => decodeImageFrame.ts} | 20 +- ...{decodeBigEndian.js => decodeBigEndian.ts} | 8 +- .../{decodeJPEG2000.js => decodeJPEG2000.ts} | 13 +- ...it-js.js => decodeJPEGBaseline12Bit-js.ts} | 15 +- ...JPEGBaseline12Bit-wasm-not-yet-working.ts} | 0 ...eline8Bit.js => decodeJPEGBaseline8Bit.ts} | 11 +- .../{decodeJPEGLS.js => decodeJPEGLS.ts} | 16 +- ...eJPEGLossless.js => decodeJPEGLossless.ts} | 15 +- ...eLittleEndian.js => decodeLittleEndian.ts} | 8 +- .../decoders/{decodeRLE.js => decodeRLE.ts} | 17 +- .../src/shared/{getMinMax.js => getMinMax.ts} | 7 +- .../{getMinMax_test.js => getMinMax_test.ts} | 0 .../src/shared/image-frame.ts | 30 + .../scaling/{scaleArray.js => scaleArray.ts} | 5 +- .../src/shared/types/load-image-options.ts | 17 + .../src/shared/types/load-request-function.ts | 6 + .../src/shared/types/metadata-modules.ts | 81 ++ .../src/{version.js => version.ts} | 0 .../{decodeTask.js => decodeTask.ts} | 26 +- .../{index.worker.js => index.worker.ts} | 0 .../webWorker/{webWorker.js => webWorker.ts} | 45 +- .../src/webWorker/webworker-messages.ts | 46 + packages/docs/CHANGELOG.md | 891 ++++----------- packages/docs/package.json | 8 +- .../CHANGELOG.md | 373 +----- .../package.json | 6 +- .../src/sharedArrayBufferImageLoader.ts | 2 + packages/tools/CHANGELOG.md | 1008 +++++------------ .../tools/examples/referenceCursors/index.ts | 300 +++++ packages/tools/package.json | 4 +- packages/tools/src/drawingSvg/drawEllipse.ts | 7 +- .../src/drawingSvg/getSvgDrawingHelper.ts | 5 +- packages/tools/src/enums/ToolBindings.ts | 7 + .../shared/getActiveToolForMouseEvent.ts | 5 +- .../shared/getMouseModifier.ts | 30 + packages/tools/src/index.ts | 2 + .../src/store/ToolGroupManager/ToolGroup.ts | 9 +- packages/tools/src/tools/CrosshairsTool.ts | 1 - packages/tools/src/tools/ReferenceCursors.ts | 471 ++++++++ packages/tools/src/tools/ZoomTool.ts | 20 +- .../tools/src/tools/annotation/AngleTool.ts | 1 - .../src/tools/annotation/ArrowAnnotateTool.ts | 1 - .../src/tools/annotation/BidirectionalTool.ts | 301 ++--- .../src/tools/annotation/EllipticalROITool.ts | 8 +- .../tools/src/tools/annotation/LengthTool.ts | 1 - .../tools/annotation/PlanarFreehandROITool.ts | 27 +- .../tools/src/tools/annotation/ProbeTool.ts | 2 - .../src/tools/annotation/RectangleROITool.ts | 1 - packages/tools/src/tools/base/BaseTool.ts | 10 +- packages/tools/src/tools/index.ts | 2 + .../tools/segmentation/CircleScissorsTool.ts | 1 - .../segmentation/RectangleScissorsTool.ts | 1 - .../tools/segmentation/SphereScissorsTool.ts | 1 - .../src/types/ToolSpecificAnnotationTypes.ts | 8 + .../segmentation/triggerSegmentationRender.ts | 4 + packages/tools/test/LengthTool_test.js | 8 +- packages/tools/test/cpu_LengthTool_test.js | 4 +- .../volumeURI_100_100_10_1_1_1_0_SEG_COR.png | Bin 3038 -> 3032 bytes ...0_100_10_1_1_1_0_SEG_SphereScissor_COR.png | Bin 3914 -> 3607 bytes .../test/groundTruth/windowLevel_canvas2.png | Bin 3362 -> 4318 bytes utils/ExampleRunner/example-info.json | 6 +- 148 files changed, 3239 insertions(+), 2949 deletions(-) create mode 100644 packages/core/src/utilities/getClosestStackImageIndexForPoint.ts rename packages/dicom-image-loader/src/{externalModules.js => externalModules.ts} (59%) rename packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/{convertPALETTECOLOR.js => convertPALETTECOLOR.ts} (86%) rename packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/{convertRGBColorByPixel.js => convertRGBColorByPixel.ts} (82%) rename packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/{convertRGBColorByPlane.js => convertRGBColorByPlane.ts} (83%) rename packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/{convertYBRFull422ByPixel.js => convertYBRFull422ByPixel.ts} (92%) rename packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/{convertYBRFullByPixel.js => convertYBRFullByPixel.ts} (88%) rename packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/{convertYBRFullByPlane.js => convertYBRFullByPlane.ts} (89%) rename packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/{index.js => index.ts} (100%) delete mode 100644 packages/dicom-image-loader/src/imageLoader/configure.js create mode 100644 packages/dicom-image-loader/src/imageLoader/configure.ts rename packages/dicom-image-loader/src/imageLoader/{convertColorSpace.js => convertColorSpace.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{createImage.js => createImage.ts} (87%) rename packages/dicom-image-loader/src/imageLoader/{decodeImageFrame-noWorkers.js => decodeImageFrame-noWorkers.ts} (89%) rename packages/dicom-image-loader/src/imageLoader/{decodeImageFrame.js => decodeImageFrame.ts} (86%) rename packages/dicom-image-loader/src/imageLoader/{decodeJPEGBaseline8BitColor.js => decodeJPEGBaseline8BitColor.ts} (75%) rename packages/dicom-image-loader/src/imageLoader/{getImageFrame.js => getImageFrame.ts} (79%) rename packages/dicom-image-loader/src/imageLoader/{getMinMax.js => getMinMax.ts} (83%) rename packages/dicom-image-loader/src/imageLoader/{getScalingParameters.js => getScalingParameters.ts} (70%) rename packages/dicom-image-loader/src/imageLoader/{imageIdToURI.js => imageIdToURI.ts} (80%) rename packages/dicom-image-loader/src/imageLoader/{index-noWorkers.js => index-noWorkers.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/{index.js => index.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/internal/{index.js => index.ts} (100%) delete mode 100644 packages/dicom-image-loader/src/imageLoader/internal/options.js create mode 100644 packages/dicom-image-loader/src/imageLoader/internal/options.ts rename packages/dicom-image-loader/src/imageLoader/internal/{xhrRequest.js => xhrRequest.ts} (79%) rename packages/dicom-image-loader/src/imageLoader/{isColorImage.js => isColorImage.ts} (85%) delete mode 100644 packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.js create mode 100644 packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.ts rename packages/dicom-image-loader/src/imageLoader/{registerLoaders.js => registerLoaders.ts} (74%) create mode 100644 packages/dicom-image-loader/src/imageLoader/wado-loader.ts rename packages/dicom-image-loader/src/imageLoader/wadors/{findIndexOfString.js => findIndexOfString.ts} (77%) rename packages/dicom-image-loader/src/imageLoader/wadors/{getPixelData.js => getPixelData.ts} (83%) rename packages/dicom-image-loader/src/imageLoader/wadors/{index.js => index.ts} (100%) delete mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/loadImage.js create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/loadImage.ts rename packages/dicom-image-loader/src/imageLoader/wadors/{loadImage_test.js => loadImage_test.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadors/metaData/{getNumberString.js => getNumberString.ts} (77%) rename packages/dicom-image-loader/src/imageLoader/wadors/metaData/{getNumberValue.js => getNumberValue.ts} (55%) rename packages/dicom-image-loader/src/imageLoader/wadors/metaData/{getNumberValues.js => getNumberValues.ts} (70%) rename packages/dicom-image-loader/src/imageLoader/wadors/metaData/{getOverlayPlaneModule.js => getOverlayPlaneModule.ts} (91%) rename packages/dicom-image-loader/src/imageLoader/wadors/metaData/{getValue.js => getValue.ts} (79%) rename packages/dicom-image-loader/src/imageLoader/wadors/metaData/{index.js => index.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadors/metaData/{metaDataProvider.js => metaDataProvider.ts} (91%) rename packages/dicom-image-loader/src/imageLoader/wadors/{metaDataManager.js => metaDataManager.ts} (58%) rename packages/dicom-image-loader/src/imageLoader/wadors/{register.js => register.ts} (66%) create mode 100644 packages/dicom-image-loader/src/imageLoader/wadors/wado-rs-metadata.ts rename packages/dicom-image-loader/src/imageLoader/wadouri/{dataSetCacheManager.js => dataSetCacheManager.ts} (51%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{dataSetCacheManager_test.js => dataSetCacheManager_test.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{fileManager.js => fileManager.ts} (56%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{getEncapsulatedImageFrame.js => getEncapsulatedImageFrame.ts} (84%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{getPixelData.js => getPixelData.ts} (79%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{getUncompressedImageFrame.js => getUncompressedImageFrame.ts} (95%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{index.js => index.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{loadFileRequest.js => loadFileRequest.ts} (70%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{loadImage.js => loadImage.ts} (59%) rename packages/dicom-image-loader/src/imageLoader/wadouri/metaData/{getImagePixelModule.js => getImagePixelModule.ts} (87%) rename packages/dicom-image-loader/src/imageLoader/wadouri/metaData/{getLUTs.js => getLUTs.ts} (73%) rename packages/dicom-image-loader/src/imageLoader/wadouri/metaData/{getModalityLUTOutputPixelRepresentation.js => getModalityLUTOutputPixelRepresentation.ts} (89%) rename packages/dicom-image-loader/src/imageLoader/wadouri/metaData/{getNumberValues.js => getNumberValues.ts} (72%) rename packages/dicom-image-loader/src/imageLoader/wadouri/metaData/{getOverlayPlaneModule.js => getOverlayPlaneModule.ts} (91%) rename packages/dicom-image-loader/src/imageLoader/wadouri/metaData/{index.js => index.ts} (100%) rename packages/dicom-image-loader/src/imageLoader/wadouri/metaData/{metaDataProvider.js => metaDataProvider.ts} (73%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{parseImageId.js => parseImageId.ts} (76%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{register.js => register.ts} (76%) rename packages/dicom-image-loader/src/imageLoader/wadouri/{unpackBinaryFrame.js => unpackBinaryFrame.ts} (75%) rename packages/dicom-image-loader/src/imageLoader/{webWorkerManager.js => webWorkerManager.ts} (77%) rename packages/dicom-image-loader/src/imageLoader/{webWorkerManager_test.js => webWorkerManager_test.ts} (100%) rename packages/dicom-image-loader/src/shared/{calculateMinMax.js => calculateMinMax.ts} (100%) rename packages/dicom-image-loader/src/shared/{calculateMinMax_test.js => calculateMinMax_test.ts} (98%) rename packages/dicom-image-loader/src/shared/{decodeImageFrame.js => decodeImageFrame.ts} (95%) rename packages/dicom-image-loader/src/shared/decoders/{decodeBigEndian.js => decodeBigEndian.ts} (80%) rename packages/dicom-image-loader/src/shared/decoders/{decodeJPEG2000.js => decodeJPEG2000.ts} (90%) rename packages/dicom-image-loader/src/shared/decoders/{decodeJPEGBaseline12Bit-js.js => decodeJPEGBaseline12Bit-js.ts} (66%) rename packages/dicom-image-loader/src/shared/decoders/{decodeJPEGBaseline12Bit-wasm-not-yet-working.js => decodeJPEGBaseline12Bit-wasm-not-yet-working.ts} (100%) rename packages/dicom-image-loader/src/shared/decoders/{decodeJPEGBaseline8Bit.js => decodeJPEGBaseline8Bit.ts} (88%) rename packages/dicom-image-loader/src/shared/decoders/{decodeJPEGLS.js => decodeJPEGLS.ts} (86%) rename packages/dicom-image-loader/src/shared/decoders/{decodeJPEGLossless.js => decodeJPEGLossless.ts} (72%) rename packages/dicom-image-loader/src/shared/decoders/{decodeLittleEndian.js => decodeLittleEndian.ts} (81%) rename packages/dicom-image-loader/src/shared/decoders/{decodeRLE.js => decodeRLE.ts} (90%) rename packages/dicom-image-loader/src/shared/{getMinMax.js => getMinMax.ts} (83%) rename packages/dicom-image-loader/src/shared/{getMinMax_test.js => getMinMax_test.ts} (100%) create mode 100644 packages/dicom-image-loader/src/shared/image-frame.ts rename packages/dicom-image-loader/src/shared/scaling/{scaleArray.js => scaleArray.ts} (84%) create mode 100644 packages/dicom-image-loader/src/shared/types/load-image-options.ts create mode 100644 packages/dicom-image-loader/src/shared/types/load-request-function.ts create mode 100644 packages/dicom-image-loader/src/shared/types/metadata-modules.ts rename packages/dicom-image-loader/src/{version.js => version.ts} (100%) rename packages/dicom-image-loader/src/webWorker/{decodeTask.js => decodeTask.ts} (71%) rename packages/dicom-image-loader/src/webWorker/{index.worker.js => index.worker.ts} (100%) rename packages/dicom-image-loader/src/webWorker/{webWorker.js => webWorker.ts} (72%) create mode 100644 packages/dicom-image-loader/src/webWorker/webworker-messages.ts create mode 100644 packages/tools/examples/referenceCursors/index.ts create mode 100644 packages/tools/src/eventDispatchers/shared/getMouseModifier.ts create mode 100644 packages/tools/src/tools/ReferenceCursors.ts diff --git a/common/reviews/api/core.api.md b/common/reviews/api/core.api.md index 673d2db45..9871fdd2c 100644 --- a/common/reviews/api/core.api.md +++ b/common/reviews/api/core.api.md @@ -545,6 +545,9 @@ type FlipDirection = { // @public (undocumented) function getClosestImageId(imageVolume: IImageVolume, worldPos: Point3, viewPlaneNormal: Point3, viewUp: Point3): string; +// @public (undocumented) +function getClosestStackImageIndexForPoint(point: Point3, viewport: IStackViewport): number | null; + // @public (undocumented) export function getEnabledElement(element: HTMLDivElement | undefined): IEnabledElement | undefined; @@ -608,6 +611,9 @@ function getVolumeActorCorners(volumeActor: any): Array; // @public (undocumented) function getVolumeViewportsContainingSameVolumes(targetViewport: IVolumeViewport, renderingEngineId?: string): Array; +// @public (undocumented) +function hasNaNValues(input: number[] | number): boolean; + // @public (undocumented) interface ICache { // (undocumented) @@ -1521,13 +1527,17 @@ declare namespace planar { export { linePlaneIntersection, planeEquation, - threePlaneIntersection + threePlaneIntersection, + planeDistanceToPoint } } // @public (undocumented) type Plane = [number, number, number, number]; +// @public (undocumented) +function planeDistanceToPoint(plane: Plane, point: Point3, signed?: boolean): number; + // @public (undocumented) function planeEquation(normal: Point3, point: Point3 | vec3): Plane; @@ -1965,9 +1975,11 @@ declare namespace utilities { getImageSliceDataForVolumeViewport, isImageActor, getViewportsWithImageURI, + getClosestStackImageIndexForPoint, calculateViewportsSpatialRegistration, spatialRegistrationMetadataProvider, - getViewportImageCornersInWorld + getViewportImageCornersInWorld, + hasNaNValues } } export { utilities } @@ -2020,8 +2032,8 @@ export class Viewport implements IViewport { _getEdges(bounds: Array): Array<[number[], number[]]>; // (undocumented) _getFocalPointForResetCamera(centeredFocalPoint: Point3, previousCamera: ICamera, { resetPan, resetToCenter }: { - resetPan: boolean; - resetToCenter: boolean; + resetPan?: boolean; + resetToCenter?: boolean; }): Point3; // (undocumented) getFrameOfReferenceUID: () => string; diff --git a/common/reviews/api/tools.api.md b/common/reviews/api/tools.api.md index d7969e1b3..e5069137c 100644 --- a/common/reviews/api/tools.api.md +++ b/common/reviews/api/tools.api.md @@ -503,8 +503,12 @@ export class BidirectionalTool extends AnnotationTool { hasMoved?: boolean; } | null; // (undocumented) + _getSignedAngle: (vector1: any, vector2: any) => number; + // (undocumented) _getTextLines: (data: any, targetId: any) => string[]; // (undocumented) + _handleDragModify: (evt: any) => void; + // (undocumented) handleSelectedCallback: (evt: EventTypes_2.MouseDownEventType, annotation: BidirectionalAnnotation, handle: ToolHandle, interactionType?: string) => void; // (undocumented) isDrawing: boolean; @@ -521,11 +525,9 @@ export class BidirectionalTool extends AnnotationTool { // (undocumented) _mouseDragModifyCallback: (evt: MouseDragEventType) => void; // (undocumented) - _mouseDragModifyHandle: (evt: any) => void; - // (undocumented) _mouseUpCallback: (evt: EventTypes_2.MouseUpEventType | EventTypes_2.MouseClickEventType) => void; // (undocumented) - _movingLongAxisWouldPutItThroughShortAxis: (proposedFirstLineSegment: any, secondLineSegment: any) => boolean; + _movingLongAxisWouldPutItThroughShortAxis: (firstLineSegment: any, secondLineSegment: any) => boolean; // (undocumented) preventHandleOutsideImage: boolean; // (undocumented) @@ -1279,7 +1281,7 @@ function drawArrow(svgDrawingHelper: SVGDrawingHelper, annotationUID: string, ar function drawCircle(svgDrawingHelper: SVGDrawingHelper, annotationUID: string, circleUID: string, center: Types_2.Point2, radius: number, options?: {}): void; // @public (undocumented) -function drawEllipse(svgDrawingHelper: SVGDrawingHelper, annotationUID: string, ellipseUID: string, corner1: Types_2.Point2, corner2: Types_2.Point2, options?: {}): void; +function drawEllipse(svgDrawingHelper: SVGDrawingHelper, annotationUID: string, ellipseUID: string, corner1: Types_2.Point2, corner2: Types_2.Point2, options?: {}, dataId?: string): void; // @public (undocumented) function drawHandles(svgDrawingHelper: SVGDrawingHelper, annotationUID: string, handleGroupUID: string, handlePoints: Array, options?: {}): void; @@ -2606,9 +2608,23 @@ enum KeyboardBindings { // (undocumented) Alt = 18, // (undocumented) + AltMeta = 1891, + // (undocumented) Ctrl = 17, // (undocumented) - Shift = 16 + CtrlAlt = 1718, + // (undocumented) + CtrlMeta = 1791, + // (undocumented) + Meta = 91, + // (undocumented) + Shift = 16, + // (undocumented) + ShiftAlt = 1618, + // (undocumented) + ShiftCtrl = 1617, + // (undocumented) + ShiftMeta = 1691 } // @public (undocumented) @@ -3591,6 +3607,63 @@ export class RectangleScissorsTool extends BaseTool { static toolName: any; } +// @public (undocumented) +interface ReferenceCursor extends Annotation { + // (undocumented) + data: { + handles: { + points: [Types_2.Point3]; + }; + }; +} + +// @public (undocumented) +export class ReferenceCursors extends AnnotationDisplayTool { + constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps); + // (undocumented) + _addAnnotation(element: HTMLDivElement, annotation: Annotation): string | null; + // (undocumented) + createInitialAnnotation: (worldPos: Types_2.Point3, element: HTMLDivElement) => void; + // (undocumented) + _currentCanvasPosition: null | Types_2.Point2; + // (undocumented) + _currentCursorWorldPosition: null | Types_2.Point3; + // (undocumented) + _disableCursorEnabled: boolean; + // (undocumented) + _elementWithCursor: null | HTMLDivElement; + // (undocumented) + filterInteractableAnnotationsForElement(element: HTMLDivElement, annotations: Annotations): Annotations; + // (undocumented) + getActiveAnnotation(element: HTMLDivElement): null | Annotation; + // (undocumented) + isDrawing: boolean; + // (undocumented) + isHandleOutsideImage: boolean; + // (undocumented) + mouseDragCallback: any; + // (undocumented) + mouseMoveCallback: (evt: EventTypes_2.MouseMoveEventType) => boolean; + // (undocumented) + onCameraModified: (evt: any) => void; + // (undocumented) + onSetToolActive(): void; + // (undocumented) + onSetToolDisabled(): void; + // (undocumented) + renderAnnotation: (enabledElement: Types_2.IEnabledElement, svgDrawingHelper: SVGDrawingHelper) => boolean; + // (undocumented) + _throttledCalculateCachedStats: any; + // (undocumented) + static toolName: any; + // (undocumented) + touchDragCallback: any; + // (undocumented) + updateAnnotationPosition(element: HTMLDivElement, annotation: Annotation): void; + // (undocumented) + updateViewportImage(viewport: Types_2.IStackViewport | Types_2.IVolumeViewport): void; +} + // @public (undocumented) interface ReferenceLineAnnotation extends Annotation { // (undocumented) @@ -4336,6 +4409,7 @@ declare namespace ToolSpecificAnnotationTypes { PlanarFreehandROIAnnotation, ArrowAnnotation, AngleAnnotation, + ReferenceCursor, ReferenceLineAnnotation } } diff --git a/package.json b/package.json index 0661e020a..064dbc859 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,10 @@ "yarn": ">=1.19.1" }, "scripts": { - "api-check": "lerna run --concurrency 1 api-check ", + "api-check": "lerna run api-check ", "build": "lerna run build --stream", "build:umd": "lerna run build:umd --stream", - "build:update-api": "lerna run --concurrency 1 build:update-api", + "build:update-api": "lerna run build:update-api", "example": "node ./utils/ExampleRunner/example-runner-cli.js", "all-examples": "node ./utils/ExampleRunner/build-all-examples-cli.js --fromRoot", "build-all-examples": "node ./utils/ExampleRunner/build-all-examples-cli.js --build --fromRoot", diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 933bfb1fe..7ec7c039e 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -3,824 +3,479 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -## [0.21.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.21.3...@cornerstonejs/core@0.21.4) (2022-11-21) - +## [0.22.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.22.2...@cornerstonejs/core@0.22.3) (2022-12-01) ### Bug Fixes -* annotation rendering engine on viewport removal ([#303](https://github.com/cornerstonejs/cornerstone3D-beta/issues/303)) ([aeb205e](https://github.com/cornerstonejs/cornerstone3D-beta/commit/aeb205e56e0d2068258c278863aa3d7447331a43)) - - +- **volumeViewport:** Add optional scaling as the volume can be undefined ([#323](https://github.com/cornerstonejs/cornerstone3D-beta/issues/323)) ([a58a831](https://github.com/cornerstonejs/cornerstone3D-beta/commit/a58a831f4c5ab4c9ea9d7d258a59cbdcb5c837e4)) +## [0.22.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.22.1...@cornerstonejs/core@0.22.2) (2022-12-01) +### Bug Fixes -## [0.21.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.21.2...@cornerstonejs/core@0.21.3) (2022-11-19) +- bidirectional tool when short and long axis changes ([#309](https://github.com/cornerstonejs/cornerstone3D-beta/issues/309)) ([f973e72](https://github.com/cornerstonejs/cornerstone3D-beta/commit/f973e7262897a2daf4f37363d3e818ae88620bb8)) +## [0.22.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.22.0...@cornerstonejs/core@0.22.1) (2022-12-01) ### Bug Fixes -* don't reset display pipeline when spacing is missing ([#301](https://github.com/cornerstonejs/cornerstone3D-beta/issues/301)) ([e12fcf3](https://github.com/cornerstonejs/cornerstone3D-beta/commit/e12fcf3c361db0f927fd5fdd448686fef8893b36)) - - +- coronal view should not be flipped ([#321](https://github.com/cornerstonejs/cornerstone3D-beta/issues/321)) ([a85a867](https://github.com/cornerstonejs/cornerstone3D-beta/commit/a85a86785de9f225154829a4934926143c86eb5e)) +# [0.22.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.21.5...@cornerstonejs/core@0.22.0) (2022-11-23) +### Features -## [0.21.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.21.1...@cornerstonejs/core@0.21.2) (2022-11-18) +- add referenceCursors tool ([#275](https://github.com/cornerstonejs/cornerstone3D-beta/issues/275)) ([3303246](https://github.com/cornerstonejs/cornerstone3D-beta/commit/3303246836c81efb51e5d5e70c1a8801fbcb019a)) +## [0.21.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.21.4...@cornerstonejs/core@0.21.5) (2022-11-23) ### Bug Fixes -* **worldToImage:** Not throw out of bounds in worldToImage ([#302](https://github.com/cornerstonejs/cornerstone3D-beta/issues/302)) ([ffb20f7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ffb20f715c768b8f590b103cd18acc2bc2068adf)) +- stack viewport flip scroll ([#304](https://github.com/cornerstonejs/cornerstone3D-beta/issues/304)) ([5605a39](https://github.com/cornerstonejs/cornerstone3D-beta/commit/5605a39b17749f4f1d0bf6f3ee6f5ee9be492be8)) + +## [0.21.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.21.3...@cornerstonejs/core@0.21.4) (2022-11-21) +### Bug Fixes +- annotation rendering engine on viewport removal ([#303](https://github.com/cornerstonejs/cornerstone3D-beta/issues/303)) ([aeb205e](https://github.com/cornerstonejs/cornerstone3D-beta/commit/aeb205e56e0d2068258c278863aa3d7447331a43)) +## [0.21.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.21.2...@cornerstonejs/core@0.21.3) (2022-11-19) +### Bug Fixes -## [0.21.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.21.0...@cornerstonejs/core@0.21.1) (2022-11-17) +- don't reset display pipeline when spacing is missing ([#301](https://github.com/cornerstonejs/cornerstone3D-beta/issues/301)) ([e12fcf3](https://github.com/cornerstonejs/cornerstone3D-beta/commit/e12fcf3c361db0f927fd5fdd448686fef8893b36)) +## [0.21.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.21.1...@cornerstonejs/core@0.21.2) (2022-11-18) ### Bug Fixes -* adjust canvas, not only off screen renderer on resize ([#279](https://github.com/cornerstonejs/cornerstone3D-beta/issues/279)) ([1959ac7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/1959ac7866305510855753f054678eac95e9c015)) - +- **worldToImage:** Not throw out of bounds in worldToImage ([#302](https://github.com/cornerstonejs/cornerstone3D-beta/issues/302)) ([ffb20f7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ffb20f715c768b8f590b103cd18acc2bc2068adf)) +## [0.21.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.21.0...@cornerstonejs/core@0.21.1) (2022-11-17) +### Bug Fixes +- adjust canvas, not only off screen renderer on resize ([#279](https://github.com/cornerstonejs/cornerstone3D-beta/issues/279)) ([1959ac7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/1959ac7866305510855753f054678eac95e9c015)) # [0.21.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.20.0...@cornerstonejs/core@0.21.0) (2022-11-11) - ### Features -* add reference lines tool ([#292](https://github.com/cornerstonejs/cornerstone3D-beta/issues/292)) ([c56df91](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c56df91a64ec005656f940dd3728f476152fa917)) - - - - +- add reference lines tool ([#292](https://github.com/cornerstonejs/cornerstone3D-beta/issues/292)) ([c56df91](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c56df91a64ec005656f940dd3728f476152fa917)) # [0.20.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.19.2...@cornerstonejs/core@0.20.0) (2022-11-11) - ### Features -* Add segmentSpecificConfiguration and add outlineOpacity config for Segmentation ([#285](https://github.com/cornerstonejs/cornerstone3D-beta/issues/285)) ([92fb495](https://github.com/cornerstonejs/cornerstone3D-beta/commit/92fb49594cfc3219f761e905ba765acaddbe1e1a)) -* add stack synchronization within or across studies ([#291](https://github.com/cornerstonejs/cornerstone3D-beta/issues/291)) ([f38bec0](https://github.com/cornerstonejs/cornerstone3D-beta/commit/f38bec06713265cee361fc905539aa5ed841e707)) - - - - +- Add segmentSpecificConfiguration and add outlineOpacity config for Segmentation ([#285](https://github.com/cornerstonejs/cornerstone3D-beta/issues/285)) ([92fb495](https://github.com/cornerstonejs/cornerstone3D-beta/commit/92fb49594cfc3219f761e905ba765acaddbe1e1a)) +- add stack synchronization within or across studies ([#291](https://github.com/cornerstonejs/cornerstone3D-beta/issues/291)) ([f38bec0](https://github.com/cornerstonejs/cornerstone3D-beta/commit/f38bec06713265cee361fc905539aa5ed841e707)) ## [0.19.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.19.1...@cornerstonejs/core@0.19.2) (2022-11-09) **Note:** Version bump only for package @cornerstonejs/core - - - - ## [0.19.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.19.0...@cornerstonejs/core@0.19.1) (2022-11-04) - ### Bug Fixes -* volume scaling should be returned in getImageData ([#282](https://github.com/cornerstonejs/cornerstone3D-beta/issues/282)) ([4df3f71](https://github.com/cornerstonejs/cornerstone3D-beta/commit/4df3f7110de1a12dbeb0fea1260e4bb9e85320fa)) - - - - +- volume scaling should be returned in getImageData ([#282](https://github.com/cornerstonejs/cornerstone3D-beta/issues/282)) ([4df3f71](https://github.com/cornerstonejs/cornerstone3D-beta/commit/4df3f7110de1a12dbeb0fea1260e4bb9e85320fa)) # [0.19.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.18.1...@cornerstonejs/core@0.19.0) (2022-11-04) - ### Features -* rendering engine should not reset camera on resize ([#273](https://github.com/cornerstonejs/cornerstone3D-beta/issues/273)) ([f1fe501](https://github.com/cornerstonejs/cornerstone3D-beta/commit/f1fe5015eaac736d1a16670e53849ab3d19baddf)) - - - - +- rendering engine should not reset camera on resize ([#273](https://github.com/cornerstonejs/cornerstone3D-beta/issues/273)) ([f1fe501](https://github.com/cornerstonejs/cornerstone3D-beta/commit/f1fe5015eaac736d1a16670e53849ab3d19baddf)) ## [0.18.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.18.0...@cornerstonejs/core@0.18.1) (2022-11-04) - ### Bug Fixes -* resetCamera and annotations for flipped viewports ([#278](https://github.com/cornerstonejs/cornerstone3D-beta/issues/278)) ([cabefce](https://github.com/cornerstonejs/cornerstone3D-beta/commit/cabefcefcba463abb1ea9bf346a2f755b2494aed)) - - - - +- resetCamera and annotations for flipped viewports ([#278](https://github.com/cornerstonejs/cornerstone3D-beta/issues/278)) ([cabefce](https://github.com/cornerstonejs/cornerstone3D-beta/commit/cabefcefcba463abb1ea9bf346a2f755b2494aed)) # [0.18.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.17.0...@cornerstonejs/core@0.18.0) (2022-11-01) - ### Features -* flip viewports via camera api instead of actor ([#271](https://github.com/cornerstonejs/cornerstone3D-beta/issues/271)) ([7c99f76](https://github.com/cornerstonejs/cornerstone3D-beta/commit/7c99f76fe10f9dac2f2221f9cdc134c90ebbe115)) - - - - +- flip viewports via camera api instead of actor ([#271](https://github.com/cornerstonejs/cornerstone3D-beta/issues/271)) ([7c99f76](https://github.com/cornerstonejs/cornerstone3D-beta/commit/7c99f76fe10f9dac2f2221f9cdc134c90ebbe115)) # [0.17.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.12...@cornerstonejs/core@0.17.0) (2022-10-31) - ### Features -* reset to center option for reset camera ([#269](https://github.com/cornerstonejs/cornerstone3D-beta/issues/269)) ([9539f6c](https://github.com/cornerstonejs/cornerstone3D-beta/commit/9539f6c56e2bd3b06f4c6b40fd6b4478d806bee3)) - - - - +- reset to center option for reset camera ([#269](https://github.com/cornerstonejs/cornerstone3D-beta/issues/269)) ([9539f6c](https://github.com/cornerstonejs/cornerstone3D-beta/commit/9539f6c56e2bd3b06f4c6b40fd6b4478d806bee3)) ## [0.16.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.11...@cornerstonejs/core@0.16.12) (2022-10-28) - ### Bug Fixes -* viewRight was calculated wrong for tools ([#255](https://github.com/cornerstonejs/cornerstone3D-beta/issues/255)) ([cf536df](https://github.com/cornerstonejs/cornerstone3D-beta/commit/cf536df66c05b4c4385ad18ad814d1dac1c8ad77)) - - - - +- viewRight was calculated wrong for tools ([#255](https://github.com/cornerstonejs/cornerstone3D-beta/issues/255)) ([cf536df](https://github.com/cornerstonejs/cornerstone3D-beta/commit/cf536df66c05b4c4385ad18ad814d1dac1c8ad77)) ## [0.16.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.10...@cornerstonejs/core@0.16.11) (2022-10-27) - ### Bug Fixes -* volume viewport getCurrentImageId ([#265](https://github.com/cornerstonejs/cornerstone3D-beta/issues/265)) ([30e4a5d](https://github.com/cornerstonejs/cornerstone3D-beta/commit/30e4a5d812a9d800887dfdc940a73149e5687ab8)) - - - - +- volume viewport getCurrentImageId ([#265](https://github.com/cornerstonejs/cornerstone3D-beta/issues/265)) ([30e4a5d](https://github.com/cornerstonejs/cornerstone3D-beta/commit/30e4a5d812a9d800887dfdc940a73149e5687ab8)) ## [0.16.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.9...@cornerstonejs/core@0.16.10) (2022-10-25) **Note:** Version bump only for package @cornerstonejs/core - - - - ## [0.16.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.8...@cornerstonejs/core@0.16.9) (2022-10-25) - ### Bug Fixes -* fixes the memory leak for volumes ([#253](https://github.com/cornerstonejs/cornerstone3D-beta/issues/253)) ([c863126](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c863126fc1df3fa989e15da1a7eae43cf94b24d0)) - - - - +- fixes the memory leak for volumes ([#253](https://github.com/cornerstonejs/cornerstone3D-beta/issues/253)) ([c863126](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c863126fc1df3fa989e15da1a7eae43cf94b24d0)) ## [0.16.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.7...@cornerstonejs/core@0.16.8) (2022-10-07) **Note:** Version bump only for package @cornerstonejs/core - - - - ## [0.16.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.6...@cornerstonejs/core@0.16.7) (2022-10-06) **Note:** Version bump only for package @cornerstonejs/core - - - - ## [0.16.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.5...@cornerstonejs/core@0.16.6) (2022-10-06) **Note:** Version bump only for package @cornerstonejs/core - - - - ## [0.16.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.4...@cornerstonejs/core@0.16.5) (2022-10-05) - ### Bug Fixes -* resetCamera should reset the rotation as well ([#236](https://github.com/cornerstonejs/cornerstone3D-beta/issues/236)) ([a347c93](https://github.com/cornerstonejs/cornerstone3D-beta/commit/a347c9338252fb3843737b605d610f2d51b2c547)) - - - - +- resetCamera should reset the rotation as well ([#236](https://github.com/cornerstonejs/cornerstone3D-beta/issues/236)) ([a347c93](https://github.com/cornerstonejs/cornerstone3D-beta/commit/a347c9338252fb3843737b605d610f2d51b2c547)) ## [0.16.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.3...@cornerstonejs/core@0.16.4) (2022-10-05) - ### Bug Fixes -* Add storeAsInitialCamera parameter to StackViewport.setCamera ([#228](https://github.com/cornerstonejs/cornerstone3D-beta/issues/228)) ([b951acc](https://github.com/cornerstonejs/cornerstone3D-beta/commit/b951acc2c893837d13ec78850e18b7d26dd32076)) - - - - +- Add storeAsInitialCamera parameter to StackViewport.setCamera ([#228](https://github.com/cornerstonejs/cornerstone3D-beta/issues/228)) ([b951acc](https://github.com/cornerstonejs/cornerstone3D-beta/commit/b951acc2c893837d13ec78850e18b7d26dd32076)) ## [0.16.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.2...@cornerstonejs/core@0.16.3) (2022-09-16) - ### Bug Fixes -* **rgba:** Handle rgba to rgb conversion based on length ([#220](https://github.com/cornerstonejs/cornerstone3D-beta/issues/220)) ([d56dd8a](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d56dd8a7b23579f2a87cd3487b6b73b40a89648b)) - - - - +- **rgba:** Handle rgba to rgb conversion based on length ([#220](https://github.com/cornerstonejs/cornerstone3D-beta/issues/220)) ([d56dd8a](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d56dd8a7b23579f2a87cd3487b6b73b40a89648b)) ## [0.16.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.1...@cornerstonejs/core@0.16.2) (2022-09-14) - ### Bug Fixes -* annotation hidden on horizontal and vertical ([#205](https://github.com/cornerstonejs/cornerstone3D-beta/issues/205)) ([9e825fd](https://github.com/cornerstonejs/cornerstone3D-beta/commit/9e825fd3d37ecfdf1722da9cd2fd6a1a75995459)) - - - - +- annotation hidden on horizontal and vertical ([#205](https://github.com/cornerstonejs/cornerstone3D-beta/issues/205)) ([9e825fd](https://github.com/cornerstonejs/cornerstone3D-beta/commit/9e825fd3d37ecfdf1722da9cd2fd6a1a75995459)) ## [0.16.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.16.0...@cornerstonejs/core@0.16.1) (2022-09-08) - ### Bug Fixes -* drag probe appearing unnecessarily on all viewports ([#204](https://github.com/cornerstonejs/cornerstone3D-beta/issues/204)) ([c292c05](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c292c05eecf17a6edbdcab5aa5a604304ef3d2e5)) - - - - +- drag probe appearing unnecessarily on all viewports ([#204](https://github.com/cornerstonejs/cornerstone3D-beta/issues/204)) ([c292c05](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c292c05eecf17a6edbdcab5aa5a604304ef3d2e5)) # [0.16.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.15.3...@cornerstonejs/core@0.16.0) (2022-09-08) - ### Features -* orientation on volumeViewport can be optional ([#203](https://github.com/cornerstonejs/cornerstone3D-beta/issues/203)) ([749dcb5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/749dcb59414c1aff2dffdca582fb3df0e4ca5ed7)) - - - - +- orientation on volumeViewport can be optional ([#203](https://github.com/cornerstonejs/cornerstone3D-beta/issues/203)) ([749dcb5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/749dcb59414c1aff2dffdca582fb3df0e4ca5ed7)) ## [0.15.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.15.2...@cornerstonejs/core@0.15.3) (2022-09-02) - ### Bug Fixes -* annotations throwing error when stack and volume viewports are converted ([#195](https://github.com/cornerstonejs/cornerstone3D-beta/issues/195)) ([ed23f05](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ed23f05b23063769942328f9e6797d792767ec49)) - - - - +- annotations throwing error when stack and volume viewports are converted ([#195](https://github.com/cornerstonejs/cornerstone3D-beta/issues/195)) ([ed23f05](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ed23f05b23063769942328f9e6797d792767ec49)) ## [0.15.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.15.1...@cornerstonejs/core@0.15.2) (2022-08-26) - ### Bug Fixes -* revert the stack viewport setting of targetImageIndex ([#192](https://github.com/cornerstonejs/cornerstone3D-beta/issues/192)) ([0cf057e](https://github.com/cornerstonejs/cornerstone3D-beta/commit/0cf057ee45a7b154ecd5ac067c719ac52403f382)) - - - - +- revert the stack viewport setting of targetImageIndex ([#192](https://github.com/cornerstonejs/cornerstone3D-beta/issues/192)) ([0cf057e](https://github.com/cornerstonejs/cornerstone3D-beta/commit/0cf057ee45a7b154ecd5ac067c719ac52403f382)) ## [0.15.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.15.0...@cornerstonejs/core@0.15.1) (2022-08-26) - ### Bug Fixes -* shadow for annotations and stack viewport targetImageIdIndex bug ([#189](https://github.com/cornerstonejs/cornerstone3D-beta/issues/189)) ([be70be7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/be70be70a543fffb18f7d05c69e16d5c0255a57e)) - - - - +- shadow for annotations and stack viewport targetImageIdIndex bug ([#189](https://github.com/cornerstonejs/cornerstone3D-beta/issues/189)) ([be70be7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/be70be70a543fffb18f7d05c69e16d5c0255a57e)) # [0.15.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.14.7...@cornerstonejs/core@0.15.0) (2022-08-23) - ### Features -* camera sync canvas relative ([#167](https://github.com/cornerstonejs/cornerstone3D-beta/issues/167)) ([2fd6c98](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2fd6c9830eb6e9da10960de0c25702b06716382a)) - - - - +- camera sync canvas relative ([#167](https://github.com/cornerstonejs/cornerstone3D-beta/issues/167)) ([2fd6c98](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2fd6c9830eb6e9da10960de0c25702b06716382a)) ## [0.14.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.14.6...@cornerstonejs/core@0.14.7) (2022-08-23) **Note:** Version bump only for package @cornerstonejs/core - - - - ## [0.14.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.14.5...@cornerstonejs/core@0.14.6) (2022-08-19) - ### Bug Fixes -* **demoData:** The URL was pointing to a private AWS account ([#175](https://github.com/cornerstonejs/cornerstone3D-beta/issues/175)) ([69dafea](https://github.com/cornerstonejs/cornerstone3D-beta/commit/69dafea902dcd224ea5d1d6d418d5e0c1cec2fe0)) - - - - +- **demoData:** The URL was pointing to a private AWS account ([#175](https://github.com/cornerstonejs/cornerstone3D-beta/issues/175)) ([69dafea](https://github.com/cornerstonejs/cornerstone3D-beta/commit/69dafea902dcd224ea5d1d6d418d5e0c1cec2fe0)) ## [0.14.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.14.4...@cornerstonejs/core@0.14.5) (2022-08-18) - ### Bug Fixes -* add extra missing exports and no static code block at build ([#179](https://github.com/cornerstonejs/cornerstone3D-beta/issues/179)) ([dfdc4bf](https://github.com/cornerstonejs/cornerstone3D-beta/commit/dfdc4bfbf331da40368a4976f3dc199bd355864a)) - - - - +- add extra missing exports and no static code block at build ([#179](https://github.com/cornerstonejs/cornerstone3D-beta/issues/179)) ([dfdc4bf](https://github.com/cornerstonejs/cornerstone3D-beta/commit/dfdc4bfbf331da40368a4976f3dc199bd355864a)) ## [0.14.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.14.3...@cornerstonejs/core@0.14.4) (2022-08-15) - ### Bug Fixes -* default voi for volumes and webLoader ([#171](https://github.com/cornerstonejs/cornerstone3D-beta/issues/171)) ([81f07a6](https://github.com/cornerstonejs/cornerstone3D-beta/commit/81f07a6f9d2a27d9cd6bb78c7ee65d6ac4456724)) - - - - +- default voi for volumes and webLoader ([#171](https://github.com/cornerstonejs/cornerstone3D-beta/issues/171)) ([81f07a6](https://github.com/cornerstonejs/cornerstone3D-beta/commit/81f07a6f9d2a27d9cd6bb78c7ee65d6ac4456724)) ## [0.14.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.14.2...@cornerstonejs/core@0.14.3) (2022-08-04) - ### Bug Fixes -* make typescript strict true ([#162](https://github.com/cornerstonejs/cornerstone3D-beta/issues/162)) ([7c311f7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/7c311f77f0532372ae82b6be2027bcd25925fa0d)) - - - - +- make typescript strict true ([#162](https://github.com/cornerstonejs/cornerstone3D-beta/issues/162)) ([7c311f7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/7c311f77f0532372ae82b6be2027bcd25925fa0d)) ## [0.14.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.14.1...@cornerstonejs/core@0.14.2) (2022-08-03) - ### Bug Fixes -* wadouri metadata was not using scaling parameters properly ([#159](https://github.com/cornerstonejs/cornerstone3D-beta/issues/159)) ([d21aba5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d21aba56f1e0a8730088d89a4dfde8358d978a60)) - - - - +- wadouri metadata was not using scaling parameters properly ([#159](https://github.com/cornerstonejs/cornerstone3D-beta/issues/159)) ([d21aba5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d21aba56f1e0a8730088d89a4dfde8358d978a60)) ## [0.14.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.14.0...@cornerstonejs/core@0.14.1) (2022-08-03) - ### Bug Fixes -* Attempt to fix build issues [@haehn](https://github.com/haehn) has reported ([#144](https://github.com/cornerstonejs/cornerstone3D-beta/issues/144)) ([2a7ec92](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2a7ec9271e012929682aa5c0a860cd65d0d5c02d)) - - - - +- Attempt to fix build issues [@haehn](https://github.com/haehn) has reported ([#144](https://github.com/cornerstonejs/cornerstone3D-beta/issues/144)) ([2a7ec92](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2a7ec9271e012929682aa5c0a860cd65d0d5c02d)) # [0.14.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.11...@cornerstonejs/core@0.14.0) (2022-07-29) - ### Features -* volume viewport api with setProperties ([#154](https://github.com/cornerstonejs/cornerstone3D-beta/issues/154)) ([fab3abe](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fab3abe907ddde1ee61bc121c40d4fc23d2dbfd7)) - - - - +- volume viewport api with setProperties ([#154](https://github.com/cornerstonejs/cornerstone3D-beta/issues/154)) ([fab3abe](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fab3abe907ddde1ee61bc121c40d4fc23d2dbfd7)) ## [0.13.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.10...@cornerstonejs/core@0.13.11) (2022-07-27) - ### Bug Fixes -* convert RGBA to RGB for GPU rendering if cached ([#152](https://github.com/cornerstonejs/cornerstone3D-beta/issues/152)) ([fb8aa36](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fb8aa36374c4bdf06d9d6da1f2df128c68dbc7da)) - - - - +- convert RGBA to RGB for GPU rendering if cached ([#152](https://github.com/cornerstonejs/cornerstone3D-beta/issues/152)) ([fb8aa36](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fb8aa36374c4bdf06d9d6da1f2df128c68dbc7da)) ## [0.13.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.9...@cornerstonejs/core@0.13.10) (2022-07-25) - ### Bug Fixes -* annotation unit hydration bug and more color image support ([#151](https://github.com/cornerstonejs/cornerstone3D-beta/issues/151)) ([4f157dc](https://github.com/cornerstonejs/cornerstone3D-beta/commit/4f157dc5d7a8d0d80abb5b68c35ed17cb5f349ed)) - - - - +- annotation unit hydration bug and more color image support ([#151](https://github.com/cornerstonejs/cornerstone3D-beta/issues/151)) ([4f157dc](https://github.com/cornerstonejs/cornerstone3D-beta/commit/4f157dc5d7a8d0d80abb5b68c35ed17cb5f349ed)) ## [0.13.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.8...@cornerstonejs/core@0.13.9) (2022-06-24) - ### Bug Fixes -* Handle cases where row and column cosines are missing ([#139](https://github.com/cornerstonejs/cornerstone3D-beta/issues/139)) ([5bd0a70](https://github.com/cornerstonejs/cornerstone3D-beta/commit/5bd0a7062adf7efd4654b20b6f4c8daed236a2db)) - - - - +- Handle cases where row and column cosines are missing ([#139](https://github.com/cornerstonejs/cornerstone3D-beta/issues/139)) ([5bd0a70](https://github.com/cornerstonejs/cornerstone3D-beta/commit/5bd0a7062adf7efd4654b20b6f4c8daed236a2db)) ## [0.13.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.7...@cornerstonejs/core@0.13.8) (2022-06-24) - ### Bug Fixes -* Pixel data array was the wrong length for color images ([#138](https://github.com/cornerstonejs/cornerstone3D-beta/issues/138)) ([e42419d](https://github.com/cornerstonejs/cornerstone3D-beta/commit/e42419d0f7be45ff0ba87cb51502017b53687171)) - - - - +- Pixel data array was the wrong length for color images ([#138](https://github.com/cornerstonejs/cornerstone3D-beta/issues/138)) ([e42419d](https://github.com/cornerstonejs/cornerstone3D-beta/commit/e42419d0f7be45ff0ba87cb51502017b53687171)) ## [0.13.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.6...@cornerstonejs/core@0.13.7) (2022-06-20) - ### Bug Fixes -* Use maximum clipping range for StackViewport ([#136](https://github.com/cornerstonejs/cornerstone3D-beta/issues/136)) ([016eff6](https://github.com/cornerstonejs/cornerstone3D-beta/commit/016eff66a02e4b120fb8ed06f90faaa3b29a8024)) - - - - +- Use maximum clipping range for StackViewport ([#136](https://github.com/cornerstonejs/cornerstone3D-beta/issues/136)) ([016eff6](https://github.com/cornerstonejs/cornerstone3D-beta/commit/016eff66a02e4b120fb8ed06f90faaa3b29a8024)) ## [0.13.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.5...@cornerstonejs/core@0.13.6) (2022-06-20) - ### Bug Fixes -* Cleanup magnify canvas on mouse up ([#135](https://github.com/cornerstonejs/cornerstone3D-beta/issues/135)) ([6fd0c3f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/6fd0c3fe114586f9e7ac0ab1f448b6c5199d1f7a)) - - - - +- Cleanup magnify canvas on mouse up ([#135](https://github.com/cornerstonejs/cornerstone3D-beta/issues/135)) ([6fd0c3f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/6fd0c3fe114586f9e7ac0ab1f448b6c5199d1f7a)) ## [0.13.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.4...@cornerstonejs/core@0.13.5) (2022-06-20) - ### Bug Fixes -* Resizing off-screen canvas was broken due to devicePixelRatio ([#134](https://github.com/cornerstonejs/cornerstone3D-beta/issues/134)) ([7b8ac34](https://github.com/cornerstonejs/cornerstone3D-beta/commit/7b8ac340f4708d8b0d99951d2fa4e2c996514968)) - - - - +- Resizing off-screen canvas was broken due to devicePixelRatio ([#134](https://github.com/cornerstonejs/cornerstone3D-beta/issues/134)) ([7b8ac34](https://github.com/cornerstonejs/cornerstone3D-beta/commit/7b8ac340f4708d8b0d99951d2fa4e2c996514968)) ## [0.13.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.3...@cornerstonejs/core@0.13.4) (2022-06-20) - ### Bug Fixes -* Fix event for camera modified firing with wrong values ([#133](https://github.com/cornerstonejs/cornerstone3D-beta/issues/133)) ([f16f994](https://github.com/cornerstonejs/cornerstone3D-beta/commit/f16f9947902a104568cb4a7be75c0d19dd4a0715)) - - - - +- Fix event for camera modified firing with wrong values ([#133](https://github.com/cornerstonejs/cornerstone3D-beta/issues/133)) ([f16f994](https://github.com/cornerstonejs/cornerstone3D-beta/commit/f16f9947902a104568cb4a7be75c0d19dd4a0715)) ## [0.13.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.2...@cornerstonejs/core@0.13.3) (2022-06-20) - ### Bug Fixes -* Address issues with CPU Flip ([#132](https://github.com/cornerstonejs/cornerstone3D-beta/issues/132)) ([62b2843](https://github.com/cornerstonejs/cornerstone3D-beta/commit/62b28430cb00fc90e212f1c9f3cb7f748dbadb84)) - - - - +- Address issues with CPU Flip ([#132](https://github.com/cornerstonejs/cornerstone3D-beta/issues/132)) ([62b2843](https://github.com/cornerstonejs/cornerstone3D-beta/commit/62b28430cb00fc90e212f1c9f3cb7f748dbadb84)) ## [0.13.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.1...@cornerstonejs/core@0.13.2) (2022-06-17) - ### Bug Fixes -* Fix resize behaviour after devicePixelRatio changes ([#131](https://github.com/cornerstonejs/cornerstone3D-beta/issues/131)) ([2e9d686](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2e9d686d83e4a529cd71f1b4d0ea19e1137cee3a)) - - - - +- Fix resize behaviour after devicePixelRatio changes ([#131](https://github.com/cornerstonejs/cornerstone3D-beta/issues/131)) ([2e9d686](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2e9d686d83e4a529cd71f1b4d0ea19e1137cee3a)) ## [0.13.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.13.0...@cornerstonejs/core@0.13.1) (2022-06-17) - ### Bug Fixes -* large image rendering, missing metadata for StackViewport, high DPI devices ([#127](https://github.com/cornerstonejs/cornerstone3D-beta/issues/127)) ([d4bf1c8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d4bf1c80391bcecaee64d9eb086416c42aa406e2)) - - - - +- large image rendering, missing metadata for StackViewport, high DPI devices ([#127](https://github.com/cornerstonejs/cornerstone3D-beta/issues/127)) ([d4bf1c8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d4bf1c80391bcecaee64d9eb086416c42aa406e2)) # [0.13.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.12.1...@cornerstonejs/core@0.13.0) (2022-06-14) - ### Features -* remove unnecessary event firing for annotations ([#123](https://github.com/cornerstonejs/cornerstone3D-beta/issues/123)) ([03551d9](https://github.com/cornerstonejs/cornerstone3D-beta/commit/03551d9f9269b7bfd3d828dad4f8f38ef51703d1)) - - - - +- remove unnecessary event firing for annotations ([#123](https://github.com/cornerstonejs/cornerstone3D-beta/issues/123)) ([03551d9](https://github.com/cornerstonejs/cornerstone3D-beta/commit/03551d9f9269b7bfd3d828dad4f8f38ef51703d1)) ## [0.12.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.12.0...@cornerstonejs/core@0.12.1) (2022-06-10) - ### Bug Fixes -* resetPan option in resetCamera was ignored for PolyData ([#125](https://github.com/cornerstonejs/cornerstone3D-beta/issues/125)) ([5f4f36d](https://github.com/cornerstonejs/cornerstone3D-beta/commit/5f4f36df1e70f25b379fccef7c08b86f8c80f3dc)) - - - - +- resetPan option in resetCamera was ignored for PolyData ([#125](https://github.com/cornerstonejs/cornerstone3D-beta/issues/125)) ([5f4f36d](https://github.com/cornerstonejs/cornerstone3D-beta/commit/5f4f36df1e70f25b379fccef7c08b86f8c80f3dc)) # [0.12.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.11.1...@cornerstonejs/core@0.12.0) (2022-06-06) - ### Features -* improved stack prefetch and zoom to mouse ([#121](https://github.com/cornerstonejs/cornerstone3D-beta/issues/121)) ([bc72d37](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bc72d37b10f5a9e3e2bc9ed1254a707047f04f45)) - - - - +- improved stack prefetch and zoom to mouse ([#121](https://github.com/cornerstonejs/cornerstone3D-beta/issues/121)) ([bc72d37](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bc72d37b10f5a9e3e2bc9ed1254a707047f04f45)) ## [0.11.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.11.0...@cornerstonejs/core@0.11.1) (2022-06-01) - ### Bug Fixes -* toolGroup default cursor ([#120](https://github.com/cornerstonejs/cornerstone3D-beta/issues/120)) ([8c385c4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/8c385c4780cbaf40400fffc310fd1e3b86056767)) - - - - +- toolGroup default cursor ([#120](https://github.com/cornerstonejs/cornerstone3D-beta/issues/120)) ([8c385c4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/8c385c4780cbaf40400fffc310fd1e3b86056767)) # [0.11.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.10.3...@cornerstonejs/core@0.11.0) (2022-05-31) - ### Features -* improved threshold volume API and refactored boundingBox utils ([#117](https://github.com/cornerstonejs/cornerstone3D-beta/issues/117)) ([adc308b](https://github.com/cornerstonejs/cornerstone3D-beta/commit/adc308bef0509852bc48c96114eb3268c3d100b9)) - - - - +- improved threshold volume API and refactored boundingBox utils ([#117](https://github.com/cornerstonejs/cornerstone3D-beta/issues/117)) ([adc308b](https://github.com/cornerstonejs/cornerstone3D-beta/commit/adc308bef0509852bc48c96114eb3268c3d100b9)) ## [0.10.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.10.2...@cornerstonejs/core@0.10.3) (2022-05-27) - ### Bug Fixes -* scale factor for zoom in perspective mode and do not update clipping planes for non Volume Actors ([#116](https://github.com/cornerstonejs/cornerstone3D-beta/issues/116)) ([ce8c13e](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ce8c13e534a48392fc11dcb615d8d81275cd01d7)) - - - - +- scale factor for zoom in perspective mode and do not update clipping planes for non Volume Actors ([#116](https://github.com/cornerstonejs/cornerstone3D-beta/issues/116)) ([ce8c13e](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ce8c13e534a48392fc11dcb615d8d81275cd01d7)) ## [0.10.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.10.1...@cornerstonejs/core@0.10.2) (2022-05-27) - ### Bug Fixes -* remove the need for slabThickness in volumeAPI for tools ([#113](https://github.com/cornerstonejs/cornerstone3D-beta/issues/113)) ([a5e431d](https://github.com/cornerstonejs/cornerstone3D-beta/commit/a5e431dee952281be340994aa773a593a85fad04)) - - - - +- remove the need for slabThickness in volumeAPI for tools ([#113](https://github.com/cornerstonejs/cornerstone3D-beta/issues/113)) ([a5e431d](https://github.com/cornerstonejs/cornerstone3D-beta/commit/a5e431dee952281be340994aa773a593a85fad04)) ## [0.10.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.10.0...@cornerstonejs/core@0.10.1) (2022-05-27) **Note:** Version bump only for package @cornerstonejs/core - - - - # [0.10.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.9.0...@cornerstonejs/core@0.10.0) (2022-05-24) - ### Features -* Add VOLUME_NEW_IMAGE event and Add jumpToSlice and default VOI for volume viewport ([#104](https://github.com/cornerstonejs/cornerstone3D-beta/issues/104)) ([d36a23a](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d36a23a4eaf5bafcc8dddc0ab796065098df616a)) - - - - +- Add VOLUME_NEW_IMAGE event and Add jumpToSlice and default VOI for volume viewport ([#104](https://github.com/cornerstonejs/cornerstone3D-beta/issues/104)) ([d36a23a](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d36a23a4eaf5bafcc8dddc0ab796065098df616a)) # [0.9.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.8.1...@cornerstonejs/core@0.9.0) (2022-05-24) - ### Features -* Add Clipping planes for rendering ([#110](https://github.com/cornerstonejs/cornerstone3D-beta/issues/110)) ([1a6e4c7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/1a6e4c742a3b89a88b46fd98d6cbeca5c95918aa)) - - - - +- Add Clipping planes for rendering ([#110](https://github.com/cornerstonejs/cornerstone3D-beta/issues/110)) ([1a6e4c7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/1a6e4c742a3b89a88b46fd98d6cbeca5c95918aa)) ## [0.8.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.8.0...@cornerstonejs/core@0.8.1) (2022-05-11) - ### Bug Fixes -* Attempt to resolve incompatible peerDeps situation ([#98](https://github.com/cornerstonejs/cornerstone3D-beta/issues/98)) ([00f141b](https://github.com/cornerstonejs/cornerstone3D-beta/commit/00f141bfa9f9a4b37c016d726a6d31f2330e2e44)) - - - - +- Attempt to resolve incompatible peerDeps situation ([#98](https://github.com/cornerstonejs/cornerstone3D-beta/issues/98)) ([00f141b](https://github.com/cornerstonejs/cornerstone3D-beta/commit/00f141bfa9f9a4b37c016d726a6d31f2330e2e44)) # [0.8.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.7.0...@cornerstonejs/core@0.8.0) (2022-05-10) - ### Features -* Add AngleTool and MagnifyTool ([#97](https://github.com/cornerstonejs/cornerstone3D-beta/issues/97)) ([2c4c800](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2c4c800c4b3ba92164f728865b904933a2539210)) - - - - +- Add AngleTool and MagnifyTool ([#97](https://github.com/cornerstonejs/cornerstone3D-beta/issues/97)) ([2c4c800](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2c4c800c4b3ba92164f728865b904933a2539210)) # [0.7.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.6.4...@cornerstonejs/core@0.7.0) (2022-04-27) - ### Features -* Add worldToImage and imageToWorld utilities ([#85](https://github.com/cornerstonejs/cornerstone3D-beta/issues/85)) ([54e1b7f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/54e1b7f718f9d23b4c9f98ebc02c523100c1ddb0)) - - - - +- Add worldToImage and imageToWorld utilities ([#85](https://github.com/cornerstonejs/cornerstone3D-beta/issues/85)) ([54e1b7f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/54e1b7f718f9d23b4c9f98ebc02c523100c1ddb0)) ## [0.6.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.6.3...@cornerstonejs/core@0.6.4) (2022-04-22) - ### Bug Fixes -* Camera events for flip and rotation changes ([#83](https://github.com/cornerstonejs/cornerstone3D-beta/issues/83)) ([82115ec](https://github.com/cornerstonejs/cornerstone3D-beta/commit/82115ec00bd924fb942473d04052473408b84eb7)) - - - - +- Camera events for flip and rotation changes ([#83](https://github.com/cornerstonejs/cornerstone3D-beta/issues/83)) ([82115ec](https://github.com/cornerstonejs/cornerstone3D-beta/commit/82115ec00bd924fb942473d04052473408b84eb7)) ## [0.6.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.6.2...@cornerstonejs/core@0.6.3) (2022-04-21) - ### Bug Fixes -* selection API, requestPoolManager and VOI and Scaling ([#82](https://github.com/cornerstonejs/cornerstone3D-beta/issues/82)) ([bedd8dd](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bedd8ddfa356c2d52a6e72f74c7cb3bb660a86ef)) - - - - +- selection API, requestPoolManager and VOI and Scaling ([#82](https://github.com/cornerstonejs/cornerstone3D-beta/issues/82)) ([bedd8dd](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bedd8ddfa356c2d52a6e72f74c7cb3bb660a86ef)) ## [0.6.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.6.1...@cornerstonejs/core@0.6.2) (2022-04-20) - ### Bug Fixes -* windowLevel event trigger and initial voi range ([#81](https://github.com/cornerstonejs/cornerstone3D-beta/issues/81)) ([38307d4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/38307d40cec60f2b3b8497abda8aa4fa657fc179)) - - - - +- windowLevel event trigger and initial voi range ([#81](https://github.com/cornerstonejs/cornerstone3D-beta/issues/81)) ([38307d4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/38307d40cec60f2b3b8497abda8aa4fa657fc179)) ## [0.6.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.6.0...@cornerstonejs/core@0.6.1) (2022-04-19) - ### Bug Fixes -* jumpToSlice and scaling of images in renderToCanvas ([#78](https://github.com/cornerstonejs/cornerstone3D-beta/issues/78)) ([bbebf7f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bbebf7fbad28e670333783cd669e571ec2ae7358)) - - - - +- jumpToSlice and scaling of images in renderToCanvas ([#78](https://github.com/cornerstonejs/cornerstone3D-beta/issues/78)) ([bbebf7f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bbebf7fbad28e670333783cd669e571ec2ae7358)) # [0.6.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.5.0...@cornerstonejs/core@0.6.0) (2022-04-14) - ### Features -* add scrollToSlice for element ([#76](https://github.com/cornerstonejs/cornerstone3D-beta/issues/76)) ([c43fe8f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c43fe8f955930a70be60015f2f6bc1d5bf9fffbb)) - - - - +- add scrollToSlice for element ([#76](https://github.com/cornerstonejs/cornerstone3D-beta/issues/76)) ([c43fe8f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c43fe8f955930a70be60015f2f6bc1d5bf9fffbb)) # [0.5.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.4.6...@cornerstonejs/core@0.5.0) (2022-04-13) - ### Features -* cachedStats to store imageId and volumeId ([#75](https://github.com/cornerstonejs/cornerstone3D-beta/issues/75)) ([a2404c4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/a2404c4f1cb15a3935ba3af58fa7fc556716458c)) - - - - +- cachedStats to store imageId and volumeId ([#75](https://github.com/cornerstonejs/cornerstone3D-beta/issues/75)) ([a2404c4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/a2404c4f1cb15a3935ba3af58fa7fc556716458c)) ## [0.4.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.4.5...@cornerstonejs/core@0.4.6) (2022-04-13) - ### Bug Fixes -* renderToCanvas to use CPU rendering ([#74](https://github.com/cornerstonejs/cornerstone3D-beta/issues/74)) ([97ba32f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/97ba32f629376960f45bfbc3f22552476f934198)) - - - - +- renderToCanvas to use CPU rendering ([#74](https://github.com/cornerstonejs/cornerstone3D-beta/issues/74)) ([97ba32f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/97ba32f629376960f45bfbc3f22552476f934198)) ## [0.4.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.4.4...@cornerstonejs/core@0.4.5) (2022-04-12) - ### Bug Fixes -* Remove resemblejs from dependencies, add detect-gpu, clonedeep, CWIL ([#73](https://github.com/cornerstonejs/cornerstone3D-beta/issues/73)) ([db65d50](https://github.com/cornerstonejs/cornerstone3D-beta/commit/db65d50a5c7488f323ab2424cf9d750055b2e6d5)) - - - - +- Remove resemblejs from dependencies, add detect-gpu, clonedeep, CWIL ([#73](https://github.com/cornerstonejs/cornerstone3D-beta/issues/73)) ([db65d50](https://github.com/cornerstonejs/cornerstone3D-beta/commit/db65d50a5c7488f323ab2424cf9d750055b2e6d5)) ## [0.4.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.4.3...@cornerstonejs/core@0.4.4) (2022-04-12) - ### Bug Fixes -* Only fire STACK_NEW_IMAGE event after we are certain this image will be displayed ([#72](https://github.com/cornerstonejs/cornerstone3D-beta/issues/72)) ([bfb8b91](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bfb8b91baafb3bd342239ab9f1c4da0a1bfdf12a)) - - - - +- Only fire STACK_NEW_IMAGE event after we are certain this image will be displayed ([#72](https://github.com/cornerstonejs/cornerstone3D-beta/issues/72)) ([bfb8b91](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bfb8b91baafb3bd342239ab9f1c4da0a1bfdf12a)) ## [0.4.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.4.2...@cornerstonejs/core@0.4.3) (2022-04-11) - ### Bug Fixes -* extract IRenderingEngine type, docs: add documentation search ([#70](https://github.com/cornerstonejs/cornerstone3D-beta/issues/70)) ([6a705a8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/6a705a8f3cb9e8463c0ab6fe4d59dd3bb8bf5ef2)) - - - - +- extract IRenderingEngine type, docs: add documentation search ([#70](https://github.com/cornerstonejs/cornerstone3D-beta/issues/70)) ([6a705a8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/6a705a8f3cb9e8463c0ab6fe4d59dd3bb8bf5ef2)) ## [0.4.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.4.1...@cornerstonejs/core@0.4.2) (2022-04-04) - ### Bug Fixes -* change package.json 'module' field to use '.js' extension from '.ts' ([#65](https://github.com/cornerstonejs/cornerstone3D-beta/issues/65)) ([42f66c2](https://github.com/cornerstonejs/cornerstone3D-beta/commit/42f66c2c8887467036c55b07d3a7041db467efab)) - - - - +- change package.json 'module' field to use '.js' extension from '.ts' ([#65](https://github.com/cornerstonejs/cornerstone3D-beta/issues/65)) ([42f66c2](https://github.com/cornerstonejs/cornerstone3D-beta/commit/42f66c2c8887467036c55b07d3a7041db467efab)) ## [0.4.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.4.0...@cornerstonejs/core@0.4.1) (2022-04-01) - ### Bug Fixes -* cleanup exports, add docs and more tutorials ([#39](https://github.com/cornerstonejs/cornerstone3D-beta/issues/39)) ([743dea8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/743dea89c7a726c29d396756bdd991c81e561105)) - - - - +- cleanup exports, add docs and more tutorials ([#39](https://github.com/cornerstonejs/cornerstone3D-beta/issues/39)) ([743dea8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/743dea89c7a726c29d396756bdd991c81e561105)) # [0.4.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.3.4...@cornerstonejs/core@0.4.0) (2022-03-31) - ### Features -* advanced examples ([#38](https://github.com/cornerstonejs/cornerstone3D-beta/issues/38)) ([27f26a1](https://github.com/cornerstonejs/cornerstone3D-beta/commit/27f26a12a1712b7542cc66ab1d077cfb0da50a86)) - - - - +- advanced examples ([#38](https://github.com/cornerstonejs/cornerstone3D-beta/issues/38)) ([27f26a1](https://github.com/cornerstonejs/cornerstone3D-beta/commit/27f26a12a1712b7542cc66ab1d077cfb0da50a86)) ## [0.3.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.3.3...@cornerstonejs/core@0.3.4) (2022-03-31) **Note:** Version bump only for package @cornerstonejs/core - - - - ## [0.3.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.3.2...@cornerstonejs/core@0.3.3) (2022-03-31) **Note:** Version bump only for package @cornerstonejs/core - - - - ## [0.3.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.3.1...@cornerstonejs/core@0.3.2) (2022-03-30) **Note:** Version bump only for package @cornerstonejs/core - - - - ## [0.3.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/core@0.3.0...@cornerstonejs/core@0.3.1) (2022-03-30) **Note:** Version bump only for package @cornerstonejs/core diff --git a/packages/core/package.json b/packages/core/package.json index f024930fe..cb571427d 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@cornerstonejs/core", - "version": "0.21.4", + "version": "0.22.3", "description": "", "main": "dist/umd/index.js", "types": "dist/esm/index.d.ts", diff --git a/packages/core/src/RenderingEngine/StackViewport.ts b/packages/core/src/RenderingEngine/StackViewport.ts index f3158554c..a7d71912a 100644 --- a/packages/core/src/RenderingEngine/StackViewport.ts +++ b/packages/core/src/RenderingEngine/StackViewport.ts @@ -138,9 +138,8 @@ class StackViewport extends Viewport implements IStackViewport { // Helpers private _imageData: vtkImageDataType; - private cameraPosOnRender: Point3; + private cameraFocalPointOnRender: Point3; // we use focalPoint since flip manipulates the position and makes it useless to track private stackInvalidated = false; // if true -> new actor is forced to be created for the stack - private panCache: Point3; private voiApplied = false; private rotationCache = 0; private _publishCalibratedEvent = false; @@ -196,8 +195,7 @@ class StackViewport extends Viewport implements IStackViewport { this.imageIds = []; this.currentImageIdIndex = 0; this.targetImageIdIndex = 0; - this.panCache = [0, 0, 0]; - this.cameraPosOnRender = [0, 0, 0]; + this.cameraFocalPointOnRender = [0, 0, 0]; this.resetCamera(); this.initializeElementDisabledHandler(); @@ -1221,7 +1219,7 @@ class StackViewport extends Viewport implements IStackViewport { break; default: - console.debug('bit allocation not implemented'); + console.log('bit allocation not implemented'); } const scalarArray = vtkDataArray.newInstance({ @@ -1666,9 +1664,11 @@ class StackViewport extends Viewport implements IStackViewport { // it in the space 3) restore the pan, zoom props. const cameraProps = this.getCamera(); - this.panCache[0] = this.cameraPosOnRender[0] - cameraProps.position[0]; - this.panCache[1] = this.cameraPosOnRender[1] - cameraProps.position[1]; - this.panCache[2] = this.cameraPosOnRender[2] - cameraProps.position[2]; + const panCache = vec3.subtract( + vec3.create(), + this.cameraFocalPointOnRender, + cameraProps.focalPoint + ); // store rotation cache since reset camera will reset it const rotationCache = this.rotationCache; @@ -1680,8 +1680,15 @@ class StackViewport extends Viewport implements IStackViewport { // restore the rotation cache for the new slice this.setRotation(rotationCache, rotationCache); - const { position } = this.getCamera(); - this.cameraPosOnRender = position; + // set the flip back to the previous value since the restore camera props + // rely on the correct flip value + this.setCameraNoEvent({ + flipHorizontal: previousCameraProps.flipHorizontal, + flipVertical: previousCameraProps.flipVertical, + }); + + const { focalPoint } = this.getCamera(); + this.cameraFocalPointOnRender = focalPoint; // This is necessary to initialize the clipping range and it is not related // to our custom slabThickness. @@ -1690,7 +1697,11 @@ class StackViewport extends Viewport implements IStackViewport { // We shouldn't restore the focalPoint, position and parallelScale after reset // if it is the first render or we have completely re-created the vtkImageData - this._restoreCameraProps(cameraProps, previousCameraProps); + this._restoreCameraProps( + cameraProps, + previousCameraProps, + panCache as Point3 + ); // Restore rotation for the new slice of the image this.rotationCache = 0; @@ -1796,8 +1807,8 @@ class StackViewport extends Viewport implements IStackViewport { actor.getProperty().setRGBTransferFunction(0, cfun); // Saving position of camera on render, to cache the panning - const { position } = this.getCamera(); - this.cameraPosOnRender = position; + const { focalPoint } = this.getCamera(); + this.cameraFocalPointOnRender = focalPoint; this.stackInvalidated = false; if (this._publishCalibratedEvent) { @@ -1977,30 +1988,24 @@ class StackViewport extends Viewport implements IStackViewport { */ private _restoreCameraProps( { parallelScale: prevScale }: ICamera, - previousCamera: ICamera + previousCamera: ICamera, + panCache: Point3 ): void { const renderer = this.getRenderer(); // get the focalPoint and position after the reset const { position, focalPoint } = this.getCamera(); - const newPosition = [ - position[0] - this.panCache[0], - position[1] - this.panCache[1], - position[2] - this.panCache[2], - ]; - - const newFocal = [ - focalPoint[0] - this.panCache[0], - focalPoint[1] - this.panCache[1], - focalPoint[2] - this.panCache[2], - ]; + const newPosition = vec3.subtract(vec3.create(), position, panCache); + const newFocal = vec3.subtract(vec3.create(), focalPoint, panCache); // Restoring previous state x,y and scale, keeping the new z + // we need to break the flip operations since they also work on the + // camera position and focal point this.setCameraNoEvent({ parallelScale: prevScale, - position: newPosition, - focalPoint: newFocal, + position: newPosition as Point3, + focalPoint: newFocal as Point3, }); const camera = this.getCamera(); diff --git a/packages/core/src/RenderingEngine/Viewport.ts b/packages/core/src/RenderingEngine/Viewport.ts index 6e7913718..cd2d34e35 100644 --- a/packages/core/src/RenderingEngine/Viewport.ts +++ b/packages/core/src/RenderingEngine/Viewport.ts @@ -191,16 +191,12 @@ class Viewport implements IViewport { return; } - const { viewPlaneNormal, viewUp, focalPoint, position } = this.getCamera(); - - const viewRight = vec3.create(); - vec3.cross(viewRight, viewPlaneNormal, viewUp); - - let viewUpToSet = vec3.create(); - vec3.copy(viewUpToSet, viewUp); + const camera = this.getCamera(); + const { viewPlaneNormal, viewUp, focalPoint, position } = camera; - let viewPlaneNormalToSet = vec3.create(); - viewPlaneNormalToSet = vec3.negate(viewPlaneNormalToSet, viewPlaneNormal); + const viewRight = vec3.cross(vec3.create(), viewPlaneNormal, viewUp); + let viewUpToSet = vec3.copy(vec3.create(), viewUp); + const viewPlaneNormalToSet = vec3.negate(vec3.create(), viewPlaneNormal); // for both flip horizontal and vertical we need to move the camera to the // other side of the image @@ -208,25 +204,27 @@ class Viewport implements IViewport { // If the pan has been applied, we need to be able // apply the pan back - const resetFocalPoint = vec3.create(); const dimensions = imageData.getDimensions(); const middleIJK = dimensions.map((d) => Math.floor(d / 2)); const idx = [middleIJK[0], middleIJK[1], middleIJK[2]]; - imageData.indexToWorld(idx, resetFocalPoint); + const centeredFocalPoint = imageData.indexToWorld(idx, vec3.create()); - // what is the difference right now between the rested focal point and - // the current focal point - // Todo: this needs to be retrieved from the function that considers maintainFrame - // just now trying it on stack Viewport - const panDir = vec3.create(); - vec3.subtract(panDir, focalPoint, resetFocalPoint); + const resetFocalPoint = this._getFocalPointForResetCamera( + centeredFocalPoint as Point3, + camera, + { resetPan: true, resetToCenter: false } + ); + const panDir = vec3.subtract(vec3.create(), focalPoint, resetFocalPoint); const panValue = vec3.length(panDir); const getPanDir = (mirrorVec) => { - const panDirMirror = vec3.create(); - vec3.scale(panDirMirror, mirrorVec, 2 * vec3.dot(panDir, mirrorVec)); + const panDirMirror = vec3.scale( + vec3.create(), + mirrorVec, + 2 * vec3.dot(panDir, mirrorVec) + ); vec3.subtract(panDirMirror, panDirMirror, panDir); vec3.normalize(panDirMirror, panDirMirror); @@ -240,20 +238,22 @@ class Viewport implements IViewport { // we need to apply the pan value to the new focal point but in the direction // that is mirrored on the viewUp for the flip horizontal and // viewRight for the flip vertical - const newFocalPoint = vec3.create(); // mirror the pan direction based on the viewUp const panDirMirror = getPanDir(viewUpToSet); // move focal point from the resetFocalPoint to the newFocalPoint // based on the panDirMirror and panValue - vec3.scaleAndAdd(newFocalPoint, resetFocalPoint, panDirMirror, panValue); + const newFocalPoint = vec3.scaleAndAdd( + vec3.create(), + resetFocalPoint, + panDirMirror, + panValue + ); // move the camera position also the same way as the focal point - const newPosition = vec3.create(); - - vec3.scaleAndAdd( - newPosition, + const newPosition = vec3.scaleAndAdd( + vec3.create(), newFocalPoint, viewPlaneNormalToSet, distance @@ -276,14 +276,15 @@ class Viewport implements IViewport { // we need to apply the pan value to the new focal point but in the direction const panDirMirror = getPanDir(viewRight); - const newFocalPoint = vec3.create(); - - vec3.scaleAndAdd(newFocalPoint, resetFocalPoint, panDirMirror, panValue); - - const newPosition = vec3.create(); + const newFocalPoint = vec3.scaleAndAdd( + vec3.create(), + resetFocalPoint, + panDirMirror, + panValue + ); - vec3.scaleAndAdd( - newPosition, + const newPosition = vec3.scaleAndAdd( + vec3.create(), newFocalPoint, viewPlaneNormalToSet, distance @@ -1065,9 +1066,7 @@ class Viewport implements IViewport { const viewUpCorners = this._getCorners(bounds); const viewRightCorners = this._getCorners(bounds); - const viewRight = vec3.create(); - - vec3.cross(viewRight, viewUp, viewPlaneNormal); + const viewRight = vec3.cross(vec3.create(), viewUp, viewPlaneNormal); let transform = vtkMatrixBuilder .buildFromDegree() @@ -1131,7 +1130,7 @@ class Viewport implements IViewport { _getFocalPointForResetCamera( centeredFocalPoint: Point3, previousCamera: ICamera, - { resetPan, resetToCenter }: { resetPan: boolean; resetToCenter: boolean } + { resetPan = true, resetToCenter = true } ): Point3 { if (resetToCenter && resetPan) { return centeredFocalPoint; @@ -1152,9 +1151,8 @@ class Viewport implements IViewport { const oldFocalPoint = oldCamera.focalPoint; const oldViewPlaneNormal = oldCamera.viewPlaneNormal; - const vectorFromOldFocalPointToCenteredFocalPoint = vec3.create(); - vec3.subtract( - vectorFromOldFocalPointToCenteredFocalPoint, + const vectorFromOldFocalPointToCenteredFocalPoint = vec3.subtract( + vec3.create(), centeredFocalPoint, oldFocalPoint ); @@ -1164,9 +1162,8 @@ class Viewport implements IViewport { oldViewPlaneNormal ); - const newFocalPoint = vec3.create(); - vec3.scaleAndAdd( - newFocalPoint, + const newFocalPoint = vec3.scaleAndAdd( + vec3.create(), centeredFocalPoint, oldViewPlaneNormal, -1 * distanceFromOldFocalPointToCenteredFocalPoint diff --git a/packages/core/src/RenderingEngine/VolumeViewport.ts b/packages/core/src/RenderingEngine/VolumeViewport.ts index d063bea8a..112f1dc73 100644 --- a/packages/core/src/RenderingEngine/VolumeViewport.ts +++ b/packages/core/src/RenderingEngine/VolumeViewport.ts @@ -751,7 +751,7 @@ class VolumeViewport extends Viewport implements IVolumeViewport { metadata: { Modality: volume?.metadata?.Modality, }, - scaling: volume.scaling, + scaling: volume?.scaling, hasPixelSpacing: true, }; } diff --git a/packages/core/src/constants/mprCameraValues.ts b/packages/core/src/constants/mprCameraValues.ts index 3c2e03154..f564c2f1e 100644 --- a/packages/core/src/constants/mprCameraValues.ts +++ b/packages/core/src/constants/mprCameraValues.ts @@ -10,7 +10,7 @@ const MPR_CAMERA_VALUES = { viewUp: [0, 0, 1], }, coronal: { - viewPlaneNormal: [0, 1, 0], + viewPlaneNormal: [0, -1, 0], viewUp: [0, 0, 1], }, }; diff --git a/packages/core/src/utilities/getClosestStackImageIndexForPoint.ts b/packages/core/src/utilities/getClosestStackImageIndexForPoint.ts new file mode 100644 index 000000000..ada80b1f9 --- /dev/null +++ b/packages/core/src/utilities/getClosestStackImageIndexForPoint.ts @@ -0,0 +1,116 @@ +import { vec3 } from 'gl-matrix'; +import { planar } from '.'; +import { metaData } from '..'; +import { IStackViewport, Point3 } from '../types'; + +/** + * Given a point in 3D space and a viewport it returns the index of the closest imageId, it assumes that stack images are sorted according to their sliceLocation + * @param point - [A, B, C] coordinates of the point in 3D space + * @param viewport - The StackViewport to search for the closest imageId + * + * @returns The imageId index of the closest imageId or null if no imageId is found + */ +export default function getClosestStackImageIndexForPoint( + point: Point3, + viewport: IStackViewport +): number | null { + const minimalDistance = calculateMinimalDistanceForStackViewport( + point, + viewport + ); + return minimalDistance ? minimalDistance.index : null; +} + +//assumes that imageIds are sorted by slice location +export function calculateMinimalDistanceForStackViewport( + point: Point3, + viewport: IStackViewport +): { distance: number; index: number } | null { + const imageIds = viewport.getImageIds(); + const currentImageIdIndex = viewport.getCurrentImageIdIndex(); + + if (imageIds.length === 0) return null; + + const getDistance = (imageId: string): null | number => { + const planeMetadata = getPlaneMetadata(imageId); + if (!planeMetadata) return null; + const plane = planar.planeEquation( + planeMetadata.planeNormal, + planeMetadata.imagePositionPatient + ); + const distance = planar.planeDistanceToPoint(plane, point); + return distance; + }; + + const closestStack = { + distance: getDistance(imageIds[currentImageIdIndex]) ?? Infinity, + index: currentImageIdIndex, + }; + + //check higher indices + const higherImageIds = imageIds.slice(currentImageIdIndex + 1); + + for (let i = 0; i < higherImageIds.length; i++) { + const id = higherImageIds[i]; + const distance = getDistance(id); + if (distance === null) continue; + if (distance <= closestStack.distance) { + closestStack.distance = distance; + closestStack.index = i + currentImageIdIndex + 1; + } else break; + } + //check lower indices + const lowerImageIds = imageIds.slice(0, currentImageIdIndex); + for (let i = lowerImageIds.length - 1; i >= 0; i--) { + const id = lowerImageIds[i]; + const distance = getDistance(id); + if (distance === null || distance === closestStack.distance) continue; + if (distance < closestStack.distance) { + closestStack.distance = distance; + closestStack.index = i; + } else break; + } + return closestStack.distance === Infinity ? null : closestStack; +} + +function getPlaneMetadata(imageId: string): null | { + rowCosines: Point3; + columnCosines: Point3; + imagePositionPatient: Point3; + planeNormal: Point3; +} { + const targetImagePlane = metaData.get('imagePlaneModule', imageId); + + if ( + !targetImagePlane || + !( + targetImagePlane.rowCosines instanceof Array && + targetImagePlane.rowCosines.length === 3 + ) || + !( + targetImagePlane.columnCosines instanceof Array && + targetImagePlane.columnCosines.length === 3 + ) || + !( + targetImagePlane.imagePositionPatient instanceof Array && + targetImagePlane.imagePositionPatient.length === 3 + ) + ) { + return null; + } + const { + rowCosines, + columnCosines, + imagePositionPatient, + }: { + rowCosines: Point3; + columnCosines: Point3; + imagePositionPatient: Point3; + } = targetImagePlane; + + const rowVec = vec3.set(vec3.create(), ...rowCosines); + const colVec = vec3.set(vec3.create(), ...columnCosines); + const planeNormal = vec3.cross(vec3.create(), rowVec, colVec) as Point3; + + return { rowCosines, columnCosines, imagePositionPatient, planeNormal }; +} diff --git a/packages/core/src/utilities/index.ts b/packages/core/src/utilities/index.ts index 2bf011903..6ced41f4d 100644 --- a/packages/core/src/utilities/index.ts +++ b/packages/core/src/utilities/index.ts @@ -27,9 +27,11 @@ import snapFocalPointToSlice from './snapFocalPointToSlice'; import getImageSliceDataForVolumeViewport from './getImageSliceDataForVolumeViewport'; import isImageActor from './isImageActor'; import getViewportsWithImageURI from './getViewportsWithImageURI'; +import getClosestStackImageIndexForPoint from './getClosestStackImageIndexForPoint'; import calculateViewportsSpatialRegistration from './calculateViewportsSpatialRegistration'; import spatialRegistrationMetadataProvider from './spatialRegistrationMetadataProvider'; import getViewportImageCornersInWorld from './getViewportImageCornersInWorld'; +import hasNaNValues from './hasNaNValues'; // name spaces import * as planar from './planar'; @@ -67,7 +69,9 @@ export { getImageSliceDataForVolumeViewport, isImageActor, getViewportsWithImageURI, + getClosestStackImageIndexForPoint, calculateViewportsSpatialRegistration, spatialRegistrationMetadataProvider, getViewportImageCornersInWorld, + hasNaNValues, }; diff --git a/packages/core/src/utilities/planar.ts b/packages/core/src/utilities/planar.ts index dac8513b3..d441c83c6 100644 --- a/packages/core/src/utilities/planar.ts +++ b/packages/core/src/utilities/planar.ts @@ -63,4 +63,29 @@ function threePlaneIntersection( return [x, y, z]; } -export { linePlaneIntersection, planeEquation, threePlaneIntersection }; +/** + * Computes the distance of a point in 3D space to a plane + * @param plane - [A, B, C, D] of plane equation A*X + B*Y + C*Z = D + * @param point - [A, B, C] the plane in World coordinate + * @param signed - if true, the distance is signed + * @returns - the distance of the point to the plane + * */ +function planeDistanceToPoint( + plane: Plane, + point: Point3, + signed = false +): number { + const [A, B, C, D] = plane; + const [x, y, z] = point; + const numerator = A * x + B * y + C * z - D; + const distance = Math.abs(numerator) / Math.sqrt(A * A + B * B + C * C); + const sign = signed ? Math.sign(numerator) : 1; + return sign * distance; +} + +export { + linePlaneIntersection, + planeEquation, + threePlaneIntersection, + planeDistanceToPoint, +}; diff --git a/packages/core/test/groundTruth/volumeURI_100_100_10_1_1_1_0_coronal_linear.png b/packages/core/test/groundTruth/volumeURI_100_100_10_1_1_1_0_coronal_linear.png index 56dad440c1f6e0a99cae745ca4fae3440d76b6a9..b0058f2398ae549f831c2e71e678d7d092fca314 100644 GIT binary patch literal 25355 zcmeHwd03KJ`#&L;QcbAQGMSQ=TAFC98VHtVWu}&erDE!vO`DqNh@c=XW41`nOl4)t z*gB&^%aj{}nZ>k;Z8DR&l0uRTf+>XhJ*cJ4_5S|+{q;Uwm-%p>bD!mN-}mRf&vVX$ z>HeF%ry{>c!eFqe>(_a1hQSQv`X8f-pv3p`>-R9&gzbCQtnpvJW(~$aE+%Tv{#`Jb zUFLz)LZ8(E<`3DsjLK2z*Gy?1YmR#H&G!aQGCo9pJ8fUOqW9|kEm-l)Hy_{5ShjX? zhsVyy1B-oGUQFUt51*#ZS}i&3>bAa~*5v-U&eqseN32<;8vfVJ{q`p8KYs6>`lb(I z=+W-ZT=KRK&8Dr@Ol3n+4H%B zXFRTTEk)X|-%RjDxmneq9yy%7xuIUyHFagV^YnQ)r%kT=%WBe`MddT%eP>mv>{26< z^CG6cT6W=Me_~?cB|8I38iH3icPY!K-97f*+f(ja-kCIM1D#F`ENlNg$tQT}g{K<~ z<*sqrMawHze)qa-uB^PprFSXkvq|wEDRBHyMCU`2ZWh2gWLMDoC|_ULB5-X4LrjFD(YaBVkMp0)>u7_I|@xr5&@7@PzDQeq(I7>r%(Z$9zDd4hPFC(n3w;@}hB>WBFFST`&-F)`6Gaj9cW z+-|J1tE(&4X$f}8lEt9LVoFkUd^mM+G{t(PkuU9d?xIA-?TL-w6BCWmw;LW2lMs)$ zveI|-_20-i8DD>V*}v=i{}2-&1F(+U6S+P* zepeh29_{VR0RP`LM%%(+^>B@YZ$vl4r9e6ENF4U7qTP{aZ)~W6!HBT+o*seJ2_NeZ z#LXf7{8NC|CuEyI~&7mRLbZeRg zdL5%r@royOFEPOoQ(+U}2qVPsIJ|!Czv@m#Ahd_PoD9dL z^|diI9pl>5m)s;0IoKe?mVb%E>n;9O0yQ|Q3J62UY{oeeAt7>r$N?e;=;<8r0%#=#t)#}N z09r{wE2(jL0z?iFIY8v_b)OL0*BecnhaWXSL!x;8?@TK z<@*ccr4UBR`KiRAZ3~&~Z;L|$h@3DJNzFIBLu?8*tWBAwE!y<1(RyqjVCSZ$vM#~J zInUPlDf!C=dL?1Gj$Jpn*4-D?2@?f9H{b(LDt@y4TL0#HPNnj$^jb-SDx_yk3q$+i z`gKdDPPvdx@yTWm>NFp6hjcQgV6dlx`N+_Hs3$4;S>G&wjxg=EWGoQeBw_+`f}RcB z6-~aTL2Wq})1phWWb}t}h7@5#G;Qm-FackL`>`ye0-HP3*za~ZEGCe}zz18KeQhIX zLF~yMPufGNvUqQ0qWk&F2R|y1w2X9>uB0vj5#k}t$PXBIR%@2&y7}9#NZ!;}C3W`p z*7(eBYlJJg!G^R@SHj@-fw`jD6G%0?%}=c!JM>j?2C=A`9gyQhXyB<|UZ1nVnUUm| zWtqEb?vqu5a8ga9NuAHQQ)1mevXE-6JfV`$IK4fir0ltoIq$4&(t`!n3Wko>_U2^V z!X~8l>M`E9Q3WkHO%xCGAhl`JECp3b8PQAO=}Mhb@jEj`LND$hSuDHtUnhgQ;Ua#c zdTK8(iOX@BDL1GYvas^7P#ss{LP>AT!hRG1y%(pR<{te>&8$CHWwO@%-%xhn)Fe zjDU(|mEOK6$rmLg^IWr=6HMETm0BwOB>R3AA@QQwUubp60>2}+f0=zu;IYfZQHx})ntlW2XWn)&w7yW}TKe3m>NaBsJxPLYh}+}>K88%Bd6l~4DpOtu zAhegc1$|zl6DT%dA(ed{c3AtcDgswBCEN+VaNG4OG3Ma z6qj2@WENd5&Yx*2PrMsq<1^Yl)q#Zw4_(Z&p{&5O0Ba`wHvhH0ZK<)#co`-W&QS{{z@S3yS7#}&5zqy)vH=(+ahs=IY3 ziB`IopXClOcV}B3n9dsf!M=Uq%Q?f&bsR3o(g1%jr%`mtMO-i9?w;`{SN`aZK*rC> zx90=+j9(K{0}EsdTy_1a3LiLpU;$eE)iU`fh@lmA9D584pnNwnK^3-p(Zi;u(2}v3Z6wKJyHA-UFrNH zNGz28Y0-1F<$@iLel#g%$|~=ba745{rY1(w^=8CJSV!UL6A2qJwNmr?HiW6HSNX|> zlx=H8@mYpc&+huWR`fUJq*9r7_BsD}fDuY=WTei>p^VC=nXQ|$?X<1A+52;e_g#uU zdP|Ef49YFU97TQa-oSf(=iJei4zx z-~B#hInRY>|AE4zHe^Q7PO5;TA1fmgx*EEx`#`7oec?7EmR(`Wio7DT{yV|%itH9K zH}nSbfjPU6zhU5?kM=o~KZ9!fF3G4<)NzFCClh^lvQvqTcVIkeiPR?b9Z3}U5IJ2trrnu0;?y&Y z0`{!vxjEK4vL+dvtoI(8}UJiyYm&AJDo4@I!lqi}di zb6%F|u$fTTW0XJF?Gv4=R=%qUjc$c+5XIsc(?54yUM1a(Aw7+x;VcNWOCm6D zl*@@!BH`%Lm8&Ql6>+mk#rw_djOs34U2+ zm8&B6PlqEqy#a9I9p@M7yUz~fMBrG1Z$q7`4`j@;P7)_c`p(Pf)rv`v zwq{ROyY99&!NgjES-aOhcF@~b(|b7j13JUCwmfg(y=P<$p|q}8oM&LW%)xOO<% zn^Ys)f66npV!+r){W*B)QX2p?>lb75!_Lm+M(Y%v-H$nm7tt={a^Ec3St`z*@cFpR zyzmg8n6K+Ru~8FPjJ7v@4a0p#BifHghb|ZUP3IALJB1fl-bv0wr@0C~ zQ8mHE`5(4&MB4u1k6rE0vmC(WF2LdC#`5^#Gsv+AfQqyYa-_&_6Q=MVLrqU=urmGi+CxD0EG?tHK8Z z=6jG?WJ1kGm+B-5;m~_(QZ5}0Kq5A|0}@Cn_+`5(h}0G7hK|BX1BZa*G>`=SJeYK!{@9G3pOf-6{C9Z$0>6Z#+M${nJ~imLd|`oW_XD z-CJ@ZJH5MvD{kK*o2|pNF*Gj}2>R+!qQFL$q@U)P|HnqKs+yJL`_$ylD%|B5z@7Q6 zuG@Zhn>C7pUkBf=|@YQ2p_I>-vbbLZvra5#3`Qw;Ir_>{1!xt zV~eCJ_NSbfUPenW>4h|ylxY9NjICJ(Mt+WEA$uovsM&pTBx}G=FC`_x<`S%hG2WH8QRi(0|qS>sfaIeU<1tK)t6)BpnIJwz*@MWed`wk!jpmH`C zI@=~kPbI7vl*?LL=yJboSznwiOZF}bVcMkmD?woE_983T>vOAWDUaG2VA@(V(20MdFBuqm@3BWd#G93Ff6rY>7KJaw7QLcCv-p8DLwxLWlY@ z1MHtDHqfkI9$3q9f5PA&%5mWl*(G!Ing-N21W+H8)T{yuXoQP^TY>Be$6Zz6$|{W` zi;(K7|KL~l?Uh+9oR`DwzCk}pVVAfN`Wm`Bhq>eyaMQ@b>xpZc{)8J>zN2^*wcuC` zK2WwROZukHv!zv1d9b!LkDsA*RF#mHjIcE()&~%hPYTaBwc6C% z=`pmtgf{rHFR$zndB;FxGNpBe=(s95lvJy@eyT6*vC)VSjHLn*UR7{6k!H<8ilok4 ze&@w3D@>#Rb0h-JZvm!hd8Zm(uhlj;^q*?*522jluf~PR$eEpgbe@{==&7Cufw3em z#?*AtG#eRZ#Jrnar?&o=(vGfXa@$OWHoYS$JJ`zke%7&PQp6R2goAWPpU(Q2OYW`Z z$WdjJ0qhNT`>Go~Fu!HdL*MuUVsH~YShh)NdXURR{LVD`-Hzuk)(5@bX_g{OBNC}b zdZ}#GR>0KjfWGVax&!bSQU>A6rfC!eWX_iI># zS(ko_2a^HRX)?zBZ!nhN$yaRCMnYz z9sC>4Rcm%+GnZZ#ep#{fUji%KxoKFVXOmy|d6BM=II^t9=N&7oPuo2c6{y%&uG{Qt zMK={L!&&TX88tckF6zT4qY>PQO&!2XI-;sE-Ou47eae^6s?%t;bC`GD=MDjb<(vHk zz{hX8De;>#q{`Htib1>lM8#LX__{oA;(<8`+u9u9jq^|MO#XnRakFJP>k==T+^`cn zlb+hwDxM?_RCk^yEge;s-mjA;u-s!x8C6GoqFrkT`g_k2)VcSF`xW%(dKQ^*-oBL4 zO1jveXi#<63MVMBtyb~#ONEzv3`fVETCo|}dwe)|c_Fd~`N*wJBbDweAN=RhbJ0Jl z7oUzRk3@vlpGsSGQy}B;?6RV6$@5BQ00Rd)XImKgIqWR zo-z^dk>#Sh^Z8l+>;(-XJA!+4u5tW-ktzc`>F@We1TWP3aKs#2BgOIP40O7&=$%3w zMSgClEX;51Wn1-z2!0%U3UV`)$cYL2&HfqBYM}qtCj@OEx-%KkP>4P4a&i|Vc01fT zfP6p8MXb^<>#J7uy=zyt9&9^va_nhAlN&HJH|{>~LKmK;={a_>r4$&N#wU=QVvxA( zR_Wf0k%P`xxOw_TTGz+w`UBfIRw+LQUjDjFLlp}uN{K^pTl>lqUX>1R;J>ne-PM{w z30>${Gyi)Eud6QQ`Ujl)Y1Li#M`X)=gzv$#jI_1gZC~{b^71HF!h-Dl5-|bCRL$w0 z*=U1m^rW@$1rk12-lp)3#1Gxe9O&?21+^iQQhqIuz&Et$Hb0e&daGXZAE&5u5!$== zqPW=-JTKF~Aiq@OMxq(g=4*@oCO=9_S^b+;`Ou>AFT6DcAU+vt(;B%PCQ2@OyECB` zXF{GwzLiBSV3&s}dd174;ds(>b|Q;$ZEjQfC?A48sTcJV?tYbaUB_8cq?r6#RG^>^ zkZ=5*`5mSxvD@hL%5`XqZv>0Ywv z_RJ5q4dxAQU)%`BnhET9vK?C&7<&IXx*l0Y<7V{gtXJ_R^!!=8NH2OucH=%Ye{{{N zciqpZzh}xd7V)GS-aUHHnx{SGGLipAoDEnETrd{74kDFqk4h~lIg}NnF;Oq%jS8A6 z7fc!`t^0%F6mp1fVf#JB3(p!oA;%iksCx3kpoqQ z5P%SX5P%SX5cvO#z<2Q7YhW;o7X5btK!FKD073vl073vl073vl073vl073vl073vl z073vl073vl073vl073vl;C~!}ilMt^gMK*|YlVK5^V~`l3j1UM~s{GK{ zF1CKVm=BIVp#L0uM`U>0nUzYMh6?>=4;sb-Tfo9YpT;+cA!1M{`Gma5W82R9+ucYb zHK``&+kOymIGz~qF}A6#zYR`C4IfXIyi_97u;bfJaU$4%H}IVK?IfGfC^?UV zAGf&Ya!F53#epFaQ7m literal 24301 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 literal 21485 zcmeHPe{hrK9e?xoEqmKq^Onq3Xdx-ZR#b=+X5}2@t*t<<7EVx)iA0Y%oD73w*j`if z=52daT!GHht2oxCC*s&VdOCYWOHEL3aAVrAG3&va=2mDUUE8!KP5L&;yYKTRZ}O(V z&bw`QJNNw2yYzYAJkR(0`F=j%@AK=jZ$stU%=G!`1VLn$uPb|)AW}T&kDdc9550N* z5<%#Q^0Jam)mumZcIw@yAG>Mi#oH?y(yE(ZuUq0)6`s+o)7+_2dv*J4i_;HXD0%1i z=X)27KEg$I4?nl7qQ+dV@GQaaLd-ts!u-)tkhs_4-bqnH z`!Pz$KhtO^aBA|g;JdOIPvgh{ob#e~(hhP7$mc)+Hus|_wE!}+grYZ6C4j*D=s zsB~kRue4dst+5#zCVLf5Rp+XB%QL^VTSERpy_Q?)+hG~%qCTpfo_t*VR1DOUk@_1?PaEpnvN!IFLyb@v&W~es#c9yM`{5fBhY@^4DAqZRrqGC8 z=Nzxe@O8T)^X12mqgF9B>>NwDdt-PxZ=wI(o4AqWwcG5GOxo9%J7aW?&liObxMtPs zG8W3w_%aJ#(O&pr6qQJhuW>_TnFgwybw~1| z6mxSWNj>O2RbAPhs-E!oqpE^$L?#hGEB~QpUI$@Ty{&xA+Uz0duSGMHLj4$w??09* zJYnMYM-{+$^oTH*KaCLlJWyBFv%ID6qA`{xDB!sY__&WD6oqi_GO+n_1gHYEImK_&#V_FAK)~o|Uy{ zEQ_&TYYZH#<7s$1XNzsXKh=kX;qF1|?SUM&&H%R=`Lpo$vJ-K59p*IPvN z2F`ATf18iUz@q+XpZV)_pZSZ(T%b-R^8FPVIf7rm6aw?v?auN4!NCEGMQ+31yr*hI z1(3wI-6l2@ycQ*+-cp%ZP+%Nc5dMaViG#H7^rlF@3IOn%fZ(n#jj{663K$GOS`>MU zHMDz*X-3i(5M0uhR2L3FuLVs9xiXvK=%hN03G#rl?*}r4kmmA0L~C!>iZ8L;gO{~) zVQp;`=TO4P{%~qka_$d670>PYyD{CTdD&7=sKgAR9V8e{5E3z8f?huk2G>%;f72QI zWV@8cS47kJ3+sWA?`6w;mJG=R&i9`K-kZ45Rxs*EOBH5X9l7bi`8U&0NxQHL&^?1{ zkR)V;C|~?t;QU$*l53|K@vSq?H-x6?R^ZfuLP@RxkYfH0S;!LBt_>je1rJGb9Yb{d zLKz8UJZr!A4N0#38j#{UsWBl-nXkGO?5SEI$+f!((A}I7mkPM%-3#`NJtN8W8jgeU z0}RUJtFr){)~?x}gZ1PpKZLbsoY7`h4_bcy?W674+#1Qu;H4>>Y5?xUelj{bD$BfHZ(Xma=Ne7KBSm6F*+v`oE~n=ZEV^y zG0cTm`rnG7@XKvTAQDlf4-T7^)#mjVX_SpDNGfpm^H~xj;6i~5 z1zwiQi%VP~NptGwR|rCL82v6l?6?N)PT*>Zt0k_MxLV?BiK`{9mU!D9PYv*#2%k{l zqd9!c8QW9DTg}SNRlJZ^qJbCBc=3!E&v^0tA6Yy*IHH@mE#)V7@~ diff --git a/packages/dicom-image-loader/.webpack/webpack-base.js b/packages/dicom-image-loader/.webpack/webpack-base.js index fce51d91a..f6aed0257 100644 --- a/packages/dicom-image-loader/.webpack/webpack-base.js +++ b/packages/dicom-image-loader/.webpack/webpack-base.js @@ -12,7 +12,7 @@ module.exports = { mode: 'development', context, entry: { - cornerstoneWADOImageLoader: './imageLoader/index.js', + cornerstoneWADOImageLoader: './imageLoader/index.ts', }, target: 'web', output: { @@ -35,6 +35,7 @@ module.exports = { }, }, resolve: { + extensions: ['.ts', '.js'], fallback: { fs: false, path: false, @@ -45,7 +46,7 @@ module.exports = { rules: [ { enforce: 'pre', - test: /\.js$/, + test: /\.(mjs|js|ts)$/, exclude: /(node_modules)|(codecs)/, loader: 'eslint-loader', options: { @@ -57,7 +58,7 @@ module.exports = { type: 'asset/resource', }, { - test: /\.worker\.js$/, + test: /\.worker\.(mjs|js|ts)$/, use: [ { loader: 'worker-loader', @@ -68,7 +69,7 @@ module.exports = { ], }, { - test: /\.js$/, + test: /\.(mjs|js|ts)$/, exclude: [/(node_modules)/, /(codecs)/], use: { loader: 'babel-loader', diff --git a/packages/dicom-image-loader/.webpack/webpack-bundle.js b/packages/dicom-image-loader/.webpack/webpack-bundle.js index 5f01476b6..531706b23 100644 --- a/packages/dicom-image-loader/.webpack/webpack-bundle.js +++ b/packages/dicom-image-loader/.webpack/webpack-bundle.js @@ -15,8 +15,8 @@ module.exports = { mode: 'production', context, entry: { - cornerstoneWADOImageLoader: './imageLoader/index.js', - cornerstoneWADOImageLoaderNoWebWorkers: './imageLoader/index-noWorkers.js', + cornerstoneWADOImageLoader: './imageLoader/index.ts', + cornerstoneWADOImageLoaderNoWebWorkers: './imageLoader/index-noWorkers.ts', }, target: 'web', output: { @@ -39,6 +39,7 @@ module.exports = { }, }, resolve: { + extensions: ['.ts', '.js'], fallback: { fs: false, path: false, @@ -49,7 +50,7 @@ module.exports = { rules: [ { enforce: 'pre', - test: /\.js$/, + test: /\.(mjs|js|ts)$/, exclude: /(node_modules)|(codecs)/, loader: 'eslint-loader', options: { @@ -61,7 +62,7 @@ module.exports = { type: 'asset/inline', }, { - test: /\.worker\.js$/, + test: /\.worker\.(mjs|js|ts)$/, use: [ { loader: 'worker-loader', @@ -73,7 +74,7 @@ module.exports = { ], }, { - test: /\.js$/, + test: /\.(mjs|js|ts)$/, exclude: [/(node_modules)/, /(codecs)/], use: { loader: 'babel-loader', diff --git a/packages/dicom-image-loader/.webpack/webpack-esm.js b/packages/dicom-image-loader/.webpack/webpack-esm.js index 354fbf052..2a34322e0 100644 --- a/packages/dicom-image-loader/.webpack/webpack-esm.js +++ b/packages/dicom-image-loader/.webpack/webpack-esm.js @@ -12,7 +12,7 @@ const config = { mode: 'development', context, entry: { - cornerstoneWADOImageLoader: './imageLoader/index.js', + cornerstoneWADOImageLoader: './imageLoader/index.ts', }, target: 'web', output: { @@ -35,6 +35,7 @@ const config = { }, }, resolve: { + extensions: ['.ts', '.js'], fallback: { fs: false, path: false, @@ -57,7 +58,7 @@ const config = { type: 'asset/resource', }, { - test: /\.js$/, + test: /\.(mjs|js|ts)$/, exclude: [/(node_modules)/, /(codecs)/], use: { loader: 'babel-loader', diff --git a/packages/dicom-image-loader/package.json b/packages/dicom-image-loader/package.json index 87b69fc07..131525bf6 100644 --- a/packages/dicom-image-loader/package.json +++ b/packages/dicom-image-loader/package.json @@ -51,6 +51,13 @@ "dicom-parser": "^1.8.9", "pako": "^2.0.4" }, + "devDependencies": { + "@types/chai": "^4.3.4", + "@types/mocha": "^9.1.1", + "chai": "^4.3.4", + "mocha": "^9.1.1" + + }, "contributors": [ { "name": "Cornerstone.js Contributors", diff --git a/packages/dicom-image-loader/src/externalModules.js b/packages/dicom-image-loader/src/externalModules.ts similarity index 59% rename from packages/dicom-image-loader/src/externalModules.js rename to packages/dicom-image-loader/src/externalModules.ts index d494efb97..18d332f45 100644 --- a/packages/dicom-image-loader/src/externalModules.js +++ b/packages/dicom-image-loader/src/externalModules.ts @@ -1,20 +1,22 @@ /* eslint import/extensions:0 */ import registerLoaders from './imageLoader/registerLoaders'; +import * as cornerstoneImport from '@cornerstonejs/core'; +import * as dicomParserImport from 'dicom-parser'; -let cornerstone; +let cornerstone: typeof cornerstoneImport; -let dicomParser; +let dicomParser: typeof dicomParserImport; const external = { - set cornerstone(cs) { + set cornerstone(cs: typeof cornerstoneImport) { cornerstone = cs; registerLoaders(cornerstone); }, - get cornerstone() { + get cornerstone(): typeof cornerstoneImport { if (!cornerstone) { - if (window && window.cornerstone) { - cornerstone = window.cornerstone; + if (window && (window as any).cornerstone) { + cornerstone = (window as any).cornerstone; registerLoaders(cornerstone); } else { @@ -26,13 +28,13 @@ const external = { return cornerstone; }, - set dicomParser(dp) { + set dicomParser(dp: typeof dicomParserImport) { dicomParser = dp; }, - get dicomParser() { + get dicomParser(): typeof dicomParserImport { if (!dicomParser) { - if (window && window.dicomParser) { - dicomParser = window.dicomParser; + if (window && (window as any).dicomParser) { + dicomParser = (window as any).dicomParser; } else { throw new Error( 'cornerstoneWADOImageLoader requires a copy of dicomParser to work properly. Please add cornerstoneWADOImageLoader.external.dicomParser = dicomParser; to your application.' diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.ts similarity index 86% rename from packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.js rename to packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.ts index 5a9b1f56f..fd7d4f455 100644 --- a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.js +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertPALETTECOLOR.ts @@ -1,6 +1,9 @@ /* eslint no-bitwise: 0 */ -function convertLUTto8Bit(lut, shift) { +import { CornerstoneWadoImageFrame } from 'dicom-image-loader/src/shared/image-frame'; +import { ByteArray } from 'dicom-parser'; + +function convertLUTto8Bit(lut: number[], shift: number) { const numEntries = lut.length; const cleanedLUT = new Uint8ClampedArray(numEntries); @@ -18,7 +21,11 @@ function convertLUTto8Bit(lut, shift) { * @param {Uint8ClampedArray} colorBuffer * @returns {void} */ -export default function (imageFrame, colorBuffer, useRGBA) { +export default function ( + imageFrame: CornerstoneWadoImageFrame, + colorBuffer: ByteArray, + useRGBA: boolean +): void { const numPixels = imageFrame.columns * imageFrame.rows; const pixelData = imageFrame.pixelData; const rData = imageFrame.redPaletteColorLookupTableData; diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.ts similarity index 82% rename from packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.js rename to packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.ts index 2222c1e3f..0b149aef1 100644 --- a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.js +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPixel.ts @@ -1,4 +1,10 @@ -export default function (imageFrame, colorBuffer, useRGBA) { +import { ByteArray } from 'dicom-parser'; + +export default function ( + imageFrame: ByteArray, + colorBuffer: ByteArray, + useRGBA: boolean +): void { if (imageFrame === undefined) { throw new Error('decodeRGB: rgbBuffer must not be undefined'); } diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.ts similarity index 83% rename from packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.js rename to packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.ts index 124d9ee03..2e5f22fce 100644 --- a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.js +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertRGBColorByPlane.ts @@ -1,4 +1,10 @@ -export default function (imageFrame, colorBuffer, useRGBA) { +import { ByteArray } from 'dicom-parser'; + +export default function ( + imageFrame: ByteArray, + colorBuffer: ByteArray, + useRGBA: boolean +): void { if (imageFrame === undefined) { throw new Error('decodeRGB: rgbBuffer must not be undefined'); } diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.ts similarity index 92% rename from packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.js rename to packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.ts index 13cc124a5..1083abad0 100644 --- a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.js +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFull422ByPixel.ts @@ -1,4 +1,10 @@ -export default function (imageFrame, colorBuffer, useRGBA) { +import { ByteArray } from 'dicom-parser'; + +export default function ( + imageFrame: ByteArray, + colorBuffer: ByteArray, + useRGBA: boolean +): void { if (imageFrame === undefined) { throw new Error('decodeRGB: ybrBuffer must not be undefined'); } diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.ts similarity index 88% rename from packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.js rename to packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.ts index dfd46fde9..2ca53110c 100644 --- a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.js +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPixel.ts @@ -1,4 +1,10 @@ -export default function (imageFrame, colorBuffer, useRGBA) { +import { ByteArray } from 'dicom-parser'; + +export default function ( + imageFrame: ByteArray, + colorBuffer: ByteArray, + useRGBA: boolean +): void { if (imageFrame === undefined) { throw new Error('decodeRGB: ybrBuffer must not be undefined'); } diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.ts similarity index 89% rename from packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.js rename to packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.ts index ccac454b9..389b6c73c 100644 --- a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.js +++ b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/convertYBRFullByPlane.ts @@ -1,4 +1,10 @@ -export default function (imageFrame, colorBuffer, useRGBA) { +import { ByteArray } from 'dicom-parser'; + +export default function ( + imageFrame: ByteArray, + colorBuffer: ByteArray, + useRGBA: boolean +): void { if (imageFrame === undefined) { throw new Error('decodeRGB: ybrBuffer must not be undefined'); } diff --git a/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/index.js b/packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/index.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/index.js rename to packages/dicom-image-loader/src/imageLoader/colorSpaceConverters/index.ts diff --git a/packages/dicom-image-loader/src/imageLoader/configure.js b/packages/dicom-image-loader/src/imageLoader/configure.js deleted file mode 100644 index 0c6f20b69..000000000 --- a/packages/dicom-image-loader/src/imageLoader/configure.js +++ /dev/null @@ -1,7 +0,0 @@ -import { setOptions } from './internal/index'; - -function configure(options) { - setOptions(options); -} - -export default configure; diff --git a/packages/dicom-image-loader/src/imageLoader/configure.ts b/packages/dicom-image-loader/src/imageLoader/configure.ts new file mode 100644 index 000000000..3fa07a5c1 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/configure.ts @@ -0,0 +1,8 @@ +import { setOptions } from './internal/index'; +import { CornerstoneWadoLoaderOptions } from './internal/options'; + +function configure(options: CornerstoneWadoLoaderOptions): void { + setOptions(options); +} + +export default configure; diff --git a/packages/dicom-image-loader/src/imageLoader/convertColorSpace.js b/packages/dicom-image-loader/src/imageLoader/convertColorSpace.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/convertColorSpace.js rename to packages/dicom-image-loader/src/imageLoader/convertColorSpace.ts diff --git a/packages/dicom-image-loader/src/imageLoader/createImage.js b/packages/dicom-image-loader/src/imageLoader/createImage.ts similarity index 87% rename from packages/dicom-image-loader/src/imageLoader/createImage.js rename to packages/dicom-image-loader/src/imageLoader/createImage.ts index 9523008bc..4361c0c6e 100644 --- a/packages/dicom-image-loader/src/imageLoader/createImage.js +++ b/packages/dicom-image-loader/src/imageLoader/createImage.ts @@ -1,16 +1,24 @@ +import { ByteArray } from 'dicom-parser'; import external from '../externalModules'; -import getImageFrame from './getImageFrame'; +import getMinMax from '../shared/getMinMax'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; +import { + CornerstoneMetadataImagePlaneModule, + CornerstoneMetadataSopCommonModule, +} from '../shared/types/metadata-modules'; +import convertColorSpace from './convertColorSpace'; +import { CornerstoneLoadImageOptions } from '../shared/types/load-image-options'; import decodeImageFrame from './decodeImageFrame'; +import getImageFrame from './getImageFrame'; +import getScalingParameters from './getScalingParameters'; +import { getOptions } from './internal/options'; import isColorImageFn from './isColorImage'; -import convertColorSpace from './convertColorSpace'; -import getMinMax from '../shared/getMinMax'; import isJPEGBaseline8BitColor from './isJPEGBaseline8BitColor'; -import { getOptions } from './internal/options'; -import getScalingParameters from './getScalingParameters'; +import { CornerstoneWadoLoaderIImage } from './wado-loader'; let lastImageIdDrawn = ''; -function isModalityLUTForDisplay(sopClassUid) { +function isModalityLUTForDisplay(sopClassUid: string): boolean { // special case for XA and XRF // https://groups.google.com/forum/#!searchin/comp.protocols.dicom/Modality$20LUT$20XA/comp.protocols.dicom/UBxhOZ2anJ0/D0R_QP8V2wIJ return ( @@ -54,7 +62,7 @@ function convertToIntPixelData(floatPixelData) { * can transfer array buffers but not typed arrays * @param imageFrame */ -function setPixelDataType(imageFrame) { +function setPixelDataType(imageFrame: CornerstoneWadoImageFrame) { if (imageFrame.bitsAllocated === 32) { imageFrame.pixelData = new Float32Array(imageFrame.pixelData); } else if (imageFrame.bitsAllocated === 16) { @@ -76,7 +84,15 @@ function setPixelDataType(imageFrame) { * @param imageFrame - decoded image in RGBA * @param targetBuffer - target buffer to write to */ -function removeAFromRGBA(imageFrame, targetBuffer) { +function removeAFromRGBA( + imageFrame: + | Float32Array // populated later after decoding + | Int16Array + | Uint16Array + | Uint8Array + | Uint8ClampedArray, + targetBuffer: Uint8ClampedArray +) { const numPixels = imageFrame.length / 4; let rgbIndex = 0; @@ -93,7 +109,12 @@ function removeAFromRGBA(imageFrame, targetBuffer) { return targetBuffer; } -function createImage(imageId, pixelData, transferSyntax, options = {}) { +function createImage( + imageId: string, + pixelData: ByteArray, + transferSyntax: string, + options: CornerstoneLoadImageOptions = {} +): Promise { // whether to use RGBA for color images, default true as cs-legacy uses RGBA // but we don't need RGBA in cs3d, and it's faster, and memory-efficient // in cs3d @@ -144,7 +165,7 @@ function createImage(imageId, pixelData, transferSyntax, options = {}) { const { decodeConfig } = getOptions(); const { convertFloatPixelDataToInt } = decodeConfig; - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { // eslint-disable-next-line complexity decodePromise.then(function (imageFrame) { // If we have a target buffer that was written to in the @@ -153,7 +174,7 @@ function createImage(imageId, pixelData, transferSyntax, options = {}) { let alreadyTyped = false; if (options.targetBuffer) { - let offset, length; + let offset: number, length: number; // If we have a target buffer, write to that instead. This helps reduce memory duplication. ({ offset, length } = options.targetBuffer); @@ -210,13 +231,13 @@ function createImage(imageId, pixelData, transferSyntax, options = {}) { setPixelDataType(imageFrame); } - const imagePlaneModule = + const imagePlaneModule: CornerstoneMetadataImagePlaneModule = cornerstone.metaData.get('imagePlaneModule', imageId) || {}; const voiLutModule = cornerstone.metaData.get('voiLutModule', imageId) || {}; const modalityLutModule = cornerstone.metaData.get('modalityLutModule', imageId) || {}; - const sopCommonModule = + const sopCommonModule: CornerstoneMetadataSopCommonModule = cornerstone.metaData.get('sopCommonModule', imageId) || {}; const isColorImage = isColorImageFn(imageFrame.photometricInterpretation); @@ -267,7 +288,8 @@ function createImage(imageId, pixelData, transferSyntax, options = {}) { convertColorSpace(imageFrame, imageData.data, true); - const colorBuffer = new imageData.data.constructor( + /** @todo check as any */ + const colorBuffer = new (imageData.data as any).constructor( (imageData.data.length / 4) * 3 ); @@ -276,14 +298,15 @@ function createImage(imageId, pixelData, transferSyntax, options = {}) { } } + /** @todo check as any */ // calculate smallest and largest PixelValue of the converted pixelData - const minMax = getMinMax(imageFrame.pixelData); + const minMax = getMinMax(imageFrame.pixelData as any); imageFrame.smallestPixelValue = minMax.min; imageFrame.largestPixelValue = minMax.max; } - const image = { + const image: CornerstoneWadoLoaderIImage = { imageId, color: isColorImage, columnPixelSpacing: imagePlaneModule.columnPixelSpacing, @@ -313,6 +336,9 @@ function createImage(imageId, pixelData, transferSyntax, options = {}) { floatPixelData: undefined, imageFrame, rgba: isColorImage && useRGBA, + getPixelData: undefined, + getCanvas: undefined, + numComps: undefined, }; // If pixel data is intrinsically floating 32 array, we convert it to int for @@ -330,9 +356,11 @@ function createImage(imageId, pixelData, transferSyntax, options = {}) { image.slope = results.slope; image.intercept = results.intercept; image.floatPixelData = floatPixelData; - image.getPixelData = () => results.intPixelData; + /** @todo check as any */ + image.getPixelData = () => results.intPixelData as any; } else { - image.getPixelData = () => imageFrame.pixelData; + /** @todo check as any */ + image.getPixelData = () => imageFrame.pixelData as any; } if (image.color) { diff --git a/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.js b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.ts similarity index 89% rename from packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.js rename to packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.ts index 0438ab10b..9c7f6369b 100644 --- a/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.js +++ b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame-noWorkers.ts @@ -1,10 +1,17 @@ -import { getOptions } from './internal/options'; import decodeJPEGBaseline8BitColor from './decodeJPEGBaseline8BitColor'; +import { getOptions } from './internal/options'; -import { default as decodeImageFrameHandler } from '../shared/decodeImageFrame'; +import { ByteArray } from 'dicom-parser'; import calculateMinMax from '../shared/calculateMinMax'; +import { default as decodeImageFrameHandler } from '../shared/decodeImageFrame'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; -function processDecodeTask(imageFrame, transferSyntax, pixelData, options) { +function processDecodeTask( + imageFrame: CornerstoneWadoImageFrame, + transferSyntax: string, + pixelData: ByteArray, + options +): Promise { const loaderOptions = getOptions(); const { strict, decodeConfig } = loaderOptions; @@ -33,12 +40,12 @@ function processDecodeTask(imageFrame, transferSyntax, pixelData, options) { } function decodeImageFrame( - imageFrame, - transferSyntax, - pixelData, - canvas, + imageFrame: CornerstoneWadoImageFrame, + transferSyntax: string, + pixelData: ByteArray, + canvas: HTMLCanvasElement, options = {} -) { +): Promise { switch (transferSyntax) { case '1.2.840.10008.1.2': // Implicit VR Little Endian diff --git a/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.js b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.ts similarity index 86% rename from packages/dicom-image-loader/src/imageLoader/decodeImageFrame.js rename to packages/dicom-image-loader/src/imageLoader/decodeImageFrame.ts index c5bcca2dd..2248eecfb 100644 --- a/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.js +++ b/packages/dicom-image-loader/src/imageLoader/decodeImageFrame.ts @@ -5,16 +5,26 @@ import decodeJPEGBaseline8BitColor from './decodeJPEGBaseline8BitColor'; // We only need one function though, so lets import that so we don't make our bundle // too large. import { inflateRaw } from 'pako/lib/inflate'; +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; -window.pako = { inflateRaw }; +/** + * @todo check any + */ +(window as any).pako = { inflateRaw }; -function processDecodeTask(imageFrame, transferSyntax, pixelData, options) { +function processDecodeTask( + imageFrame: CornerstoneWadoImageFrame, + transferSyntax: string, + pixelData: ByteArray, + options +): Promise { const priority = options.priority || undefined; const transferList = options.transferPixelData ? [pixelData.buffer] : undefined; - return webWorkerManager.addTask( + return webWorkerManager.addTask( 'decodeTask', { imageFrame, @@ -28,12 +38,12 @@ function processDecodeTask(imageFrame, transferSyntax, pixelData, options) { } function decodeImageFrame( - imageFrame, - transferSyntax, - pixelData, - canvas, + imageFrame: CornerstoneWadoImageFrame, + transferSyntax: string, + pixelData: ByteArray, + canvas: HTMLCanvasElement, options = {} -) { +): Promise { switch (transferSyntax) { case '1.2.840.10008.1.2': // Implicit VR Little Endian diff --git a/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.js b/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.ts similarity index 75% rename from packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.js rename to packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.ts index f34cbd345..663e7555e 100644 --- a/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.js +++ b/packages/dicom-image-loader/src/imageLoader/decodeJPEGBaseline8BitColor.ts @@ -1,10 +1,12 @@ +import { ByteArray } from 'dicom-parser'; import getMinMax from '../shared/getMinMax'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; /** * Special decoder for 8 bit jpeg that leverages the browser's built in JPEG decoder for increased performance */ -function arrayBufferToString(buffer) { +function arrayBufferToString(buffer: ArrayBuffer) { return binaryToString( String.fromCharCode.apply( null, @@ -13,7 +15,7 @@ function arrayBufferToString(buffer) { ); } -function binaryToString(binary) { +function binaryToString(binary: string) { let error; try { @@ -27,7 +29,11 @@ function binaryToString(binary) { } } -function decodeJPEGBaseline8BitColor(imageFrame, pixelData, canvas) { +function decodeJPEGBaseline8BitColor( + imageFrame: CornerstoneWadoImageFrame, + pixelData: ByteArray, + canvas: HTMLCanvasElement +): Promise { const start = new Date().getTime(); const imgBlob = new Blob([pixelData], { type: 'image/jpeg' }); @@ -50,7 +56,10 @@ function decodeJPEGBaseline8BitColor(imageFrame, pixelData, canvas) { imageFrame.columns = img.width; const context = canvas.getContext('2d'); - context.drawImage(this, 0, 0); + /** + * @todo check this context + */ + context.drawImage(this as any, 0, 0); const imageData = context.getImageData(0, 0, img.width, img.height); const end = new Date().getTime(); @@ -73,10 +82,12 @@ function decodeJPEGBaseline8BitColor(imageFrame, pixelData, canvas) { if (fileReader.readAsBinaryString === undefined) { img.src = `data:image/jpeg;base64,${window.btoa( - arrayBufferToString(fileReader.result) + arrayBufferToString(fileReader.result as ArrayBuffer) )}`; } else { - img.src = `data:image/jpeg;base64,${window.btoa(fileReader.result)}`; // doesn't work on IE11 + img.src = `data:image/jpeg;base64,${window.btoa( + fileReader.result as string + )}`; // doesn't work on IE11 } }; diff --git a/packages/dicom-image-loader/src/imageLoader/getImageFrame.js b/packages/dicom-image-loader/src/imageLoader/getImageFrame.ts similarity index 79% rename from packages/dicom-image-loader/src/imageLoader/getImageFrame.js rename to packages/dicom-image-loader/src/imageLoader/getImageFrame.ts index 5673263c2..1c313812a 100644 --- a/packages/dicom-image-loader/src/imageLoader/getImageFrame.js +++ b/packages/dicom-image-loader/src/imageLoader/getImageFrame.ts @@ -1,11 +1,11 @@ import external from '../externalModules'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; +import { CornerstoneMetadataImagePixelModule } from '../shared/types/metadata-modules'; -function getImageFrame(imageId) { +function getImageFrame(imageId: string): CornerstoneWadoImageFrame { const { cornerstone } = external; - const imagePixelModule = cornerstone.metaData.get( - 'imagePixelModule', - imageId - ); + const imagePixelModule: CornerstoneMetadataImagePixelModule = + cornerstone.metaData.get('imagePixelModule', imageId); return { samplesPerPixel: imagePixelModule.samplesPerPixel, diff --git a/packages/dicom-image-loader/src/imageLoader/getMinMax.js b/packages/dicom-image-loader/src/imageLoader/getMinMax.ts similarity index 83% rename from packages/dicom-image-loader/src/imageLoader/getMinMax.js rename to packages/dicom-image-loader/src/imageLoader/getMinMax.ts index c59e817e4..b63f021f7 100644 --- a/packages/dicom-image-loader/src/imageLoader/getMinMax.js +++ b/packages/dicom-image-loader/src/imageLoader/getMinMax.ts @@ -1,4 +1,7 @@ -export default function getMinMax(storedPixelData) { +export default function getMinMax(storedPixelData: ArrayLike): { + min: number; + max: number; +} { // we always calculate the min max values since they are not always // present in DICOM and we don't want to trust them anyway as cornerstone // depends on us providing reliable values for these diff --git a/packages/dicom-image-loader/src/imageLoader/getScalingParameters.js b/packages/dicom-image-loader/src/imageLoader/getScalingParameters.ts similarity index 70% rename from packages/dicom-image-loader/src/imageLoader/getScalingParameters.js rename to packages/dicom-image-loader/src/imageLoader/getScalingParameters.ts index 30372bc8e..418e3b61a 100644 --- a/packages/dicom-image-loader/src/imageLoader/getScalingParameters.js +++ b/packages/dicom-image-loader/src/imageLoader/getScalingParameters.ts @@ -1,3 +1,6 @@ +import { CornerstoneMetadataGeneralSeriesModule } from '../shared/types/metadata-modules'; +import type * as cornerstoneImport from '@cornerstonejs/core'; + /** * It returns the scaling parameters for the image with the given imageId. This can be * used to get passed (as an option) to the imageLoader in order to apply scaling to the image inside @@ -5,10 +8,13 @@ * @param imageId - The imageId of the image * @returns ScalingParameters */ -export default function getScalingParameters(metaData, imageId) { +export default function getScalingParameters( + metaData: typeof cornerstoneImport.metaData, + imageId: string +) { const modalityLutModule = metaData.get('modalityLutModule', imageId) || {}; - const generalSeriesModule = + const generalSeriesModule: CornerstoneMetadataGeneralSeriesModule = metaData.get('generalSeriesModule', imageId) || {}; const { modality } = generalSeriesModule; diff --git a/packages/dicom-image-loader/src/imageLoader/imageIdToURI.js b/packages/dicom-image-loader/src/imageLoader/imageIdToURI.ts similarity index 80% rename from packages/dicom-image-loader/src/imageLoader/imageIdToURI.js rename to packages/dicom-image-loader/src/imageLoader/imageIdToURI.ts index 7be55b075..4813c2c5f 100644 --- a/packages/dicom-image-loader/src/imageLoader/imageIdToURI.js +++ b/packages/dicom-image-loader/src/imageLoader/imageIdToURI.ts @@ -5,7 +5,7 @@ * @returns {string} imageId without the data loader scheme * @memberof Cache */ -export default function imageIdToURI(imageId) { +export default function imageIdToURI(imageId: string): string { const colonIndex = imageId.indexOf(':'); return imageId.substring(colonIndex + 1); diff --git a/packages/dicom-image-loader/src/imageLoader/index-noWorkers.js b/packages/dicom-image-loader/src/imageLoader/index-noWorkers.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/index-noWorkers.js rename to packages/dicom-image-loader/src/imageLoader/index-noWorkers.ts diff --git a/packages/dicom-image-loader/src/imageLoader/index.js b/packages/dicom-image-loader/src/imageLoader/index.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/index.js rename to packages/dicom-image-loader/src/imageLoader/index.ts diff --git a/packages/dicom-image-loader/src/imageLoader/internal/index.js b/packages/dicom-image-loader/src/imageLoader/internal/index.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/internal/index.js rename to packages/dicom-image-loader/src/imageLoader/internal/index.ts diff --git a/packages/dicom-image-loader/src/imageLoader/internal/options.js b/packages/dicom-image-loader/src/imageLoader/internal/options.js deleted file mode 100644 index 90cfe4fed..000000000 --- a/packages/dicom-image-loader/src/imageLoader/internal/options.js +++ /dev/null @@ -1,22 +0,0 @@ -let options = { - // callback allowing customization of the xhr (e.g. adding custom auth headers, cors, etc) - beforeSend(/* xhr, imageId */) {}, - // callback allowing modification of the xhr response before creating image objects - beforeProcessing(xhr) { - return Promise.resolve(xhr.response); - }, - // callback allowing modification of newly created image objects - imageCreated(/* image */) {}, - strict: false, - decodeConfig: { - convertFloatPixelDataToInt: true, - }, -}; - -export function setOptions(newOptions) { - options = Object.assign(options, newOptions); -} - -export function getOptions() { - return options; -} diff --git a/packages/dicom-image-loader/src/imageLoader/internal/options.ts b/packages/dicom-image-loader/src/imageLoader/internal/options.ts new file mode 100644 index 000000000..18bc505ab --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/internal/options.ts @@ -0,0 +1,50 @@ +import { + CornerstoneWadoLoaderXhrRequestError, + CornerstoneWadoLoaderXhrRequestParams, +} from './xhrRequest'; + +export interface CornerstoneWadoLoaderOptions { + // callback allowing customization of the xhr (e.g. adding custom auth headers, cors, etc) + beforeSend: ( + xhr: XMLHttpRequest, + imageId: string, + defaultHeaders: Record, + params: CornerstoneWadoLoaderXhrRequestParams + ) => Record | void; + // callback allowing modification of the xhr response before creating image objects + beforeProcessing: (xhr: XMLHttpRequest) => Promise; + // callback allowing modification of newly created image objects + imageCreated: (...args: any[]) => void; + onloadstart?: (event: ProgressEvent, params: any) => void; + onloadend?: (event: ProgressEvent, params: any) => void; + onreadystatechange?: (event: Event, params: any) => void; + onprogress?: (event: ProgressEvent, params: any) => void; + errorInterceptor?: (error: CornerstoneWadoLoaderXhrRequestError) => void; + strict: boolean; + decodeConfig: { + convertFloatPixelDataToInt: boolean; + }; +} + +let options: CornerstoneWadoLoaderOptions = { + // callback allowing customization of the xhr (e.g. adding custom auth headers, cors, etc) + beforeSend(/* xhr, imageId */) {}, + // callback allowing modification of the xhr response before creating image objects + beforeProcessing(xhr: XMLHttpRequest) { + return Promise.resolve(xhr.response as ArrayBuffer); + }, + // callback allowing modification of newly created image objects + imageCreated(/* image */) {}, + strict: false, + decodeConfig: { + convertFloatPixelDataToInt: true, + }, +}; + +export function setOptions(newOptions: CornerstoneWadoLoaderOptions): void { + options = Object.assign(options, newOptions); +} + +export function getOptions(): CornerstoneWadoLoaderOptions { + return options; +} diff --git a/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.js b/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.ts similarity index 79% rename from packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.js rename to packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.ts index 928558430..dc5fdf7da 100644 --- a/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.js +++ b/packages/dicom-image-loader/src/imageLoader/internal/xhrRequest.ts @@ -1,13 +1,38 @@ import external from '../../externalModules'; import { getOptions } from './options'; -function xhrRequest(url, imageId, defaultHeaders = {}, params = {}) { +export interface CornerstoneWadoLoaderXhrRequestError extends Error { + request: XMLHttpRequest; + response: any; + status: number; +} + +/** + * @description mutable object + */ +export interface CornerstoneWadoLoaderXhrRequestParams { + url?: string; + deferred?: { + resolve: (value: ArrayBuffer | PromiseLike) => void; + reject: (reason?: any) => void; + }; + imageId?: string; +} + +function xhrRequest( + url: string, + imageId: string, + defaultHeaders: Record = {}, + params: CornerstoneWadoLoaderXhrRequestParams = {} +): Promise { const { cornerstone } = external; const options = getOptions(); - const errorInterceptor = (xhr) => { + const errorInterceptor = (xhr: XMLHttpRequest) => { if (typeof options.errorInterceptor === 'function') { - const error = new Error('request failed'); + const error = new Error( + 'request failed' + ) as CornerstoneWadoLoaderXhrRequestError; error.request = xhr; error.response = xhr.response; @@ -17,7 +42,7 @@ function xhrRequest(url, imageId, defaultHeaders = {}, params = {}) { }; // Make the request for the DICOM P10 SOP Instance - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('get', url, true); @@ -63,7 +88,7 @@ function xhrRequest(url, imageId, defaultHeaders = {}, params = {}) { }; cornerstone.triggerEvent( - cornerstone.events, + (cornerstone as any).events, 'cornerstoneimageloadstart', eventData ); @@ -83,7 +108,7 @@ function xhrRequest(url, imageId, defaultHeaders = {}, params = {}) { // Event cornerstone.triggerEvent( - cornerstone.events, + (cornerstone as any).events, 'cornerstoneimageloadend', eventData ); @@ -124,9 +149,9 @@ function xhrRequest(url, imageId, defaultHeaders = {}, params = {}) { // console.log('progress:',oProgress) const loaded = oProgress.loaded; // evt.loaded the bytes browser receive - let total; + let total: number; - let percentComplete; + let percentComplete: number; if (oProgress.lengthComputable) { total = oProgress.total; // evt.total the total bytes seted by the header @@ -148,7 +173,7 @@ function xhrRequest(url, imageId, defaultHeaders = {}, params = {}) { }; cornerstone.triggerEvent( - cornerstone.events, + (cornerstone as any).events, cornerstone.EVENTS.IMAGE_LOAD_PROGRESS, eventData ); diff --git a/packages/dicom-image-loader/src/imageLoader/isColorImage.js b/packages/dicom-image-loader/src/imageLoader/isColorImage.ts similarity index 85% rename from packages/dicom-image-loader/src/imageLoader/isColorImage.js rename to packages/dicom-image-loader/src/imageLoader/isColorImage.ts index bc75fffaa..e6edfa634 100644 --- a/packages/dicom-image-loader/src/imageLoader/isColorImage.js +++ b/packages/dicom-image-loader/src/imageLoader/isColorImage.ts @@ -1,4 +1,4 @@ -export default function (photoMetricInterpretation) { +export default function (photoMetricInterpretation: string): boolean { return ( photoMetricInterpretation === 'RGB' || photoMetricInterpretation === 'PALETTE COLOR' || diff --git a/packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.js b/packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.js deleted file mode 100644 index 1b2bf5f16..000000000 --- a/packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.js +++ /dev/null @@ -1,13 +0,0 @@ -function isJPEGBaseline8BitColor(imageFrame, transferSyntax) { - transferSyntax = transferSyntax || imageFrame.transferSyntax; - - if ( - imageFrame.bitsAllocated === 8 && - transferSyntax === '1.2.840.10008.1.2.4.50' && - (imageFrame.samplesPerPixel === 3 || imageFrame.samplesPerPixel === 4) - ) { - return true; - } -} - -export default isJPEGBaseline8BitColor; diff --git a/packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.ts b/packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.ts new file mode 100644 index 000000000..f9a19994a --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/isJPEGBaseline8BitColor.ts @@ -0,0 +1,19 @@ +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; + +function isJPEGBaseline8BitColor( + imageFrame: CornerstoneWadoImageFrame, + transferSyntax: string +): boolean { + /** @todo check as any */ + transferSyntax = transferSyntax || (imageFrame as any).transferSyntax; + + if ( + imageFrame.bitsAllocated === 8 && + transferSyntax === '1.2.840.10008.1.2.4.50' && + (imageFrame.samplesPerPixel === 3 || imageFrame.samplesPerPixel === 4) + ) { + return true; + } +} + +export default isJPEGBaseline8BitColor; diff --git a/packages/dicom-image-loader/src/imageLoader/registerLoaders.js b/packages/dicom-image-loader/src/imageLoader/registerLoaders.ts similarity index 74% rename from packages/dicom-image-loader/src/imageLoader/registerLoaders.js rename to packages/dicom-image-loader/src/imageLoader/registerLoaders.ts index 4ecd98d94..67722ef89 100644 --- a/packages/dicom-image-loader/src/imageLoader/registerLoaders.js +++ b/packages/dicom-image-loader/src/imageLoader/registerLoaders.ts @@ -1,5 +1,6 @@ import wadors from './wadors/index'; import wadouri from './wadouri/index'; +import * as cornerstoneImport from '@cornerstonejs/core'; /** * Register the WADO-URI and WADO-RS image loaders and metaData providers @@ -7,7 +8,7 @@ import wadouri from './wadouri/index'; * * @param cornerstone The Cornerstone Core library to register the image loaders with */ -function registerLoaders(cornerstone) { +function registerLoaders(cornerstone: typeof cornerstoneImport): void { wadors.register(cornerstone); wadouri.register(cornerstone); } diff --git a/packages/dicom-image-loader/src/imageLoader/wado-loader.ts b/packages/dicom-image-loader/src/imageLoader/wado-loader.ts new file mode 100644 index 000000000..b9a53234b --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wado-loader.ts @@ -0,0 +1,18 @@ +import type { Types } from '@cornerstonejs/core'; +import { ByteArray, DataSet } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; + +export interface CornerstoneWadoLoaderIImage extends Types.IImage { + decodeTimeInMS: number; + floatPixelData?: ByteArray | Float32Array; + loadTimeInMS?: number; + totalTimeInMS?: number; + data?: DataSet; + imageFrame?: CornerstoneWadoImageFrame; +} + +export interface CornerstoneWadoLoaderIImageLoadObject + extends Types.IImageLoadObject { + promise: Promise; + decache?: () => void; +} diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.js b/packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.ts similarity index 77% rename from packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.js rename to packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.ts index f703ecb66..f5bbd3583 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/findIndexOfString.ts @@ -1,4 +1,4 @@ -function checkToken(token, data, dataOffset) { +function checkToken(token, data, dataOffset): boolean { if (dataOffset + token.length > data.length) { return false; } @@ -14,7 +14,7 @@ function checkToken(token, data, dataOffset) { return true; } -function stringToUint8Array(str) { +function stringToUint8Array(str: string): Uint8Array { const uint = new Uint8Array(str.length); for (let i = 0, j = str.length; i < j; i++) { @@ -24,7 +24,11 @@ function stringToUint8Array(str) { return uint; } -function findIndexOfString(data, str, offset) { +function findIndexOfString( + data: Uint8Array, + str: string, + offset?: number +): number { offset = offset || 0; const token = stringToUint8Array(str); diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.js b/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.ts similarity index 83% rename from packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.js rename to packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.ts index 6135a923d..3fa4e64a0 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/getPixelData.ts @@ -1,7 +1,7 @@ import { xhrRequest } from '../internal/index'; import findIndexOfString from './findIndexOfString'; -function findBoundary(header) { +function findBoundary(header: string[]): string { for (let i = 0; i < header.length; i++) { if (header[i].substr(0, 2) === '--') { return header[i]; @@ -9,7 +9,7 @@ function findBoundary(header) { } } -function findContentType(header) { +function findContentType(header: string[]): string { for (let i = 0; i < header.length; i++) { if (header[i].substr(0, 13) === 'Content-Type:') { return header[i].substr(13).trim(); @@ -29,12 +29,22 @@ function uint8ArrayToString(data, offset, length) { return str; } -function getPixelData(uri, imageId, mediaType = 'application/octet-stream') { +export interface GetPixelDataResponse { + contentType: string; + imageFrame: { + pixelData: Uint8Array; + }; +} +function getPixelData( + uri: string, + imageId: string, + mediaType = 'application/octet-stream' +): Promise { const headers = { Accept: mediaType, }; - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const loadPromise = xhrRequest(uri, imageId, headers); loadPromise.then(function (imageFrameAsArrayBuffer /* , xhr*/) { diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/index.js b/packages/dicom-image-loader/src/imageLoader/wadors/index.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/index.js rename to packages/dicom-image-loader/src/imageLoader/wadors/index.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.js b/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.js deleted file mode 100644 index 4adb88502..000000000 --- a/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.js +++ /dev/null @@ -1,132 +0,0 @@ -import external from '../../externalModules'; -import getPixelData from './getPixelData'; -import createImage from '../createImage'; - -/** - * Helper method to extract the transfer-syntax from the response of the server. - * @param {string} contentType The value of the content-type header as returned by the WADO-RS server. - * @return The transfer-syntax as announced by the server, or Implicit Little Endian by default. - */ -export function getTransferSyntaxForContentType(contentType) { - const defaultTransferSyntax = '1.2.840.10008.1.2'; // Default is Implicit Little Endian. - - if (!contentType) { - return defaultTransferSyntax; - } - - // Browse through the content type parameters - const parameters = contentType.split(';'); - const params = {}; - - parameters.forEach((parameter) => { - // Look for a transfer-syntax=XXXX pair - const parameterValues = parameter.split('='); - - if (parameterValues.length !== 2) { - return; - } - - const value = parameterValues[1].trim().replace(/"/g, ''); - - params[parameterValues[0].trim()] = value; - }); - - // This is useful if the PACS doesn't respond with a syntax - // in the content type. - // http://dicom.nema.org/medical/dicom/current/output/chtml/part18/chapter_6.html#table_6.1.1.8-3b - const defaultTransferSyntaxByType = { - 'image/jpeg': '1.2.840.10008.1.2.4.50', - 'image/x-dicom-rle': '1.2.840.10008.1.2.5', - 'image/x-jls': '1.2.840.10008.1.2.4.80', - 'image/jls': '1.2.840.10008.1.2.4.80', - 'image/jll': '1.2.840.10008.1.2.4.70', - 'image/jp2': '1.2.840.10008.1.2.4.90', - 'image/jpx': '1.2.840.10008.1.2.4.92', - }; - - if (params['transfer-syntax']) { - return params['transfer-syntax']; - } else if ( - contentType && - !Object.keys(params).length && - defaultTransferSyntaxByType[contentType] - ) { - // dcm4che seems to be reporting the content type as just 'image/jp2'? - return defaultTransferSyntaxByType[contentType]; - } else if (params.type && defaultTransferSyntaxByType[params.type]) { - return defaultTransferSyntaxByType[params.type]; - } - - return defaultTransferSyntax; -} - -function getImageRetrievalPool() { - return external.cornerstone.imageRetrievalPoolManager; -} - -function loadImage(imageId, options = {}) { - const imageRetrievalPool = getImageRetrievalPool(); - - const start = new Date().getTime(); - - const promise = new Promise((resolve, reject) => { - // TODO: load bulk data items that we might need - - // Uncomment this on to test jpegls codec in OHIF - // const mediaType = 'multipart/related; type="image/x-jls"'; - // const mediaType = 'multipart/related; type="application/octet-stream"; transfer-syntax="image/x-jls"'; - const mediaType = - 'multipart/related; type=application/octet-stream; transfer-syntax=*'; - // const mediaType = - // 'multipart/related; type="image/jpeg"; transfer-syntax=1.2.840.10008.1.2.4.50'; - - function sendXHR(imageURI, imageId, mediaType) { - // get the pixel data from the server - return getPixelData(imageURI, imageId, mediaType) - .then((result) => { - const transferSyntax = getTransferSyntaxForContentType( - result.contentType - ); - const pixelData = result.imageFrame.pixelData; - const imagePromise = createImage( - imageId, - pixelData, - transferSyntax, - options - ); - - imagePromise.then((image) => { - // add the loadTimeInMS property - const end = new Date().getTime(); - - image.loadTimeInMS = end - start; - resolve(image); - }, reject); - }, reject) - .catch((error) => { - reject(error); - }); - } - - const requestType = options.requestType || 'interaction'; - const additionalDetails = options.additionalDetails || { imageId }; - const priority = options.priority === undefined ? 5 : options.priority; - const addToBeginning = options.addToBeginning || false; - const uri = imageId.substring(7); - - imageRetrievalPool.addRequest( - sendXHR.bind(this, uri, imageId, mediaType), - requestType, - additionalDetails, - priority, - addToBeginning - ); - }); - - return { - promise, - cancelFn: undefined, - }; -} - -export default loadImage; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.ts b/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.ts new file mode 100644 index 000000000..c18168b52 --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/loadImage.ts @@ -0,0 +1,155 @@ +import { CornerstoneLoadImageOptions } from 'dicom-image-loader/src/shared/types/load-image-options'; +import external from '../../externalModules'; +import createImage from '../createImage'; +import { + CornerstoneWadoLoaderIImage, + CornerstoneWadoLoaderIImageLoadObject, +} from '../wado-loader'; +import getPixelData from './getPixelData'; + +/** + * Helper method to extract the transfer-syntax from the response of the server. + * @param {string} contentType The value of the content-type header as returned by the WADO-RS server. + * @return The transfer-syntax as announced by the server, or Implicit Little Endian by default. + */ +export function getTransferSyntaxForContentType(contentType: string): string { + const defaultTransferSyntax = '1.2.840.10008.1.2'; // Default is Implicit Little Endian. + + if (!contentType) { + return defaultTransferSyntax; + } + + // Browse through the content type parameters + const parameters = contentType.split(';'); + const params: Record = {}; + + parameters.forEach((parameter) => { + // Look for a transfer-syntax=XXXX pair + const parameterValues = parameter.split('='); + + if (parameterValues.length !== 2) { + return; + } + + const value = parameterValues[1].trim().replace(/"/g, ''); + + params[parameterValues[0].trim()] = value; + }); + + // This is useful if the PACS doesn't respond with a syntax + // in the content type. + // http://dicom.nema.org/medical/dicom/current/output/chtml/part18/chapter_6.html#table_6.1.1.8-3b + const defaultTransferSyntaxByType = { + 'image/jpeg': '1.2.840.10008.1.2.4.50', + 'image/x-dicom-rle': '1.2.840.10008.1.2.5', + 'image/x-jls': '1.2.840.10008.1.2.4.80', + 'image/jls': '1.2.840.10008.1.2.4.80', + 'image/jll': '1.2.840.10008.1.2.4.70', + 'image/jp2': '1.2.840.10008.1.2.4.90', + 'image/jpx': '1.2.840.10008.1.2.4.92', + }; + + if (params['transfer-syntax']) { + return params['transfer-syntax']; + } else if ( + contentType && + !Object.keys(params).length && + defaultTransferSyntaxByType[contentType] + ) { + // dcm4che seems to be reporting the content type as just 'image/jp2'? + return defaultTransferSyntaxByType[contentType]; + } else if (params.type && defaultTransferSyntaxByType[params.type]) { + return defaultTransferSyntaxByType[params.type]; + } + + return defaultTransferSyntax; +} + +function getImageRetrievalPool() { + return external.cornerstone.imageRetrievalPoolManager; +} + +export interface CornerstoneWadoRsLoaderOptions + extends CornerstoneLoadImageOptions { + requestType?: string; + additionalDetails?: { + imageId: string; + }; + priority?: number; + addToBeginning?: boolean; +} + +function loadImage( + imageId: string, + options: CornerstoneWadoRsLoaderOptions = {} +): CornerstoneWadoLoaderIImageLoadObject { + const imageRetrievalPool = getImageRetrievalPool(); + + const start = new Date().getTime(); + + const promise = new Promise( + (resolve, reject) => { + // TODO: load bulk data items that we might need + + // Uncomment this on to test jpegls codec in OHIF + // const mediaType = 'multipart/related; type="image/x-jls"'; + // const mediaType = 'multipart/related; type="application/octet-stream"; transfer-syntax="image/x-jls"'; + const mediaType = + 'multipart/related; type=application/octet-stream; transfer-syntax=*'; + // const mediaType = + // 'multipart/related; type="image/jpeg"; transfer-syntax=1.2.840.10008.1.2.4.50'; + + function sendXHR(imageURI: string, imageId: string, mediaType: string) { + // get the pixel data from the server + return getPixelData(imageURI, imageId, mediaType) + .then((result) => { + const transferSyntax = getTransferSyntaxForContentType( + result.contentType + ); + const pixelData = result.imageFrame.pixelData; + const imagePromise = createImage( + imageId, + pixelData, + transferSyntax, + options + ); + + imagePromise.then((image) => { + // add the loadTimeInMS property + const end = new Date().getTime(); + + image.loadTimeInMS = end - start; + resolve(image); + }, reject); + }, reject) + .catch((error) => { + reject(error); + }); + } + + const requestType = options.requestType || 'interaction'; + const additionalDetails = options.additionalDetails || { imageId }; + const priority = options.priority === undefined ? 5 : options.priority; + const addToBeginning = options.addToBeginning || false; + const uri = imageId.substring(7); + + /** + * @todo check arguments + */ + imageRetrievalPool.addRequest( + sendXHR.bind(this, uri, imageId, mediaType), + requestType, + additionalDetails, + priority, + addToBeginning + ); + } + ); + + return { + promise, + cancelFn: undefined, + }; +} + +export default loadImage; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/loadImage_test.js b/packages/dicom-image-loader/src/imageLoader/wadors/loadImage_test.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/loadImage_test.js rename to packages/dicom-image-loader/src/imageLoader/wadors/loadImage_test.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.ts similarity index 77% rename from packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.js rename to packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.ts index aae181c53..8c3ed5d01 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberString.ts @@ -1,3 +1,4 @@ +import { WadoRsMetaDataElement } from '../wado-rs-metadata'; import getValue from './getValue'; /** @@ -8,7 +9,11 @@ import getValue from './getValue'; * @param [defaultValue] - The default value to return if the element does not exist * @returns {*} */ -function getNumberString(element, index, defaultValue) { +function getNumberString( + element: WadoRsMetaDataElement, + index: number, + defaultValue +) { const value = getValue(element, index, defaultValue); if (value === undefined) { diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.ts similarity index 55% rename from packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.js rename to packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.ts index ad1c39374..a76e038d7 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValue.ts @@ -1,6 +1,10 @@ +import { WadoRsMetaDataElement } from '../wado-rs-metadata'; import getValue from './getValue'; -function getNumberValue(element, index) { +function getNumberValue( + element: WadoRsMetaDataElement, + index?: number +): number { const value = getValue(element, index); if (value === undefined) { diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.ts similarity index 70% rename from packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.js rename to packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.ts index 8a1199598..983831953 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getNumberValues.ts @@ -1,3 +1,5 @@ +import { WadoRsMetaDataElement } from '../wado-rs-metadata'; + /** * Returns the values as an array of javascript numbers * @@ -5,7 +7,10 @@ * @param [minimumLength] - the minimum number of values * @returns {*} */ -function getNumberValues(element, minimumLength) { +function getNumberValues( + element: WadoRsMetaDataElement, + minimumLength?: number +): number[] { if (!element) { return; } @@ -18,10 +23,10 @@ function getNumberValues(element, minimumLength) { return; } - const values = []; + const values: number[] = []; for (let i = 0; i < element.Value.length; i++) { - values.push(parseFloat(element.Value[i])); + values.push(parseFloat(element.Value[i] as string)); } return values; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.ts similarity index 91% rename from packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.js rename to packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.ts index 516a572ce..e460f5c07 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getOverlayPlaneModule.ts @@ -1,7 +1,8 @@ import getValue from './getValue'; import getNumberValue from './getNumberValue'; +import { WadoRsMetaData } from '../wado-rs-metadata'; -export default function getOverlayPlaneModule(metaData) { +export default function getOverlayPlaneModule(metaData: WadoRsMetaData) { const overlays = []; for (let overlayGroup = 0x00; overlayGroup <= 0x1e; overlayGroup += 0x02) { diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.ts similarity index 79% rename from packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.js rename to packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.ts index 334b46e7b..816a6b8ec 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/getValue.ts @@ -1,3 +1,5 @@ +import { WadoRsMetaDataElement } from '../wado-rs-metadata'; + /** * Returns the raw value * @@ -6,7 +8,11 @@ * @param [defaultValue] - The default value to return if the element does not exist * @returns {*} */ -function getValue(element, index, defaultValue) { +function getValue( + element: WadoRsMetaDataElement, + index?: number, + defaultValue?: number | string +) { index = index || 0; if (!element) { return defaultValue; diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/index.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/index.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadors/metaData/index.js rename to packages/dicom-image-loader/src/imageLoader/wadors/metaData/index.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.ts similarity index 91% rename from packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.js rename to packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.ts index 13db5d719..1a4d0d2b4 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaData/metaDataProvider.ts @@ -5,7 +5,7 @@ import getNumberValue from './getNumberValue'; import getOverlayPlaneModule from './getOverlayPlaneModule'; import metaDataManager from '../metaDataManager'; -function metaDataProvider(type, imageId) { +function metaDataProvider(type: string, imageId: string) { const { dicomParser } = external; const metaData = metaDataManager.get(imageId); @@ -52,14 +52,14 @@ function metaDataProvider(type, imageId) { if (imageOrientationPatient) { rowCosines = [ - parseFloat(imageOrientationPatient[0]), - parseFloat(imageOrientationPatient[1]), - parseFloat(imageOrientationPatient[2]), + parseFloat(imageOrientationPatient[0] as any), + parseFloat(imageOrientationPatient[1] as any), + parseFloat(imageOrientationPatient[2] as any), ]; columnCosines = [ - parseFloat(imageOrientationPatient[3]), - parseFloat(imageOrientationPatient[4]), - parseFloat(imageOrientationPatient[5]), + parseFloat(imageOrientationPatient[3] as any), + parseFloat(imageOrientationPatient[4] as any), + parseFloat(imageOrientationPatient[5] as any), ]; } @@ -142,7 +142,7 @@ function metaDataProvider(type, imageId) { return { radiopharmaceuticalInfo: { radiopharmaceuticalStartTime: dicomParser.parseTM( - getValue(radiopharmaceuticalInfo['00181072'], 0, '') + getValue(radiopharmaceuticalInfo['00181072'], 0, '') as string ), radionuclideTotalDose: getNumberValue( radiopharmaceuticalInfo['00181074'] diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.js b/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.ts similarity index 58% rename from packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.js rename to packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.ts index 1139e2699..c84369cb6 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/metaDataManager.ts @@ -1,26 +1,27 @@ import imageIdToURI from '../imageIdToURI'; +import { WadoRsMetaData } from './wado-rs-metadata'; -let metadataByImageURI = []; +let metadataByImageURI: WadoRsMetaData[] = []; -function add(imageId, metadata) { +function add(imageId: string, metadata: WadoRsMetaData): void { const imageURI = imageIdToURI(imageId); metadataByImageURI[imageURI] = metadata; } -function get(imageId) { +function get(imageId: string): WadoRsMetaData { const imageURI = imageIdToURI(imageId); return metadataByImageURI[imageURI]; } -function remove(imageId) { +function remove(imageId: string): void { const imageURI = imageIdToURI(imageId); metadataByImageURI[imageURI] = undefined; } -function purge() { +function purge(): void { metadataByImageURI = []; } diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/register.js b/packages/dicom-image-loader/src/imageLoader/wadors/register.ts similarity index 66% rename from packages/dicom-image-loader/src/imageLoader/wadors/register.js rename to packages/dicom-image-loader/src/imageLoader/wadors/register.ts index 3451be2d5..913dd9079 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadors/register.js +++ b/packages/dicom-image-loader/src/imageLoader/wadors/register.ts @@ -1,7 +1,8 @@ +import * as cornerstoneImport from '@cornerstonejs/core'; import loadImage from './loadImage'; import { metaDataProvider } from './metaData/index'; -export default function (cornerstone) { +export default function (cornerstone: typeof cornerstoneImport): void { // register wadors scheme and metadata provider cornerstone.registerImageLoader('wadors', loadImage); cornerstone.metaData.addProvider(metaDataProvider); diff --git a/packages/dicom-image-loader/src/imageLoader/wadors/wado-rs-metadata.ts b/packages/dicom-image-loader/src/imageLoader/wadors/wado-rs-metadata.ts new file mode 100644 index 000000000..f455c724c --- /dev/null +++ b/packages/dicom-image-loader/src/imageLoader/wadors/wado-rs-metadata.ts @@ -0,0 +1,5 @@ +export interface WadoRsMetaDataElement { + Value: string[] | number[]; +} + +export type WadoRsMetaData = Record; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.js b/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.ts similarity index 51% rename from packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.ts index 529383411..5728b8aa6 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager.ts @@ -1,5 +1,7 @@ +import { DataSet } from 'dicom-parser'; import external from '../../externalModules'; import { xhrRequest } from '../internal/index'; +import { CornerstoneWadoLoaderLoadRequestFunction } from '../../shared/types/load-request-function'; /** * This object supports loading of DICOM P10 dataset from a uri and caching it so it can be accessed @@ -9,16 +11,21 @@ import { xhrRequest } from '../internal/index'; */ let cacheSizeInBytes = 0; -let loadedDataSets = {}; +let loadedDataSets: Record = + {}; -let promises = {}; +let promises: Record = {}; + +export interface CornerstoneWadoLoaderCachedPromise extends Promise { + cacheCount?: number; +} // returns true if the wadouri for the specified index has been loaded -function isLoaded(uri) { +function isLoaded(uri: string): boolean { return loadedDataSets[uri] !== undefined; } -function get(uri) { +function get(uri: string): DataSet { if (!loadedDataSets[uri]) { return; } @@ -27,7 +34,11 @@ function get(uri) { } // loads the dicom dataset from the wadouri sp -function load(uri, loadRequest = xhrRequest, imageId) { +function load( + uri: string, + loadRequest: CornerstoneWadoLoaderLoadRequestFunction = xhrRequest, + imageId: string +): CornerstoneWadoLoaderCachedPromise { const { cornerstone, dicomParser } = external; // if already loaded return it right away @@ -51,44 +62,50 @@ function load(uri, loadRequest = xhrRequest, imageId) { const loadDICOMPromise = loadRequest(uri, imageId); // handle success and failure of the XHR request load - const promise = new Promise((resolve, reject) => { - loadDICOMPromise - .then(function (dicomPart10AsArrayBuffer /* , xhr*/) { - const byteArray = new Uint8Array(dicomPart10AsArrayBuffer); - - // Reject the promise if parsing the dicom file fails - let dataSet; - - try { - dataSet = dicomParser.parseDicom(byteArray); - } catch (error) { - return reject(error); - } - - loadedDataSets[uri] = { - dataSet, - cacheCount: promise.cacheCount, - }; - cacheSizeInBytes += dataSet.byteArray.length; - resolve(dataSet); - - cornerstone.triggerEvent(cornerstone.events, 'datasetscachechanged', { - uri, - action: 'loaded', - cacheInfo: getInfo(), - }); - }, reject) - .then( - () => { - // Remove the promise if success - delete promises[uri]; - }, - () => { - // Remove the promise if failure - delete promises[uri]; - } - ); - }); + const promise: CornerstoneWadoLoaderCachedPromise = new Promise( + (resolve, reject) => { + loadDICOMPromise + .then(function (dicomPart10AsArrayBuffer /* , xhr*/) { + const byteArray = new Uint8Array(dicomPart10AsArrayBuffer); + + // Reject the promise if parsing the dicom file fails + let dataSet; + + try { + dataSet = dicomParser.parseDicom(byteArray); + } catch (error) { + return reject(error); + } + + loadedDataSets[uri] = { + dataSet, + cacheCount: promise.cacheCount, + }; + cacheSizeInBytes += dataSet.byteArray.length; + resolve(dataSet); + + cornerstone.triggerEvent( + (cornerstone as any).events, + 'datasetscachechanged', + { + uri, + action: 'loaded', + cacheInfo: getInfo(), + } + ); + }, reject) + .then( + () => { + // Remove the promise if success + delete promises[uri]; + }, + () => { + // Remove the promise if failure + delete promises[uri]; + } + ); + } + ); promise.cacheCount = 1; @@ -98,7 +115,7 @@ function load(uri, loadRequest = xhrRequest, imageId) { } // remove the cached/loaded dicom dataset for the specified wadouri to free up memory -function unload(uri) { +function unload(uri: string): void { const { cornerstone } = external; // console.log('unload for ' + uri); @@ -109,16 +126,24 @@ function unload(uri) { cacheSizeInBytes -= loadedDataSets[uri].dataSet.byteArray.length; delete loadedDataSets[uri]; - cornerstone.triggerEvent(cornerstone.events, 'datasetscachechanged', { - uri, - action: 'unloaded', - cacheInfo: getInfo(), - }); + cornerstone.triggerEvent( + (cornerstone as any).events, + 'datasetscachechanged', + { + uri, + action: 'unloaded', + cacheInfo: getInfo(), + } + ); } } } -export function getInfo() { +export interface CornerstoneWadoLoaderCacheManagerInfoResponse { + cacheSizeInBytes: number; + numberOfDataSetsCached: number; +} +export function getInfo(): CornerstoneWadoLoaderCacheManagerInfoResponse { return { cacheSizeInBytes, numberOfDataSetsCached: Object.keys(loadedDataSets).length, @@ -126,7 +151,7 @@ export function getInfo() { } // removes all cached datasets from memory -function purge() { +function purge(): void { loadedDataSets = {}; promises = {}; cacheSizeInBytes = 0; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager_test.js b/packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager_test.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager_test.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/dataSetCacheManager_test.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.js b/packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.ts similarity index 56% rename from packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.ts index 6b9853bc2..10fbc9aa7 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/fileManager.ts @@ -1,20 +1,20 @@ -let files = []; +let files: Blob[] = []; -function add(file) { +function add(file: Blob): string { const fileIndex = files.push(file); return `dicomfile:${fileIndex - 1}`; } -function get(index) { +function get(index: number): Blob { return files[index]; } -function remove(index) { +function remove(index: number): void { files[index] = undefined; } -function purge() { +function purge(): void { files = []; } diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.js b/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.ts similarity index 84% rename from packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.ts index 87869458e..0c14ea70f 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/getEncapsulatedImageFrame.ts @@ -1,17 +1,21 @@ +import { ByteArray, DataSet } from 'dicom-parser'; import external from '../../externalModules'; /** * Function to deal with extracting an image frame from an encapsulated data set. */ -function framesAreFragmented(dataSet) { +function framesAreFragmented(dataSet: DataSet) { const numberOfFrames = dataSet.intString('x00280008'); const pixelDataElement = dataSet.elements.x7fe00010; return numberOfFrames !== pixelDataElement.fragments.length; } -export default function getEncapsulatedImageFrame(dataSet, frameIndex) { +export default function getEncapsulatedImageFrame( + dataSet: DataSet, + frameIndex: number +): ByteArray { const { dicomParser } = external; if ( diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.js b/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.ts similarity index 79% rename from packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.ts index 5afac52e1..a2748b73c 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/getPixelData.ts @@ -1,7 +1,8 @@ +import { ByteArray, DataSet } from 'dicom-parser'; import getEncapsulatedImageFrame from './getEncapsulatedImageFrame'; import getUncompressedImageFrame from './getUncompressedImageFrame'; -function getPixelData(dataSet, frameIndex = 0) { +function getPixelData(dataSet: DataSet, frameIndex = 0): ByteArray { const pixelDataElement = dataSet.elements.x7fe00010 || dataSet.elements.x7fe00008; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.js b/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.ts similarity index 95% rename from packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.ts index 264ef71b8..10d1eeee8 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/getUncompressedImageFrame.ts @@ -1,10 +1,14 @@ +import { DataSet } from 'dicom-parser'; import unpackBinaryFrame from './unpackBinaryFrame'; /** * Function to deal with extracting an image frame from an encapsulated data set. */ -function getUncompressedImageFrame(dataSet, frameIndex) { +function getUncompressedImageFrame( + dataSet: DataSet, + frameIndex: number +): Uint8Array { const pixelDataElement = dataSet.elements.x7fe00010 || dataSet.elements.x7fe00008; const bitsAllocated = dataSet.uint16('x00280100'); diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/index.js b/packages/dicom-image-loader/src/imageLoader/wadouri/index.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/index.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/index.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.js b/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.ts similarity index 70% rename from packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.ts index 781fa704a..20d5a8c0e 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/loadFileRequest.ts @@ -1,16 +1,16 @@ import parseImageId from './parseImageId'; import fileManager from './fileManager'; -function loadFileRequest(uri) { +function loadFileRequest(uri: string): Promise { const parsedImageId = parseImageId(uri); const fileIndex = parseInt(parsedImageId.url, 10); const file = fileManager.get(fileIndex); - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const fileReader = new FileReader(); fileReader.onload = (e) => { - const dicomPart10AsArrayBuffer = e.target.result; + const dicomPart10AsArrayBuffer = e.target.result as ArrayBuffer; resolve(dicomPart10AsArrayBuffer); }; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.js b/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.ts similarity index 59% rename from packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.ts index 785170c0f..624ae2a82 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/loadImage.ts @@ -1,12 +1,22 @@ +import { CornerstoneLoadImageOptions } from 'dicom-image-loader/src/shared/types/load-image-options'; +import { DataSet } from 'dicom-parser'; import createImage from '../createImage'; -import parseImageId from './parseImageId'; +import { xhrRequest } from '../internal/index'; +import { + CornerstoneWadoLoaderIImage, + CornerstoneWadoLoaderIImageLoadObject, +} from '../wado-loader'; import dataSetCacheManager from './dataSetCacheManager'; -import loadFileRequest from './loadFileRequest'; +import { CornerstoneWadoLoaderLoadRequestFunction } from '../../shared/types/load-request-function'; import getPixelData from './getPixelData'; -import { xhrRequest } from '../internal/index'; +import loadFileRequest from './loadFileRequest'; +import parseImageId from './parseImageId'; // add a decache callback function to clear out our dataSetCacheManager -function addDecache(imageLoadObject, imageId) { +function addDecache( + imageLoadObject: CornerstoneWadoLoaderIImageLoadObject, + imageId: string +) { imageLoadObject.decache = function () { // console.log('decache'); const parsedImageId = parseImageId(imageId); @@ -16,16 +26,19 @@ function addDecache(imageLoadObject, imageId) { } function loadImageFromPromise( - dataSetPromise, - imageId, + dataSetPromise: Promise, + imageId: string, frame = 0, - sharedCacheKey, - options, - callbacks -) { + sharedCacheKey: string, + options: CornerstoneLoadImageOptions, + callbacks?: { + imageDoneCallback: (image: CornerstoneWadoLoaderIImage) => void; + } +): CornerstoneWadoLoaderIImageLoadObject { const start = new Date().getTime(); - const imageLoadObject = { + const imageLoadObject: CornerstoneWadoLoaderIImageLoadObject = { cancelFn: undefined, + promise: undefined, }; imageLoadObject.promise = new Promise((resolve, reject) => { @@ -82,43 +95,45 @@ function loadImageFromPromise( function loadImageFromDataSet( dataSet, - imageId, + imageId: string, frame = 0, - sharedCacheKey, + sharedCacheKey: string, options -) { +): CornerstoneWadoLoaderIImageLoadObject { const start = new Date().getTime(); - const promise = new Promise((resolve, reject) => { - const loadEnd = new Date().getTime(); + const promise = new Promise( + (resolve, reject) => { + const loadEnd = new Date().getTime(); - let imagePromise; + let imagePromise: Promise; - try { - const pixelData = getPixelData(dataSet, frame); - const transferSyntax = dataSet.string('x00020010'); + try { + const pixelData = getPixelData(dataSet, frame); + const transferSyntax = dataSet.string('x00020010'); - imagePromise = createImage(imageId, pixelData, transferSyntax, options); - } catch (error) { - // Reject the error, and the dataSet - reject({ - error, - dataSet, - }); + imagePromise = createImage(imageId, pixelData, transferSyntax, options); + } catch (error) { + // Reject the error, and the dataSet + reject({ + error, + dataSet, + }); - return; - } + return; + } - imagePromise.then((image) => { - image.data = dataSet; - image.sharedCacheKey = sharedCacheKey; - const end = new Date().getTime(); + imagePromise.then((image) => { + image.data = dataSet; + image.sharedCacheKey = sharedCacheKey; + const end = new Date().getTime(); - image.loadTimeInMS = loadEnd - start; - image.totalTimeInMS = end - start; - resolve(image); - }, reject); - }); + image.loadTimeInMS = loadEnd - start; + image.totalTimeInMS = end - start; + resolve(image); + }, reject); + } + ); return { promise, @@ -126,7 +141,9 @@ function loadImageFromDataSet( }; } -function getLoaderForScheme(scheme) { +function getLoaderForScheme( + scheme: string +): CornerstoneWadoLoaderLoadRequestFunction { if (scheme === 'dicomweb' || scheme === 'wadouri') { return xhrRequest; } else if (scheme === 'dicomfile') { @@ -134,7 +151,10 @@ function getLoaderForScheme(scheme) { } } -function loadImage(imageId, options = {}) { +function loadImage( + imageId: string, + options: CornerstoneLoadImageOptions = {} +): CornerstoneWadoLoaderIImageLoadObject { const parsedImageId = parseImageId(imageId); options = Object.assign({}, options); @@ -148,7 +168,14 @@ function loadImage(imageId, options = {}) { // if the dataset for this url is already loaded, use it if (dataSetCacheManager.isLoaded(parsedImageId.url)) { - const dataSet = dataSetCacheManager.get(parsedImageId.url, loader, imageId); + /** + * @todo The arguments to the dataSetCacheManager below are incorrect. + */ + const dataSet: DataSet = (dataSetCacheManager as any).get( + parsedImageId.url, + loader, + imageId + ); return loadImageFromDataSet( dataSet, diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.ts similarity index 87% rename from packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.ts index 27db277de..e19512edb 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getImagePixelModule.ts @@ -1,4 +1,7 @@ -function getLutDescriptor(dataSet, tag) { +import { CornerstoneMetadataImagePixelModule } from 'dicom-image-loader/src/shared/types/metadata-modules'; +import { DataSet } from 'dicom-parser'; + +function getLutDescriptor(dataSet: DataSet, tag: string) { if (!dataSet.elements[tag] || dataSet.elements[tag].length !== 6) { return; } @@ -10,7 +13,7 @@ function getLutDescriptor(dataSet, tag) { ]; } -function getLutData(lutDataSet, tag, lutDescriptor) { +function getLutData(lutDataSet: DataSet, tag: string, lutDescriptor): number[] { const lut = []; const lutData = lutDataSet.elements[tag]; @@ -26,7 +29,10 @@ function getLutData(lutDataSet, tag, lutDescriptor) { return lut; } -function populatePaletteColorLut(dataSet, imagePixelModule) { +function populatePaletteColorLut( + dataSet: DataSet, + imagePixelModule: CornerstoneMetadataImagePixelModule +) { imagePixelModule.redPaletteColorLookupTableDescriptor = getLutDescriptor( dataSet, 'x00281101' @@ -91,7 +97,10 @@ function populatePaletteColorLut(dataSet, imagePixelModule) { ); } -function populateSmallestLargestPixelValues(dataSet, imagePixelModule) { +function populateSmallestLargestPixelValues( + dataSet: DataSet, + imagePixelModule: CornerstoneMetadataImagePixelModule +) { const pixelRepresentation = dataSet.uint16('x00280103'); if (pixelRepresentation === 0) { @@ -103,7 +112,9 @@ function populateSmallestLargestPixelValues(dataSet, imagePixelModule) { } } -function getImagePixelModule(dataSet) { +function getImagePixelModule( + dataSet: DataSet +): CornerstoneMetadataImagePixelModule { const imagePixelModule = { samplesPerPixel: dataSet.uint16('x00280002'), photometricInterpretation: dataSet.string('x00280004'), @@ -115,7 +126,7 @@ function getImagePixelModule(dataSet) { pixelRepresentation: dataSet.uint16('x00280103'), planarConfiguration: dataSet.uint16('x00280006'), pixelAspectRatio: dataSet.string('x00280034'), - }; + } as CornerstoneMetadataImagePixelModule; populateSmallestLargestPixelValues(dataSet, imagePixelModule); diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.ts similarity index 73% rename from packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.ts index ebb761481..6dd0281b5 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getLUTs.ts @@ -1,4 +1,16 @@ -function getLUT(pixelRepresentation, lutDataSet) { +import { DataSet, Element } from 'dicom-parser'; + +export interface CornerstoneWadoLoaderLut { + id: string; + firstValueMapped: number; + numBitsPerEntry: number; + lut: number[]; +} + +function getLUT( + pixelRepresentation: number, + lutDataSet: DataSet +): CornerstoneWadoLoaderLut { let numLUTEntries = lutDataSet.uint16('x00283002', 0); if (numLUTEntries === 0) { @@ -32,11 +44,14 @@ function getLUT(pixelRepresentation, lutDataSet) { return lut; } -function getLUTs(pixelRepresentation, lutSequence) { +function getLUTs( + pixelRepresentation: number, + lutSequence: Element +): CornerstoneWadoLoaderLut[] { if (!lutSequence || !lutSequence.items || !lutSequence.items.length) { return; } - const luts = []; + const luts: CornerstoneWadoLoaderLut[] = []; for (let i = 0; i < lutSequence.items.length; i++) { const lutDataSet = lutSequence.items[i].dataSet; diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.ts similarity index 89% rename from packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.ts index 72f7cdedb..d42b78896 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getModalityLUTOutputPixelRepresentation.ts @@ -1,6 +1,8 @@ /* eslint no-bitwise: 0 */ -function getMinStoredPixelValue(dataSet) { +import { DataSet } from 'dicom-parser'; + +function getMinStoredPixelValue(dataSet: DataSet) { const pixelRepresentation = dataSet.uint16('x00280103'); const bitsStored = dataSet.uint16('x00280101'); @@ -12,7 +14,7 @@ function getMinStoredPixelValue(dataSet) { } // 0 = unsigned / US, 1 = signed / SS -function getModalityLUTOutputPixelRepresentation(dataSet) { +function getModalityLUTOutputPixelRepresentation(dataSet: DataSet) { // CT SOP Classes are always signed const sopClassUID = dataSet.string('x00080016'); diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.ts similarity index 72% rename from packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.ts index a2f9ee918..e429ddfc9 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getNumberValues.ts @@ -1,4 +1,10 @@ -function getNumberValues(dataSet, tag, minimumLength) { +import { DataSet } from 'dicom-parser'; + +function getNumberValues( + dataSet: DataSet, + tag: string, + minimumLength: number +): number[] { const values = []; const valueAsString = dataSet.string(tag); diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.ts similarity index 91% rename from packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.ts index ecdce907d..b5a000ffe 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/getOverlayPlaneModule.ts @@ -1,4 +1,6 @@ -export default function getOverlayPlaneModule(dataSet) { +import { DataSet } from 'dicom-parser'; + +export default function getOverlayPlaneModule(dataSet: DataSet) { const overlays = []; for (let overlayGroup = 0x00; overlayGroup <= 0x1e; overlayGroup += 0x02) { diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/index.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/index.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/wadouri/metaData/index.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/metaData/index.ts diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.js b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.ts similarity index 73% rename from packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.ts index 6d7de0dd1..8dedb279a 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/metaData/metaDataProvider.ts @@ -1,13 +1,49 @@ +import { + CornerstoneMetadataGeneralSeriesModule, + CornerstoneMetadataImagePixelModule, + CornerstoneMetadataImagePlaneModule, + CornerstoneMetadataPatientStudyModule, + CornerstoneMetadataSopCommonModule, + CornerstoneMetadataTransferSyntax, + CornerstoneMetaDataTypes, +} from 'dicom-image-loader/src/shared/types/metadata-modules'; import external from '../../../externalModules'; -import getNumberValues from './getNumberValues'; -import parseImageId from '../parseImageId'; import dataSetCacheManager from '../dataSetCacheManager'; +import parseImageId from '../parseImageId'; import getImagePixelModule from './getImagePixelModule'; -import getOverlayPlaneModule from './getOverlayPlaneModule'; import getLUTs from './getLUTs'; import getModalityLUTOutputPixelRepresentation from './getModalityLUTOutputPixelRepresentation'; +import getNumberValues from './getNumberValues'; +import getOverlayPlaneModule from './getOverlayPlaneModule'; -function metaDataProvider(type, imageId) { +function metaDataProvider( + type: 'generalSeriesModule', + imageId: string +): CornerstoneMetadataGeneralSeriesModule; +function metaDataProvider( + type: 'patientStudyModule', + imageId: string +): CornerstoneMetadataPatientStudyModule; +function metaDataProvider( + type: 'imagePlaneModule', + imageId: string +): CornerstoneMetadataImagePlaneModule; +function metaDataProvider( + type: 'imagePixelModule', + imageId: string +): CornerstoneMetadataImagePixelModule; +function metaDataProvider( + type: 'transferSyntax', + imageId: string +): CornerstoneMetadataTransferSyntax; +function metaDataProvider( + type: 'sopCommonModule', + imageId: string +): CornerstoneMetadataSopCommonModule; +function metaDataProvider( + type: CornerstoneMetaDataTypes, + imageId: string +): any { const { dicomParser } = external; const parsedImageId = parseImageId(imageId); @@ -41,9 +77,9 @@ function metaDataProvider(type, imageId) { const imagePositionPatient = getNumberValues(dataSet, 'x00200032', 3); const pixelSpacing = getNumberValues(dataSet, 'x00280030', 2); - let columnPixelSpacing = null; + let columnPixelSpacing: number = null; - let rowPixelSpacing = null; + let rowPixelSpacing: number = null; if (pixelSpacing) { rowPixelSpacing = pixelSpacing[0]; @@ -56,14 +92,14 @@ function metaDataProvider(type, imageId) { if (imageOrientationPatient) { rowCosines = [ - parseFloat(imageOrientationPatient[0]), - parseFloat(imageOrientationPatient[1]), - parseFloat(imageOrientationPatient[2]), + parseFloat(imageOrientationPatient[0] as any), + parseFloat(imageOrientationPatient[1] as any), + parseFloat(imageOrientationPatient[2] as any), ]; columnCosines = [ - parseFloat(imageOrientationPatient[3]), - parseFloat(imageOrientationPatient[4]), - parseFloat(imageOrientationPatient[5]), + parseFloat(imageOrientationPatient[3] as any), + parseFloat(imageOrientationPatient[4] as any), + parseFloat(imageOrientationPatient[5] as any), ]; } diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.js b/packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.ts similarity index 76% rename from packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.ts index 07e7e804e..9fcd71a07 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/parseImageId.ts @@ -1,4 +1,10 @@ -function parseImageId(imageId) { +export interface CornerstoneImageUrl { + scheme: string; + url: string; + frame: number; +} + +function parseImageId(imageId: string): CornerstoneImageUrl { // build a url by parsing out the url scheme and frame index from the imageId const firstColonIndex = imageId.indexOf(':'); diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/register.js b/packages/dicom-image-loader/src/imageLoader/wadouri/register.ts similarity index 76% rename from packages/dicom-image-loader/src/imageLoader/wadouri/register.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/register.ts index ed24e59d1..e5c477a49 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/register.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/register.ts @@ -1,7 +1,8 @@ +import * as cornerstoneImport from '@cornerstonejs/core'; import { loadImage } from './loadImage'; import { metaDataProvider } from './metaData/index'; -export default function (cornerstone) { +export default function (cornerstone: typeof cornerstoneImport): void { // register dicomweb and wadouri image loader prefixes cornerstone.registerImageLoader('dicomweb', loadImage); cornerstone.registerImageLoader('wadouri', loadImage); diff --git a/packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.js b/packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.ts similarity index 75% rename from packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.js rename to packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.ts index 22a5dbfb2..e416ec2db 100644 --- a/packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.js +++ b/packages/dicom-image-loader/src/imageLoader/wadouri/unpackBinaryFrame.ts @@ -1,13 +1,19 @@ /* eslint no-bitwise: 0 */ -function isBitSet(byte, bitPos) { +import { ByteArray } from 'dicom-parser'; + +function isBitSet(byte: number, bitPos: number) { return byte & (1 << bitPos); } /** * Function to deal with unpacking a binary frame */ -function unpackBinaryFrame(byteArray, frameOffset, pixelsPerFrame) { +function unpackBinaryFrame( + byteArray: ByteArray, + frameOffset: number, + pixelsPerFrame: number +): Uint8Array { // Create a new pixel array given the image size const pixelData = new Uint8Array(pixelsPerFrame); diff --git a/packages/dicom-image-loader/src/imageLoader/webWorkerManager.js b/packages/dicom-image-loader/src/imageLoader/webWorkerManager.ts similarity index 77% rename from packages/dicom-image-loader/src/imageLoader/webWorkerManager.js rename to packages/dicom-image-loader/src/imageLoader/webWorkerManager.ts index 8c099412b..e8814b6c9 100644 --- a/packages/dicom-image-loader/src/imageLoader/webWorkerManager.js +++ b/packages/dicom-image-loader/src/imageLoader/webWorkerManager.ts @@ -2,6 +2,10 @@ // eslint-disable-next-line // import cornerstoneWADOImageLoaderWebWorker from 'worker-loader!../webWorker/index.worker'; import cornerstoneWADOImageLoaderWebWorker from '../webWorker/index.worker'; +import { + CornerstoneWadoWebWorkerDecodeTaskData, + CornerstoneWadoWebWorkerResponse, +} from '../webWorker/webworker-messages'; // This is for the Webpack 5 approch but it's currently broken // so we will continue relying on worker-loader for now @@ -16,16 +20,56 @@ import { getOptions } from './internal/options'; // the taskId to assign to the next task added via addTask() let nextTaskId = 0; +export interface CornerstoneWadoWebWorkerDecodeConfig { + initializeCodecsOnStartup: boolean; + strict?: boolean; +} + +export interface CornerstoneWadoWebWorkerTaskOptions { + decodeTask: CornerstoneWadoWebWorkerDecodeConfig; +} + +interface CornerstoneWebWorkerDeferredObject { + resolve: (arg: T | PromiseLike) => void; + reject: (err: any) => void; +} +export type CornerstoneWadoWorkerTaskTypes = + | 'decodeTask' + | 'loadWebWorkerTask' + | 'initialize'; + // array of queued tasks sorted with highest priority task first -const tasks = []; +export interface CornerstoneWorkerTask { + taskId: number; + taskType: CornerstoneWadoWorkerTaskTypes; + status: 'ready' | 'success' | 'failed'; + added: number; + start?: number; + data: CornerstoneWadoWebWorkerDecodeTaskData; + deferred: CornerstoneWebWorkerDeferredObject; + priority: number; + transferList: Transferable[]; +} +const tasks: CornerstoneWorkerTask[] = []; // array of web workers to dispatch decode tasks to -const webWorkers = []; +const webWorkers: { + worker: Worker; + status: 'ready' | 'busy' | 'initializing'; + task?: CornerstoneWorkerTask; +}[] = []; // The options for CornerstoneWADOImageLoader const options = getOptions(); -const defaultConfig = { +export interface CornerstoneWadoWebWorkerOptions { + maxWebWorkers?: number; + startWebWorkersOnDemand?: boolean; + webWorkerTaskPaths?: string[]; + taskConfiguration?: CornerstoneWadoWebWorkerTaskOptions; +} + +const defaultConfig: CornerstoneWadoWebWorkerOptions = { maxWebWorkers: navigator.hardwareConcurrency || 1, startWebWorkersOnDemand: true, webWorkerTaskPaths: [], @@ -37,7 +81,7 @@ const defaultConfig = { }, }; -let config; +let config: CornerstoneWadoWebWorkerOptions; const statistics = { maxWebWorkers: 0, @@ -101,7 +145,9 @@ function startTaskOnWebWorker() { * Function to handle a message from a web worker * @param msg */ -function handleMessageFromWorker(msg) { +function handleMessageFromWorker( + msg: MessageEvent +) { // console.log('handleMessageFromWorker', msg.data); if (msg.data.taskType === 'initialize') { webWorkers[msg.data.workerIndex].status = 'ready'; @@ -137,7 +183,7 @@ function spawnWebWorker() { } // spawn the webworker - const worker = new cornerstoneWADOImageLoaderWebWorker(); + const worker: Worker = new (cornerstoneWADOImageLoaderWebWorker as any)(); // This is for the Webpack 5 approach but it's currently broken /* const worker = new Worker(cornerstoneWADOImageLoaderWebWorkerPath, { @@ -168,7 +214,7 @@ function spawnWebWorker() { * Initialization function for the web worker manager - spawns web workers * @param configObject */ -function initialize(configObject) { +function initialize(configObject?: CornerstoneWadoWebWorkerOptions): void { configObject = configObject || defaultConfig; // prevent being initialized more than once @@ -192,7 +238,7 @@ function initialize(configObject) { /** * Terminate all running web workers. */ -function terminate() { +function terminate(): void { for (let i = 0; i < webWorkers.length; i++) { webWorkers[i].worker.terminate(); } @@ -205,7 +251,7 @@ function terminate() { * @param sourcePath * @param taskConfig */ -function loadWebWorkerTask(sourcePath, taskConfig) { +function loadWebWorkerTask(sourcePath: string, taskConfig): void { // add it to the list of web worker tasks paths so on demand web workers // load this properly config.webWorkerTaskPaths.push(sourcePath); @@ -238,13 +284,21 @@ function loadWebWorkerTask(sourcePath, taskConfig) { * @param transferList - optional array of data to transfer to web worker * @returns {*} */ -function addTask(taskType, data, priority = 0, transferList) { +function addTask( + taskType: CornerstoneWadoWorkerTaskTypes, + data: CornerstoneWadoWebWorkerDecodeTaskData, + priority = 0, + transferList: Transferable[] +): { taskId: number; promise: Promise } { if (!config) { initialize(); } - let deferred = {}; - const promise = new Promise((resolve, reject) => { + let deferred: CornerstoneWebWorkerDeferredObject = { + resolve: undefined, + reject: undefined, + }; + const promise = new Promise((resolve, reject) => { deferred = { resolve, reject, @@ -252,7 +306,7 @@ function addTask(taskType, data, priority = 0, transferList) { }); // find the right spot to insert this decode task (based on priority) - let i; + let i: number; for (i = 0; i < tasks.length; i++) { if (tasks[i].priority < priority) { @@ -289,7 +343,7 @@ function addTask(taskType, data, priority = 0, transferList) { * @param priority - priority of the task (defaults to 0), > 0 is higher, < 0 is lower * @returns boolean - true on success, false if taskId not found */ -function setTaskPriority(taskId, priority = 0) { +function setTaskPriority(taskId: number, priority = 0): boolean { // search for this taskId for (let i = 0; i < tasks.length; i++) { if (tasks[i].taskId === taskId) { @@ -322,14 +376,18 @@ function setTaskPriority(taskId, priority = 0) { * @param reason - optional reason the task was rejected * @returns boolean - true on success, false if taskId not found */ -function cancelTask(taskId, reason) { +function cancelTask(taskId: number, reason: string): boolean { // search for this taskId for (let i = 0; i < tasks.length; i++) { if (tasks[i].taskId === taskId) { // taskId found, remove it + /** + * @todo Check if this is a bug. Splice returns an array but task is + * treated as a single task object + */ const task = tasks.splice(i, 1); - task.deferred.reject(reason); + (task as any).deferred.reject(reason); return true; } @@ -342,7 +400,7 @@ function cancelTask(taskId, reason) { * Function to return the statistics on running web workers * @returns object containing statistics */ -function getStatistics() { +function getStatistics(): typeof config { statistics.maxWebWorkers = config.maxWebWorkers; statistics.numWebWorkers = webWorkers.length; statistics.numTasksQueued = tasks.length; diff --git a/packages/dicom-image-loader/src/imageLoader/webWorkerManager_test.js b/packages/dicom-image-loader/src/imageLoader/webWorkerManager_test.ts similarity index 100% rename from packages/dicom-image-loader/src/imageLoader/webWorkerManager_test.js rename to packages/dicom-image-loader/src/imageLoader/webWorkerManager_test.ts diff --git a/packages/dicom-image-loader/src/shared/calculateMinMax.js b/packages/dicom-image-loader/src/shared/calculateMinMax.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/calculateMinMax.js rename to packages/dicom-image-loader/src/shared/calculateMinMax.ts diff --git a/packages/dicom-image-loader/src/shared/calculateMinMax_test.js b/packages/dicom-image-loader/src/shared/calculateMinMax_test.ts similarity index 98% rename from packages/dicom-image-loader/src/shared/calculateMinMax_test.js rename to packages/dicom-image-loader/src/shared/calculateMinMax_test.ts index 461f79e2a..2f669b341 100644 --- a/packages/dicom-image-loader/src/shared/calculateMinMax_test.js +++ b/packages/dicom-image-loader/src/shared/calculateMinMax_test.ts @@ -2,7 +2,7 @@ import { expect } from 'chai'; import calculateMinMax from './calculateMinMax'; describe('#calculateMinMax', () => { - let imageFrame = {}; + let imageFrame: any = {}; beforeEach(() => { imageFrame = { diff --git a/packages/dicom-image-loader/src/shared/decodeImageFrame.js b/packages/dicom-image-loader/src/shared/decodeImageFrame.ts similarity index 95% rename from packages/dicom-image-loader/src/shared/decodeImageFrame.js rename to packages/dicom-image-loader/src/shared/decodeImageFrame.ts index 8904777c7..ee90e5445 100644 --- a/packages/dicom-image-loader/src/shared/decodeImageFrame.js +++ b/packages/dicom-image-loader/src/shared/decodeImageFrame.ts @@ -9,18 +9,20 @@ import decodeJPEGLossless from './decoders/decodeJPEGLossless'; import decodeJPEGLS from './decoders/decodeJPEGLS'; import decodeJPEG2000 from './decoders/decodeJPEG2000'; import scaleArray from './scaling/scaleArray'; +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from './image-frame'; function decodeImageFrame( - imageFrame, - transferSyntax, - pixelData, + imageFrame: CornerstoneWadoImageFrame, + transferSyntax: string, + pixelData: ByteArray, decodeConfig, options, - callbackFn -) { + callbackFn: (...args: any[]) => void +): void { const start = new Date().getTime(); - let decodePromise = null; + let decodePromise: Promise = null; let opts; @@ -141,7 +143,11 @@ function decodeImageFrame( }); } -function postProcessDecodedPixels(imageFrame, options, start) { +function postProcessDecodedPixels( + imageFrame: CornerstoneWadoImageFrame, + options, + start: number +) { const shouldShift = imageFrame.pixelRepresentation !== undefined && imageFrame.pixelRepresentation === 1; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.js b/packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.ts similarity index 80% rename from packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.js rename to packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.ts index 53cde8cd6..771b85b5d 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.js +++ b/packages/dicom-image-loader/src/shared/decoders/decodeBigEndian.ts @@ -1,9 +1,15 @@ +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../image-frame'; + /* eslint no-bitwise: 0 */ function swap16(val) { return ((val & 0xff) << 8) | ((val >> 8) & 0xff); } -async function decodeBigEndian(imageFrame, pixelData) { +async function decodeBigEndian( + imageFrame: CornerstoneWadoImageFrame, + pixelData: ByteArray +): Promise { if (imageFrame.bitsAllocated === 16) { let arrayBuffer = pixelData.buffer; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.ts similarity index 90% rename from packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.js rename to packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.ts index 39dbdb7e6..c74bcb3a1 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.js +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEG2000.ts @@ -7,14 +7,18 @@ import openJpegFactory from '@cornerstonejs/codec-openjpeg/dist/openjpegwasm_dec // This is closer to what Webpack 5 wants but it doesn't seem to work now // const wasm = new URL('./blah.wasm', import.meta.url) import openjpegWasm from '@cornerstonejs/codec-openjpeg/dist/openjpegwasm_decode.wasm'; +import { CornerstoneWadoWebWorkerDecodeConfig } from 'dicom-image-loader/src/imageLoader/webWorkerManager'; +import { CornerstoneWadoImageFrame } from '../image-frame'; const local = { codec: undefined, decoder: undefined, - decodeConfig: {}, + decodeConfig: {} as CornerstoneWadoWebWorkerDecodeConfig, }; -export function initialize(decodeConfig) { +export function initialize( + decodeConfig?: CornerstoneWadoWebWorkerDecodeConfig +): Promise { local.decodeConfig = decodeConfig; if (local.codec) { @@ -41,7 +45,10 @@ export function initialize(decodeConfig) { } // https://github.com/chafey/openjpegjs/blob/master/test/browser/index.html -async function decodeAsync(compressedImageFrame, imageInfo) { +async function decodeAsync( + compressedImageFrame, + imageInfo +): Promise { await initialize(); const decoder = local.decoder; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.ts similarity index 66% rename from packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.js rename to packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.ts index 2a54b8c67..aea807db8 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.js +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-js.ts @@ -1,9 +1,15 @@ +import { CornerstoneWadoWebWorkerDecodeConfig } from 'dicom-image-loader/src/imageLoader/webWorkerManager'; +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../image-frame'; + const local = { JpegImage: undefined, - decodeConfig: {}, + decodeConfig: {} as CornerstoneWadoWebWorkerDecodeConfig, }; -export function initialize(decodeConfig) { +export function initialize( + decodeConfig?: CornerstoneWadoWebWorkerDecodeConfig +): Promise { local.decodeConfig = decodeConfig; if (local.JpegImage) { @@ -18,7 +24,10 @@ export function initialize(decodeConfig) { }); } -async function decodeJPEGBaseline12BitAsync(imageFrame, pixelData) { +async function decodeJPEGBaseline12BitAsync( + imageFrame: CornerstoneWadoImageFrame, + pixelData: ByteArray +): Promise { // check to make sure codec is loaded await initialize(); if (typeof local.JpegImage === 'undefined') { diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-wasm-not-yet-working.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-wasm-not-yet-working.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-wasm-not-yet-working.js rename to packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline12Bit-wasm-not-yet-working.ts diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.ts similarity index 88% rename from packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.js rename to packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.ts index 1faa1f34c..4c0d348a2 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.js +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGBaseline8Bit.ts @@ -2,13 +2,15 @@ import libjpegTurboFactory from '@cornerstonejs/codec-libjpeg-turbo-8bit/dist/li // Webpack asset/resource copies this to our output folder import libjpegTurboWasm from '@cornerstonejs/codec-libjpeg-turbo-8bit/dist/libjpegturbowasm_decode.wasm'; +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../image-frame'; const local = { codec: undefined, decoder: undefined, }; -function initLibjpegTurbo() { +function initLibjpegTurbo(): Promise { if (local.codec) { return Promise.resolve(); } @@ -39,7 +41,10 @@ function initLibjpegTurbo() { * @param {object} imageInfo * @param {boolean} imageInfo.signed - */ -async function decodeAsync(compressedImageFrame, imageInfo) { +async function decodeAsync( + compressedImageFrame, + imageInfo +): Promise { await initLibjpegTurbo(); const decoder = local.decoder; @@ -86,7 +91,7 @@ async function decodeAsync(compressedImageFrame, imageInfo) { }; } -function getPixelData(frameInfo, decodedBuffer) { +function getPixelData(frameInfo, decodedBuffer: ByteArray) { if (frameInfo.isSigned) { return new Int8Array( decodedBuffer.buffer, diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.ts similarity index 86% rename from packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.js rename to packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.ts index 73b8656c8..d2b54bf1e 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.js +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLS.ts @@ -3,12 +3,15 @@ import charlsFactory from '@cornerstonejs/codec-charls/dist/charlswasm_decode'; // Webpack asset/resource copies this to our output folder import charlsWasm from '@cornerstonejs/codec-charls/dist/charlswasm_decode.wasm'; +import { CornerstoneWadoWebWorkerDecodeConfig } from 'dicom-image-loader/src/imageLoader/webWorkerManager'; +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../image-frame'; // import charlsWasm from '@cornerstonejs/codec-charls/dist/debug/charlswasm.wasm'; const local = { codec: undefined, decoder: undefined, - decodeConfig: {}, + decodeConfig: {} as CornerstoneWadoWebWorkerDecodeConfig, }; function getExceptionMessage(exception) { @@ -17,7 +20,9 @@ function getExceptionMessage(exception) { : exception; } -export function initialize(decodeConfig) { +export function initialize( + decodeConfig?: CornerstoneWadoWebWorkerDecodeConfig +): Promise { local.decodeConfig = decodeConfig; if (local.codec) { @@ -49,7 +54,10 @@ export function initialize(decodeConfig) { * @param {object} imageInfo * @param {boolean} imageInfo.signed - (pixelRepresentation === 1) */ -async function decodeAsync(compressedImageFrame, imageInfo) { +async function decodeAsync( + compressedImageFrame, + imageInfo +): Promise { try { await initialize(); const decoder = local.decoder; @@ -113,7 +121,7 @@ async function decodeAsync(compressedImageFrame, imageInfo) { } } -function getPixelData(frameInfo, decodedBuffer, signed) { +function getPixelData(frameInfo, decodedBuffer: ByteArray, signed: boolean) { if (frameInfo.bitsPerSample > 8) { if (signed) { return new Int16Array( diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.js b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.ts similarity index 72% rename from packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.js rename to packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.ts index 016ce6848..92bb3fe5e 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.js +++ b/packages/dicom-image-loader/src/shared/decoders/decodeJPEGLossless.ts @@ -1,9 +1,15 @@ +import { CornerstoneWadoWebWorkerDecodeConfig } from 'dicom-image-loader/src/imageLoader/webWorkerManager'; +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../image-frame'; + const local = { jpeg: undefined, - decodeConfig: {}, + decodeConfig: {} as CornerstoneWadoWebWorkerDecodeConfig, }; -export function initialize(decodeConfig) { +export function initialize( + decodeConfig?: CornerstoneWadoWebWorkerDecodeConfig +): Promise { local.decodeConfig = decodeConfig; if (local.jpeg) { @@ -18,7 +24,10 @@ export function initialize(decodeConfig) { }); } -async function decodeJPEGLossless(imageFrame, pixelData) { +async function decodeJPEGLossless( + imageFrame: CornerstoneWadoImageFrame, + pixelData: ByteArray +): Promise { await initialize(); // check to make sure codec is loaded diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.js b/packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.ts similarity index 81% rename from packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.js rename to packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.ts index 0930d8248..9e3727413 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.js +++ b/packages/dicom-image-loader/src/shared/decoders/decodeLittleEndian.ts @@ -1,4 +1,10 @@ -async function decodeLittleEndian(imageFrame, pixelData) { +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../image-frame'; + +async function decodeLittleEndian( + imageFrame: CornerstoneWadoImageFrame, + pixelData: ByteArray +): Promise { let arrayBuffer = pixelData.buffer; let offset = pixelData.byteOffset; diff --git a/packages/dicom-image-loader/src/shared/decoders/decodeRLE.js b/packages/dicom-image-loader/src/shared/decoders/decodeRLE.ts similarity index 90% rename from packages/dicom-image-loader/src/shared/decoders/decodeRLE.js rename to packages/dicom-image-loader/src/shared/decoders/decodeRLE.ts index 204bbb965..db622cf6c 100644 --- a/packages/dicom-image-loader/src/shared/decoders/decodeRLE.js +++ b/packages/dicom-image-loader/src/shared/decoders/decodeRLE.ts @@ -1,4 +1,10 @@ -async function decodeRLE(imageFrame, pixelData) { +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoImageFrame } from '../image-frame'; + +async function decodeRLE( + imageFrame: CornerstoneWadoImageFrame, + pixelData: ByteArray +): Promise { if (imageFrame.bitsAllocated === 8) { if (imageFrame.planarConfiguration) { return decode8Planar(imageFrame, pixelData); @@ -12,7 +18,7 @@ async function decodeRLE(imageFrame, pixelData) { throw new Error('unsupported pixel format for RLE'); } -function decode8(imageFrame, pixelData) { +function decode8(imageFrame: CornerstoneWadoImageFrame, pixelData: ByteArray) { const frameData = pixelData; const frameSize = imageFrame.rows * imageFrame.columns; const outFrame = new ArrayBuffer(frameSize * imageFrame.samplesPerPixel); @@ -63,7 +69,10 @@ function decode8(imageFrame, pixelData) { return imageFrame; } -function decode8Planar(imageFrame, pixelData) { +function decode8Planar( + imageFrame: CornerstoneWadoImageFrame, + pixelData: ByteArray +) { const frameData = pixelData; const frameSize = imageFrame.rows * imageFrame.columns; const outFrame = new ArrayBuffer(frameSize * imageFrame.samplesPerPixel); @@ -114,7 +123,7 @@ function decode8Planar(imageFrame, pixelData) { return imageFrame; } -function decode16(imageFrame, pixelData) { +function decode16(imageFrame: CornerstoneWadoImageFrame, pixelData: ByteArray) { const frameData = pixelData; const frameSize = imageFrame.rows * imageFrame.columns; const outFrame = new ArrayBuffer(frameSize * imageFrame.samplesPerPixel * 2); diff --git a/packages/dicom-image-loader/src/shared/getMinMax.js b/packages/dicom-image-loader/src/shared/getMinMax.ts similarity index 83% rename from packages/dicom-image-loader/src/shared/getMinMax.js rename to packages/dicom-image-loader/src/shared/getMinMax.ts index a3d727399..02eb142a2 100644 --- a/packages/dicom-image-loader/src/shared/getMinMax.js +++ b/packages/dicom-image-loader/src/shared/getMinMax.ts @@ -1,10 +1,15 @@ +import { ByteArray } from 'dicom-parser'; + /** * Calculate the minimum and maximum values in an Array * * @param {Number[]} storedPixelData * @return {{min: Number, max: Number}} */ -function getMinMax(storedPixelData) { +function getMinMax(storedPixelData: ByteArray | number[]): { + min: number; + max: number; +} { // we always calculate the min max values since they are not always // present in DICOM and we don't want to trust them anyway as cornerstone // depends on us providing reliable values for these diff --git a/packages/dicom-image-loader/src/shared/getMinMax_test.js b/packages/dicom-image-loader/src/shared/getMinMax_test.ts similarity index 100% rename from packages/dicom-image-loader/src/shared/getMinMax_test.js rename to packages/dicom-image-loader/src/shared/getMinMax_test.ts diff --git a/packages/dicom-image-loader/src/shared/image-frame.ts b/packages/dicom-image-loader/src/shared/image-frame.ts new file mode 100644 index 000000000..b9293dec1 --- /dev/null +++ b/packages/dicom-image-loader/src/shared/image-frame.ts @@ -0,0 +1,30 @@ +export interface CornerstoneWadoImageFrame { + samplesPerPixel: number; + photometricInterpretation: string; + planarConfiguration: number; + rows: number; + columns: number; + bitsAllocated: number; + bitsStored: number; + pixelRepresentation: number; + smallestPixelValue: number; + largestPixelValue: number; + redPaletteColorLookupTableDescriptor: number[]; + greenPaletteColorLookupTableDescriptor: number[]; + bluePaletteColorLookupTableDescriptor: number[]; + redPaletteColorLookupTableData: number[]; + greenPaletteColorLookupTableData: number[]; + bluePaletteColorLookupTableData: number[]; + // populated later after decoding + pixelData: + | Float32Array + | Int16Array + | Uint16Array + | Uint8Array + | Uint8ClampedArray + | undefined; + imageData?: ImageData; + decodeTimeInMS?: number; + pixelDataLength?: number; + preScale?: any; +} diff --git a/packages/dicom-image-loader/src/shared/scaling/scaleArray.js b/packages/dicom-image-loader/src/shared/scaling/scaleArray.ts similarity index 84% rename from packages/dicom-image-loader/src/shared/scaling/scaleArray.js rename to packages/dicom-image-loader/src/shared/scaling/scaleArray.ts index 545ef7879..d3f89c0be 100644 --- a/packages/dicom-image-loader/src/shared/scaling/scaleArray.js +++ b/packages/dicom-image-loader/src/shared/scaling/scaleArray.ts @@ -1,4 +1,7 @@ -export default function scaleArray(array, scalingParameters) { +export default function scaleArray( + array: number[], + scalingParameters +): boolean { const arrayLength = array.length; const { rescaleSlope, rescaleIntercept, suvbw } = scalingParameters; diff --git a/packages/dicom-image-loader/src/shared/types/load-image-options.ts b/packages/dicom-image-loader/src/shared/types/load-image-options.ts new file mode 100644 index 000000000..b5c263b3f --- /dev/null +++ b/packages/dicom-image-loader/src/shared/types/load-image-options.ts @@ -0,0 +1,17 @@ +import { Types } from '@cornerstonejs/core'; +import { CornerstoneWadoLoaderLoadRequestFunction } from 'dicom-image-loader/src/shared/types/load-request-function'; + +export interface CornerstoneLoadImageOptions { + useRGBA?: boolean; + preScale?: { + enabled: boolean; + scalingParameters?: Types.ScalingParameters; + }; + targetBuffer?: { + type: 'Uint8Array' | 'Uint16Array' | 'Float32Array'; + arrayBuffer: ArrayBufferLike; + length: number; + offset: number; + }; + loader?: CornerstoneWadoLoaderLoadRequestFunction; +} diff --git a/packages/dicom-image-loader/src/shared/types/load-request-function.ts b/packages/dicom-image-loader/src/shared/types/load-request-function.ts new file mode 100644 index 000000000..130936f3b --- /dev/null +++ b/packages/dicom-image-loader/src/shared/types/load-request-function.ts @@ -0,0 +1,6 @@ + +export type CornerstoneWadoLoaderLoadRequestFunction = ( + url: string, + imageId: string, + ...args: any[] +) => Promise; diff --git a/packages/dicom-image-loader/src/shared/types/metadata-modules.ts b/packages/dicom-image-loader/src/shared/types/metadata-modules.ts new file mode 100644 index 000000000..207fc190c --- /dev/null +++ b/packages/dicom-image-loader/src/shared/types/metadata-modules.ts @@ -0,0 +1,81 @@ +export type CornerstoneMetaDataTypes = + | 'generalSeriesModule' + | 'patientStudyModule' + | 'imagePlaneModule' + | 'imagePixelModule' + | 'transferSyntax' + | 'sopCommonModule' + | string; + +export interface DicomDateObject { + year: number; + month: number; + day: number; +} + +export interface DicomTimeObject { + hours: number; + minutes?: number; + seconds?: number; + fractionalSeconds?: number; +} + +export interface CornerstoneMetadataGeneralSeriesModule { + modality: string; + seriesInstanceUID: string; + seriesNumber: number; + studyInstanceUID: string; + seriesDate: DicomDateObject; + seriesTime: DicomTimeObject; +} + +export interface CornerstoneMetadataPatientStudyModule { + patientAge: number; + patientSize: number; + patientWeight: number; +} + +export interface CornerstoneMetadataImagePlaneModule { + frameOfReferenceUID: string; + rows: string; + columns: string; + imageOrientationPatient: number[]; + rowCosines: number[]; + columnCosines: number[]; + imagePositionPatient: number[]; + sliceThickness: string; + sliceLocation: string; + pixelSpacing: number[]; + rowPixelSpacing: number | null; + columnPixelSpacing: number | null; +} + +export interface CornerstoneMetadataImagePixelModule { + samplesPerPixel: number; + photometricInterpretation: string; + rows: number; + columns: number; + bitsAllocated: number; + bitsStored: number; + highBit: number; + pixelRepresentation: number; + planarConfiguration: number; + pixelAspectRatio: string; + redPaletteColorLookupTableDescriptor: number[]; + greenPaletteColorLookupTableDescriptor: number[]; + bluePaletteColorLookupTableDescriptor: number[]; + redPaletteColorLookupTableData: number[]; + greenPaletteColorLookupTableData: number[]; + bluePaletteColorLookupTableData: number[]; + smallestPixelValue?: number; + largestPixelValue?: number; +} + +export interface CornerstoneMetadataSopCommonModule { + sopClassUID: string; + sopInstanceUID: string; +} + +export interface CornerstoneMetadataTransferSyntax { + transferSyntaxUID: string; +} diff --git a/packages/dicom-image-loader/src/version.js b/packages/dicom-image-loader/src/version.ts similarity index 100% rename from packages/dicom-image-loader/src/version.js rename to packages/dicom-image-loader/src/version.ts diff --git a/packages/dicom-image-loader/src/webWorker/decodeTask.js b/packages/dicom-image-loader/src/webWorker/decodeTask.ts similarity index 71% rename from packages/dicom-image-loader/src/webWorker/decodeTask.js rename to packages/dicom-image-loader/src/webWorker/decodeTask.ts index 9ade7d214..33918dca7 100644 --- a/packages/dicom-image-loader/src/webWorker/decodeTask.js +++ b/packages/dicom-image-loader/src/webWorker/decodeTask.ts @@ -1,16 +1,19 @@ -import { initialize as initializeJPEG2000 } from '../shared/decoders/decodeJPEG2000'; -import { initialize as initializeJPEGLS } from '../shared/decoders/decodeJPEGLS'; +import { CornerstoneWadoWebWorkerTaskOptions } from '../imageLoader/webWorkerManager'; import calculateMinMax from '../shared/calculateMinMax'; import decodeImageFrame from '../shared/decodeImageFrame'; +import { initialize as initializeJPEG2000 } from '../shared/decoders/decodeJPEG2000'; +import { initialize as initializeJPEGLS } from '../shared/decoders/decodeJPEGLS'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; +import { CornerstoneWadoWebWorkerDecodeData } from './webworker-messages'; // the configuration object for the decodeTask -let decodeConfig; +let decodeConfig: CornerstoneWadoWebWorkerTaskOptions; /** * Function to control loading and initializing the codecs * @param config */ -function loadCodecs(config) { +function loadCodecs(config: CornerstoneWadoWebWorkerTaskOptions) { // Initialize the codecs if (config.decodeTask.initializeCodecsOnStartup) { initializeJPEG2000(config.decodeTask); @@ -21,7 +24,7 @@ function loadCodecs(config) { /** * Task initialization function */ -function initialize(config) { +function initialize(config: CornerstoneWadoWebWorkerTaskOptions): void { decodeConfig = config; loadCodecs(config); @@ -30,7 +33,13 @@ function initialize(config) { /** * Task handler function */ -function handler(data, doneCallback) { +function handler( + data: CornerstoneWadoWebWorkerDecodeData, + doneCallback: ( + imageFrame: CornerstoneWadoImageFrame, + pixelData: Transferable[] + ) => void +): void { // Load the codecs if they aren't already loaded loadCodecs(decodeConfig); @@ -42,7 +51,7 @@ function handler(data, doneCallback) { const pixelData = new Uint8Array(data.data.pixelData); // TODO switch to promise - function finishedCallback(imageFrame) { + function finishedCallback(imageFrame: CornerstoneWadoImageFrame) { if (!imageFrame.pixelData) { throw new Error( 'decodeTask: imageFrame.pixelData is undefined after decoding' @@ -51,9 +60,10 @@ function handler(data, doneCallback) { calculateMinMax(imageFrame, strict); + /** @todo check as any */ // convert from TypedArray to ArrayBuffer since web workers support passing ArrayBuffers but not // typed arrays - imageFrame.pixelData = imageFrame.pixelData.buffer; + imageFrame.pixelData = imageFrame.pixelData.buffer as any; // invoke the callback with our result and pass the pixelData in the transferList to move it to // UI thread without making a copy diff --git a/packages/dicom-image-loader/src/webWorker/index.worker.js b/packages/dicom-image-loader/src/webWorker/index.worker.ts similarity index 100% rename from packages/dicom-image-loader/src/webWorker/index.worker.js rename to packages/dicom-image-loader/src/webWorker/index.worker.ts diff --git a/packages/dicom-image-loader/src/webWorker/webWorker.js b/packages/dicom-image-loader/src/webWorker/webWorker.ts similarity index 72% rename from packages/dicom-image-loader/src/webWorker/webWorker.js rename to packages/dicom-image-loader/src/webWorker/webWorker.ts index fc2bd20ab..2dd64fe21 100644 --- a/packages/dicom-image-loader/src/webWorker/webWorker.js +++ b/packages/dicom-image-loader/src/webWorker/webWorker.ts @@ -1,17 +1,43 @@ +/// + +import { + CornerstoneWadoWebWorkerOptions, + CornerstoneWadoWebWorkerTaskOptions, + CornerstoneWadoWorkerTaskTypes, +} from '../imageLoader/webWorkerManager'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; +import { + CornerstoneWadoWebWorkerData, + CornerstoneWadoWebWorkerDecodeData, + CornerstoneWadoWebWorkerInitializeData, +} from './webworker-messages'; + +interface CornerstoneWadoWebWorkerTaskHandler { + taskType: CornerstoneWadoWorkerTaskTypes; + handler: ( + data: CornerstoneWadoWebWorkerDecodeData, + cb: ( + result: CornerstoneWadoImageFrame, + transferables: Transferable[] + ) => void + ) => void; + initialize: (config: CornerstoneWadoWebWorkerTaskOptions) => void; +} + // an object of task handlers -const taskHandlers = {}; +const taskHandlers: Record = {}; // Flag to ensure web worker is only initialized once let initialized = false; // the configuration object passed in when the web worker manager is initialized -let config; +let config: CornerstoneWadoWebWorkerOptions; /** * Initialization function that loads additional web workers and initializes them * @param data */ -function initialize(data) { +function initialize(data: CornerstoneWadoWebWorkerInitializeData) { // console.log('web worker initialize ', data.workerIndex); // prevent initialization from happening more than once if (initialized) { @@ -21,8 +47,11 @@ function initialize(data) { // save the config data config = data.config; + /** + * @todo review any + */ // Additional web worker tasks can self-register by calling self.registerTaskHandler - self.registerTaskHandler = registerTaskHandler; + (self as any).registerTaskHandler = registerTaskHandler; // load any additional web worker tasks if (data.config.webWorkerTaskPaths) { @@ -51,7 +80,9 @@ function initialize(data) { * Function exposed to web worker tasks to register themselves * @param taskHandler */ -export function registerTaskHandler(taskHandler) { +export function registerTaskHandler( + taskHandler: CornerstoneWadoWebWorkerTaskHandler +): false | void { if (taskHandlers[taskHandler.taskType]) { console.log( 'attempt to register duplicate task handler "', @@ -80,7 +111,7 @@ function loadWebWorkerTask(data) { * Web worker message handler - dispatches messages to the registered task handlers * @param msg */ -self.onmessage = function (msg) { +self.onmessage = function (msg: MessageEvent) { if (!msg.data.taskType) { console.log(msg.data); @@ -120,7 +151,7 @@ self.onmessage = function (msg) { ); } ); - } catch (error) { + } catch (error: any) { console.log(`task ${msg.data.taskType} failed - ${error.message}`); self.postMessage({ taskType: msg.data.taskType, diff --git a/packages/dicom-image-loader/src/webWorker/webworker-messages.ts b/packages/dicom-image-loader/src/webWorker/webworker-messages.ts new file mode 100644 index 000000000..5735dca87 --- /dev/null +++ b/packages/dicom-image-loader/src/webWorker/webworker-messages.ts @@ -0,0 +1,46 @@ +import { ByteArray } from 'dicom-parser'; +import { CornerstoneWadoLoaderOptions } from '../imageLoader/internal/options'; +import { + CornerstoneWadoWebWorkerOptions, + CornerstoneWadoWorkerTaskTypes, +} from '../imageLoader/webWorkerManager'; +import { CornerstoneWadoImageFrame } from '../shared/image-frame'; + +export interface CornerstoneWadoWebWorkerDecodeTaskData { + imageFrame: CornerstoneWadoImageFrame; + transferSyntax: string; + pixelData: ByteArray; + options: CornerstoneWadoLoaderOptions; +} + +export interface CornerstoneWadoWebWorkerDecodeData { + taskType: 'decodeTask'; + workerIndex: number; + data: CornerstoneWadoWebWorkerDecodeTaskData; +} + +export interface CornerstoneWadoWebWorkerLoadData { + taskType: 'loadWebWorkerTask'; + workerIndex: number; + sourcePath: string; + config: CornerstoneWadoWebWorkerOptions; +} + +export interface CornerstoneWadoWebWorkerInitializeData { + taskType: 'initialize'; + workerIndex: number; + config: CornerstoneWadoWebWorkerOptions; +} + +export type CornerstoneWadoWebWorkerData = + | CornerstoneWadoWebWorkerDecodeData + | CornerstoneWadoWebWorkerLoadData + | CornerstoneWadoWebWorkerInitializeData; + +export interface CornerstoneWadoWebWorkerResponse { + taskType: CornerstoneWadoWorkerTaskTypes; + status: 'failed' | 'success'; + workerIndex: number; + data?: CornerstoneWadoImageFrame; + result: string | CornerstoneWadoImageFrame; +} diff --git a/packages/docs/CHANGELOG.md b/packages/docs/CHANGELOG.md index cef9597bf..ae23b0bc7 100644 --- a/packages/docs/CHANGELOG.md +++ b/packages/docs/CHANGELOG.md @@ -3,1065 +3,584 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -## [0.7.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.6...docs@0.7.7) (2022-11-21) +## [0.7.17](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.16...docs@0.7.17) (2022-12-01) **Note:** Version bump only for package docs +## [0.7.16](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.15...docs@0.7.16) (2022-12-01) +**Note:** Version bump only for package docs +## [0.7.15](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.14...docs@0.7.15) (2022-12-01) +**Note:** Version bump only for package docs -## [0.7.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.5...docs@0.7.6) (2022-11-19) +## [0.7.14](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.13...docs@0.7.14) (2022-12-01) **Note:** Version bump only for package docs +## [0.7.13](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.12...docs@0.7.13) (2022-12-01) +**Note:** Version bump only for package docs +## [0.7.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.11...docs@0.7.12) (2022-12-01) +**Note:** Version bump only for package docs -## [0.7.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.4...docs@0.7.5) (2022-11-18) +## [0.7.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.10...docs@0.7.11) (2022-11-24) **Note:** Version bump only for package docs +## [0.7.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.9...docs@0.7.10) (2022-11-23) +**Note:** Version bump only for package docs +## [0.7.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.8...docs@0.7.9) (2022-11-23) +**Note:** Version bump only for package docs -## [0.7.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.3...docs@0.7.4) (2022-11-17) +## [0.7.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.7...docs@0.7.8) (2022-11-23) **Note:** Version bump only for package docs +## [0.7.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.6...docs@0.7.7) (2022-11-21) +**Note:** Version bump only for package docs +## [0.7.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.5...docs@0.7.6) (2022-11-19) +**Note:** Version bump only for package docs -## [0.7.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.2...docs@0.7.3) (2022-11-16) +## [0.7.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.4...docs@0.7.5) (2022-11-18) **Note:** Version bump only for package docs +## [0.7.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.3...docs@0.7.4) (2022-11-17) +**Note:** Version bump only for package docs +## [0.7.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.2...docs@0.7.3) (2022-11-16) +**Note:** Version bump only for package docs ## [0.7.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.1...docs@0.7.2) (2022-11-14) **Note:** Version bump only for package docs - - - - ## [0.7.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.7.0...docs@0.7.1) (2022-11-11) **Note:** Version bump only for package docs - - - - # [0.7.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.28...docs@0.7.0) (2022-11-11) - ### Features -* Add segmentSpecificConfiguration and add outlineOpacity config for Segmentation ([#285](https://github.com/cornerstonejs/cornerstone3D-beta/issues/285)) ([92fb495](https://github.com/cornerstonejs/cornerstone3D-beta/commit/92fb49594cfc3219f761e905ba765acaddbe1e1a)) - - - - +- Add segmentSpecificConfiguration and add outlineOpacity config for Segmentation ([#285](https://github.com/cornerstonejs/cornerstone3D-beta/issues/285)) ([92fb495](https://github.com/cornerstonejs/cornerstone3D-beta/commit/92fb49594cfc3219f761e905ba765acaddbe1e1a)) ## [0.6.28](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.27...docs@0.6.28) (2022-11-10) **Note:** Version bump only for package docs - - - - ## [0.6.27](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.26...docs@0.6.27) (2022-11-09) **Note:** Version bump only for package docs - - - - ## [0.6.26](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.25...docs@0.6.26) (2022-11-07) **Note:** Version bump only for package docs - - - - ## [0.6.25](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.24...docs@0.6.25) (2022-11-04) **Note:** Version bump only for package docs - - - - ## [0.6.24](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.23...docs@0.6.24) (2022-11-04) **Note:** Version bump only for package docs - - - - ## [0.6.23](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.22...docs@0.6.23) (2022-11-04) **Note:** Version bump only for package docs +## [0.6.22](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.21...docs@0.6.22) (2022-11-01) +**Note:** Version bump only for package docs +## [0.6.21](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.20...docs@0.6.21) (2022-11-01) +**Note:** Version bump only for package docs -## [0.6.22](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.21...docs@0.6.22) (2022-11-01) +## [0.6.20](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.19...docs@0.6.20) (2022-10-31) **Note:** Version bump only for package docs +## [0.6.19](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.18...docs@0.6.19) (2022-10-28) +**Note:** Version bump only for package docs +## [0.6.18](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.17...docs@0.6.18) (2022-10-28) +**Note:** Version bump only for package docs -## [0.6.21](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.20...docs@0.6.21) (2022-11-01) +## [0.6.17](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.16...docs@0.6.17) (2022-10-27) **Note:** Version bump only for package docs +## [0.6.16](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.15...docs@0.6.16) (2022-10-25) +**Note:** Version bump only for package docs +## [0.6.15](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.14...docs@0.6.15) (2022-10-25) +**Note:** Version bump only for package docs -## [0.6.20](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.19...docs@0.6.20) (2022-10-31) +## [0.6.14](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.13...docs@0.6.14) (2022-10-25) **Note:** Version bump only for package docs +## [0.6.13](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.12...docs@0.6.13) (2022-10-25) + +### Bug Fixes +- typo cornerStreaming --> cornerstoneStreaming ([#260](https://github.com/cornerstonejs/cornerstone3D-beta/issues/260)) ([78ff266](https://github.com/cornerstonejs/cornerstone3D-beta/commit/78ff2660c3ad7785d89af0cfe55d38dbbae0e6f4)) +## [0.6.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.11...docs@0.6.12) (2022-10-11) +**Note:** Version bump only for package docs -## [0.6.19](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.18...docs@0.6.19) (2022-10-28) +## [0.6.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.10...docs@0.6.11) (2022-10-07) **Note:** Version bump only for package docs +## [0.6.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.9...docs@0.6.10) (2022-10-06) +**Note:** Version bump only for package docs +## [0.6.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.8...docs@0.6.9) (2022-10-06) +**Note:** Version bump only for package docs -## [0.6.18](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.17...docs@0.6.18) (2022-10-28) +## [0.6.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.7...docs@0.6.8) (2022-10-06) **Note:** Version bump only for package docs +## [0.6.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.6...docs@0.6.7) (2022-10-05) +**Note:** Version bump only for package docs +## [0.6.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.5...docs@0.6.6) (2022-10-05) +**Note:** Version bump only for package docs -## [0.6.17](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.16...docs@0.6.17) (2022-10-27) +## [0.6.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.4...docs@0.6.5) (2022-10-05) **Note:** Version bump only for package docs +## [0.6.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.3...docs@0.6.4) (2022-10-04) +**Note:** Version bump only for package docs +## [0.6.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.2...docs@0.6.3) (2022-09-16) +**Note:** Version bump only for package docs -## [0.6.16](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.15...docs@0.6.16) (2022-10-25) +## [0.6.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.1...docs@0.6.2) (2022-09-14) **Note:** Version bump only for package docs +## [0.6.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.0...docs@0.6.1) (2022-09-08) + +**Note:** Version bump only for package docs +# [0.6.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.20...docs@0.6.0) (2022-09-08) +### Features +- orientation on volumeViewport can be optional ([#203](https://github.com/cornerstonejs/cornerstone3D-beta/issues/203)) ([749dcb5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/749dcb59414c1aff2dffdca582fb3df0e4ca5ed7)) -## [0.6.15](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.14...docs@0.6.15) (2022-10-25) +## [0.5.20](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.19...docs@0.5.20) (2022-09-05) **Note:** Version bump only for package docs +## [0.5.19](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.18...docs@0.5.19) (2022-09-02) +**Note:** Version bump only for package docs +## [0.5.18](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.17...docs@0.5.18) (2022-09-02) +**Note:** Version bump only for package docs -## [0.6.14](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.13...docs@0.6.14) (2022-10-25) +## [0.5.17](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.16...docs@0.5.17) (2022-08-30) **Note:** Version bump only for package docs +## [0.5.16](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.15...docs@0.5.16) (2022-08-30) +**Note:** Version bump only for package docs +## [0.5.15](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.14...docs@0.5.15) (2022-08-26) +**Note:** Version bump only for package docs -## [0.6.13](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.12...docs@0.6.13) (2022-10-25) - +## [0.5.14](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.13...docs@0.5.14) (2022-08-26) ### Bug Fixes -* typo cornerStreaming --> cornerstoneStreaming ([#260](https://github.com/cornerstonejs/cornerstone3D-beta/issues/260)) ([78ff266](https://github.com/cornerstonejs/cornerstone3D-beta/commit/78ff2660c3ad7785d89af0cfe55d38dbbae0e6f4)) +- shadow for annotations and stack viewport targetImageIdIndex bug ([#189](https://github.com/cornerstonejs/cornerstone3D-beta/issues/189)) ([be70be7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/be70be70a543fffb18f7d05c69e16d5c0255a57e)) +## [0.5.13](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.12...docs@0.5.13) (2022-08-23) +**Note:** Version bump only for package docs +## [0.5.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.11...docs@0.5.12) (2022-08-23) +**Note:** Version bump only for package docs -## [0.6.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.11...docs@0.6.12) (2022-10-11) +## [0.5.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.10...docs@0.5.11) (2022-08-23) **Note:** Version bump only for package docs +## [0.5.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.9...docs@0.5.10) (2022-08-23) +### Bug Fixes +- docs on netlify ([#183](https://github.com/cornerstonejs/cornerstone3D-beta/issues/183)) ([8b2c4a8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/8b2c4a8acbccf41daf86c00315fa43d329caa4ff)) - -## [0.6.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.10...docs@0.6.11) (2022-10-07) +## [0.5.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.8...docs@0.5.9) (2022-08-19) **Note:** Version bump only for package docs +## [0.5.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.7...docs@0.5.8) (2022-08-18) +**Note:** Version bump only for package docs +## [0.5.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.6...docs@0.5.7) (2022-08-15) +**Note:** Version bump only for package docs -## [0.6.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.9...docs@0.6.10) (2022-10-06) +## [0.5.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.5...docs@0.5.6) (2022-08-12) **Note:** Version bump only for package docs +## [0.5.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.4...docs@0.5.5) (2022-08-11) +**Note:** Version bump only for package docs +## [0.5.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.3...docs@0.5.4) (2022-08-10) +**Note:** Version bump only for package docs -## [0.6.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.8...docs@0.6.9) (2022-10-06) +## [0.5.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.2...docs@0.5.3) (2022-08-04) **Note:** Version bump only for package docs +## [0.5.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.1...docs@0.5.2) (2022-08-03) +### Bug Fixes +- wadouri metadata was not using scaling parameters properly ([#159](https://github.com/cornerstonejs/cornerstone3D-beta/issues/159)) ([d21aba5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d21aba56f1e0a8730088d89a4dfde8358d978a60)) - -## [0.6.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.7...docs@0.6.8) (2022-10-06) +## [0.5.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.0...docs@0.5.1) (2022-08-03) **Note:** Version bump only for package docs +# [0.5.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.26...docs@0.5.0) (2022-07-29) +### Features +- volume viewport api with setProperties ([#154](https://github.com/cornerstonejs/cornerstone3D-beta/issues/154)) ([fab3abe](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fab3abe907ddde1ee61bc121c40d4fc23d2dbfd7)) +## [0.4.26](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.25...docs@0.4.26) (2022-07-29) -## [0.6.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.6...docs@0.6.7) (2022-10-05) +### Bug Fixes -**Note:** Version bump only for package docs +- github links from API Docs ([#143](https://github.com/cornerstonejs/cornerstone3D-beta/issues/143)) ([dc4e6f1](https://github.com/cornerstonejs/cornerstone3D-beta/commit/dc4e6f1346b7af4c91faab8be73c5f054796a439)) +## [0.4.25](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.24...docs@0.4.25) (2022-07-27) +### Bug Fixes +- convert RGBA to RGB for GPU rendering if cached ([#152](https://github.com/cornerstonejs/cornerstone3D-beta/issues/152)) ([fb8aa36](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fb8aa36374c4bdf06d9d6da1f2df128c68dbc7da)) +## [0.4.24](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.23...docs@0.4.24) (2022-07-25) -## [0.6.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.5...docs@0.6.6) (2022-10-05) +### Bug Fixes -**Note:** Version bump only for package docs +- annotation unit hydration bug and more color image support ([#151](https://github.com/cornerstonejs/cornerstone3D-beta/issues/151)) ([4f157dc](https://github.com/cornerstonejs/cornerstone3D-beta/commit/4f157dc5d7a8d0d80abb5b68c35ed17cb5f349ed)) +## [0.4.23](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.21...docs@0.4.23) (2022-07-15) +**Note:** Version bump only for package docs +## [0.4.22](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.21...docs@0.4.22) (2022-07-08) +**Note:** Version bump only for package docs -## [0.6.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.4...docs@0.6.5) (2022-10-05) +## [0.4.21](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.20...docs@0.4.21) (2022-06-24) **Note:** Version bump only for package docs +## [0.4.20](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.19...docs@0.4.20) (2022-06-24) +**Note:** Version bump only for package docs +## [0.4.19](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.18...docs@0.4.19) (2022-06-20) +**Note:** Version bump only for package docs -## [0.6.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.3...docs@0.6.4) (2022-10-04) +## [0.4.18](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.17...docs@0.4.18) (2022-06-20) **Note:** Version bump only for package docs +## [0.4.17](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.16...docs@0.4.17) (2022-06-20) +**Note:** Version bump only for package docs +## [0.4.16](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.15...docs@0.4.16) (2022-06-20) +**Note:** Version bump only for package docs -## [0.6.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.2...docs@0.6.3) (2022-09-16) +## [0.4.15](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.14...docs@0.4.15) (2022-06-20) **Note:** Version bump only for package docs +## [0.4.14](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.13...docs@0.4.14) (2022-06-17) + +**Note:** Version bump only for package docs +## [0.4.13](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.12...docs@0.4.13) (2022-06-17) +### Bug Fixes +- large image rendering, missing metadata for StackViewport, high DPI devices ([#127](https://github.com/cornerstonejs/cornerstone3D-beta/issues/127)) ([d4bf1c8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d4bf1c80391bcecaee64d9eb086416c42aa406e2)) -## [0.6.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.1...docs@0.6.2) (2022-09-14) +## [0.4.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.11...docs@0.4.12) (2022-06-16) **Note:** Version bump only for package docs +## [0.4.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.10...docs@0.4.11) (2022-06-14) +**Note:** Version bump only for package docs +## [0.4.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.9...docs@0.4.10) (2022-06-14) +**Note:** Version bump only for package docs -## [0.6.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.6.0...docs@0.6.1) (2022-09-08) +## [0.4.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.8...docs@0.4.9) (2022-06-10) **Note:** Version bump only for package docs +## [0.4.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.7...docs@0.4.8) (2022-06-06) +**Note:** Version bump only for package docs +## [0.4.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.6...docs@0.4.7) (2022-06-01) +**Note:** Version bump only for package docs -# [0.6.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.20...docs@0.6.0) (2022-09-08) +## [0.4.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.5...docs@0.4.6) (2022-05-31) +**Note:** Version bump only for package docs -### Features +## [0.4.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.4...docs@0.4.5) (2022-05-30) -* orientation on volumeViewport can be optional ([#203](https://github.com/cornerstonejs/cornerstone3D-beta/issues/203)) ([749dcb5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/749dcb59414c1aff2dffdca582fb3df0e4ca5ed7)) +**Note:** Version bump only for package docs +## [0.4.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.3...docs@0.4.4) (2022-05-27) +**Note:** Version bump only for package docs +## [0.4.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.2...docs@0.4.3) (2022-05-27) +**Note:** Version bump only for package docs -## [0.5.20](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.19...docs@0.5.20) (2022-09-05) +## [0.4.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.1...docs@0.4.2) (2022-05-27) **Note:** Version bump only for package docs +## [0.4.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.0...docs@0.4.1) (2022-05-24) +**Note:** Version bump only for package docs +# [0.4.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.3.7...docs@0.4.0) (2022-05-24) +### Features -## [0.5.19](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.18...docs@0.5.19) (2022-09-02) +- Add Clipping planes for rendering ([#110](https://github.com/cornerstonejs/cornerstone3D-beta/issues/110)) ([1a6e4c7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/1a6e4c742a3b89a88b46fd98d6cbeca5c95918aa)) + +## [0.3.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.3.6...docs@0.3.7) (2022-05-16) **Note:** Version bump only for package docs +## [0.3.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.3.5...docs@0.3.6) (2022-05-16) +**Note:** Version bump only for package docs +## [0.3.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.3.4...docs@0.3.5) (2022-05-16) +**Note:** Version bump only for package docs -## [0.5.18](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.17...docs@0.5.18) (2022-09-02) +## [0.3.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.3.3...docs@0.3.4) (2022-05-13) **Note:** Version bump only for package docs +## [0.3.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.3.2...docs@0.3.3) (2022-05-12) +**Note:** Version bump only for package docs +## [0.3.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.3.1...docs@0.3.2) (2022-05-11) +**Note:** Version bump only for package docs -## [0.5.17](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.16...docs@0.5.17) (2022-08-30) +## [0.3.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.3.0...docs@0.3.1) (2022-05-10) **Note:** Version bump only for package docs +# [0.3.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.26...docs@0.3.0) (2022-05-09) +### Features +- Add toolStyles configuration and DragProbe ([#93](https://github.com/cornerstonejs/cornerstone3D-beta/issues/93)) ([ba15be6](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ba15be6d268b8c568bdf0e247e571f5ca29a26ad)) - -## [0.5.16](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.15...docs@0.5.16) (2022-08-30) +## [0.2.26](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.25...docs@0.2.26) (2022-05-03) **Note:** Version bump only for package docs +## [0.2.25](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.24...docs@0.2.25) (2022-05-03) +**Note:** Version bump only for package docs +## [0.2.24](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.23...docs@0.2.24) (2022-05-03) +**Note:** Version bump only for package docs -## [0.5.15](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.14...docs@0.5.15) (2022-08-26) +## [0.2.23](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.22...docs@0.2.23) (2022-04-27) **Note:** Version bump only for package docs +## [0.2.22](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.21...docs@0.2.22) (2022-04-26) +**Note:** Version bump only for package docs +## [0.2.21](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.20...docs@0.2.21) (2022-04-22) +**Note:** Version bump only for package docs -## [0.5.14](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.13...docs@0.5.14) (2022-08-26) - +## [0.2.20](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.19...docs@0.2.20) (2022-04-21) ### Bug Fixes -* shadow for annotations and stack viewport targetImageIdIndex bug ([#189](https://github.com/cornerstonejs/cornerstone3D-beta/issues/189)) ([be70be7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/be70be70a543fffb18f7d05c69e16d5c0255a57e)) +- selection API, requestPoolManager and VOI and Scaling ([#82](https://github.com/cornerstonejs/cornerstone3D-beta/issues/82)) ([bedd8dd](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bedd8ddfa356c2d52a6e72f74c7cb3bb660a86ef)) +## [0.2.19](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.18...docs@0.2.19) (2022-04-20) +**Note:** Version bump only for package docs +## [0.2.18](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.17...docs@0.2.18) (2022-04-19) +**Note:** Version bump only for package docs -## [0.5.13](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.12...docs@0.5.13) (2022-08-23) +## [0.2.17](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.16...docs@0.2.17) (2022-04-14) **Note:** Version bump only for package docs +## [0.2.16](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.15...docs@0.2.16) (2022-04-13) +**Note:** Version bump only for package docs +## [0.2.15](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.14...docs@0.2.15) (2022-04-13) +**Note:** Version bump only for package docs -## [0.5.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.11...docs@0.5.12) (2022-08-23) - -**Note:** Version bump only for package docs - - - - - -## [0.5.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.10...docs@0.5.11) (2022-08-23) - -**Note:** Version bump only for package docs - - - - - -## [0.5.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.9...docs@0.5.10) (2022-08-23) - - -### Bug Fixes - -* docs on netlify ([#183](https://github.com/cornerstonejs/cornerstone3D-beta/issues/183)) ([8b2c4a8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/8b2c4a8acbccf41daf86c00315fa43d329caa4ff)) - - - - - -## [0.5.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.8...docs@0.5.9) (2022-08-19) - -**Note:** Version bump only for package docs - - - - - -## [0.5.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.7...docs@0.5.8) (2022-08-18) - -**Note:** Version bump only for package docs - - - - - -## [0.5.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.6...docs@0.5.7) (2022-08-15) - -**Note:** Version bump only for package docs - - - - - -## [0.5.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.5...docs@0.5.6) (2022-08-12) - -**Note:** Version bump only for package docs - - - - - -## [0.5.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.4...docs@0.5.5) (2022-08-11) - -**Note:** Version bump only for package docs - - - - - -## [0.5.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.3...docs@0.5.4) (2022-08-10) - -**Note:** Version bump only for package docs - - - - - -## [0.5.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.2...docs@0.5.3) (2022-08-04) - -**Note:** Version bump only for package docs - - - - - -## [0.5.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.1...docs@0.5.2) (2022-08-03) - - -### Bug Fixes - -* wadouri metadata was not using scaling parameters properly ([#159](https://github.com/cornerstonejs/cornerstone3D-beta/issues/159)) ([d21aba5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d21aba56f1e0a8730088d89a4dfde8358d978a60)) - - - - - -## [0.5.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.5.0...docs@0.5.1) (2022-08-03) - -**Note:** Version bump only for package docs - - - - - -# [0.5.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.26...docs@0.5.0) (2022-07-29) - - -### Features - -* volume viewport api with setProperties ([#154](https://github.com/cornerstonejs/cornerstone3D-beta/issues/154)) ([fab3abe](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fab3abe907ddde1ee61bc121c40d4fc23d2dbfd7)) - - - - - -## [0.4.26](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.25...docs@0.4.26) (2022-07-29) - - -### Bug Fixes - -* github links from API Docs ([#143](https://github.com/cornerstonejs/cornerstone3D-beta/issues/143)) ([dc4e6f1](https://github.com/cornerstonejs/cornerstone3D-beta/commit/dc4e6f1346b7af4c91faab8be73c5f054796a439)) - - - - - -## [0.4.25](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.24...docs@0.4.25) (2022-07-27) - - -### Bug Fixes - -* convert RGBA to RGB for GPU rendering if cached ([#152](https://github.com/cornerstonejs/cornerstone3D-beta/issues/152)) ([fb8aa36](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fb8aa36374c4bdf06d9d6da1f2df128c68dbc7da)) - - - - - -## [0.4.24](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.23...docs@0.4.24) (2022-07-25) - - -### Bug Fixes - -* annotation unit hydration bug and more color image support ([#151](https://github.com/cornerstonejs/cornerstone3D-beta/issues/151)) ([4f157dc](https://github.com/cornerstonejs/cornerstone3D-beta/commit/4f157dc5d7a8d0d80abb5b68c35ed17cb5f349ed)) - - - - - -## [0.4.23](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.21...docs@0.4.23) (2022-07-15) - -**Note:** Version bump only for package docs - - - - - -## [0.4.22](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.21...docs@0.4.22) (2022-07-08) - -**Note:** Version bump only for package docs - - - - - -## [0.4.21](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.20...docs@0.4.21) (2022-06-24) - -**Note:** Version bump only for package docs - - - - - -## [0.4.20](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.19...docs@0.4.20) (2022-06-24) - -**Note:** Version bump only for package docs - - - - - -## [0.4.19](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.18...docs@0.4.19) (2022-06-20) - -**Note:** Version bump only for package docs - - - - - -## [0.4.18](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.17...docs@0.4.18) (2022-06-20) - -**Note:** Version bump only for package docs - - - - - -## [0.4.17](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.16...docs@0.4.17) (2022-06-20) - -**Note:** Version bump only for package docs - - - - - -## [0.4.16](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.15...docs@0.4.16) (2022-06-20) - -**Note:** Version bump only for package docs - - - - - -## [0.4.15](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.14...docs@0.4.15) (2022-06-20) - -**Note:** Version bump only for package docs - - - - - -## [0.4.14](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.13...docs@0.4.14) (2022-06-17) - -**Note:** Version bump only for package docs - - - - - -## [0.4.13](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.12...docs@0.4.13) (2022-06-17) - - -### Bug Fixes - -* large image rendering, missing metadata for StackViewport, high DPI devices ([#127](https://github.com/cornerstonejs/cornerstone3D-beta/issues/127)) ([d4bf1c8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d4bf1c80391bcecaee64d9eb086416c42aa406e2)) - - - - - -## [0.4.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.11...docs@0.4.12) (2022-06-16) - -**Note:** Version bump only for package docs - - - - - -## [0.4.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.10...docs@0.4.11) (2022-06-14) - -**Note:** Version bump only for package docs - - - - - -## [0.4.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.9...docs@0.4.10) (2022-06-14) - -**Note:** Version bump only for package docs - - - - - -## [0.4.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.8...docs@0.4.9) (2022-06-10) - -**Note:** Version bump only for package docs - - - - - -## [0.4.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.7...docs@0.4.8) (2022-06-06) - -**Note:** Version bump only for package docs - - - - - -## [0.4.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.6...docs@0.4.7) (2022-06-01) - -**Note:** Version bump only for package docs - - - - - -## [0.4.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.5...docs@0.4.6) (2022-05-31) - -**Note:** Version bump only for package docs - - - - - -## [0.4.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.4...docs@0.4.5) (2022-05-30) - -**Note:** Version bump only for package docs - - - - - -## [0.4.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.3...docs@0.4.4) (2022-05-27) - -**Note:** Version bump only for package docs - - - - - -## [0.4.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.2...docs@0.4.3) (2022-05-27) - -**Note:** Version bump only for package docs - - - - - -## [0.4.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.1...docs@0.4.2) (2022-05-27) - -**Note:** Version bump only for package docs - - - - - -## [0.4.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.4.0...docs@0.4.1) (2022-05-24) - -**Note:** Version bump only for package docs - - - - - -# [0.4.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.3.7...docs@0.4.0) (2022-05-24) - - -### Features - -* Add Clipping planes for rendering ([#110](https://github.com/cornerstonejs/cornerstone3D-beta/issues/110)) ([1a6e4c7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/1a6e4c742a3b89a88b46fd98d6cbeca5c95918aa)) - - - - - -## [0.3.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.3.6...docs@0.3.7) (2022-05-16) - -**Note:** Version bump only for package docs - - - - - -## [0.3.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.3.5...docs@0.3.6) (2022-05-16) - -**Note:** Version bump only for package docs - - - - - -## [0.3.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.3.4...docs@0.3.5) (2022-05-16) - -**Note:** Version bump only for package docs - - - - - -## [0.3.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.3.3...docs@0.3.4) (2022-05-13) - -**Note:** Version bump only for package docs - - - - - -## [0.3.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.3.2...docs@0.3.3) (2022-05-12) - -**Note:** Version bump only for package docs - - - - - -## [0.3.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.3.1...docs@0.3.2) (2022-05-11) - -**Note:** Version bump only for package docs - - - - - -## [0.3.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.3.0...docs@0.3.1) (2022-05-10) - -**Note:** Version bump only for package docs - - - - - -# [0.3.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.26...docs@0.3.0) (2022-05-09) - - -### Features - -* Add toolStyles configuration and DragProbe ([#93](https://github.com/cornerstonejs/cornerstone3D-beta/issues/93)) ([ba15be6](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ba15be6d268b8c568bdf0e247e571f5ca29a26ad)) - - - - - -## [0.2.26](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.25...docs@0.2.26) (2022-05-03) - -**Note:** Version bump only for package docs - - - - - -## [0.2.25](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.24...docs@0.2.25) (2022-05-03) - -**Note:** Version bump only for package docs - - - - - -## [0.2.24](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.23...docs@0.2.24) (2022-05-03) - -**Note:** Version bump only for package docs - - - - - -## [0.2.23](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.22...docs@0.2.23) (2022-04-27) - -**Note:** Version bump only for package docs - - - - - -## [0.2.22](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.21...docs@0.2.22) (2022-04-26) - -**Note:** Version bump only for package docs - - - - - -## [0.2.21](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.20...docs@0.2.21) (2022-04-22) - -**Note:** Version bump only for package docs - - - - - -## [0.2.20](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.19...docs@0.2.20) (2022-04-21) - - -### Bug Fixes - -* selection API, requestPoolManager and VOI and Scaling ([#82](https://github.com/cornerstonejs/cornerstone3D-beta/issues/82)) ([bedd8dd](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bedd8ddfa356c2d52a6e72f74c7cb3bb660a86ef)) - - - - - -## [0.2.19](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.18...docs@0.2.19) (2022-04-20) - -**Note:** Version bump only for package docs - - - - - -## [0.2.18](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.17...docs@0.2.18) (2022-04-19) - -**Note:** Version bump only for package docs - - - - - -## [0.2.17](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.16...docs@0.2.17) (2022-04-14) - -**Note:** Version bump only for package docs - - - - - -## [0.2.16](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.15...docs@0.2.16) (2022-04-13) - -**Note:** Version bump only for package docs - - - - - -## [0.2.15](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.14...docs@0.2.15) (2022-04-13) - -**Note:** Version bump only for package docs - - - - - -## [0.2.14](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.13...docs@0.2.14) (2022-04-12) - -**Note:** Version bump only for package docs - - - - - -## [0.2.13](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.12...docs@0.2.13) (2022-04-12) - -**Note:** Version bump only for package docs - - - - - -## [0.2.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.11...docs@0.2.12) (2022-04-11) +## [0.2.14](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.13...docs@0.2.14) (2022-04-12) **Note:** Version bump only for package docs +## [0.2.13](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.12...docs@0.2.13) (2022-04-12) +**Note:** Version bump only for package docs +## [0.2.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.11...docs@0.2.12) (2022-04-11) +**Note:** Version bump only for package docs ## [0.2.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.10...docs@0.2.11) (2022-04-11) - ### Bug Fixes -* extract IRenderingEngine type, docs: add documentation search ([#70](https://github.com/cornerstonejs/cornerstone3D-beta/issues/70)) ([6a705a8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/6a705a8f3cb9e8463c0ab6fe4d59dd3bb8bf5ef2)) - - - - +- extract IRenderingEngine type, docs: add documentation search ([#70](https://github.com/cornerstonejs/cornerstone3D-beta/issues/70)) ([6a705a8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/6a705a8f3cb9e8463c0ab6fe4d59dd3bb8bf5ef2)) ## [0.2.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.9...docs@0.2.10) (2022-04-04) **Note:** Version bump only for package docs - - - - ## [0.2.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.8...docs@0.2.9) (2022-04-04) **Note:** Version bump only for package docs - - - - ## [0.2.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.7...docs@0.2.8) (2022-04-01) **Note:** Version bump only for package docs - - - - ## [0.2.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.6...docs@0.2.7) (2022-04-01) **Note:** Version bump only for package docs - - - - ## [0.2.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.5...docs@0.2.6) (2022-04-01) **Note:** Version bump only for package docs - - - - ## [0.2.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.4...docs@0.2.5) (2022-04-01) **Note:** Version bump only for package docs - - - - ## [0.2.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.3...docs@0.2.4) (2022-04-01) **Note:** Version bump only for package docs - - - - ## [0.2.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.2...docs@0.2.3) (2022-04-01) **Note:** Version bump only for package docs - - - - ## [0.2.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.1...docs@0.2.2) (2022-04-01) - ### Bug Fixes -* cleanup exports, add docs and more tutorials ([#39](https://github.com/cornerstonejs/cornerstone3D-beta/issues/39)) ([743dea8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/743dea89c7a726c29d396756bdd991c81e561105)) - - - - +- cleanup exports, add docs and more tutorials ([#39](https://github.com/cornerstonejs/cornerstone3D-beta/issues/39)) ([743dea8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/743dea89c7a726c29d396756bdd991c81e561105)) ## [0.2.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.2.0...docs@0.2.1) (2022-03-31) **Note:** Version bump only for package docs - - - - # [0.2.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.1.11...docs@0.2.0) (2022-03-31) - ### Features -* advanced examples ([#38](https://github.com/cornerstonejs/cornerstone3D-beta/issues/38)) ([27f26a1](https://github.com/cornerstonejs/cornerstone3D-beta/commit/27f26a12a1712b7542cc66ab1d077cfb0da50a86)) - - - - +- advanced examples ([#38](https://github.com/cornerstonejs/cornerstone3D-beta/issues/38)) ([27f26a1](https://github.com/cornerstonejs/cornerstone3D-beta/commit/27f26a12a1712b7542cc66ab1d077cfb0da50a86)) ## [0.1.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.1.10...docs@0.1.11) (2022-03-31) **Note:** Version bump only for package docs - - - - ## [0.1.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.1.9...docs@0.1.10) (2022-03-31) **Note:** Version bump only for package docs - - - - ## [0.1.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.1.8...docs@0.1.9) (2022-03-31) **Note:** Version bump only for package docs - - - - ## [0.1.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.1.7...docs@0.1.8) (2022-03-31) **Note:** Version bump only for package docs - - - - ## [0.1.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.1.6...docs@0.1.7) (2022-03-30) **Note:** Version bump only for package docs - - - - ## [0.1.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.1.5...docs@0.1.6) (2022-03-30) **Note:** Version bump only for package docs - - - - ## [0.1.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/docs@0.1.4...docs@0.1.5) (2022-03-30) **Note:** Version bump only for package docs diff --git a/packages/docs/package.json b/packages/docs/package.json index d928103ab..bf5271ed5 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -1,6 +1,6 @@ { "name": "docs", - "version": "0.7.7", + "version": "0.7.17", "private": true, "repository": "https://github.com/cornerstonejs/cornerstone3D-beta", "scripts": { @@ -28,9 +28,9 @@ "write-heading-ids": "docusaurus write-heading-ids" }, "dependencies": { - "@cornerstonejs/core": "^0.21.4", - "@cornerstonejs/streaming-image-volume-loader": "^0.6.5", - "@cornerstonejs/tools": "^0.29.6", + "@cornerstonejs/core": "^0.22.3", + "@cornerstonejs/streaming-image-volume-loader": "^0.6.11", + "@cornerstonejs/tools": "^0.30.7", "@docusaurus/core": "2.0.0-rc.1", "@docusaurus/module-type-aliases": "2.0.0-rc.1", "@docusaurus/preset-classic": "2.0.0-rc.1", diff --git a/packages/streaming-image-volume-loader/CHANGELOG.md b/packages/streaming-image-volume-loader/CHANGELOG.md index e86c2d7dc..f73dfa971 100644 --- a/packages/streaming-image-volume-loader/CHANGELOG.md +++ b/packages/streaming-image-volume-loader/CHANGELOG.md @@ -3,691 +3,382 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -## [0.6.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.6.4...@cornerstonejs/streaming-image-volume-loader@0.6.5) (2022-11-21) +## [0.6.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.6.10...@cornerstonejs/streaming-image-volume-loader@0.6.11) (2022-12-01) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader +## [0.6.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.6.9...@cornerstonejs/streaming-image-volume-loader@0.6.10) (2022-12-01) +**Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - -## [0.6.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.6.3...@cornerstonejs/streaming-image-volume-loader@0.6.4) (2022-11-19) +## [0.6.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.6.8...@cornerstonejs/streaming-image-volume-loader@0.6.9) (2022-12-01) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader +## [0.6.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.6.7...@cornerstonejs/streaming-image-volume-loader@0.6.8) (2022-12-01) +### Bug Fixes +- htj2k and keymodifier ([#313](https://github.com/cornerstonejs/cornerstone3D-beta/issues/313)) ([48bd8a1](https://github.com/cornerstonejs/cornerstone3D-beta/commit/48bd8a14b81e31cba9f3237b0b68b7082bd66892)) - -## [0.6.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.6.2...@cornerstonejs/streaming-image-volume-loader@0.6.3) (2022-11-18) +## [0.6.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.6.6...@cornerstonejs/streaming-image-volume-loader@0.6.7) (2022-11-23) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader +## [0.6.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.6.5...@cornerstonejs/streaming-image-volume-loader@0.6.6) (2022-11-23) +**Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader +## [0.6.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.6.4...@cornerstonejs/streaming-image-volume-loader@0.6.5) (2022-11-21) +**Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader -## [0.6.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.6.1...@cornerstonejs/streaming-image-volume-loader@0.6.2) (2022-11-17) +## [0.6.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.6.3...@cornerstonejs/streaming-image-volume-loader@0.6.4) (2022-11-19) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader +## [0.6.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.6.2...@cornerstonejs/streaming-image-volume-loader@0.6.3) (2022-11-18) +**Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader +## [0.6.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.6.1...@cornerstonejs/streaming-image-volume-loader@0.6.2) (2022-11-17) +**Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader ## [0.6.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.6.0...@cornerstonejs/streaming-image-volume-loader@0.6.1) (2022-11-11) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - # [0.6.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.19...@cornerstonejs/streaming-image-volume-loader@0.6.0) (2022-11-11) - ### Features -* Add segmentSpecificConfiguration and add outlineOpacity config for Segmentation ([#285](https://github.com/cornerstonejs/cornerstone3D-beta/issues/285)) ([92fb495](https://github.com/cornerstonejs/cornerstone3D-beta/commit/92fb49594cfc3219f761e905ba765acaddbe1e1a)) - - - - +- Add segmentSpecificConfiguration and add outlineOpacity config for Segmentation ([#285](https://github.com/cornerstonejs/cornerstone3D-beta/issues/285)) ([92fb495](https://github.com/cornerstonejs/cornerstone3D-beta/commit/92fb49594cfc3219f761e905ba765acaddbe1e1a)) ## [0.5.19](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.18...@cornerstonejs/streaming-image-volume-loader@0.5.19) (2022-11-09) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.18](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.17...@cornerstonejs/streaming-image-volume-loader@0.5.18) (2022-11-04) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.17](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.16...@cornerstonejs/streaming-image-volume-loader@0.5.17) (2022-11-04) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.16](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.15...@cornerstonejs/streaming-image-volume-loader@0.5.16) (2022-11-04) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.15](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.14...@cornerstonejs/streaming-image-volume-loader@0.5.15) (2022-11-01) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.14](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.13...@cornerstonejs/streaming-image-volume-loader@0.5.14) (2022-10-31) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.13](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.12...@cornerstonejs/streaming-image-volume-loader@0.5.13) (2022-10-28) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.11...@cornerstonejs/streaming-image-volume-loader@0.5.12) (2022-10-28) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.10...@cornerstonejs/streaming-image-volume-loader@0.5.11) (2022-10-27) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.9...@cornerstonejs/streaming-image-volume-loader@0.5.10) (2022-10-25) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.8...@cornerstonejs/streaming-image-volume-loader@0.5.9) (2022-10-25) - ### Bug Fixes -* fixes the memory leak for volumes ([#253](https://github.com/cornerstonejs/cornerstone3D-beta/issues/253)) ([c863126](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c863126fc1df3fa989e15da1a7eae43cf94b24d0)) - - - - +- fixes the memory leak for volumes ([#253](https://github.com/cornerstonejs/cornerstone3D-beta/issues/253)) ([c863126](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c863126fc1df3fa989e15da1a7eae43cf94b24d0)) ## [0.5.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.7...@cornerstonejs/streaming-image-volume-loader@0.5.8) (2022-10-07) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.6...@cornerstonejs/streaming-image-volume-loader@0.5.7) (2022-10-06) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.5...@cornerstonejs/streaming-image-volume-loader@0.5.6) (2022-10-06) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.4...@cornerstonejs/streaming-image-volume-loader@0.5.5) (2022-10-05) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.3...@cornerstonejs/streaming-image-volume-loader@0.5.4) (2022-10-05) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.2...@cornerstonejs/streaming-image-volume-loader@0.5.3) (2022-09-16) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.1...@cornerstonejs/streaming-image-volume-loader@0.5.2) (2022-09-14) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.5.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.5.0...@cornerstonejs/streaming-image-volume-loader@0.5.1) (2022-09-08) - ### Bug Fixes -* drag probe appearing unnecessarily on all viewports ([#204](https://github.com/cornerstonejs/cornerstone3D-beta/issues/204)) ([c292c05](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c292c05eecf17a6edbdcab5aa5a604304ef3d2e5)) - - - - +- drag probe appearing unnecessarily on all viewports ([#204](https://github.com/cornerstonejs/cornerstone3D-beta/issues/204)) ([c292c05](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c292c05eecf17a6edbdcab5aa5a604304ef3d2e5)) # [0.5.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.23...@cornerstonejs/streaming-image-volume-loader@0.5.0) (2022-09-08) - ### Features -* orientation on volumeViewport can be optional ([#203](https://github.com/cornerstonejs/cornerstone3D-beta/issues/203)) ([749dcb5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/749dcb59414c1aff2dffdca582fb3df0e4ca5ed7)) - - - - +- orientation on volumeViewport can be optional ([#203](https://github.com/cornerstonejs/cornerstone3D-beta/issues/203)) ([749dcb5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/749dcb59414c1aff2dffdca582fb3df0e4ca5ed7)) ## [0.4.23](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.22...@cornerstonejs/streaming-image-volume-loader@0.4.23) (2022-09-02) - ### Bug Fixes -* annotations throwing error when stack and volume viewports are converted ([#195](https://github.com/cornerstonejs/cornerstone3D-beta/issues/195)) ([ed23f05](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ed23f05b23063769942328f9e6797d792767ec49)) - - - - +- annotations throwing error when stack and volume viewports are converted ([#195](https://github.com/cornerstonejs/cornerstone3D-beta/issues/195)) ([ed23f05](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ed23f05b23063769942328f9e6797d792767ec49)) ## [0.4.22](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.21...@cornerstonejs/streaming-image-volume-loader@0.4.22) (2022-08-26) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.21](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.20...@cornerstonejs/streaming-image-volume-loader@0.4.21) (2022-08-26) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.20](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.19...@cornerstonejs/streaming-image-volume-loader@0.4.20) (2022-08-23) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.19](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.18...@cornerstonejs/streaming-image-volume-loader@0.4.19) (2022-08-23) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.18](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.17...@cornerstonejs/streaming-image-volume-loader@0.4.18) (2022-08-19) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.17](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.16...@cornerstonejs/streaming-image-volume-loader@0.4.17) (2022-08-18) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.16](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.15...@cornerstonejs/streaming-image-volume-loader@0.4.16) (2022-08-15) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.15](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.14...@cornerstonejs/streaming-image-volume-loader@0.4.15) (2022-08-04) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.14](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.13...@cornerstonejs/streaming-image-volume-loader@0.4.14) (2022-08-03) - ### Bug Fixes -* wadouri metadata was not using scaling parameters properly ([#159](https://github.com/cornerstonejs/cornerstone3D-beta/issues/159)) ([d21aba5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d21aba56f1e0a8730088d89a4dfde8358d978a60)) - - - - +- wadouri metadata was not using scaling parameters properly ([#159](https://github.com/cornerstonejs/cornerstone3D-beta/issues/159)) ([d21aba5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d21aba56f1e0a8730088d89a4dfde8358d978a60)) ## [0.4.13](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.12...@cornerstonejs/streaming-image-volume-loader@0.4.13) (2022-08-03) - ### Bug Fixes -* Attempt to fix build issues [@haehn](https://github.com/haehn) has reported ([#144](https://github.com/cornerstonejs/cornerstone3D-beta/issues/144)) ([2a7ec92](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2a7ec9271e012929682aa5c0a860cd65d0d5c02d)) - - - - +- Attempt to fix build issues [@haehn](https://github.com/haehn) has reported ([#144](https://github.com/cornerstonejs/cornerstone3D-beta/issues/144)) ([2a7ec92](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2a7ec9271e012929682aa5c0a860cd65d0d5c02d)) ## [0.4.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.11...@cornerstonejs/streaming-image-volume-loader@0.4.12) (2022-07-29) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.10...@cornerstonejs/streaming-image-volume-loader@0.4.11) (2022-07-27) - ### Bug Fixes -* convert RGBA to RGB for GPU rendering if cached ([#152](https://github.com/cornerstonejs/cornerstone3D-beta/issues/152)) ([fb8aa36](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fb8aa36374c4bdf06d9d6da1f2df128c68dbc7da)) - - - - +- convert RGBA to RGB for GPU rendering if cached ([#152](https://github.com/cornerstonejs/cornerstone3D-beta/issues/152)) ([fb8aa36](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fb8aa36374c4bdf06d9d6da1f2df128c68dbc7da)) ## [0.4.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.9...@cornerstonejs/streaming-image-volume-loader@0.4.10) (2022-07-25) - ### Bug Fixes -* annotation unit hydration bug and more color image support ([#151](https://github.com/cornerstonejs/cornerstone3D-beta/issues/151)) ([4f157dc](https://github.com/cornerstonejs/cornerstone3D-beta/commit/4f157dc5d7a8d0d80abb5b68c35ed17cb5f349ed)) - - - - +- annotation unit hydration bug and more color image support ([#151](https://github.com/cornerstonejs/cornerstone3D-beta/issues/151)) ([4f157dc](https://github.com/cornerstonejs/cornerstone3D-beta/commit/4f157dc5d7a8d0d80abb5b68c35ed17cb5f349ed)) ## [0.4.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.8...@cornerstonejs/streaming-image-volume-loader@0.4.9) (2022-06-24) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.7...@cornerstonejs/streaming-image-volume-loader@0.4.8) (2022-06-24) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.6...@cornerstonejs/streaming-image-volume-loader@0.4.7) (2022-06-20) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.5...@cornerstonejs/streaming-image-volume-loader@0.4.6) (2022-06-20) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.4...@cornerstonejs/streaming-image-volume-loader@0.4.5) (2022-06-20) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.3...@cornerstonejs/streaming-image-volume-loader@0.4.4) (2022-06-20) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.2...@cornerstonejs/streaming-image-volume-loader@0.4.3) (2022-06-20) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.1...@cornerstonejs/streaming-image-volume-loader@0.4.2) (2022-06-17) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.4.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.4.0...@cornerstonejs/streaming-image-volume-loader@0.4.1) (2022-06-17) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - # [0.4.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.3.7...@cornerstonejs/streaming-image-volume-loader@0.4.0) (2022-06-14) - ### Features -* remove unnecessary event firing for annotations ([#123](https://github.com/cornerstonejs/cornerstone3D-beta/issues/123)) ([03551d9](https://github.com/cornerstonejs/cornerstone3D-beta/commit/03551d9f9269b7bfd3d828dad4f8f38ef51703d1)) - - - - +- remove unnecessary event firing for annotations ([#123](https://github.com/cornerstonejs/cornerstone3D-beta/issues/123)) ([03551d9](https://github.com/cornerstonejs/cornerstone3D-beta/commit/03551d9f9269b7bfd3d828dad4f8f38ef51703d1)) ## [0.3.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.3.6...@cornerstonejs/streaming-image-volume-loader@0.3.7) (2022-06-10) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.3.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.3.5...@cornerstonejs/streaming-image-volume-loader@0.3.6) (2022-06-06) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.3.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.3.4...@cornerstonejs/streaming-image-volume-loader@0.3.5) (2022-06-01) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.3.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.3.3...@cornerstonejs/streaming-image-volume-loader@0.3.4) (2022-05-31) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.3.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.3.2...@cornerstonejs/streaming-image-volume-loader@0.3.3) (2022-05-27) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.3.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.3.1...@cornerstonejs/streaming-image-volume-loader@0.3.2) (2022-05-27) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.3.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.3.0...@cornerstonejs/streaming-image-volume-loader@0.3.1) (2022-05-27) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - # [0.3.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.27...@cornerstonejs/streaming-image-volume-loader@0.3.0) (2022-05-24) - ### Features -* Add VOLUME_NEW_IMAGE event and Add jumpToSlice and default VOI for volume viewport ([#104](https://github.com/cornerstonejs/cornerstone3D-beta/issues/104)) ([d36a23a](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d36a23a4eaf5bafcc8dddc0ab796065098df616a)) - - - - +- Add VOLUME_NEW_IMAGE event and Add jumpToSlice and default VOI for volume viewport ([#104](https://github.com/cornerstonejs/cornerstone3D-beta/issues/104)) ([d36a23a](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d36a23a4eaf5bafcc8dddc0ab796065098df616a)) ## [0.2.27](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.26...@cornerstonejs/streaming-image-volume-loader@0.2.27) (2022-05-24) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.26](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.25...@cornerstonejs/streaming-image-volume-loader@0.2.26) (2022-05-11) - ### Bug Fixes -* Attempt to resolve incompatible peerDeps situation ([#98](https://github.com/cornerstonejs/cornerstone3D-beta/issues/98)) ([00f141b](https://github.com/cornerstonejs/cornerstone3D-beta/commit/00f141bfa9f9a4b37c016d726a6d31f2330e2e44)) - - - - +- Attempt to resolve incompatible peerDeps situation ([#98](https://github.com/cornerstonejs/cornerstone3D-beta/issues/98)) ([00f141b](https://github.com/cornerstonejs/cornerstone3D-beta/commit/00f141bfa9f9a4b37c016d726a6d31f2330e2e44)) ## [0.2.25](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.24...@cornerstonejs/streaming-image-volume-loader@0.2.25) (2022-05-10) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.24](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.23...@cornerstonejs/streaming-image-volume-loader@0.2.24) (2022-04-27) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.23](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.22...@cornerstonejs/streaming-image-volume-loader@0.2.23) (2022-04-22) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.22](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.21...@cornerstonejs/streaming-image-volume-loader@0.2.22) (2022-04-21) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.21](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.20...@cornerstonejs/streaming-image-volume-loader@0.2.21) (2022-04-20) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.20](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.19...@cornerstonejs/streaming-image-volume-loader@0.2.20) (2022-04-19) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.19](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.18...@cornerstonejs/streaming-image-volume-loader@0.2.19) (2022-04-14) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.18](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.17...@cornerstonejs/streaming-image-volume-loader@0.2.18) (2022-04-13) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.17](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.16...@cornerstonejs/streaming-image-volume-loader@0.2.17) (2022-04-13) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.16](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.15...@cornerstonejs/streaming-image-volume-loader@0.2.16) (2022-04-12) - ### Bug Fixes -* Remove resemblejs from dependencies, add detect-gpu, clonedeep, CWIL ([#73](https://github.com/cornerstonejs/cornerstone3D-beta/issues/73)) ([db65d50](https://github.com/cornerstonejs/cornerstone3D-beta/commit/db65d50a5c7488f323ab2424cf9d750055b2e6d5)) - - - - +- Remove resemblejs from dependencies, add detect-gpu, clonedeep, CWIL ([#73](https://github.com/cornerstonejs/cornerstone3D-beta/issues/73)) ([db65d50](https://github.com/cornerstonejs/cornerstone3D-beta/commit/db65d50a5c7488f323ab2424cf9d750055b2e6d5)) ## [0.2.15](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.14...@cornerstonejs/streaming-image-volume-loader@0.2.15) (2022-04-12) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.14](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.13...@cornerstonejs/streaming-image-volume-loader@0.2.14) (2022-04-11) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.13](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.12...@cornerstonejs/streaming-image-volume-loader@0.2.13) (2022-04-04) - ### Bug Fixes -* Correct module property for ESM builds in package.json ([#66](https://github.com/cornerstonejs/cornerstone3D-beta/issues/66)) ([d53b857](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d53b8575aa8b93907f8bf127f36d9dfc10821478)) - - - - +- Correct module property for ESM builds in package.json ([#66](https://github.com/cornerstonejs/cornerstone3D-beta/issues/66)) ([d53b857](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d53b8575aa8b93907f8bf127f36d9dfc10821478)) ## [0.2.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.11...@cornerstonejs/streaming-image-volume-loader@0.2.12) (2022-04-04) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.10...@cornerstonejs/streaming-image-volume-loader@0.2.11) (2022-04-01) - ### Bug Fixes -* Webpack externals were not properly defined ([70499a5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/70499a55c5824b3f94920ffd48411118e6fe4bb8)) - - - - +- Webpack externals were not properly defined ([70499a5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/70499a55c5824b3f94920ffd48411118e6fe4bb8)) ## [0.2.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.9...@cornerstonejs/streaming-image-volume-loader@0.2.10) (2022-04-01) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.8...@cornerstonejs/streaming-image-volume-loader@0.2.9) (2022-03-31) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.7...@cornerstonejs/streaming-image-volume-loader@0.2.8) (2022-03-31) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.6...@cornerstonejs/streaming-image-volume-loader@0.2.7) (2022-03-31) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.5...@cornerstonejs/streaming-image-volume-loader@0.2.6) (2022-03-30) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader - - - - ## [0.2.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/streaming-image-volume-loader@0.2.4...@cornerstonejs/streaming-image-volume-loader@0.2.5) (2022-03-30) **Note:** Version bump only for package @cornerstonejs/streaming-image-volume-loader diff --git a/packages/streaming-image-volume-loader/package.json b/packages/streaming-image-volume-loader/package.json index c57687ca7..2b60ba222 100644 --- a/packages/streaming-image-volume-loader/package.json +++ b/packages/streaming-image-volume-loader/package.json @@ -1,6 +1,6 @@ { "name": "@cornerstonejs/streaming-image-volume-loader", - "version": "0.6.5", + "version": "0.6.11", "description": "", "main": "dist/umd/index.js", "types": "dist/esm/index.d.ts", @@ -26,8 +26,8 @@ "webpack:watch": "webpack --mode development --progress --watch --config ./.webpack/webpack.dev.js" }, "dependencies": { - "@cornerstonejs/core": "^0.21.4", - "@cornerstonejs/dicom-image-loader": "^0.1.1" + "@cornerstonejs/core": "^0.22.3", + "cornerstone-wado-image-loader": "^4.2.1" }, "peerDependencies": { "@cornerstonejs/calculate-suv": "1.0.2" diff --git a/packages/streaming-image-volume-loader/src/sharedArrayBufferImageLoader.ts b/packages/streaming-image-volume-loader/src/sharedArrayBufferImageLoader.ts index cf37d8ae1..f1db80811 100644 --- a/packages/streaming-image-volume-loader/src/sharedArrayBufferImageLoader.ts +++ b/packages/streaming-image-volume-loader/src/sharedArrayBufferImageLoader.ts @@ -129,6 +129,8 @@ function getTransferSyntaxForContentType(contentType: string): string { 'image/x-jls': '1.2.840.10008.1.2.4.80', 'image/jp2': '1.2.840.10008.1.2.4.90', 'image/jpx': '1.2.840.10008.1.2.4.92', + 'image/jphc': '3.2.840.10008.1.2.4.96', + 'image/jls': '1.2.840.10008.1.2.4.80', }; if (params['transfer-syntax']) { diff --git a/packages/tools/CHANGELOG.md b/packages/tools/CHANGELOG.md index 1c3a1a50b..5b7b54be5 100644 --- a/packages/tools/CHANGELOG.md +++ b/packages/tools/CHANGELOG.md @@ -3,1139 +3,663 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -## [0.29.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.29.5...@cornerstonejs/tools@0.29.6) (2022-11-21) - +## [0.30.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.30.6...@cornerstonejs/tools@0.30.7) (2022-12-01) ### Bug Fixes -* annotation rendering engine on viewport removal ([#303](https://github.com/cornerstonejs/cornerstone3D-beta/issues/303)) ([aeb205e](https://github.com/cornerstonejs/cornerstone3D-beta/commit/aeb205e56e0d2068258c278863aa3d7447331a43)) - +- Use queryselector instead of firstChild to get svg-layer ([#268](https://github.com/cornerstonejs/cornerstone3D-beta/issues/268)) ([1dd315c](https://github.com/cornerstonejs/cornerstone3D-beta/commit/1dd315c61476f7bca5640033f530bcc956d14307)) +## [0.30.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.30.5...@cornerstonejs/tools@0.30.6) (2022-12-01) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.30.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.30.4...@cornerstonejs/tools@0.30.5) (2022-12-01) -## [0.29.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.29.4...@cornerstonejs/tools@0.29.5) (2022-11-19) +### Bug Fixes -**Note:** Version bump only for package @cornerstonejs/tools +- bidirectional tool when short and long axis changes ([#309](https://github.com/cornerstonejs/cornerstone3D-beta/issues/309)) ([f973e72](https://github.com/cornerstonejs/cornerstone3D-beta/commit/f973e7262897a2daf4f37363d3e818ae88620bb8)) +## [0.30.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.30.3...@cornerstonejs/tools@0.30.4) (2022-12-01) +### Bug Fixes +- coronal view should not be flipped ([#321](https://github.com/cornerstonejs/cornerstone3D-beta/issues/321)) ([a85a867](https://github.com/cornerstonejs/cornerstone3D-beta/commit/a85a86785de9f225154829a4934926143c86eb5e)) +## [0.30.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.30.2...@cornerstonejs/tools@0.30.3) (2022-12-01) -## [0.29.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.29.3...@cornerstonejs/tools@0.29.4) (2022-11-18) +### Bug Fixes -**Note:** Version bump only for package @cornerstonejs/tools +- htj2k and keymodifier ([#313](https://github.com/cornerstonejs/cornerstone3D-beta/issues/313)) ([48bd8a1](https://github.com/cornerstonejs/cornerstone3D-beta/commit/48bd8a14b81e31cba9f3237b0b68b7082bd66892)) +## [0.30.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.30.1...@cornerstonejs/tools@0.30.2) (2022-12-01) +### Bug Fixes +- filter planarFreeHandeROI based on parallel normals instead of equal normals. ([#315](https://github.com/cornerstonejs/cornerstone3D-beta/issues/315)) ([70e4ffa](https://github.com/cornerstonejs/cornerstone3D-beta/commit/70e4ffa0c28ed293473c6674d7b158c644f9b1be)) +- get correct imageData with targetId in BaseTool ([#294](https://github.com/cornerstonejs/cornerstone3D-beta/issues/294)) ([6e8e51b](https://github.com/cornerstonejs/cornerstone3D-beta/commit/6e8e51b4b3dde358134fcc7493237a59bec687ab)) +- If planar annotation is not visible, filter it ([#318](https://github.com/cornerstonejs/cornerstone3D-beta/issues/318)) ([ea8e32a](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ea8e32a768d3f2d43fc0f1bc9b29388101825ad2)) +## [0.30.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.30.0...@cornerstonejs/tools@0.30.1) (2022-11-24) -## [0.29.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.29.2...@cornerstonejs/tools@0.29.3) (2022-11-17) +### Bug Fixes -**Note:** Version bump only for package @cornerstonejs/tools +- ZoomTool fix for polyData actors with no imageData ([#308](https://github.com/cornerstonejs/cornerstone3D-beta/issues/308)) ([1350eca](https://github.com/cornerstonejs/cornerstone3D-beta/commit/1350eca3cdc8d456642c6497dd2b2460a3584c7e)) +# [0.30.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.29.8...@cornerstonejs/tools@0.30.0) (2022-11-23) +### Features +- add referenceCursors tool ([#275](https://github.com/cornerstonejs/cornerstone3D-beta/issues/275)) ([3303246](https://github.com/cornerstonejs/cornerstone3D-beta/commit/3303246836c81efb51e5d5e70c1a8801fbcb019a)) +## [0.29.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.29.7...@cornerstonejs/tools@0.29.8) (2022-11-23) -## [0.29.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.29.1...@cornerstonejs/tools@0.29.2) (2022-11-16) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.29.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.29.6...@cornerstonejs/tools@0.29.7) (2022-11-23) ### Bug Fixes -* revert synchronizer event firing being unnecessary async ([#299](https://github.com/cornerstonejs/cornerstone3D-beta/issues/299)) ([1e244d1](https://github.com/cornerstonejs/cornerstone3D-beta/commit/1e244d11778d74b66df671f936138c73adb5a699)) - - +- mouse-up should not unhighlight annotations ([#305](https://github.com/cornerstonejs/cornerstone3D-beta/issues/305)) ([0ca9653](https://github.com/cornerstonejs/cornerstone3D-beta/commit/0ca96533d253c35534c9820e4174b54270483d5e)) +## [0.29.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.29.5...@cornerstonejs/tools@0.29.6) (2022-11-21) +### Bug Fixes -## [0.29.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.29.0...@cornerstonejs/tools@0.29.1) (2022-11-14) +- annotation rendering engine on viewport removal ([#303](https://github.com/cornerstonejs/cornerstone3D-beta/issues/303)) ([aeb205e](https://github.com/cornerstonejs/cornerstone3D-beta/commit/aeb205e56e0d2068258c278863aa3d7447331a43)) +## [0.29.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.29.4...@cornerstonejs/tools@0.29.5) (2022-11-19) -### Bug Fixes +**Note:** Version bump only for package @cornerstonejs/tools -* reference line exports and add cpu demo ([#297](https://github.com/cornerstonejs/cornerstone3D-beta/issues/297)) ([e20d0b2](https://github.com/cornerstonejs/cornerstone3D-beta/commit/e20d0b25c5ff0aafab4fa541b38815b4bee412b2)) +## [0.29.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.29.3...@cornerstonejs/tools@0.29.4) (2022-11-18) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.29.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.29.2...@cornerstonejs/tools@0.29.3) (2022-11-17) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.29.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.29.1...@cornerstonejs/tools@0.29.2) (2022-11-16) -# [0.29.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.28.0...@cornerstonejs/tools@0.29.0) (2022-11-11) +### Bug Fixes +- revert synchronizer event firing being unnecessary async ([#299](https://github.com/cornerstonejs/cornerstone3D-beta/issues/299)) ([1e244d1](https://github.com/cornerstonejs/cornerstone3D-beta/commit/1e244d11778d74b66df671f936138c73adb5a699)) -### Features +## [0.29.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.29.0...@cornerstonejs/tools@0.29.1) (2022-11-14) -* add reference lines tool ([#292](https://github.com/cornerstonejs/cornerstone3D-beta/issues/292)) ([c56df91](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c56df91a64ec005656f940dd3728f476152fa917)) +### Bug Fixes +- reference line exports and add cpu demo ([#297](https://github.com/cornerstonejs/cornerstone3D-beta/issues/297)) ([e20d0b2](https://github.com/cornerstonejs/cornerstone3D-beta/commit/e20d0b25c5ff0aafab4fa541b38815b4bee412b2)) +# [0.29.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.28.0...@cornerstonejs/tools@0.29.0) (2022-11-11) +### Features +- add reference lines tool ([#292](https://github.com/cornerstonejs/cornerstone3D-beta/issues/292)) ([c56df91](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c56df91a64ec005656f940dd3728f476152fa917)) # [0.28.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.27.2...@cornerstonejs/tools@0.28.0) (2022-11-11) - ### Features -* Add segmentSpecificConfiguration and add outlineOpacity config for Segmentation ([#285](https://github.com/cornerstonejs/cornerstone3D-beta/issues/285)) ([92fb495](https://github.com/cornerstonejs/cornerstone3D-beta/commit/92fb49594cfc3219f761e905ba765acaddbe1e1a)) -* add stack synchronization within or across studies ([#291](https://github.com/cornerstonejs/cornerstone3D-beta/issues/291)) ([f38bec0](https://github.com/cornerstonejs/cornerstone3D-beta/commit/f38bec06713265cee361fc905539aa5ed841e707)) +- Add segmentSpecificConfiguration and add outlineOpacity config for Segmentation ([#285](https://github.com/cornerstonejs/cornerstone3D-beta/issues/285)) ([92fb495](https://github.com/cornerstonejs/cornerstone3D-beta/commit/92fb49594cfc3219f761e905ba765acaddbe1e1a)) +- add stack synchronization within or across studies ([#291](https://github.com/cornerstonejs/cornerstone3D-beta/issues/291)) ([f38bec0](https://github.com/cornerstonejs/cornerstone3D-beta/commit/f38bec06713265cee361fc905539aa5ed841e707)) +## [0.27.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.27.1...@cornerstonejs/tools@0.27.2) (2022-11-10) +### Bug Fixes +- limit disabled element not need to render for annotations ([#289](https://github.com/cornerstonejs/cornerstone3D-beta/issues/289)) ([8232ed0](https://github.com/cornerstonejs/cornerstone3D-beta/commit/8232ed00ee42ab3fd837ab2c5a75b2128c8f87a6)) +## [0.27.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.27.0...@cornerstonejs/tools@0.27.1) (2022-11-09) -## [0.27.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.27.1...@cornerstonejs/tools@0.27.2) (2022-11-10) +**Note:** Version bump only for package @cornerstonejs/tools +# [0.27.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.26.5...@cornerstonejs/tools@0.27.0) (2022-11-07) -### Bug Fixes +### Features -* limit disabled element not need to render for annotations ([#289](https://github.com/cornerstonejs/cornerstone3D-beta/issues/289)) ([8232ed0](https://github.com/cornerstonejs/cornerstone3D-beta/commit/8232ed00ee42ab3fd837ab2c5a75b2128c8f87a6)) +- add annotation display Tool ([#283](https://github.com/cornerstonejs/cornerstone3D-beta/issues/283)) ([e4a0324](https://github.com/cornerstonejs/cornerstone3D-beta/commit/e4a0324840f8f5ac29f9db292e8df0c59ee69322)) +## [0.26.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.26.4...@cornerstonejs/tools@0.26.5) (2022-11-04) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.26.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.26.3...@cornerstonejs/tools@0.26.4) (2022-11-04) +**Note:** Version bump only for package @cornerstonejs/tools -## [0.27.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.27.0...@cornerstonejs/tools@0.27.1) (2022-11-09) +## [0.26.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.26.2...@cornerstonejs/tools@0.26.3) (2022-11-04) -**Note:** Version bump only for package @cornerstonejs/tools +### Bug Fixes +- resetCamera and annotations for flipped viewports ([#278](https://github.com/cornerstonejs/cornerstone3D-beta/issues/278)) ([cabefce](https://github.com/cornerstonejs/cornerstone3D-beta/commit/cabefcefcba463abb1ea9bf346a2f755b2494aed)) +## [0.26.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.26.1...@cornerstonejs/tools@0.26.2) (2022-11-01) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.26.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.26.0...@cornerstonejs/tools@0.26.1) (2022-11-01) -# [0.27.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.26.5...@cornerstonejs/tools@0.27.0) (2022-11-07) +**Note:** Version bump only for package @cornerstonejs/tools +# [0.26.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.25.0...@cornerstonejs/tools@0.26.0) (2022-10-31) ### Features -* add annotation display Tool ([#283](https://github.com/cornerstonejs/cornerstone3D-beta/issues/283)) ([e4a0324](https://github.com/cornerstonejs/cornerstone3D-beta/commit/e4a0324840f8f5ac29f9db292e8df0c59ee69322)) +- reset to center option for reset camera ([#269](https://github.com/cornerstonejs/cornerstone3D-beta/issues/269)) ([9539f6c](https://github.com/cornerstonejs/cornerstone3D-beta/commit/9539f6c56e2bd3b06f4c6b40fd6b4478d806bee3)) + +# [0.25.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.17...@cornerstonejs/tools@0.25.0) (2022-10-28) +### Bug Fixes +- viewRight was calculated wrong for tools ([#255](https://github.com/cornerstonejs/cornerstone3D-beta/issues/255)) ([cf536df](https://github.com/cornerstonejs/cornerstone3D-beta/commit/cf536df66c05b4c4385ad18ad814d1dac1c8ad77)) +### Features +- add data id to length and rectangle svg for e2e tests ([#240](https://github.com/cornerstonejs/cornerstone3D-beta/issues/240)) ([3c4e023](https://github.com/cornerstonejs/cornerstone3D-beta/commit/3c4e02305423c59ddcad5d2551cd2ca629738eea)) -## [0.26.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.26.4...@cornerstonejs/tools@0.26.5) (2022-11-04) +## [0.24.17](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.16...@cornerstonejs/tools@0.24.17) (2022-10-27) **Note:** Version bump only for package @cornerstonejs/tools +## [0.24.16](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.15...@cornerstonejs/tools@0.24.16) (2022-10-25) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.24.15](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.14...@cornerstonejs/tools@0.24.15) (2022-10-25) +**Note:** Version bump only for package @cornerstonejs/tools -## [0.26.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.26.3...@cornerstonejs/tools@0.26.4) (2022-11-04) +## [0.24.14](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.13...@cornerstonejs/tools@0.24.14) (2022-10-25) **Note:** Version bump only for package @cornerstonejs/tools +## [0.24.13](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.12...@cornerstonejs/tools@0.24.13) (2022-10-25) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.24.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.11...@cornerstonejs/tools@0.24.12) (2022-10-11) +**Note:** Version bump only for package @cornerstonejs/tools -## [0.26.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.26.2...@cornerstonejs/tools@0.26.3) (2022-11-04) +## [0.24.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.10...@cornerstonejs/tools@0.24.11) (2022-10-07) +**Note:** Version bump only for package @cornerstonejs/tools -### Bug Fixes +## [0.24.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.9...@cornerstonejs/tools@0.24.10) (2022-10-06) -* resetCamera and annotations for flipped viewports ([#278](https://github.com/cornerstonejs/cornerstone3D-beta/issues/278)) ([cabefce](https://github.com/cornerstonejs/cornerstone3D-beta/commit/cabefcefcba463abb1ea9bf346a2f755b2494aed)) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.24.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.8...@cornerstonejs/tools@0.24.9) (2022-10-06) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.24.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.7...@cornerstonejs/tools@0.24.8) (2022-10-06) +**Note:** Version bump only for package @cornerstonejs/tools -## [0.26.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.26.1...@cornerstonejs/tools@0.26.2) (2022-11-01) +## [0.24.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.6...@cornerstonejs/tools@0.24.7) (2022-10-05) **Note:** Version bump only for package @cornerstonejs/tools +## [0.24.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.5...@cornerstonejs/tools@0.24.6) (2022-10-05) +### Bug Fixes +- stackScroll should honor invert configuration ([#234](https://github.com/cornerstonejs/cornerstone3D-beta/issues/234)) ([aa8f1c4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/aa8f1c4de6837b3438ef62ae48d3412b4d3847bf)) - -## [0.26.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.26.0...@cornerstonejs/tools@0.26.1) (2022-11-01) +## [0.24.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.4...@cornerstonejs/tools@0.24.5) (2022-10-05) **Note:** Version bump only for package @cornerstonejs/tools +## [0.24.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.3...@cornerstonejs/tools@0.24.4) (2022-10-04) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.24.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.2...@cornerstonejs/tools@0.24.3) (2022-09-16) +**Note:** Version bump only for package @cornerstonejs/tools -# [0.26.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.25.0...@cornerstonejs/tools@0.26.0) (2022-10-31) +## [0.24.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.1...@cornerstonejs/tools@0.24.2) (2022-09-14) +### Bug Fixes -### Features +- annotation hidden on horizontal and vertical ([#205](https://github.com/cornerstonejs/cornerstone3D-beta/issues/205)) ([9e825fd](https://github.com/cornerstonejs/cornerstone3D-beta/commit/9e825fd3d37ecfdf1722da9cd2fd6a1a75995459)) -* reset to center option for reset camera ([#269](https://github.com/cornerstonejs/cornerstone3D-beta/issues/269)) ([9539f6c](https://github.com/cornerstonejs/cornerstone3D-beta/commit/9539f6c56e2bd3b06f4c6b40fd6b4478d806bee3)) +## [0.24.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.0...@cornerstonejs/tools@0.24.1) (2022-09-08) +### Bug Fixes +- drag probe appearing unnecessarily on all viewports ([#204](https://github.com/cornerstonejs/cornerstone3D-beta/issues/204)) ([c292c05](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c292c05eecf17a6edbdcab5aa5a604304ef3d2e5)) +# [0.24.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.23.3...@cornerstonejs/tools@0.24.0) (2022-09-08) +### Features -# [0.25.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.17...@cornerstonejs/tools@0.25.0) (2022-10-28) +- orientation on volumeViewport can be optional ([#203](https://github.com/cornerstonejs/cornerstone3D-beta/issues/203)) ([749dcb5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/749dcb59414c1aff2dffdca582fb3df0e4ca5ed7)) +## [0.23.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.23.2...@cornerstonejs/tools@0.23.3) (2022-09-05) ### Bug Fixes -* viewRight was calculated wrong for tools ([#255](https://github.com/cornerstonejs/cornerstone3D-beta/issues/255)) ([cf536df](https://github.com/cornerstonejs/cornerstone3D-beta/commit/cf536df66c05b4c4385ad18ad814d1dac1c8ad77)) +- wrong ushape calculation when loading SR/freehand from server ([#199](https://github.com/cornerstonejs/cornerstone3D-beta/issues/199)) ([ce0c5c9](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ce0c5c9b1c2ef7df9d571c113f37571261cad26f)) +## [0.23.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.23.1...@cornerstonejs/tools@0.23.2) (2022-09-02) -### Features - -* add data id to length and rectangle svg for e2e tests ([#240](https://github.com/cornerstonejs/cornerstone3D-beta/issues/240)) ([3c4e023](https://github.com/cornerstonejs/cornerstone3D-beta/commit/3c4e02305423c59ddcad5d2551cd2ca629738eea)) +### Bug Fixes +- annotations throwing error when stack and volume viewports are converted ([#195](https://github.com/cornerstonejs/cornerstone3D-beta/issues/195)) ([ed23f05](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ed23f05b23063769942328f9e6797d792767ec49)) +## [0.23.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.23.0...@cornerstonejs/tools@0.23.1) (2022-09-02) +### Bug Fixes +- zoomTool should not consume the preMouse event ([#196](https://github.com/cornerstonejs/cornerstone3D-beta/issues/196)) ([8ec505a](https://github.com/cornerstonejs/cornerstone3D-beta/commit/8ec505a3e2b55d74f5ad3af6159e83398017b87b)) -## [0.24.17](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.16...@cornerstonejs/tools@0.24.17) (2022-10-27) +# [0.23.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.22.3...@cornerstonejs/tools@0.23.0) (2022-08-30) -**Note:** Version bump only for package @cornerstonejs/tools +### Features +- draw center point of the ellipticalROI tool and make it configurable ([#191](https://github.com/cornerstonejs/cornerstone3D-beta/issues/191)) ([b0ad00c](https://github.com/cornerstonejs/cornerstone3D-beta/commit/b0ad00ce263d55214e1b3d61e51e319c63d11c42)), closes [#190](https://github.com/cornerstonejs/cornerstone3D-beta/issues/190) [#190](https://github.com/cornerstonejs/cornerstone3D-beta/issues/190) [#190](https://github.com/cornerstonejs/cornerstone3D-beta/issues/190) [#190](https://github.com/cornerstonejs/cornerstone3D-beta/issues/190) [#190](https://github.com/cornerstonejs/cornerstone3D-beta/issues/190) [#190](https://github.com/cornerstonejs/cornerstone3D-beta/issues/190) +## [0.22.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.22.2...@cornerstonejs/tools@0.22.3) (2022-08-30) +### Bug Fixes +- toolName typo for Crosshairs tool ([#193](https://github.com/cornerstonejs/cornerstone3D-beta/issues/193)) ([46d13bc](https://github.com/cornerstonejs/cornerstone3D-beta/commit/46d13bcb047c2b71c17b0246359d9494fbd8fb89)) -## [0.24.16](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.15...@cornerstonejs/tools@0.24.16) (2022-10-25) +## [0.22.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.22.1...@cornerstonejs/tools@0.22.2) (2022-08-26) **Note:** Version bump only for package @cornerstonejs/tools +## [0.22.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.22.0...@cornerstonejs/tools@0.22.1) (2022-08-26) +### Bug Fixes +- shadow for annotations and stack viewport targetImageIdIndex bug ([#189](https://github.com/cornerstonejs/cornerstone3D-beta/issues/189)) ([be70be7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/be70be70a543fffb18f7d05c69e16d5c0255a57e)) +# [0.22.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.11...@cornerstonejs/tools@0.22.0) (2022-08-23) -## [0.24.15](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.14...@cornerstonejs/tools@0.24.15) (2022-10-25) - -**Note:** Version bump only for package @cornerstonejs/tools +### Features +- camera sync canvas relative ([#167](https://github.com/cornerstonejs/cornerstone3D-beta/issues/167)) ([2fd6c98](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2fd6c9830eb6e9da10960de0c25702b06716382a)) +## [0.21.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.10...@cornerstonejs/tools@0.21.11) (2022-08-23) +### Bug Fixes +- invalid keybindings Alt and Ctrl ([#176](https://github.com/cornerstonejs/cornerstone3D-beta/issues/176)) ([d74d696](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d74d696b5de5fe1cd1fb6d36a32660c60140caa0)) -## [0.24.14](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.13...@cornerstonejs/tools@0.24.14) (2022-10-25) +## [0.21.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.9...@cornerstonejs/tools@0.21.10) (2022-08-23) **Note:** Version bump only for package @cornerstonejs/tools +## [0.21.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.8...@cornerstonejs/tools@0.21.9) (2022-08-19) +### Bug Fixes +- **demoData:** The URL was pointing to a private AWS account ([#175](https://github.com/cornerstonejs/cornerstone3D-beta/issues/175)) ([69dafea](https://github.com/cornerstonejs/cornerstone3D-beta/commit/69dafea902dcd224ea5d1d6d418d5e0c1cec2fe0)) +## [0.21.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.7...@cornerstonejs/tools@0.21.8) (2022-08-18) -## [0.24.13](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.12...@cornerstonejs/tools@0.24.13) (2022-10-25) +### Bug Fixes -**Note:** Version bump only for package @cornerstonejs/tools +- add extra missing exports and no static code block at build ([#179](https://github.com/cornerstonejs/cornerstone3D-beta/issues/179)) ([dfdc4bf](https://github.com/cornerstonejs/cornerstone3D-beta/commit/dfdc4bfbf331da40368a4976f3dc199bd355864a)) +## [0.21.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.6...@cornerstonejs/tools@0.21.7) (2022-08-15) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.21.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.5...@cornerstonejs/tools@0.21.6) (2022-08-12) +**Note:** Version bump only for package @cornerstonejs/tools -## [0.24.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.11...@cornerstonejs/tools@0.24.12) (2022-10-11) +## [0.21.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.4...@cornerstonejs/tools@0.21.5) (2022-08-11) **Note:** Version bump only for package @cornerstonejs/tools +## [0.21.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.3...@cornerstonejs/tools@0.21.4) (2022-08-10) +### Bug Fixes +- unify handling of annotation units and remove 'MO' ([#161](https://github.com/cornerstonejs/cornerstone3D-beta/issues/161)) ([7fddeab](https://github.com/cornerstonejs/cornerstone3D-beta/commit/7fddeab0f686fce5dc0e9c6953025ff14c00e252)) +## [0.21.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.2...@cornerstonejs/tools@0.21.3) (2022-08-04) -## [0.24.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.10...@cornerstonejs/tools@0.24.11) (2022-10-07) - -**Note:** Version bump only for package @cornerstonejs/tools +### Bug Fixes +- make typescript strict true ([#162](https://github.com/cornerstonejs/cornerstone3D-beta/issues/162)) ([7c311f7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/7c311f77f0532372ae82b6be2027bcd25925fa0d)) +## [0.21.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.1...@cornerstonejs/tools@0.21.2) (2022-08-03) +### Bug Fixes +- wadouri metadata was not using scaling parameters properly ([#159](https://github.com/cornerstonejs/cornerstone3D-beta/issues/159)) ([d21aba5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d21aba56f1e0a8730088d89a4dfde8358d978a60)) -## [0.24.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.9...@cornerstonejs/tools@0.24.10) (2022-10-06) +## [0.21.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.0...@cornerstonejs/tools@0.21.1) (2022-08-03) -**Note:** Version bump only for package @cornerstonejs/tools +### Bug Fixes +- Attempt to fix build issues [@haehn](https://github.com/haehn) has reported ([#144](https://github.com/cornerstonejs/cornerstone3D-beta/issues/144)) ([2a7ec92](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2a7ec9271e012929682aa5c0a860cd65d0d5c02d)) +# [0.21.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.15...@cornerstonejs/tools@0.21.0) (2022-07-29) +### Features +- volume viewport api with setProperties ([#154](https://github.com/cornerstonejs/cornerstone3D-beta/issues/154)) ([fab3abe](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fab3abe907ddde1ee61bc121c40d4fc23d2dbfd7)) -## [0.24.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.8...@cornerstonejs/tools@0.24.9) (2022-10-06) +## [0.20.15](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.14...@cornerstonejs/tools@0.20.15) (2022-07-27) **Note:** Version bump only for package @cornerstonejs/tools +## [0.20.14](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.13...@cornerstonejs/tools@0.20.14) (2022-07-25) +### Bug Fixes +- annotation unit hydration bug and more color image support ([#151](https://github.com/cornerstonejs/cornerstone3D-beta/issues/151)) ([4f157dc](https://github.com/cornerstonejs/cornerstone3D-beta/commit/4f157dc5d7a8d0d80abb5b68c35ed17cb5f349ed)) +## [0.20.13](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.11...@cornerstonejs/tools@0.20.13) (2022-07-15) -## [0.24.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.7...@cornerstonejs/tools@0.24.8) (2022-10-06) - -**Note:** Version bump only for package @cornerstonejs/tools - +### Bug Fixes +- Ensure d3 packages are also listed on dependencies ([#146](https://github.com/cornerstonejs/cornerstone3D-beta/issues/146)) ([5747dc6](https://github.com/cornerstonejs/cornerstone3D-beta/commit/5747dc6cbcb05eec690bf636ef733789c88f959f)) +## [0.20.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.11...@cornerstonejs/tools@0.20.12) (2022-07-08) +**Note:** Version bump only for package @cornerstonejs/tools -## [0.24.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.6...@cornerstonejs/tools@0.24.7) (2022-10-05) +## [0.20.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.10...@cornerstonejs/tools@0.20.11) (2022-06-24) **Note:** Version bump only for package @cornerstonejs/tools +## [0.20.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.9...@cornerstonejs/tools@0.20.10) (2022-06-24) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.20.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.8...@cornerstonejs/tools@0.20.9) (2022-06-20) +**Note:** Version bump only for package @cornerstonejs/tools -## [0.24.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.5...@cornerstonejs/tools@0.24.6) (2022-10-05) - +## [0.20.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.7...@cornerstonejs/tools@0.20.8) (2022-06-20) ### Bug Fixes -* stackScroll should honor invert configuration ([#234](https://github.com/cornerstonejs/cornerstone3D-beta/issues/234)) ([aa8f1c4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/aa8f1c4de6837b3438ef62ae48d3412b4d3847bf)) +- Cleanup magnify canvas on mouse up ([#135](https://github.com/cornerstonejs/cornerstone3D-beta/issues/135)) ([6fd0c3f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/6fd0c3fe114586f9e7ac0ab1f448b6c5199d1f7a)) +## [0.20.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.6...@cornerstonejs/tools@0.20.7) (2022-06-20) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.20.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.5...@cornerstonejs/tools@0.20.6) (2022-06-20) +**Note:** Version bump only for package @cornerstonejs/tools -## [0.24.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.4...@cornerstonejs/tools@0.24.5) (2022-10-05) +## [0.20.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.4...@cornerstonejs/tools@0.20.5) (2022-06-20) **Note:** Version bump only for package @cornerstonejs/tools +## [0.20.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.3...@cornerstonejs/tools@0.20.4) (2022-06-17) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.20.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.2...@cornerstonejs/tools@0.20.3) (2022-06-17) +### Bug Fixes -## [0.24.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.3...@cornerstonejs/tools@0.24.4) (2022-10-04) +- large image rendering, missing metadata for StackViewport, high DPI devices ([#127](https://github.com/cornerstonejs/cornerstone3D-beta/issues/127)) ([d4bf1c8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d4bf1c80391bcecaee64d9eb086416c42aa406e2)) -**Note:** Version bump only for package @cornerstonejs/tools +## [0.20.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.1...@cornerstonejs/tools@0.20.2) (2022-06-16) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.20.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.0...@cornerstonejs/tools@0.20.1) (2022-06-14) +**Note:** Version bump only for package @cornerstonejs/tools +# [0.20.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.19.1...@cornerstonejs/tools@0.20.0) (2022-06-14) -## [0.24.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.2...@cornerstonejs/tools@0.24.3) (2022-09-16) +### Features -**Note:** Version bump only for package @cornerstonejs/tools +- remove unnecessary event firing for annotations ([#123](https://github.com/cornerstonejs/cornerstone3D-beta/issues/123)) ([03551d9](https://github.com/cornerstonejs/cornerstone3D-beta/commit/03551d9f9269b7bfd3d828dad4f8f38ef51703d1)) +## [0.19.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.19.0...@cornerstonejs/tools@0.19.1) (2022-06-10) +**Note:** Version bump only for package @cornerstonejs/tools +# [0.19.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.18.1...@cornerstonejs/tools@0.19.0) (2022-06-06) +### Features -## [0.24.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.1...@cornerstonejs/tools@0.24.2) (2022-09-14) +- improved stack prefetch and zoom to mouse ([#121](https://github.com/cornerstonejs/cornerstone3D-beta/issues/121)) ([bc72d37](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bc72d37b10f5a9e3e2bc9ed1254a707047f04f45)) +## [0.18.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.18.0...@cornerstonejs/tools@0.18.1) (2022-06-01) ### Bug Fixes -* annotation hidden on horizontal and vertical ([#205](https://github.com/cornerstonejs/cornerstone3D-beta/issues/205)) ([9e825fd](https://github.com/cornerstonejs/cornerstone3D-beta/commit/9e825fd3d37ecfdf1722da9cd2fd6a1a75995459)) +- toolGroup default cursor ([#120](https://github.com/cornerstonejs/cornerstone3D-beta/issues/120)) ([8c385c4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/8c385c4780cbaf40400fffc310fd1e3b86056767)) +# [0.18.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.17.4...@cornerstonejs/tools@0.18.0) (2022-05-31) +### Features +- improved threshold volume API and refactored boundingBox utils ([#117](https://github.com/cornerstonejs/cornerstone3D-beta/issues/117)) ([adc308b](https://github.com/cornerstonejs/cornerstone3D-beta/commit/adc308bef0509852bc48c96114eb3268c3d100b9)) +## [0.17.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.17.3...@cornerstonejs/tools@0.17.4) (2022-05-30) -## [0.24.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.24.0...@cornerstonejs/tools@0.24.1) (2022-09-08) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.17.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.17.2...@cornerstonejs/tools@0.17.3) (2022-05-27) ### Bug Fixes -* drag probe appearing unnecessarily on all viewports ([#204](https://github.com/cornerstonejs/cornerstone3D-beta/issues/204)) ([c292c05](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c292c05eecf17a6edbdcab5aa5a604304ef3d2e5)) +- scale factor for zoom in perspective mode and do not update clipping planes for non Volume Actors ([#116](https://github.com/cornerstonejs/cornerstone3D-beta/issues/116)) ([ce8c13e](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ce8c13e534a48392fc11dcb615d8d81275cd01d7)) +## [0.17.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.17.1...@cornerstonejs/tools@0.17.2) (2022-05-27) +### Bug Fixes +- remove the need for slabThickness in volumeAPI for tools ([#113](https://github.com/cornerstonejs/cornerstone3D-beta/issues/113)) ([a5e431d](https://github.com/cornerstonejs/cornerstone3D-beta/commit/a5e431dee952281be340994aa773a593a85fad04)) +## [0.17.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.17.0...@cornerstonejs/tools@0.17.1) (2022-05-27) -# [0.24.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.23.3...@cornerstonejs/tools@0.24.0) (2022-09-08) +**Note:** Version bump only for package @cornerstonejs/tools +# [0.17.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.16.0...@cornerstonejs/tools@0.17.0) (2022-05-24) ### Features -* orientation on volumeViewport can be optional ([#203](https://github.com/cornerstonejs/cornerstone3D-beta/issues/203)) ([749dcb5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/749dcb59414c1aff2dffdca582fb3df0e4ca5ed7)) +- Add VOLUME_NEW_IMAGE event and Add jumpToSlice and default VOI for volume viewport ([#104](https://github.com/cornerstonejs/cornerstone3D-beta/issues/104)) ([d36a23a](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d36a23a4eaf5bafcc8dddc0ab796065098df616a)) +# [0.16.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.15.4...@cornerstonejs/tools@0.16.0) (2022-05-24) +### Features +- Add Clipping planes for rendering ([#110](https://github.com/cornerstonejs/cornerstone3D-beta/issues/110)) ([1a6e4c7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/1a6e4c742a3b89a88b46fd98d6cbeca5c95918aa)) +## [0.15.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.15.3...@cornerstonejs/tools@0.15.4) (2022-05-16) -## [0.23.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.23.2...@cornerstonejs/tools@0.23.3) (2022-09-05) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.15.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.15.2...@cornerstonejs/tools@0.15.3) (2022-05-16) -### Bug Fixes +**Note:** Version bump only for package @cornerstonejs/tools + +## [0.15.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.15.1...@cornerstonejs/tools@0.15.2) (2022-05-16) -* wrong ushape calculation when loading SR/freehand from server ([#199](https://github.com/cornerstonejs/cornerstone3D-beta/issues/199)) ([ce0c5c9](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ce0c5c9b1c2ef7df9d571c113f37571261cad26f)) +**Note:** Version bump only for package @cornerstonejs/tools +## [0.15.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.15.0...@cornerstonejs/tools@0.15.1) (2022-05-13) +**Note:** Version bump only for package @cornerstonejs/tools +# [0.15.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.14.1...@cornerstonejs/tools@0.15.0) (2022-05-12) +### Features -## [0.23.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.23.1...@cornerstonejs/tools@0.23.2) (2022-09-02) +- Add CINE tool via playClip ([#99](https://github.com/cornerstonejs/cornerstone3D-beta/issues/99)) ([916d783](https://github.com/cornerstonejs/cornerstone3D-beta/commit/916d783a56a7abc2a46c7477e2685ad436ad3637)) +## [0.14.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.14.0...@cornerstonejs/tools@0.14.1) (2022-05-11) ### Bug Fixes -* annotations throwing error when stack and volume viewports are converted ([#195](https://github.com/cornerstonejs/cornerstone3D-beta/issues/195)) ([ed23f05](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ed23f05b23063769942328f9e6797d792767ec49)) - +- Attempt to resolve incompatible peerDeps situation ([#98](https://github.com/cornerstonejs/cornerstone3D-beta/issues/98)) ([00f141b](https://github.com/cornerstonejs/cornerstone3D-beta/commit/00f141bfa9f9a4b37c016d726a6d31f2330e2e44)) +# [0.14.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.13.0...@cornerstonejs/tools@0.14.0) (2022-05-10) +### Features +- Add AngleTool and MagnifyTool ([#97](https://github.com/cornerstonejs/cornerstone3D-beta/issues/97)) ([2c4c800](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2c4c800c4b3ba92164f728865b904933a2539210)) -## [0.23.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.23.0...@cornerstonejs/tools@0.23.1) (2022-09-02) +# [0.13.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.12.1...@cornerstonejs/tools@0.13.0) (2022-05-09) +### Features -### Bug Fixes +- Add toolStyles configuration and DragProbe ([#93](https://github.com/cornerstonejs/cornerstone3D-beta/issues/93)) ([ba15be6](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ba15be6d268b8c568bdf0e247e571f5ca29a26ad)) -* zoomTool should not consume the preMouse event ([#196](https://github.com/cornerstonejs/cornerstone3D-beta/issues/196)) ([8ec505a](https://github.com/cornerstonejs/cornerstone3D-beta/commit/8ec505a3e2b55d74f5ad3af6159e83398017b87b)) +## [0.12.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.12.0...@cornerstonejs/tools@0.12.1) (2022-05-03) +### Bug Fixes +- rename ArrowTool to ArrowAnnotate ([#91](https://github.com/cornerstonejs/cornerstone3D-beta/issues/91)) ([9bd0cd8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/9bd0cd882746df909ee76549bc9818834ccc2ee3)) +# [0.12.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.11.0...@cornerstonejs/tools@0.12.0) (2022-05-03) +### Features -# [0.23.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.22.3...@cornerstonejs/tools@0.23.0) (2022-08-30) +- Planar freehand roi tool ([#89](https://github.com/cornerstonejs/cornerstone3D-beta/issues/89)) ([0067339](https://github.com/cornerstonejs/cornerstone3D-beta/commit/0067339e7cf7f6b26e8fd6342113d82eb6915409)) +# [0.11.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.10.1...@cornerstonejs/tools@0.11.0) (2022-05-03) ### Features -* draw center point of the ellipticalROI tool and make it configurable ([#191](https://github.com/cornerstonejs/cornerstone3D-beta/issues/191)) ([b0ad00c](https://github.com/cornerstonejs/cornerstone3D-beta/commit/b0ad00ce263d55214e1b3d61e51e319c63d11c42)), closes [#190](https://github.com/cornerstonejs/cornerstone3D-beta/issues/190) [#190](https://github.com/cornerstonejs/cornerstone3D-beta/issues/190) [#190](https://github.com/cornerstonejs/cornerstone3D-beta/issues/190) [#190](https://github.com/cornerstonejs/cornerstone3D-beta/issues/190) [#190](https://github.com/cornerstonejs/cornerstone3D-beta/issues/190) [#190](https://github.com/cornerstonejs/cornerstone3D-beta/issues/190) +- Add ArrowTool and remove toolName from drawing API ([#88](https://github.com/cornerstonejs/cornerstone3D-beta/issues/88)) ([217637c](https://github.com/cornerstonejs/cornerstone3D-beta/commit/217637cb2a48ca6e73cea7d1781a4a83fc482e79)) +## [0.10.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.10.0...@cornerstonejs/tools@0.10.1) (2022-04-27) +**Note:** Version bump only for package @cornerstonejs/tools +# [0.10.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.9.4...@cornerstonejs/tools@0.10.0) (2022-04-26) +### Features -## [0.22.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.22.2...@cornerstonejs/tools@0.22.3) (2022-08-30) +- Add annotation completed event ([#84](https://github.com/cornerstonejs/cornerstone3D-beta/issues/84)) ([cd574da](https://github.com/cornerstonejs/cornerstone3D-beta/commit/cd574da73403e3030a5bc414778e08536fb77381)) +## [0.9.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.9.3...@cornerstonejs/tools@0.9.4) (2022-04-22) ### Bug Fixes -* toolName typo for Crosshairs tool ([#193](https://github.com/cornerstonejs/cornerstone3D-beta/issues/193)) ([46d13bc](https://github.com/cornerstonejs/cornerstone3D-beta/commit/46d13bcb047c2b71c17b0246359d9494fbd8fb89)) - - - - - -## [0.22.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.22.1...@cornerstonejs/tools@0.22.2) (2022-08-26) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.22.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.22.0...@cornerstonejs/tools@0.22.1) (2022-08-26) - - -### Bug Fixes - -* shadow for annotations and stack viewport targetImageIdIndex bug ([#189](https://github.com/cornerstonejs/cornerstone3D-beta/issues/189)) ([be70be7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/be70be70a543fffb18f7d05c69e16d5c0255a57e)) - - - - - -# [0.22.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.11...@cornerstonejs/tools@0.22.0) (2022-08-23) - - -### Features - -* camera sync canvas relative ([#167](https://github.com/cornerstonejs/cornerstone3D-beta/issues/167)) ([2fd6c98](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2fd6c9830eb6e9da10960de0c25702b06716382a)) - - - - - -## [0.21.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.10...@cornerstonejs/tools@0.21.11) (2022-08-23) - - -### Bug Fixes - -* invalid keybindings Alt and Ctrl ([#176](https://github.com/cornerstonejs/cornerstone3D-beta/issues/176)) ([d74d696](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d74d696b5de5fe1cd1fb6d36a32660c60140caa0)) - - - - - -## [0.21.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.9...@cornerstonejs/tools@0.21.10) (2022-08-23) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.21.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.8...@cornerstonejs/tools@0.21.9) (2022-08-19) - - -### Bug Fixes - -* **demoData:** The URL was pointing to a private AWS account ([#175](https://github.com/cornerstonejs/cornerstone3D-beta/issues/175)) ([69dafea](https://github.com/cornerstonejs/cornerstone3D-beta/commit/69dafea902dcd224ea5d1d6d418d5e0c1cec2fe0)) - - - - - -## [0.21.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.7...@cornerstonejs/tools@0.21.8) (2022-08-18) - - -### Bug Fixes - -* add extra missing exports and no static code block at build ([#179](https://github.com/cornerstonejs/cornerstone3D-beta/issues/179)) ([dfdc4bf](https://github.com/cornerstonejs/cornerstone3D-beta/commit/dfdc4bfbf331da40368a4976f3dc199bd355864a)) - - - - - -## [0.21.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.6...@cornerstonejs/tools@0.21.7) (2022-08-15) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.21.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.5...@cornerstonejs/tools@0.21.6) (2022-08-12) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.21.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.4...@cornerstonejs/tools@0.21.5) (2022-08-11) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.21.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.3...@cornerstonejs/tools@0.21.4) (2022-08-10) - - -### Bug Fixes - -* unify handling of annotation units and remove 'MO' ([#161](https://github.com/cornerstonejs/cornerstone3D-beta/issues/161)) ([7fddeab](https://github.com/cornerstonejs/cornerstone3D-beta/commit/7fddeab0f686fce5dc0e9c6953025ff14c00e252)) - - - - - -## [0.21.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.2...@cornerstonejs/tools@0.21.3) (2022-08-04) - - -### Bug Fixes - -* make typescript strict true ([#162](https://github.com/cornerstonejs/cornerstone3D-beta/issues/162)) ([7c311f7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/7c311f77f0532372ae82b6be2027bcd25925fa0d)) - - - - - -## [0.21.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.1...@cornerstonejs/tools@0.21.2) (2022-08-03) - - -### Bug Fixes - -* wadouri metadata was not using scaling parameters properly ([#159](https://github.com/cornerstonejs/cornerstone3D-beta/issues/159)) ([d21aba5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d21aba56f1e0a8730088d89a4dfde8358d978a60)) - - - - - -## [0.21.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.21.0...@cornerstonejs/tools@0.21.1) (2022-08-03) - - -### Bug Fixes - -* Attempt to fix build issues [@haehn](https://github.com/haehn) has reported ([#144](https://github.com/cornerstonejs/cornerstone3D-beta/issues/144)) ([2a7ec92](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2a7ec9271e012929682aa5c0a860cd65d0d5c02d)) - - - - - -# [0.21.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.15...@cornerstonejs/tools@0.21.0) (2022-07-29) - - -### Features - -* volume viewport api with setProperties ([#154](https://github.com/cornerstonejs/cornerstone3D-beta/issues/154)) ([fab3abe](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fab3abe907ddde1ee61bc121c40d4fc23d2dbfd7)) - - - - - -## [0.20.15](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.14...@cornerstonejs/tools@0.20.15) (2022-07-27) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.20.14](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.13...@cornerstonejs/tools@0.20.14) (2022-07-25) - - -### Bug Fixes - -* annotation unit hydration bug and more color image support ([#151](https://github.com/cornerstonejs/cornerstone3D-beta/issues/151)) ([4f157dc](https://github.com/cornerstonejs/cornerstone3D-beta/commit/4f157dc5d7a8d0d80abb5b68c35ed17cb5f349ed)) - - - - - -## [0.20.13](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.11...@cornerstonejs/tools@0.20.13) (2022-07-15) - - -### Bug Fixes - -* Ensure d3 packages are also listed on dependencies ([#146](https://github.com/cornerstonejs/cornerstone3D-beta/issues/146)) ([5747dc6](https://github.com/cornerstonejs/cornerstone3D-beta/commit/5747dc6cbcb05eec690bf636ef733789c88f959f)) - - - - - -## [0.20.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.11...@cornerstonejs/tools@0.20.12) (2022-07-08) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.20.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.10...@cornerstonejs/tools@0.20.11) (2022-06-24) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.20.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.9...@cornerstonejs/tools@0.20.10) (2022-06-24) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.20.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.8...@cornerstonejs/tools@0.20.9) (2022-06-20) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.20.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.7...@cornerstonejs/tools@0.20.8) (2022-06-20) - - -### Bug Fixes - -* Cleanup magnify canvas on mouse up ([#135](https://github.com/cornerstonejs/cornerstone3D-beta/issues/135)) ([6fd0c3f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/6fd0c3fe114586f9e7ac0ab1f448b6c5199d1f7a)) - - - - - -## [0.20.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.6...@cornerstonejs/tools@0.20.7) (2022-06-20) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.20.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.5...@cornerstonejs/tools@0.20.6) (2022-06-20) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.20.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.4...@cornerstonejs/tools@0.20.5) (2022-06-20) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.20.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.3...@cornerstonejs/tools@0.20.4) (2022-06-17) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.20.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.2...@cornerstonejs/tools@0.20.3) (2022-06-17) - - -### Bug Fixes - -* large image rendering, missing metadata for StackViewport, high DPI devices ([#127](https://github.com/cornerstonejs/cornerstone3D-beta/issues/127)) ([d4bf1c8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d4bf1c80391bcecaee64d9eb086416c42aa406e2)) - - - - - -## [0.20.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.1...@cornerstonejs/tools@0.20.2) (2022-06-16) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.20.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.20.0...@cornerstonejs/tools@0.20.1) (2022-06-14) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -# [0.20.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.19.1...@cornerstonejs/tools@0.20.0) (2022-06-14) - - -### Features - -* remove unnecessary event firing for annotations ([#123](https://github.com/cornerstonejs/cornerstone3D-beta/issues/123)) ([03551d9](https://github.com/cornerstonejs/cornerstone3D-beta/commit/03551d9f9269b7bfd3d828dad4f8f38ef51703d1)) - - - - - -## [0.19.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.19.0...@cornerstonejs/tools@0.19.1) (2022-06-10) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -# [0.19.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.18.1...@cornerstonejs/tools@0.19.0) (2022-06-06) - - -### Features - -* improved stack prefetch and zoom to mouse ([#121](https://github.com/cornerstonejs/cornerstone3D-beta/issues/121)) ([bc72d37](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bc72d37b10f5a9e3e2bc9ed1254a707047f04f45)) - - - - - -## [0.18.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.18.0...@cornerstonejs/tools@0.18.1) (2022-06-01) - - -### Bug Fixes - -* toolGroup default cursor ([#120](https://github.com/cornerstonejs/cornerstone3D-beta/issues/120)) ([8c385c4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/8c385c4780cbaf40400fffc310fd1e3b86056767)) - - - - - -# [0.18.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.17.4...@cornerstonejs/tools@0.18.0) (2022-05-31) - - -### Features - -* improved threshold volume API and refactored boundingBox utils ([#117](https://github.com/cornerstonejs/cornerstone3D-beta/issues/117)) ([adc308b](https://github.com/cornerstonejs/cornerstone3D-beta/commit/adc308bef0509852bc48c96114eb3268c3d100b9)) - - - - - -## [0.17.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.17.3...@cornerstonejs/tools@0.17.4) (2022-05-30) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.17.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.17.2...@cornerstonejs/tools@0.17.3) (2022-05-27) - - -### Bug Fixes - -* scale factor for zoom in perspective mode and do not update clipping planes for non Volume Actors ([#116](https://github.com/cornerstonejs/cornerstone3D-beta/issues/116)) ([ce8c13e](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ce8c13e534a48392fc11dcb615d8d81275cd01d7)) - - - - - -## [0.17.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.17.1...@cornerstonejs/tools@0.17.2) (2022-05-27) - - -### Bug Fixes - -* remove the need for slabThickness in volumeAPI for tools ([#113](https://github.com/cornerstonejs/cornerstone3D-beta/issues/113)) ([a5e431d](https://github.com/cornerstonejs/cornerstone3D-beta/commit/a5e431dee952281be340994aa773a593a85fad04)) - - - - - -## [0.17.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.17.0...@cornerstonejs/tools@0.17.1) (2022-05-27) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -# [0.17.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.16.0...@cornerstonejs/tools@0.17.0) (2022-05-24) - - -### Features - -* Add VOLUME_NEW_IMAGE event and Add jumpToSlice and default VOI for volume viewport ([#104](https://github.com/cornerstonejs/cornerstone3D-beta/issues/104)) ([d36a23a](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d36a23a4eaf5bafcc8dddc0ab796065098df616a)) - - - - - -# [0.16.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.15.4...@cornerstonejs/tools@0.16.0) (2022-05-24) - - -### Features - -* Add Clipping planes for rendering ([#110](https://github.com/cornerstonejs/cornerstone3D-beta/issues/110)) ([1a6e4c7](https://github.com/cornerstonejs/cornerstone3D-beta/commit/1a6e4c742a3b89a88b46fd98d6cbeca5c95918aa)) - - - - - -## [0.15.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.15.3...@cornerstonejs/tools@0.15.4) (2022-05-16) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.15.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.15.2...@cornerstonejs/tools@0.15.3) (2022-05-16) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.15.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.15.1...@cornerstonejs/tools@0.15.2) (2022-05-16) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -## [0.15.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.15.0...@cornerstonejs/tools@0.15.1) (2022-05-13) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -# [0.15.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.14.1...@cornerstonejs/tools@0.15.0) (2022-05-12) - - -### Features - -* Add CINE tool via playClip ([#99](https://github.com/cornerstonejs/cornerstone3D-beta/issues/99)) ([916d783](https://github.com/cornerstonejs/cornerstone3D-beta/commit/916d783a56a7abc2a46c7477e2685ad436ad3637)) - - - - - -## [0.14.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.14.0...@cornerstonejs/tools@0.14.1) (2022-05-11) - - -### Bug Fixes - -* Attempt to resolve incompatible peerDeps situation ([#98](https://github.com/cornerstonejs/cornerstone3D-beta/issues/98)) ([00f141b](https://github.com/cornerstonejs/cornerstone3D-beta/commit/00f141bfa9f9a4b37c016d726a6d31f2330e2e44)) - - - - - -# [0.14.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.13.0...@cornerstonejs/tools@0.14.0) (2022-05-10) - - -### Features - -* Add AngleTool and MagnifyTool ([#97](https://github.com/cornerstonejs/cornerstone3D-beta/issues/97)) ([2c4c800](https://github.com/cornerstonejs/cornerstone3D-beta/commit/2c4c800c4b3ba92164f728865b904933a2539210)) - - - - - -# [0.13.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.12.1...@cornerstonejs/tools@0.13.0) (2022-05-09) - - -### Features - -* Add toolStyles configuration and DragProbe ([#93](https://github.com/cornerstonejs/cornerstone3D-beta/issues/93)) ([ba15be6](https://github.com/cornerstonejs/cornerstone3D-beta/commit/ba15be6d268b8c568bdf0e247e571f5ca29a26ad)) - - - - - -## [0.12.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.12.0...@cornerstonejs/tools@0.12.1) (2022-05-03) - - -### Bug Fixes - -* rename ArrowTool to ArrowAnnotate ([#91](https://github.com/cornerstonejs/cornerstone3D-beta/issues/91)) ([9bd0cd8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/9bd0cd882746df909ee76549bc9818834ccc2ee3)) - - - - - -# [0.12.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.11.0...@cornerstonejs/tools@0.12.0) (2022-05-03) - - -### Features - -* Planar freehand roi tool ([#89](https://github.com/cornerstonejs/cornerstone3D-beta/issues/89)) ([0067339](https://github.com/cornerstonejs/cornerstone3D-beta/commit/0067339e7cf7f6b26e8fd6342113d82eb6915409)) - - - - - -# [0.11.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.10.1...@cornerstonejs/tools@0.11.0) (2022-05-03) - - -### Features - -* Add ArrowTool and remove toolName from drawing API ([#88](https://github.com/cornerstonejs/cornerstone3D-beta/issues/88)) ([217637c](https://github.com/cornerstonejs/cornerstone3D-beta/commit/217637cb2a48ca6e73cea7d1781a4a83fc482e79)) - - - - - -## [0.10.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.10.0...@cornerstonejs/tools@0.10.1) (2022-04-27) - -**Note:** Version bump only for package @cornerstonejs/tools - - - - - -# [0.10.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.9.4...@cornerstonejs/tools@0.10.0) (2022-04-26) - - -### Features - -* Add annotation completed event ([#84](https://github.com/cornerstonejs/cornerstone3D-beta/issues/84)) ([cd574da](https://github.com/cornerstonejs/cornerstone3D-beta/commit/cd574da73403e3030a5bc414778e08536fb77381)) - - - - - -## [0.9.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.9.3...@cornerstonejs/tools@0.9.4) (2022-04-22) - - -### Bug Fixes - -* Camera events for flip and rotation changes ([#83](https://github.com/cornerstonejs/cornerstone3D-beta/issues/83)) ([82115ec](https://github.com/cornerstonejs/cornerstone3D-beta/commit/82115ec00bd924fb942473d04052473408b84eb7)) - - - - - -## [0.9.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.9.2...@cornerstonejs/tools@0.9.3) (2022-04-21) +- Camera events for flip and rotation changes ([#83](https://github.com/cornerstonejs/cornerstone3D-beta/issues/83)) ([82115ec](https://github.com/cornerstonejs/cornerstone3D-beta/commit/82115ec00bd924fb942473d04052473408b84eb7)) +## [0.9.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.9.2...@cornerstonejs/tools@0.9.3) (2022-04-21) ### Bug Fixes -* selection API, requestPoolManager and VOI and Scaling ([#82](https://github.com/cornerstonejs/cornerstone3D-beta/issues/82)) ([bedd8dd](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bedd8ddfa356c2d52a6e72f74c7cb3bb660a86ef)) - - - - +- selection API, requestPoolManager and VOI and Scaling ([#82](https://github.com/cornerstonejs/cornerstone3D-beta/issues/82)) ([bedd8dd](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bedd8ddfa356c2d52a6e72f74c7cb3bb660a86ef)) ## [0.9.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.9.1...@cornerstonejs/tools@0.9.2) (2022-04-20) - ### Bug Fixes -* windowLevel event trigger and initial voi range ([#81](https://github.com/cornerstonejs/cornerstone3D-beta/issues/81)) ([38307d4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/38307d40cec60f2b3b8497abda8aa4fa657fc179)) - - - - +- windowLevel event trigger and initial voi range ([#81](https://github.com/cornerstonejs/cornerstone3D-beta/issues/81)) ([38307d4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/38307d40cec60f2b3b8497abda8aa4fa657fc179)) ## [0.9.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.9.0...@cornerstonejs/tools@0.9.1) (2022-04-19) - ### Bug Fixes -* jumpToSlice and scaling of images in renderToCanvas ([#78](https://github.com/cornerstonejs/cornerstone3D-beta/issues/78)) ([bbebf7f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bbebf7fbad28e670333783cd669e571ec2ae7358)) - - - - +- jumpToSlice and scaling of images in renderToCanvas ([#78](https://github.com/cornerstonejs/cornerstone3D-beta/issues/78)) ([bbebf7f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/bbebf7fbad28e670333783cd669e571ec2ae7358)) # [0.9.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.8.0...@cornerstonejs/tools@0.9.0) (2022-04-14) - ### Features -* add scrollToSlice for element ([#76](https://github.com/cornerstonejs/cornerstone3D-beta/issues/76)) ([c43fe8f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c43fe8f955930a70be60015f2f6bc1d5bf9fffbb)) - - - - +- add scrollToSlice for element ([#76](https://github.com/cornerstonejs/cornerstone3D-beta/issues/76)) ([c43fe8f](https://github.com/cornerstonejs/cornerstone3D-beta/commit/c43fe8f955930a70be60015f2f6bc1d5bf9fffbb)) # [0.8.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.7.12...@cornerstonejs/tools@0.8.0) (2022-04-13) - ### Features -* cachedStats to store imageId and volumeId ([#75](https://github.com/cornerstonejs/cornerstone3D-beta/issues/75)) ([a2404c4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/a2404c4f1cb15a3935ba3af58fa7fc556716458c)) - - - - +- cachedStats to store imageId and volumeId ([#75](https://github.com/cornerstonejs/cornerstone3D-beta/issues/75)) ([a2404c4](https://github.com/cornerstonejs/cornerstone3D-beta/commit/a2404c4f1cb15a3935ba3af58fa7fc556716458c)) ## [0.7.12](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.7.11...@cornerstonejs/tools@0.7.12) (2022-04-13) **Note:** Version bump only for package @cornerstonejs/tools - - - - ## [0.7.11](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.7.10...@cornerstonejs/tools@0.7.11) (2022-04-12) - ### Bug Fixes -* Remove resemblejs from dependencies, add detect-gpu, clonedeep, CWIL ([#73](https://github.com/cornerstonejs/cornerstone3D-beta/issues/73)) ([db65d50](https://github.com/cornerstonejs/cornerstone3D-beta/commit/db65d50a5c7488f323ab2424cf9d750055b2e6d5)) - - - - +- Remove resemblejs from dependencies, add detect-gpu, clonedeep, CWIL ([#73](https://github.com/cornerstonejs/cornerstone3D-beta/issues/73)) ([db65d50](https://github.com/cornerstonejs/cornerstone3D-beta/commit/db65d50a5c7488f323ab2424cf9d750055b2e6d5)) ## [0.7.10](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.7.9...@cornerstonejs/tools@0.7.10) (2022-04-12) **Note:** Version bump only for package @cornerstonejs/tools - - - - ## [0.7.9](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.7.8...@cornerstonejs/tools@0.7.9) (2022-04-11) **Note:** Version bump only for package @cornerstonejs/tools - - - - ## [0.7.8](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.7.7...@cornerstonejs/tools@0.7.8) (2022-04-04) - ### Bug Fixes -* Correct module property for ESM builds in package.json ([#66](https://github.com/cornerstonejs/cornerstone3D-beta/issues/66)) ([d53b857](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d53b8575aa8b93907f8bf127f36d9dfc10821478)) - - - - +- Correct module property for ESM builds in package.json ([#66](https://github.com/cornerstonejs/cornerstone3D-beta/issues/66)) ([d53b857](https://github.com/cornerstonejs/cornerstone3D-beta/commit/d53b8575aa8b93907f8bf127f36d9dfc10821478)) ## [0.7.7](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.7.6...@cornerstonejs/tools@0.7.7) (2022-04-04) **Note:** Version bump only for package @cornerstonejs/tools - - - - ## [0.7.6](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.7.5...@cornerstonejs/tools@0.7.6) (2022-04-01) **Note:** Version bump only for package @cornerstonejs/tools - - - - ## [0.7.5](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.7.4...@cornerstonejs/tools@0.7.5) (2022-04-01) **Note:** Version bump only for package @cornerstonejs/tools - - - - ## [0.7.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.7.3...@cornerstonejs/tools@0.7.4) (2022-04-01) **Note:** Version bump only for package @cornerstonejs/tools - - - - ## [0.7.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.7.2...@cornerstonejs/tools@0.7.3) (2022-04-01) - ### Bug Fixes -* Webpack externals were not properly defined ([70499a5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/70499a55c5824b3f94920ffd48411118e6fe4bb8)) - - - - +- Webpack externals were not properly defined ([70499a5](https://github.com/cornerstonejs/cornerstone3D-beta/commit/70499a55c5824b3f94920ffd48411118e6fe4bb8)) ## [0.7.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.7.1...@cornerstonejs/tools@0.7.2) (2022-04-01) **Note:** Version bump only for package @cornerstonejs/tools - - - - ## [0.7.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.7.0...@cornerstonejs/tools@0.7.1) (2022-04-01) - ### Bug Fixes -* cleanup exports, add docs and more tutorials ([#39](https://github.com/cornerstonejs/cornerstone3D-beta/issues/39)) ([743dea8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/743dea89c7a726c29d396756bdd991c81e561105)) - - - - +- cleanup exports, add docs and more tutorials ([#39](https://github.com/cornerstonejs/cornerstone3D-beta/issues/39)) ([743dea8](https://github.com/cornerstonejs/cornerstone3D-beta/commit/743dea89c7a726c29d396756bdd991c81e561105)) # [0.7.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.6.0...@cornerstonejs/tools@0.7.0) (2022-03-31) - ### Features -* add crosshairs example and fix locking ([#40](https://github.com/cornerstonejs/cornerstone3D-beta/issues/40)) ([fe9ec50](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fe9ec50a61c16a2f3655b1dbb405fa7e2ec2438f)) - - - - +- add crosshairs example and fix locking ([#40](https://github.com/cornerstonejs/cornerstone3D-beta/issues/40)) ([fe9ec50](https://github.com/cornerstonejs/cornerstone3D-beta/commit/fe9ec50a61c16a2f3655b1dbb405fa7e2ec2438f)) # [0.6.0](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.5.4...@cornerstonejs/tools@0.6.0) (2022-03-31) - ### Features -* advanced examples ([#38](https://github.com/cornerstonejs/cornerstone3D-beta/issues/38)) ([27f26a1](https://github.com/cornerstonejs/cornerstone3D-beta/commit/27f26a12a1712b7542cc66ab1d077cfb0da50a86)) - - - - +- advanced examples ([#38](https://github.com/cornerstonejs/cornerstone3D-beta/issues/38)) ([27f26a1](https://github.com/cornerstonejs/cornerstone3D-beta/commit/27f26a12a1712b7542cc66ab1d077cfb0da50a86)) ## [0.5.4](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.5.3...@cornerstonejs/tools@0.5.4) (2022-03-31) **Note:** Version bump only for package @cornerstonejs/tools - - - - ## [0.5.3](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.5.2...@cornerstonejs/tools@0.5.3) (2022-03-31) **Note:** Version bump only for package @cornerstonejs/tools - - - - ## [0.5.2](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.5.1...@cornerstonejs/tools@0.5.2) (2022-03-30) **Note:** Version bump only for package @cornerstonejs/tools - - - - ## [0.5.1](https://github.com/cornerstonejs/cornerstone3D-beta/compare/@cornerstonejs/tools@0.5.0...@cornerstonejs/tools@0.5.1) (2022-03-30) **Note:** Version bump only for package @cornerstonejs/tools diff --git a/packages/tools/examples/referenceCursors/index.ts b/packages/tools/examples/referenceCursors/index.ts new file mode 100644 index 000000000..e6e696e48 --- /dev/null +++ b/packages/tools/examples/referenceCursors/index.ts @@ -0,0 +1,300 @@ +import { + RenderingEngine, + Types, + volumeLoader, + Enums, +} from '@cornerstonejs/core'; +import { + initDemo, + createImageIdsAndCacheMetaData, + setTitleAndDescription, + addDropdownToToolbar, + addSliderToToolbar, +} from '../../../../utils/demo/helpers'; +import * as cornerstoneTools from '@cornerstonejs/tools'; + +// This is for debugging purposes +console.warn( + 'Click on index.ts to open source code for this example --------->' +); + +const { + ToolGroupManager, + StackScrollMouseWheelTool, + ReferenceCursors, + PanTool, + ZoomTool, + Enums: csToolsEnums, +} = cornerstoneTools; + +const { ViewportType } = Enums; + +// Define a unique id for the volume +const volumeName = 'CT_VOLUME_ID'; // Id of the volume less loader prefix +const volumeLoaderScheme = 'cornerstoneStreamingImageVolume'; // Loader id which defines which volume loader to use +const volumeId = `${volumeLoaderScheme}:${volumeName}`; // VolumeId with loader id + volume id + +const initialDisableCursor = false; + +// ======== Set up page ======== // +setTitleAndDescription( + 'Cursor corsshair syncing example', + 'This example shows how to sync the crosshair cursors between 3 viewports (2 Stack viewports and 1 Volume viewport with a slightly different orientation). To disable orther cursors, set disableCursor to on and then disable and reactivate the tool.' +); + +const size = '500px'; +const content = document.getElementById('content'); +const viewportGrid = document.createElement('div'); + +viewportGrid.style.display = 'flex'; +viewportGrid.style.display = 'flex'; +viewportGrid.style.flexDirection = 'row'; + +const element1 = document.createElement('div'); +const element2 = document.createElement('div'); +const element3 = document.createElement('div'); +element1.style.width = size; +element1.style.height = size; +element1.oncontextmenu = (e) => e.preventDefault(); +element2.style.width = size; +element2.style.height = size; +element2.oncontextmenu = (e) => e.preventDefault(); +element3.style.height = size; +element3.style.width = size; +element3.oncontextmenu = (e) => e.preventDefault(); + +viewportGrid.appendChild(element1); +viewportGrid.appendChild(element2); +viewportGrid.appendChild(element3); + +content.appendChild(viewportGrid); + +const toolGroupId = 'STACK_TOOL_GROUP_ID'; + +const instructions = document.createElement('p'); +instructions.innerText = + 'Simply move the mouse over the viewports to see the correlating positions in the other viewports'; + +content.append(instructions); + +addDropdownToToolbar({ + options: { + values: ['positionSync on', 'positionSync off'], + defaultValue: 'positionSync on', + }, + onSelectedValueChange: (newPositionSync) => { + const toolGroup = ToolGroupManager.getToolGroup(toolGroupId); + if (toolGroup) { + toolGroup.setToolConfiguration(ReferenceCursors.toolName, { + positionSync: newPositionSync === 'positionSync on', + }); + } + }, +}); + +addDropdownToToolbar({ + options: { + values: ['disableCursor on', 'disableCursor off'], + defaultValue: initialDisableCursor + ? 'disableCursor on' + : 'disableCursor off', + }, + onSelectedValueChange: (newDisableCursor) => { + const toolGroup = ToolGroupManager.getToolGroup(toolGroupId); + if (toolGroup) { + toolGroup.setToolConfiguration(ReferenceCursors.toolName, { + disableCursor: newDisableCursor === 'disableCursor on', + }); + } + }, +}); + +addDropdownToToolbar({ + options: { + values: ['tool enabled', 'tool disabled', 'tool passive', 'tool active'], + defaultValue: 'tool active', + }, + onSelectedValueChange: (newState) => { + const toolGroup = ToolGroupManager.getToolGroup(toolGroupId); + if (toolGroup) { + switch (newState) { + case 'tool enabled': + toolGroup.setToolEnabled(ReferenceCursors.toolName); + break; + case 'tool disabled': + toolGroup.setToolDisabled(ReferenceCursors.toolName); + break; + case 'tool passive': + toolGroup.setToolPassive(ReferenceCursors.toolName); + break; + case 'tool active': + toolGroup.setToolActive(ReferenceCursors.toolName); + break; + default: + throw new Error('unhandled selector value'); + } + } + }, +}); + +addSliderToToolbar({ + title: ' displayThreshold: 5 ', + range: [0, 100], + defaultValue: 5, + updateLabelOnChange(value, label) { + label.innerText = ` displayThreshold: ${value} `; + }, + onSelectedValueChange: (newDisplayThreshold) => { + const toolGroup = ToolGroupManager.getToolGroup(toolGroupId); + if (toolGroup) { + toolGroup.setToolConfiguration(ReferenceCursors.toolName, { + displayThreshold: newDisplayThreshold, + }); + } + }, +}); +// ============================= // + +/** + * Runs the demo + */ +async function run() { + // Init Cornerstone and related libraries + await initDemo(); + + // Add tools to Cornerstone3D + cornerstoneTools.addTool(ReferenceCursors); + cornerstoneTools.addTool(StackScrollMouseWheelTool); + cornerstoneTools.addTool(PanTool); + cornerstoneTools.addTool(ZoomTool); + + // Define a tool group, which defines how mouse events map to tool commands for + // Any viewport using the group + const toolGroup = ToolGroupManager.createToolGroup(toolGroupId); + + // Add the tools to the tool group and specify which volume they are pointing at + toolGroup.addTool(ReferenceCursors.toolName); + toolGroup.addTool(StackScrollMouseWheelTool.toolName); + toolGroup.addTool(PanTool.toolName); + toolGroup.addTool(ZoomTool.toolName); + + toolGroup?.setToolConfiguration(ReferenceCursors.toolName, { + positionSync: true, + disableCursor: initialDisableCursor, + }); + + // Get Cornerstone imageIds and fetch metadata into RAM + const volumeImageIds = await createImageIdsAndCacheMetaData({ + StudyInstanceUID: + '1.3.6.1.4.1.14519.5.2.1.7009.2403.334240657131972136850343327463', + SeriesInstanceUID: + '1.3.6.1.4.1.14519.5.2.1.7009.2403.226151125820845824875394858561', + wadoRsRoot: 'https://d3t6nz73ql33tx.cloudfront.net/dicomweb', + type: 'VOLUME', + }); + + const stackImageIds = await createImageIdsAndCacheMetaData({ + StudyInstanceUID: + '1.3.6.1.4.1.14519.5.2.1.7009.2403.334240657131972136850343327463', + SeriesInstanceUID: + '1.3.6.1.4.1.14519.5.2.1.7009.2403.226151125820845824875394858561', + wadoRsRoot: 'https://d3t6nz73ql33tx.cloudfront.net/dicomweb', + type: 'STACK', + }); + + const smallVolumeImageIds = [volumeImageIds[42], volumeImageIds[43]]; // Small bit of the body + const smallStackImageIds = [stackImageIds[42], stackImageIds[43]]; // Small bit of the body + + // Instantiate a rendering engine + const renderingEngineId = 'myRenderingEngine'; + const renderingEngine = new RenderingEngine(renderingEngineId); + + // Create the viewports + const viewportIds = ['CT_AXIAL_VOLUME', 'CT_AXIAL_STACK', 'CT_AXIAL_STACK2']; + + const viewportInputArray = [ + { + viewportId: viewportIds[0], + type: ViewportType.ORTHOGRAPHIC, + element: element1, + defaultOptions: { + orientation: Enums.OrientationAxis.AXIAL, + background: [0.2, 0, 0.2], + }, + }, + { + viewportId: viewportIds[1], + type: ViewportType.STACK, + element: element2, + defaultOptions: { + background: [0.2, 0, 0.2], + }, + }, + { + viewportId: viewportIds[2], + type: ViewportType.STACK, + element: element3, + defaultOptions: { + background: [0.2, 0, 0.2], + }, + }, + ]; + + renderingEngine.setViewports(viewportInputArray); + + // Set the tool group on the viewports + viewportIds.forEach((viewportId) => + toolGroup.addViewport(viewportId, renderingEngineId) + ); + + // Define a volume in memory + const volume = await volumeLoader.createAndCacheVolume(volumeId, { + imageIds: smallVolumeImageIds, + }); + + const volumeViewport = ( + renderingEngine.getViewport(viewportIds[0]) + ); + const stackViewport = ( + renderingEngine.getViewport(viewportIds[1]) + ); + + const stackViewport2 = ( + renderingEngine.getViewport(viewportIds[2]) + ); + + // Set the stack on the stackViewport + stackViewport.setStack(smallStackImageIds); + stackViewport2.setStack(smallStackImageIds); + + // Set the volume to load + volume.load(); + + // Set the volume on the viewport + volumeViewport.setVolumes([{ volumeId }]).then(() => { + volumeViewport.setCamera({ + viewPlaneNormal: [0, 0.1, -1], + viewUp: [0, 1, 0], + }); + }); + + // As the Stack Scroll mouse wheel is a tool using the `mouseWheelCallback` + // hook instead of mouse buttons, it does not need to assign any mouse button. + toolGroup.setToolActive(StackScrollMouseWheelTool.toolName); + + toolGroup.setToolActive(PanTool.toolName, { + bindings: [{ mouseButton: csToolsEnums.MouseBindings.Primary }], + }); + toolGroup.setToolActive(ZoomTool.toolName, { + bindings: [{ mouseButton: csToolsEnums.MouseBindings.Secondary }], + }); + + // Set the initial state of the tools, here we set one tool active on left click. + // This means left click will draw that tool. + toolGroup.setToolActive(ReferenceCursors.toolName); + + // Render the image + renderingEngine.renderViewports(viewportIds); +} + +run(); diff --git a/packages/tools/package.json b/packages/tools/package.json index c73df7491..ae79b2292 100644 --- a/packages/tools/package.json +++ b/packages/tools/package.json @@ -1,6 +1,6 @@ { "name": "@cornerstonejs/tools", - "version": "0.29.6", + "version": "0.30.7", "description": "Cornerstone3D Tools", "main": "dist/umd/index.js", "types": "dist/esm/index.d.ts", @@ -26,7 +26,7 @@ "webpack:watch": "webpack --mode development --progress --watch --config ./.webpack/webpack.dev.js" }, "dependencies": { - "@cornerstonejs/core": "^0.21.4", + "@cornerstonejs/core": "^0.22.3", "lodash.clonedeep": "4.5.0", "lodash.get": "^4.4.2" }, diff --git a/packages/tools/src/drawingSvg/drawEllipse.ts b/packages/tools/src/drawingSvg/drawEllipse.ts index c9c0d5eee..1031d7347 100644 --- a/packages/tools/src/drawingSvg/drawEllipse.ts +++ b/packages/tools/src/drawingSvg/drawEllipse.ts @@ -11,7 +11,8 @@ function drawEllipse( ellipseUID: string, corner1: Types.Point2, corner2: Types.Point2, - options = {} + options = {}, + dataId = '' ): void { const { color, width, lineWidth, lineDash } = Object.assign( { @@ -57,6 +58,10 @@ function drawEllipse( } else { const svgEllipseElement = document.createElementNS(svgns, 'ellipse'); + if (dataId !== '') { + svgEllipseElement.setAttribute('data-id', dataId); + } + _setNewAttributesIfValid(attributes, svgEllipseElement); svgDrawingHelper.appendNode(svgEllipseElement, svgNodeHash); diff --git a/packages/tools/src/drawingSvg/getSvgDrawingHelper.ts b/packages/tools/src/drawingSvg/getSvgDrawingHelper.ts index 358102de8..baed7faee 100644 --- a/packages/tools/src/drawingSvg/getSvgDrawingHelper.ts +++ b/packages/tools/src/drawingSvg/getSvgDrawingHelper.ts @@ -2,6 +2,8 @@ import { state } from '../store'; import { getEnabledElement } from '@cornerstonejs/core'; import { SVGDrawingHelper } from '../types'; +const VIEWPORT_ELEMENT = 'viewport-element'; + /** * Returns the SVG drawing helper for the given HTML element. * @param element - The HTML element to get the SVG drawing helper for. @@ -34,7 +36,8 @@ function getSvgDrawingHelper(element: HTMLDivElement): SVGDrawingHelper { * @private */ function _getSvgLayer(element) { - const internalDivElement = element.firstChild; + const viewportElement = `.${VIEWPORT_ELEMENT}`; + const internalDivElement = element.querySelector(viewportElement); const svgLayer = internalDivElement.querySelector('.svg-layer'); return svgLayer; diff --git a/packages/tools/src/enums/ToolBindings.ts b/packages/tools/src/enums/ToolBindings.ts index 548f1aecc..21f5424dd 100644 --- a/packages/tools/src/enums/ToolBindings.ts +++ b/packages/tools/src/enums/ToolBindings.ts @@ -25,6 +25,13 @@ enum KeyboardBindings { Shift = 16, Ctrl = 17, Alt = 18, + Meta = 91, + ShiftCtrl = 1617, + ShiftAlt = 1618, + ShiftMeta = 1691, + CtrlAlt = 1718, + CtrlMeta = 1791, + AltMeta = 1891, } export { MouseBindings, KeyboardBindings }; diff --git a/packages/tools/src/eventDispatchers/shared/getActiveToolForMouseEvent.ts b/packages/tools/src/eventDispatchers/shared/getActiveToolForMouseEvent.ts index a670b0ad9..6fac058a6 100644 --- a/packages/tools/src/eventDispatchers/shared/getActiveToolForMouseEvent.ts +++ b/packages/tools/src/eventDispatchers/shared/getActiveToolForMouseEvent.ts @@ -2,6 +2,7 @@ import { ToolGroupManager } from '../../store'; import { MouseBindings, ToolModes } from '../../enums'; import { keyEventListener } from '../../eventListeners'; import { EventTypes } from '../../types'; +import getMouseModifier from './getMouseModifier'; const { Active } = ToolModes; @@ -22,7 +23,9 @@ export default function getActiveToolForMouseEvent( const mouseEvent = evt.detail.event; // If any keyboard modifier key is also pressed - const modifierKey = keyEventListener.getModifierKey(); + // Use the actual key if set, otherwise get the key from the mouse event. + const modifierKey = + keyEventListener.getModifierKey() || getMouseModifier(mouseEvent); const toolGroup = ToolGroupManager.getToolGroupForViewport( viewportId, diff --git a/packages/tools/src/eventDispatchers/shared/getMouseModifier.ts b/packages/tools/src/eventDispatchers/shared/getMouseModifier.ts new file mode 100644 index 000000000..43259b849 --- /dev/null +++ b/packages/tools/src/eventDispatchers/shared/getMouseModifier.ts @@ -0,0 +1,30 @@ +import { KeyboardBindings as kb } from '../../enums'; + +/** + * Gets the mouse modifier key from a mouse event. + * Supports Shift, Ctrl, Alt, in singly and in combinations of 2 + * Supports Meta singly. + */ +const getMouseModifierKey = (evt) => { + // The logic is a hard coded key mapping + if (evt.shiftKey) { + if (evt.ctrlKey) return kb.ShiftCtrl; + if (evt.altKey) return kb.ShiftAlt; + if (evt.metaKey) return kb.ShiftMeta; + return kb.Shift; + } + if (evt.ctrlKey) { + if (evt.altKey) return kb.CtrlAlt; + if (evt.metaKey) return kb.CtrlMeta; + return kb.Ctrl; + } + if (evt.altKey) { + return (evt.metaKey && kb.AltMeta) || kb.Alt; + } + if (evt.metaKey) { + kb.Meta; + } + return undefined; +}; + +export default getMouseModifierKey; diff --git a/packages/tools/src/index.ts b/packages/tools/src/index.ts index eb7f8a840..5a85179e2 100644 --- a/packages/tools/src/index.ts +++ b/packages/tools/src/index.ts @@ -50,6 +50,7 @@ import { BrushTool, AngleTool, MagnifyTool, + ReferenceCursors, ReferenceLines, } from './tools'; @@ -87,6 +88,7 @@ export { ArrowAnnotateTool, AngleTool, MagnifyTool, + ReferenceCursors, ReferenceLines, // Segmentation Display SegmentationDisplayTool, diff --git a/packages/tools/src/store/ToolGroupManager/ToolGroup.ts b/packages/tools/src/store/ToolGroupManager/ToolGroup.ts index ec2c880b1..2cf662fa5 100644 --- a/packages/tools/src/store/ToolGroupManager/ToolGroup.ts +++ b/packages/tools/src/store/ToolGroupManager/ToolGroup.ts @@ -273,9 +273,12 @@ export default class ToolGroup implements IToolGroup { if (this._hasMousePrimaryButtonBinding(toolBindingsOptions) && useCursor) { this.setViewportsCursorByToolName(toolName); } else { - // reset to default cursor - const cursor = MouseCursor.getDefinedCursor('default'); - this._setCursorForViewports(cursor); + // reset to default cursor only if there is no other tool with primary binding + const activeToolName = this.getActivePrimaryMouseButtonTool(); + if (!activeToolName && useCursor) { + const cursor = MouseCursor.getDefinedCursor('default'); + this._setCursorForViewports(cursor); + } } if (typeof this._toolInstances[toolName].onSetToolActive === 'function') { diff --git a/packages/tools/src/tools/CrosshairsTool.ts b/packages/tools/src/tools/CrosshairsTool.ts index 1ecfdc224..9d7ca5150 100644 --- a/packages/tools/src/tools/CrosshairsTool.ts +++ b/packages/tools/src/tools/CrosshairsTool.ts @@ -1924,7 +1924,6 @@ class CrosshairsTool extends AnnotationTool { const eventDetail = evt.detail; const { element } = eventDetail; - this.editData.annotation.highlighted = false; this.editData.annotation.data.handles.activeOperation = null; this.editData.annotation.data.activeViewportIds = []; diff --git a/packages/tools/src/tools/ReferenceCursors.ts b/packages/tools/src/tools/ReferenceCursors.ts new file mode 100644 index 000000000..3911343b6 --- /dev/null +++ b/packages/tools/src/tools/ReferenceCursors.ts @@ -0,0 +1,471 @@ +import { + getEnabledElement, + StackViewport, + VolumeViewport, + utilities, + getEnabledElementByIds, +} from '@cornerstonejs/core'; +import type { Types } from '@cornerstonejs/core'; +import { + addAnnotation, + getAnnotations, +} from '../stateManagement/annotation/annotationState'; +import { isAnnotationVisible } from '../stateManagement/annotation/annotationVisibility'; +import { drawLine } from '../drawingSvg'; +import { getViewportIdsWithToolToRender } from '../utilities/viewportFilters'; +import { + EventTypes, + PublicToolProps, + ToolProps, + SVGDrawingHelper, + Annotation, + Annotations, +} from '../types'; +import { ReferenceCursor } from '../types/ToolSpecificAnnotationTypes'; + +import triggerAnnotationRenderForViewportIds from '../utilities/triggerAnnotationRenderForViewportIds'; +import { StyleSpecifier } from '../types/AnnotationStyle'; +import { vec3 } from 'gl-matrix'; +import AnnotationDisplayTool from './base/AnnotationDisplayTool'; +import vtkMath from '@kitware/vtk.js/Common/Core/Math'; +import { + hideElementCursor, + resetElementCursor, +} from '../cursors/elementCursor'; +import { getToolGroup } from '../store/ToolGroupManager'; + +/** + * ReferenceCursors is a tool that will show your cursors position in all other elements in the toolGroup if they have a matching FrameOfReference relative to its position in world space. + * Also when positionSync is enabled, it will try to sync viewports so that the cursor can be displayed in the correct position in all viewports. + * + * Configuration: + * - positionSync: boolean, if true, it will try to sync viewports so that the cursor can be displayed in the correct position in all viewports. + * - disableCursor: boolean, if true, it will hide the cursor in all viewports. You need to disable and reactivate the tool for this to apply. + * - displayThreshold: number, if the distance of the cursor in a viewport is bigger than this threshold the cursor will not be displayed. + * + * Only uses Active and Disabled state + */ +class ReferenceCursors extends AnnotationDisplayTool { + static toolName; + touchDragCallback: any; + mouseDragCallback: any; + _throttledCalculateCachedStats: any; + isDrawing = false; + isHandleOutsideImage = false; + _elementWithCursor: null | HTMLDivElement = null; + _currentCursorWorldPosition: null | Types.Point3 = null; + _currentCanvasPosition: null | Types.Point2 = null; + //need to keep track if this was enabled when tool was enabled because we need to know if we should reset cursors + _disableCursorEnabled = false; + + constructor( + toolProps: PublicToolProps = {}, + defaultToolProps: ToolProps = { + supportedInteractionTypes: ['Mouse', 'Touch'], + configuration: { + shadow: true, + preventHandleOutsideImage: false, + displayThreshold: 5, + positionSync: true, + disableCursor: false, + }, + } + ) { + super(toolProps, defaultToolProps); + this._disableCursorEnabled = this.configuration.disableCursor; + } + + /** + * Overwritten mouseMoveCallback since we want to keep track of the current mouse position and redraw on mouseMove + * @virtual Event handler for Cornerstone MOUSE_MOVE event. + * + * + * @param evt - The normalized mouse event + * @param filteredAnnotations - The annotations to check for hover interactions + * @returns True if the annotation needs to be re-drawn by the annotationRenderingEngine. + */ + mouseMoveCallback = (evt: EventTypes.MouseMoveEventType): boolean => { + const { detail } = evt; + const { element, currentPoints } = detail; + + //save current positions and current element the curser is hovering over + this._currentCursorWorldPosition = currentPoints.world; + this._currentCanvasPosition = currentPoints.canvas; + this._elementWithCursor = element; + + const annotation = this.getActiveAnnotation(element); + if (annotation === null) { + this.createInitialAnnotation(currentPoints.world, element); + return false; + } + this.updateAnnotationPosition(element, annotation); + return false; + }; + + onSetToolActive(): void { + this._disableCursorEnabled = this.configuration.disableCursor; + if (!this._disableCursorEnabled) return; + const viewportIds = getToolGroup(this.toolGroupId).viewportsInfo; + if (!viewportIds) return; + const enabledElements = viewportIds.map((e) => + getEnabledElementByIds(e.viewportId, e.renderingEngineId) + ); + + enabledElements.forEach((element) => { + if (element) hideElementCursor(element.viewport.element); + }); + } + onSetToolDisabled(): void { + if (!this._disableCursorEnabled) return; + const viewportIds = getToolGroup(this.toolGroupId).viewportsInfo; + if (!viewportIds) return; + const enabledElements = viewportIds.map((e) => + getEnabledElementByIds(e.viewportId, e.renderingEngineId) + ); + enabledElements.forEach((element) => { + if (element) resetElementCursor(element.viewport.element); + }); + } + + createInitialAnnotation = ( + worldPos: Types.Point3, + element: HTMLDivElement + ): void => { + const enabledElement = getEnabledElement(element); + if (!enabledElement) throw new Error('No enabled element found'); + const { viewport, renderingEngine } = enabledElement; + + this.isDrawing = true; + + const camera = viewport.getCamera(); + const { viewPlaneNormal, viewUp } = camera; + if (!viewPlaneNormal || !viewUp) throw new Error('Camera not found'); + + const referencedImageId = this.getReferencedImageId( + viewport, + worldPos, + viewPlaneNormal, + viewUp + ); + + const annotation = { + highlighted: true, + invalidated: true, + metadata: { + toolName: this.getToolName(), + viewPlaneNormal: [...viewPlaneNormal], + viewUp: [...viewUp], + FrameOfReferenceUID: viewport.getFrameOfReferenceUID(), + referencedImageId, + }, + data: { + label: '', + handles: { + points: [[...worldPos]] as [Types.Point3], + activeHandleIndex: null, + textBox: { + hasMoved: false, + worldPosition: [0, 0, 0], + worldBoundingBox: { + topLeft: [0, 0, 0], + topRight: [0, 0, 0], + bottomLeft: [0, 0, 0], + bottomRight: [0, 0, 0], + }, + }, + }, + }, + }; + + const annotationId = this._addAnnotation(element, annotation); + + if (annotationId === null) return; + + const viewportIdsToRender = getViewportIdsWithToolToRender( + element, + this.getToolName(), + false + ); + + triggerAnnotationRenderForViewportIds(renderingEngine, viewportIdsToRender); + }; + + //custom addAnnotations to make sure there is never more than one cursor Annotation + _addAnnotation( + element: HTMLDivElement, + annotation: Annotation + ): string | null { + const annotations = getAnnotations(element, this.getToolName()); + if (annotations instanceof Array && annotations.length > 0) return null; + return addAnnotation(element, annotation); + } + + getActiveAnnotation(element: HTMLDivElement): null | Annotation { + const annotations = getAnnotations(element, this.getToolName()); + if (annotations === undefined || annotations.length === 0) { + return null; + } + const targetAnnotation = annotations[0]; + return targetAnnotation; + } + + /** + * updates the position of the annotation to match the currently set world position + */ + updateAnnotationPosition( + element: HTMLDivElement, + annotation: Annotation + ): void { + const worldPos = this._currentCursorWorldPosition; + if (!worldPos) return; + if (!annotation.data?.handles?.points) return; + annotation.data.handles.points = [[...worldPos]]; + annotation.invalidated = true; + + const viewportIdsToRender = getViewportIdsWithToolToRender( + element, + this.getToolName(), + false + ); + const enabledElement = getEnabledElement(element); + if (!enabledElement) return; + const { renderingEngine } = enabledElement; + triggerAnnotationRenderForViewportIds(renderingEngine, viewportIdsToRender); + } + + //checks if we need to update the annotation position due to camera changes + onCameraModified = (evt: any): void => { + const eventDetail = evt.detail; + const { element, previousCamera, camera } = eventDetail; + const enabledElement = getEnabledElement(element); + const viewport = enabledElement.viewport as + | Types.IVolumeViewport + | Types.IStackViewport; + + //only react to changes for element with cursor, otherwise would cause infinite loop + if (element !== this._elementWithCursor) return; + //check if camera moved along its normal + const oldFocalPoint = previousCamera.focalPoint; + const cameraNormal = camera.viewPlaneNormal; + const newFocalPoint = camera.focalPoint; + + const deltaCameraFocalPoint: Types.Point3 = [0, 0, 0]; + vtkMath.subtract(newFocalPoint, oldFocalPoint, deltaCameraFocalPoint); + //check if focal point changed + if (deltaCameraFocalPoint.reduce((a, b) => a + b, 0) === 0) return; + //if nomrmal is perpendicular to focal point change, then we are not moving along the normal + const dotProduct = vtkMath.dot(deltaCameraFocalPoint, cameraNormal); + //dot product is 0 -> perpendicular + if (Math.abs(dotProduct) < 1e-2) return; + + //need to update the position of the annotation since camera changed + if (!this._currentCanvasPosition) return; + + const newWorldPos = viewport.canvasToWorld(this._currentCanvasPosition); + this._currentCursorWorldPosition = newWorldPos; + this.updateAnnotationPosition(element, this.getActiveAnnotation(element)); + }; + + //display annotation if current viewing plane has a max distance of "displayThreshold" from the annotation + filterInteractableAnnotationsForElement( + element: HTMLDivElement, + annotations: Annotations + ): Annotations { + //calculate distance of current viewport to annotation + if (!(annotations instanceof Array) || annotations.length === 0) return []; + const annotation = annotations[0]; + const viewport = getEnabledElement(element)?.viewport; + if (!viewport) return []; + const camera = viewport.getCamera(); + const { viewPlaneNormal, focalPoint } = camera; + if (!viewPlaneNormal || !focalPoint) return []; + const points = annotation.data?.handles?.points; + if (!(points instanceof Array) || points.length !== 1) return []; + const worldPos = points[0]; + const plane = utilities.planar.planeEquation(viewPlaneNormal, focalPoint); + const distance = utilities.planar.planeDistanceToPoint(plane, worldPos); + return distance < this.configuration.displayThreshold ? [annotation] : []; + } + + /** + * Draws the cursor representation on the enabledElement + * Checks if a stack change has happened and updates annotation in that case + * + * @param enabledElement - The Cornerstone's enabledElement. + * @param svgDrawingHelper - The svgDrawingHelper providing the context for drawing. + */ + renderAnnotation = ( + enabledElement: Types.IEnabledElement, + svgDrawingHelper: SVGDrawingHelper + ): boolean => { + let renderStatus = false; + const { viewport } = enabledElement; + + const isElementWithCursor = this._elementWithCursor === viewport.element; + + //update stack position if position sync is enabled + if (this.configuration.positionSync && !isElementWithCursor) { + this.updateViewportImage(viewport); + } + + const { element } = viewport; + + let annotations = getAnnotations(element, this.getToolName()); + + if (!annotations?.length) { + return renderStatus; + } + + //the viewport change from updateStackPosition might not be applied yet, so sometimes the annotation might not be immediately visible + annotations = this.filterInteractableAnnotationsForElement( + element, + annotations + ) as Annotations; + + if (!annotations?.length) { + return renderStatus; + } + + const styleSpecifier: StyleSpecifier = { + toolGroupId: this.toolGroupId, + toolName: this.getToolName(), + viewportId: enabledElement.viewport.id, + }; + + for (let i = 0; i < annotations.length; i++) { + const annotation = annotations[i] as ReferenceCursor; + const { annotationUID, data } = annotation; + const { handles } = data; + const { points } = handles; + + if (!annotationUID) return renderStatus; + styleSpecifier.annotationUID = annotationUID; + + const lineWidthBase = parseFloat( + this.getStyle('lineWidth', styleSpecifier, annotation) as string + ); + + const lineWidth = + typeof lineWidthBase === 'number' && isElementWithCursor + ? lineWidthBase + : lineWidthBase; + const lineDash = this.getStyle('lineDash', styleSpecifier, annotation); + const color = this.getStyle('color', styleSpecifier, annotation); + + if (points[0].some((e) => isNaN(e))) return renderStatus; + const canvasCoordinates = points.map((p) => + viewport.worldToCanvas(p) + ) as [Types.Point2]; + + // If rendering engine has been destroyed while rendering + if (!viewport.getRenderingEngine()) { + console.warn('Rendering Engine has been destroyed'); + return renderStatus; + } + + if (!isAnnotationVisible(annotationUID)) { + continue; + } + + const crosshairUIDs = { + upper: 'upper', + right: 'right', + lower: 'lower', + left: 'left', + }; + const [x, y] = canvasCoordinates[0]; + const centerSpace = isElementWithCursor ? 20 : 7; + const lineLength = isElementWithCursor ? 5 : 7; + drawLine( + svgDrawingHelper, + annotationUID, + crosshairUIDs.upper, + [x, y - (centerSpace / 2 + lineLength)], + [x, y - centerSpace / 2], + { color, lineDash, lineWidth } + ); + drawLine( + svgDrawingHelper, + annotationUID, + crosshairUIDs.lower, + [x, y + (centerSpace / 2 + lineLength)], + [x, y + centerSpace / 2], + { color, lineDash, lineWidth } + ); + drawLine( + svgDrawingHelper, + annotationUID, + crosshairUIDs.right, + [x + (centerSpace / 2 + lineLength), y], + [x + centerSpace / 2, y], + { color, lineDash, lineWidth } + ); + drawLine( + svgDrawingHelper, + annotationUID, + crosshairUIDs.left, + [x - (centerSpace / 2 + lineLength), y], + [x - centerSpace / 2, y], + { color, lineDash, lineWidth } + ); + renderStatus = true; + } + + return renderStatus; + }; + + updateViewportImage( + viewport: Types.IStackViewport | Types.IVolumeViewport + ): void { + const currentMousePosition = this._currentCursorWorldPosition; + + if (!currentMousePosition || currentMousePosition.some((e) => isNaN(e))) + return; + + if (viewport instanceof StackViewport) { + const closestIndex = utilities.getClosestStackImageIndexForPoint( + currentMousePosition, + viewport + ); + + if (closestIndex === null) return; + if (closestIndex !== viewport.getCurrentImageIdIndex()) + viewport.setImageIdIndex(closestIndex); + } else if (viewport instanceof VolumeViewport) { + const { focalPoint, viewPlaneNormal } = viewport.getCamera(); + if (!focalPoint || !viewPlaneNormal) return; + const plane = utilities.planar.planeEquation(viewPlaneNormal, focalPoint); + const currentDistance = utilities.planar.planeDistanceToPoint( + plane, + currentMousePosition, + true + ); + + if (Math.abs(currentDistance) < 0.5) return; + const normalizedViewPlane = vec3.normalize( + vec3.create(), + vec3.fromValues(...viewPlaneNormal) + ); + const scaledPlaneNormal = vec3.scale( + vec3.create(), + normalizedViewPlane, + currentDistance + ); + const newFocalPoint = vec3.add( + vec3.create(), + vec3.fromValues(...focalPoint), + scaledPlaneNormal + ) as Types.Point3; + //TODO: make check if new focal point is within bounds of volume + const isInBounds = true; + if (isInBounds) { + viewport.setCamera({ focalPoint: newFocalPoint }); + const renderingEngine = viewport.getRenderingEngine(); + if (renderingEngine) renderingEngine.renderViewport(viewport.id); + } + } + } +} + +ReferenceCursors.toolName = 'ReferenceCursors'; +export default ReferenceCursors; diff --git a/packages/tools/src/tools/ZoomTool.ts b/packages/tools/src/tools/ZoomTool.ts index c7254330b..e84269556 100644 --- a/packages/tools/src/tools/ZoomTool.ts +++ b/packages/tools/src/tools/ZoomTool.ts @@ -151,9 +151,13 @@ class ZoomTool extends BaseTool { // If it is a regular GPU accelerated viewport, then parallel scale // has a physical meaning and we can use that to determine the threshold + // Added spacing preset in case there is no imageData on viewport const imageData = viewport.getImageData(); + let spacing = [1, 1, 1]; + if (imageData) { + spacing = imageData.spacing; + } - const { spacing } = imageData; const { minZoomScale, maxZoomScale } = this.configuration; const t = element.clientHeight * spacing[1] * 0.5; @@ -162,12 +166,14 @@ class ZoomTool extends BaseTool { let cappedParallelScale = parallelScaleToSet; let thresholdExceeded = false; - if (scale < minZoomScale) { - cappedParallelScale = t / minZoomScale; - thresholdExceeded = true; - } else if (scale >= maxZoomScale) { - cappedParallelScale = t / maxZoomScale; - thresholdExceeded = true; + if (imageData) { + if (scale < minZoomScale) { + cappedParallelScale = t / minZoomScale; + thresholdExceeded = true; + } else if (scale >= maxZoomScale) { + cappedParallelScale = t / maxZoomScale; + thresholdExceeded = true; + } } viewport.setCamera({ diff --git a/packages/tools/src/tools/annotation/AngleTool.ts b/packages/tools/src/tools/annotation/AngleTool.ts index ba0c9a538..53dd6d89a 100644 --- a/packages/tools/src/tools/annotation/AngleTool.ts +++ b/packages/tools/src/tools/annotation/AngleTool.ts @@ -343,7 +343,6 @@ class AngleTool extends AnnotationTool { } this.angleStartedNotYetCompleted = false; - annotation.highlighted = false; data.handles.activeHandleIndex = null; this._deactivateModify(element); diff --git a/packages/tools/src/tools/annotation/ArrowAnnotateTool.ts b/packages/tools/src/tools/annotation/ArrowAnnotateTool.ts index eff55d35e..38d130b01 100644 --- a/packages/tools/src/tools/annotation/ArrowAnnotateTool.ts +++ b/packages/tools/src/tools/annotation/ArrowAnnotateTool.ts @@ -306,7 +306,6 @@ class ArrowAnnotateTool extends AnnotationTool { return; } - annotation.highlighted = false; data.handles.activeHandleIndex = null; this._deactivateModify(element); diff --git a/packages/tools/src/tools/annotation/BidirectionalTool.ts b/packages/tools/src/tools/annotation/BidirectionalTool.ts index 049160dea..bd39bef4c 100644 --- a/packages/tools/src/tools/annotation/BidirectionalTool.ts +++ b/packages/tools/src/tools/annotation/BidirectionalTool.ts @@ -1,4 +1,4 @@ -import { vec2, vec3 } from 'gl-matrix'; +import { vec2, vec3, mat2, mat3, mat2d } from 'gl-matrix'; import { getEnabledElement, triggerEvent, @@ -404,7 +404,6 @@ class BidirectionalTool extends AnnotationTool { return; } - annotation.highlighted = false; data.handles.activeHandleIndex = null; this._deactivateModify(element); @@ -543,7 +542,8 @@ class BidirectionalTool extends AnnotationTool { }; // ~~ calculate worldPos of our short axis handles - // 1/3 distance between long points + // short axis is perpendicular to long axis, and we set its length to be 2/3 of long axis + // (meaning each) const dist = vec2.distance(canvasCoordPoints[0], canvasCoordPoints[1]); const shortAxisDistFromCenter = dist / 3; @@ -619,7 +619,7 @@ class BidirectionalTool extends AnnotationTool { }); annotation.invalidated = true; } else { - this._mouseDragModifyHandle(evt); + this._handleDragModify(evt); annotation.invalidated = true; } @@ -630,12 +630,12 @@ class BidirectionalTool extends AnnotationTool { * Mouse dragging a handle callback * @param evt - mouse drag event */ - _mouseDragModifyHandle = (evt) => { + _handleDragModify = (evt) => { const eventDetail = evt.detail; const { currentPoints, element } = eventDetail; const enabledElement = getEnabledElement(element); const { viewport } = enabledElement; - const { annotation, handleIndex } = this.editData; + const { annotation, handleIndex: movingHandleIndex } = this.editData; const { data } = annotation; // Moving handle @@ -646,7 +646,7 @@ class BidirectionalTool extends AnnotationTool { viewport.worldToCanvas(data.handles.points[2]), viewport.worldToCanvas(data.handles.points[3]), ]; - // Which line is long? Which line is short? + const firstLineSegment = { start: { x: canvasCoordHandlesCurrent[0][0], @@ -672,16 +672,38 @@ class BidirectionalTool extends AnnotationTool { const proposedPoint = [...worldPos]; const proposedCanvasCoord = viewport.worldToCanvas(proposedPoint); - if (handleIndex === 0 || handleIndex === 1) { - const fixedHandleIndex = handleIndex === 0 ? 1 : 0; + if (movingHandleIndex === 0 || movingHandleIndex === 1) { + const fixedHandleIndex = movingHandleIndex === 0 ? 1 : 0; + + const fixedHandleCanvasCoord = + canvasCoordHandlesCurrent[fixedHandleIndex]; - const fixedCanvasCoord = canvasCoordHandlesCurrent[fixedHandleIndex]; + const fixedHandleToProposedCoordVec = vec2.set( + vec2.create(), + proposedCanvasCoord[0] - fixedHandleCanvasCoord[0], + proposedCanvasCoord[1] - fixedHandleCanvasCoord[1] + ); + + const fixedHandleToOldCoordVec = vec2.set( + vec2.create(), + canvasCoordHandlesCurrent[movingHandleIndex][0] - + fixedHandleCanvasCoord[0], + canvasCoordHandlesCurrent[movingHandleIndex][1] - + fixedHandleCanvasCoord[1] + ); + + // normalize vector + vec2.normalize( + fixedHandleToProposedCoordVec, + fixedHandleToProposedCoordVec + ); + vec2.normalize(fixedHandleToOldCoordVec, fixedHandleToOldCoordVec); // Check whether this const proposedFirstLineSegment = { start: { - x: fixedCanvasCoord[0], - y: fixedCanvasCoord[1], + x: fixedHandleCanvasCoord[0], + y: fixedHandleCanvasCoord[1], }, end: { x: proposedCanvasCoord[0], @@ -689,6 +711,11 @@ class BidirectionalTool extends AnnotationTool { }, }; + // Note: this is the case when we are modifying the long axis line segment + // and we make it shorter and shorter until its second half size becomes zero + // which basically means that any more modification would make the long axis + // second half disappear. In this case, we just bail out and do not update + // since we don't want to disrupt the bidirectional shape. if ( this._movingLongAxisWouldPutItThroughShortAxis( proposedFirstLineSegment, @@ -698,73 +725,62 @@ class BidirectionalTool extends AnnotationTool { return; } - // --> We need to preserve this distance - const intersectionPoint = lineSegment.intersectLine( - [secondLineSegment.start.x, secondLineSegment.start.y], - [secondLineSegment.end.x, secondLineSegment.end.y], - [firstLineSegment.start.x, firstLineSegment.start.y], - [firstLineSegment.end.x, firstLineSegment.end.y] + const centerOfRotation = fixedHandleCanvasCoord; + + const angle = this._getSignedAngle( + fixedHandleToOldCoordVec, + fixedHandleToProposedCoordVec ); - const intersectionCoord = vec2.create(); + // rotate handles around the center of rotation, first translate to origin, + // then rotate, then translate back + let firstPointX = canvasCoordHandlesCurrent[2][0]; + let firstPointY = canvasCoordHandlesCurrent[2][1]; - vec2.set(intersectionCoord, intersectionPoint[0], intersectionPoint[1]); + let secondPointX = canvasCoordHandlesCurrent[3][0]; + let secondPointY = canvasCoordHandlesCurrent[3][1]; - // 1. distance from intersection point to start handle? - const distFromLeftHandle = vec2.distance( - canvasCoordHandlesCurrent[2], - intersectionCoord - ); + // translate to origin + firstPointX -= centerOfRotation[0]; + firstPointY -= centerOfRotation[1]; - // 2. distance from intersection point to end handle? - const distFromRightHandle = vec2.distance( - canvasCoordHandlesCurrent[3], - intersectionCoord - ); + secondPointX -= centerOfRotation[0]; + secondPointY -= centerOfRotation[1]; - // 3. distance from long's opposite handle and intersect point - // Need new intersect x/y - const distIntersectAndFixedPoint = Math.abs( - vec2.distance(fixedCanvasCoord, intersectionCoord) - ); + // rotate + const rotatedFirstPoint = + firstPointX * Math.cos(angle) - firstPointY * Math.sin(angle); + const rotatedFirstPointY = + firstPointX * Math.sin(angle) + firstPointY * Math.cos(angle); - // Find inclination of perpindicular - // Should use proposed point to find new inclination - const dx = fixedCanvasCoord[0] - proposedCanvasCoord[0]; - const dy = fixedCanvasCoord[1] - proposedCanvasCoord[1]; - const length = Math.sqrt(dx * dx + dy * dy); - const vectorX = dx / length; - const vectorY = dy / length; - - // Find new intersection point - // --> fixedPoint, magnitude in perpendicular - // minus if right - // add if left - const intersectX = - fixedCanvasCoord[0] - distIntersectAndFixedPoint * vectorX; - const intersectY = - fixedCanvasCoord[1] - distIntersectAndFixedPoint * vectorY; - - // short points 1/4 distance from center of long points - // Flip signs depending on grabbed handle - const mod = handleIndex === 0 ? -1 : 1; - const leftX = intersectX + distFromLeftHandle * vectorY * mod; - const leftY = intersectY - distFromLeftHandle * vectorX * mod; - const rightX = intersectX - distFromRightHandle * vectorY * mod; - const rightY = intersectY + distFromRightHandle * vectorX * mod; - - data.handles.points[handleIndex] = proposedPoint; - data.handles.points[2] = viewport.canvasToWorld([leftX, leftY]); - data.handles.points[3] = viewport.canvasToWorld([rightX, rightY]); + const rotatedSecondPoint = + secondPointX * Math.cos(angle) - secondPointY * Math.sin(angle); + const rotatedSecondPointY = + secondPointX * Math.sin(angle) + secondPointY * Math.cos(angle); + + // translate back + firstPointX = rotatedFirstPoint + centerOfRotation[0]; + firstPointY = rotatedFirstPointY + centerOfRotation[1]; + + secondPointX = rotatedSecondPoint + centerOfRotation[0]; + secondPointY = rotatedSecondPointY + centerOfRotation[1]; + + // update handles + const newFirstPoint = viewport.canvasToWorld([firstPointX, firstPointY]); + const newSecondPoint = viewport.canvasToWorld([ + secondPointX, + secondPointY, + ]); + + // the fixed handle is the one that is not being moved so we + // don't need to update it + data.handles.points[movingHandleIndex] = proposedPoint; + data.handles.points[2] = newFirstPoint; + data.handles.points[3] = newSecondPoint; } else { // Translation manipulator - const translateHandleIndex = handleIndex === 2 ? 3 : 2; + const translateHandleIndex = movingHandleIndex === 2 ? 3 : 2; - // does not rotate, but can translate entire line (other end of short) - const proposedCanvasCoordPoint = { - x: proposedCanvasCoord[0], - y: proposedCanvasCoord[1], - }; const canvasCoordsCurrent = { longLineSegment: { start: firstLineSegment.start, @@ -776,75 +792,95 @@ class BidirectionalTool extends AnnotationTool { }, }; - // get incline of other line (should not change w/ this movement) - const dx = - canvasCoordsCurrent.longLineSegment.start.x - - canvasCoordsCurrent.longLineSegment.end.x; - const dy = - canvasCoordsCurrent.longLineSegment.start.y - - canvasCoordsCurrent.longLineSegment.end.y; - const length = Math.sqrt(dx * dx + dy * dy); - const vectorX = dx / length; - const vectorY = dy / length; - // Create a helper line to find the intesection point in the long line - const highNumber = Number.MAX_SAFE_INTEGER; - // Get the multiplier - // +1 or -1 depending on which perp end we grabbed (and if it was "fixed" end) - const mod = handleIndex === 0 || handleIndex === 3 ? 1 : -1; - const multiplier = mod * highNumber; - const helperLine = { - start: proposedCanvasCoordPoint, // could be start or end - end: { - x: proposedCanvasCoordPoint.x + vectorY * multiplier, - y: proposedCanvasCoordPoint.y + vectorX * multiplier * -1, - }, - }; - - const newIntersectionPoint = lineSegment.intersectLine( + const longLineSegmentVec = vec2.subtract( + vec2.create(), + [ + canvasCoordsCurrent.longLineSegment.end.x, + canvasCoordsCurrent.longLineSegment.end.y, + ], [ canvasCoordsCurrent.longLineSegment.start.x, canvasCoordsCurrent.longLineSegment.start.y, - ], + ] + ); + + const longLineSegmentVecNormalized = vec2.normalize( + vec2.create(), + longLineSegmentVec + ); + + const proposedToCurrentVec = vec2.subtract( + vec2.create(), + [proposedCanvasCoord[0], proposedCanvasCoord[1]], [ - canvasCoordsCurrent.longLineSegment.end.x, - canvasCoordsCurrent.longLineSegment.end.y, + canvasCoordHandlesCurrent[movingHandleIndex][0], + canvasCoordHandlesCurrent[movingHandleIndex][1], + ] + ); + + const movementLength = vec2.length(proposedToCurrentVec); + + const angle = this._getSignedAngle( + longLineSegmentVecNormalized, + proposedToCurrentVec + ); + + const movementAlongLineSegmentLength = Math.cos(angle) * movementLength; + + const newTranslatedPoint = vec2.scaleAndAdd( + vec2.create(), + [ + canvasCoordHandlesCurrent[translateHandleIndex][0], + canvasCoordHandlesCurrent[translateHandleIndex][1], ], - [helperLine.start.x, helperLine.start.y], - [helperLine.end.x, helperLine.end.y] + longLineSegmentVecNormalized, + movementAlongLineSegmentLength ); - // short-circuit - if (newIntersectionPoint === undefined) { + // don't update if it passes through the other line segment + if ( + this._movingLongAxisWouldPutItThroughShortAxis( + { + start: { + x: proposedCanvasCoord[0], + y: proposedCanvasCoord[1], + }, + end: { + x: newTranslatedPoint[0], + y: newTranslatedPoint[1], + }, + }, + { + start: { + x: canvasCoordsCurrent.longLineSegment.start.x, + y: canvasCoordsCurrent.longLineSegment.start.y, + }, + end: { + x: canvasCoordsCurrent.longLineSegment.end.x, + y: canvasCoordsCurrent.longLineSegment.end.y, + }, + } + ) + ) { return; } - // 1. distance from intersection point to start handle? - const distFromTranslateHandle = vec2.distance( - canvasCoordHandlesCurrent[translateHandleIndex], - [newIntersectionPoint[0], newIntersectionPoint[1]] + const intersectionPoint = lineSegment.intersectLine( + [proposedCanvasCoord[0], proposedCanvasCoord[1]], + [newTranslatedPoint[0], newTranslatedPoint[1]], + [firstLineSegment.start.x, firstLineSegment.start.y], + [firstLineSegment.end.x, firstLineSegment.end.y] ); - // isStart if index is 0 or 2 - const shortLineSegment = { - start: { - x: newIntersectionPoint[0] + vectorY * distFromTranslateHandle, - y: newIntersectionPoint[1] + vectorX * distFromTranslateHandle * -1, - }, - end: { - x: newIntersectionPoint[0] + vectorY * distFromTranslateHandle * -1, - y: newIntersectionPoint[1] + vectorX * distFromTranslateHandle, - }, - }; - const translatedHandleCoords = - translateHandleIndex === 2 - ? shortLineSegment.start - : shortLineSegment.end; - - data.handles.points[translateHandleIndex] = viewport.canvasToWorld([ - translatedHandleCoords.x, - translatedHandleCoords.y, - ]); - data.handles.points[handleIndex] = proposedPoint; + // don't update if it doesn't intersect + if (!intersectionPoint) { + return; + } + + data.handles.points[translateHandleIndex] = viewport.canvasToWorld( + newTranslatedPoint as Types.Point2 + ); + data.handles.points[movingHandleIndex] = proposedPoint; } }; @@ -1131,7 +1167,7 @@ class BidirectionalTool extends AnnotationTool { }; _movingLongAxisWouldPutItThroughShortAxis = ( - proposedFirstLineSegment, + firstLineSegment, secondLineSegment ) => { const vectorInSecondLineDirection = vec2.create(); @@ -1161,8 +1197,8 @@ class BidirectionalTool extends AnnotationTool { const proposedIntersectionPoint = lineSegment.intersectLine( [extendedSecondLineSegment.start.x, extendedSecondLineSegment.start.y], [extendedSecondLineSegment.end.x, extendedSecondLineSegment.end.y], - [proposedFirstLineSegment.start.x, proposedFirstLineSegment.start.y], - [proposedFirstLineSegment.end.x, proposedFirstLineSegment.end.y] + [firstLineSegment.start.x, firstLineSegment.start.y], + [firstLineSegment.end.x, firstLineSegment.end.y] ); const wouldPutThroughShortAxis = !proposedIntersectionPoint; @@ -1269,6 +1305,13 @@ class BidirectionalTool extends AnnotationTool { csUtils.indexWithinDimensions(index4, dimensions) ); }; + + _getSignedAngle = (vector1, vector2) => { + return Math.atan2( + vector1[0] * vector2[1] - vector1[1] * vector2[0], + vector1[0] * vector2[0] + vector1[1] * vector2[1] + ); + }; } BidirectionalTool.toolName = 'Bidirectional'; diff --git a/packages/tools/src/tools/annotation/EllipticalROITool.ts b/packages/tools/src/tools/annotation/EllipticalROITool.ts index ce13ea765..10df4d271 100644 --- a/packages/tools/src/tools/annotation/EllipticalROITool.ts +++ b/packages/tools/src/tools/annotation/EllipticalROITool.ts @@ -422,6 +422,10 @@ class EllipticalROITool extends AnnotationTool { return; } + // Elliptical ROI tool should reset its highlight to false on mouse up (as opposed + // to other tools that keep it highlighted until the user moves. The reason + // is that we use top-left and bottom-right handles to define the ellipse, + // and they are by definition not in the ellipse on mouse up. annotation.highlighted = false; data.handles.activeHandleIndex = null; @@ -868,6 +872,7 @@ class EllipticalROITool extends AnnotationTool { ); } + const dataId = `${annotationUID}-ellipse`; const ellipseUID = '0'; drawEllipseSvg( svgDrawingHelper, @@ -879,7 +884,8 @@ class EllipticalROITool extends AnnotationTool { color, lineDash, lineWidth, - } + }, + dataId ); // draw center point, if "centerPointRadius" configuration is valid. diff --git a/packages/tools/src/tools/annotation/LengthTool.ts b/packages/tools/src/tools/annotation/LengthTool.ts index 7084760a3..d1d7770ff 100644 --- a/packages/tools/src/tools/annotation/LengthTool.ts +++ b/packages/tools/src/tools/annotation/LengthTool.ts @@ -347,7 +347,6 @@ class LengthTool extends AnnotationTool { return; } - annotation.highlighted = false; data.handles.activeHandleIndex = null; this._deactivateModify(element); diff --git a/packages/tools/src/tools/annotation/PlanarFreehandROITool.ts b/packages/tools/src/tools/annotation/PlanarFreehandROITool.ts index fa0eca533..de08aac1e 100644 --- a/packages/tools/src/tools/annotation/PlanarFreehandROITool.ts +++ b/packages/tools/src/tools/annotation/PlanarFreehandROITool.ts @@ -1,4 +1,5 @@ import { + CONSTANTS, getEnabledElement, triggerEvent, eventTarget, @@ -42,7 +43,9 @@ import { PlanarFreehandROIAnnotation } from '../../types/ToolSpecificAnnotationT import { PlanarFreehandROICommonData } from '../../utilities/math/polyline/planarFreehandROIInternalTypes'; const { pointCanProjectOnLine } = polyline; +const { EPSILON } = CONSTANTS; +const PARALLEL_THRESHOLD = 1 - EPSILON; /** * PlanarFreehandROITool lets you draw annotations that define an arbitrarily drawn region. * You can use the PlanarFreehandROITool in all perpendicular views (axial, sagittal, coronal), @@ -488,13 +491,21 @@ class PlanarFreehandROITool extends AnnotationTool { spacingInNormalDirection: number ): Annotations { const { viewPlaneNormal } = camera; - const annotationsWithSameNormal = annotations.filter((td: Annotation) => { - const annotationViewPlaneNormal = td.metadata.viewPlaneNormal; - return csUtils.isEqual(annotationViewPlaneNormal, viewPlaneNormal); - }); + + const annotationsWithParallelNormals = annotations.filter( + (td: Annotation) => { + const annotationViewPlaneNormal = td.metadata.viewPlaneNormal; + + const isParallel = + Math.abs(vec3.dot(viewPlaneNormal, annotationViewPlaneNormal)) > + PARALLEL_THRESHOLD; + + return annotationViewPlaneNormal && isParallel; + } + ); // No in plane annotations. - if (!annotationsWithSameNormal.length) { + if (!annotationsWithParallelNormals.length) { return []; } @@ -506,10 +517,14 @@ class PlanarFreehandROITool extends AnnotationTool { const annotationsWithinSlice = []; - for (const annotation of annotationsWithSameNormal) { + for (const annotation of annotationsWithParallelNormals) { const data = annotation.data; const point = data.polyline[0]; + if (!annotation.isVisible) { + continue; + } + // A = point // B = focal point // P = normal diff --git a/packages/tools/src/tools/annotation/ProbeTool.ts b/packages/tools/src/tools/annotation/ProbeTool.ts index fc5f65c40..e2adbe1cb 100644 --- a/packages/tools/src/tools/annotation/ProbeTool.ts +++ b/packages/tools/src/tools/annotation/ProbeTool.ts @@ -274,8 +274,6 @@ class ProbeTool extends AnnotationTool { const { annotation, viewportIdsToRender, newAnnotation } = this.editData; - annotation.highlighted = false; - const enabledElement = getEnabledElement(element); const { renderingEngine } = enabledElement; diff --git a/packages/tools/src/tools/annotation/RectangleROITool.ts b/packages/tools/src/tools/annotation/RectangleROITool.ts index 75f3fc9db..cd4c92b8d 100644 --- a/packages/tools/src/tools/annotation/RectangleROITool.ts +++ b/packages/tools/src/tools/annotation/RectangleROITool.ts @@ -355,7 +355,6 @@ class RectangleROITool extends AnnotationTool { return; } - annotation.highlighted = false; data.handles.activeHandleIndex = null; this._deactivateModify(element); diff --git a/packages/tools/src/tools/base/BaseTool.ts b/packages/tools/src/tools/base/BaseTool.ts index 3543c09b0..d34926875 100644 --- a/packages/tools/src/tools/base/BaseTool.ts +++ b/packages/tools/src/tools/base/BaseTool.ts @@ -144,7 +144,7 @@ abstract class BaseTool implements IBaseTool { if (targetId.startsWith('imageId:')) { const imageId = targetId.split('imageId:')[1]; const imageURI = utilities.imageIdToURI(imageId); - const viewports = utilities.getViewportsWithImageURI( + let viewports = utilities.getViewportsWithImageURI( imageURI, renderingEngine.id ); @@ -153,6 +153,14 @@ abstract class BaseTool implements IBaseTool { return; } + viewports = viewports.filter((viewport) => { + return viewport.getCurrentImageId() === imageId; + }); + + if (!viewports || !viewports.length) { + return; + } + return viewports[0].getImageData(); } else if (targetId.startsWith('volumeId:')) { const volumeId = targetId.split('volumeId:')[1]; diff --git a/packages/tools/src/tools/index.ts b/packages/tools/src/tools/index.ts index fa5e411c7..700f4427b 100644 --- a/packages/tools/src/tools/index.ts +++ b/packages/tools/src/tools/index.ts @@ -20,6 +20,7 @@ import EllipticalROITool from './annotation/EllipticalROITool'; import PlanarFreehandROITool from './annotation/PlanarFreehandROITool'; import ArrowAnnotateTool from './annotation/ArrowAnnotateTool'; import AngleTool from './annotation/AngleTool'; +import ReferenceCursors from './ReferenceCursors'; import ReferenceLines from './ReferenceLinesTool'; // Segmentation DisplayTool @@ -58,6 +59,7 @@ export { PlanarFreehandROITool, ArrowAnnotateTool, AngleTool, + ReferenceCursors, // Segmentations Display SegmentationDisplayTool, // Segmentations Tools diff --git a/packages/tools/src/tools/segmentation/CircleScissorsTool.ts b/packages/tools/src/tools/segmentation/CircleScissorsTool.ts index 53c576250..724895545 100644 --- a/packages/tools/src/tools/segmentation/CircleScissorsTool.ts +++ b/packages/tools/src/tools/segmentation/CircleScissorsTool.ts @@ -239,7 +239,6 @@ class CircleScissorsTool extends BaseTool { return; } - annotation.highlighted = false; data.handles.activeHandleIndex = null; this._deactivateDraw(element); diff --git a/packages/tools/src/tools/segmentation/RectangleScissorsTool.ts b/packages/tools/src/tools/segmentation/RectangleScissorsTool.ts index ba3f843d9..781e91d8d 100644 --- a/packages/tools/src/tools/segmentation/RectangleScissorsTool.ts +++ b/packages/tools/src/tools/segmentation/RectangleScissorsTool.ts @@ -276,7 +276,6 @@ class RectangleScissorsTool extends BaseTool { return; } - annotation.highlighted = false; data.handles.activeHandleIndex = null; this._deactivateDraw(element); diff --git a/packages/tools/src/tools/segmentation/SphereScissorsTool.ts b/packages/tools/src/tools/segmentation/SphereScissorsTool.ts index 904abb40a..1ef669753 100644 --- a/packages/tools/src/tools/segmentation/SphereScissorsTool.ts +++ b/packages/tools/src/tools/segmentation/SphereScissorsTool.ts @@ -239,7 +239,6 @@ class SphereScissorsTool extends BaseTool { if (newAnnotation && !hasMoved) { return; } - annotation.highlighted = false; data.handles.activeHandleIndex = null; diff --git a/packages/tools/src/types/ToolSpecificAnnotationTypes.ts b/packages/tools/src/types/ToolSpecificAnnotationTypes.ts index ce2263bf5..d471993ab 100644 --- a/packages/tools/src/types/ToolSpecificAnnotationTypes.ts +++ b/packages/tools/src/types/ToolSpecificAnnotationTypes.ts @@ -257,6 +257,14 @@ export interface AngleAnnotation extends Annotation { }; } +export interface ReferenceCursor extends Annotation { + data: { + handles: { + points: [Types.Point3]; + }; + }; +} + export interface ReferenceLineAnnotation extends Annotation { data: { handles: { diff --git a/packages/tools/src/utilities/segmentation/triggerSegmentationRender.ts b/packages/tools/src/utilities/segmentation/triggerSegmentationRender.ts index 8971e315a..6dd5b3fc3 100644 --- a/packages/tools/src/utilities/segmentation/triggerSegmentationRender.ts +++ b/packages/tools/src/utilities/segmentation/triggerSegmentationRender.ts @@ -129,6 +129,10 @@ class SegmentationRenderingEngine { const segmentationDisplayToolInstance = toolGroup.getToolInstance( SegmentationDisplayTool.toolName ) as SegmentationDisplayTool; + if (!segmentationDisplayToolInstance) { + console.warn('No segmentation tool found inside', toolGroupId); + return; + } function onSegmentationRender(evt: Types.EventTypes.ImageRenderedEvent) { const { element, viewportId, renderingEngineId } = evt.detail; diff --git a/packages/tools/test/LengthTool_test.js b/packages/tools/test/LengthTool_test.js index 9c3cc1491..f5776caef 100644 --- a/packages/tools/test/LengthTool_test.js +++ b/packages/tools/test/LengthTool_test.js @@ -245,7 +245,7 @@ describe('LengthTool:', () => { const lengthAnnotation = lengthAnnotations[0]; expect(lengthAnnotation.metadata.toolName).toBe(LengthTool.toolName); expect(lengthAnnotation.invalidated).toBe(false); - expect(lengthAnnotation.highlighted).toBe(false); + expect(lengthAnnotation.highlighted).toBe(true); const data = lengthAnnotation.data.cachedStats; const targets = Array.from(Object.keys(data)); @@ -359,7 +359,7 @@ describe('LengthTool:', () => { expect(lengthAnnotation.metadata.referencedImageId).toBe(imageId1); expect(lengthAnnotation.metadata.toolName).toBe(LengthTool.toolName); expect(lengthAnnotation.invalidated).toBe(false); - expect(lengthAnnotation.highlighted).toBe(false); + expect(lengthAnnotation.highlighted).toBe(true); const data = lengthAnnotation.data.cachedStats; const targets = Array.from(Object.keys(data)); @@ -500,7 +500,7 @@ describe('LengthTool:', () => { expect(lengthAnnotation.metadata.referencedImageId).toBe(imageId1); expect(lengthAnnotation.metadata.toolName).toBe(LengthTool.toolName); expect(lengthAnnotation.invalidated).toBe(false); - expect(lengthAnnotation.highlighted).toBe(false); + expect(lengthAnnotation.highlighted).toBe(true); const data = lengthAnnotation.data.cachedStats; const targets = Array.from(Object.keys(data)); @@ -1139,7 +1139,7 @@ describe('LengthTool:', () => { const lengthAnnotation = lengthAnnotations[0] expect(lengthAnnotation.metadata.toolName).toBe(LengthTool.toolName) expect(lengthAnnotation.invalidated).toBe(false) - expect(lengthAnnotation.highlighted).toBe(false) + expect(lengthAnnotation.highlighted).toBe(true) const data = lengthAnnotation.data.cachedStats const targets = Array.from(Object.keys(data)) diff --git a/packages/tools/test/cpu_LengthTool_test.js b/packages/tools/test/cpu_LengthTool_test.js index 3f1f30a1f..8aaeee992 100644 --- a/packages/tools/test/cpu_LengthTool_test.js +++ b/packages/tools/test/cpu_LengthTool_test.js @@ -250,7 +250,7 @@ describe('Length Tool (CPU):', () => { expect(lengthAnnotation.metadata.referencedImageId).toBe(imageId1); expect(lengthAnnotation.metadata.toolName).toBe(LengthTool.toolName); expect(lengthAnnotation.invalidated).toBe(false); - expect(lengthAnnotation.highlighted).toBe(false); + expect(lengthAnnotation.highlighted).toBe(true); const data = lengthAnnotation.data.cachedStats; const targets = Array.from(Object.keys(data)); @@ -391,7 +391,7 @@ describe('Length Tool (CPU):', () => { expect(lengthAnnotation.metadata.referencedImageId).toBe(imageId1); expect(lengthAnnotation.metadata.toolName).toBe(LengthTool.toolName); expect(lengthAnnotation.invalidated).toBe(false); - expect(lengthAnnotation.highlighted).toBe(false); + expect(lengthAnnotation.highlighted).toBe(true); const data = lengthAnnotation.data.cachedStats; const targets = Array.from(Object.keys(data)); diff --git a/packages/tools/test/groundTruth/volumeURI_100_100_10_1_1_1_0_SEG_COR.png b/packages/tools/test/groundTruth/volumeURI_100_100_10_1_1_1_0_SEG_COR.png index 2fa4476655de8c05c5bce2346c8edeab4d04b88a..74283ec8ae96b9642ac9e11d9ccd9f72050f8398 100644 GIT binary patch literal 3032 zcmeAS@N?(olHy`uVBq!ia0vp^zd)FS4M=vpiLzy2V2sRkb`J1#c2)=|%1_J8No8Qr zn3y|ZzqeDM%+dZ-j=ch%%Y>>Nom*Y^$Yh1Eb2i1@;?M4U{dMWVVEyyrSKr(cGjY>> z>zI(7tLxk7TJON?==~t**RQzvrD5McJ+1js^zLavgPy+dp)X7)#B;O-`&X^}%6s)Y z3#;P~Lyp#ulR94fVv78*cJA`9R`*wTm;A}z{AW^DNc-dN?SD_c_!;nc{r<;a(t3o{ z|1OyM;Ls+<^Aa2PWpkgbKEf>4s$@4|PU%mVqFYb9m!(?@D(_R|`yg{#z+RyJQts~@ z>E~x<|4nsV_THFF+cU`CSHMc?g1|AIX&b!m{&~-9zSmGhaRWd1?GsAu(pr1PN_-`b zeAZ}4=2A@Jy=*e;&5!c(wR1I?i`!Y&uaz}!^nPVmaOYO9UGN>j2fsoLy8oKIT3P8G zZ9MC=7wZelqB+}5518{^c`y5X?<0$^#tVK6?pRgJWcxqq-O=zr62P#INsaJK^YvxW z02o16GVKjIa%&%fBcy73f}&HakP87GyDW_0IXZ1x2aF#mMTB#n9CUWaO9R1H-x~ zGubn*B((^r8EPBMfw)yb&9c!41s78ALE;813XB{(E*pJ#MB8yqTj6zqfq{Lur;B4q z1>@U0dnbmZi?CdX6lIekH zzq75~EjMl6y6LaKK9Xl*k&Ak;z5U*~A{LGs(SVY6hXep$7o|NZ!x@!xU(nmso4bzk23>x@tJ#Xnhnd*bD_%fGnp-@4+y`-2vyeJ|8`j)s44SvaNtNq3ywf{&as zf*)M%7kz1-|MBWy#;*S*Q9%1HyCoYiZ5Iysay#;uFN>e{hYR(k-><*Ed~fc-x{VF` zzx3I@9~Z3PY!v^$==ZCAE^q#wF$L<{dgQIOCeUN=R$Es}PpeY^3bAut)?)eR{osQ5 z-_!pKKgIp8`CT7>_x1MQds*ayAN>3zqx-F7Z_N6O-1a^V4s#p!@4D`qmcX>LVbSxn zIDr*F2kbh*u!^L7_eU2-f z8db3=Y-$s@HLCKSu{K&Ux~}g&bAY9Y(e?bf w88Hi=U=^`7|J($$ebK1pqrpDx6Pz96MQiQtM|&0ko9YYzopr0Hl#q@c;k- literal 3038 zcmeAS@N?(olHy`uVBq!ia0vp^zd)FS4M=vpiLzy2V06lKb`J1#c2)=|%1_J8No8Qr zn3$Z9AmpK=aUwA>A>qVXZB4GC@}Q26o}h&KV+YPC98x%^a7tnNjF^}Q5&{pHLk=-4 z4m`L$o2N(N*CxFaYyRc;?EGe*r<>emecI&l-NQ>~yb5Fp_sS|Xn(&YLi04UGS5+RK z9!`gCMU|e69e0^hxxXTyhdOFOIyIIru4W?^ZJ@5 zHck{|X4crFxXS)ML%Z@~33jJ73uZPREHaw#kxy~jjKc>uFiY?=eHKX4Ixi{lLqt-7 zPfy1~$E(G<;iI&7;jE2MsBRtc5eHpZXYz_t%Mm7d!Ad8WK2}lS**^EH8212|&lYs@S zhJnEjNHZ`nEntF+{93?_V1p#VstT z4fPE4;bsH1+JHo@{EISEfi{E8w==W>t3(k)*aJ}?kda@K4-AE(%w*5JlGLJtB4CJs zbsIr-<5q!gR#0kjeoiS!b7)>>i5<)UG+}gI&iT1OON)zTe7W>VBfr0∨B4q1>@U0XM5*76=Qi|mgFd)b7OLgER&Lek^+bO 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 literal 3914 zcmeHKi#L>8AAUz@av%C~&y2oGg>kDeGsvji@5MsNWiVl8%nUP$Ga?xYm5xf|l8&R> zMp>FL0Ks^ zDF6Uu?QCt_!CA2SLM6eGIq8D|0EjOhi*>cbV&Sf2VhBD02LL)3BF|$ST3l6 z9^Pqs3oEhS^0uvRVbByj5qp;_XPxuJ)3(bYr;w0%Ckbwv${W#gy_r^Ut+wE$RzX(b z#@6(=Sdz_CGJL)^*8} z;QBCFD5xKC{gS@`_t2QSSXX5(s1*9>R&-{jSuxt8G)bybpq5HosYNl`ViNfA ziOP&(l_rU3EsGf%#${ubdbLHs*`gJbou+}mMB2<$KZKfSRufLZptF!)PjcdsHH5bt z!*n5D9ov6b4-S^AkqHN@?T7QW3vqG+c7hlRh(jcSbs&NOV&I^-h9Mx<`NpT<0rAfo z0I&dO01zt>`^pFk)_udPn+!GU98e;S_w=TEJ2{#M5hL{jf{B4ReR?EmRREyr<{*s3 zQ3K%g$Or<(oQ~1{tS|@hDvi{Jf0j_gG1}fvu5c`ojDzpdH_$iGwvd9u;b?Mjh`GDX zfi-h*h0zY9Qc31WB#lPXry1)L$)QL?Gcz-!ff3TkNDox#QBDx30dzeAWy=>Q|M;=N zQG&>L5*1G*z*qeS1QMgE7;Wv0Nd<`#kB8slj%FCrz=9A4F;F9m~E4q?esLp!ODaMvrLFX>bSqyzZ$^_z=8ZHw2GB zz!gd)gV0ByRp>X@YbPntS94}C`%%yQ5`jqMzwodk_kl2g!MKM=XtG!G_Me!LNdd&P zpbCT5Rs|49;a+GT6I`hMT>PxT|Ia-*)pb>sA(|K;=Im+=$t&}mddDeEnVOm!773Rf zUX@z2>uYJ_K`Za7xMP`K{ANqWN|Z$pm$8Hs^(I9@C*_x=X_pj*edVDoqxEglv>ZM9 z!uvte-`%%{Uq1-%E7rfu?eABQiHSM0mpG(*_fSI9ZAIHu(e!Xj!1B|1o^A)r%-F9X z?nHI`@;q-@uK5PBFf*e^P8tS^MjodPPfX_DucC~1$SUjmsdVIFQ1d00lgRma{>WqY zf)LCx0Q^uhZ%C?(ag9!0;(5p_ro4B_x6mAFh(`$=T6gTzFm#NrnEvZ&7Qz{yJt&ud z4Y|xZbQ^Vr`%u7fn!Bce8G>Q6&l$7_o~3>Cts=;RY5L9YaNyL(EzPum<`b-7Utizl zm5Jqczrdvxd_!WBn|Q+pcINSjyQPoW)^+ckqv-XPS%%Ii=hzAoF8p126!&?c^epWF-v+qw#%URT@hWZtp^xAg$S4drK>z>|gv%_R64DrJrc z$AKNp8_6HbJ(BKMEp97&w#3kI3$Chehk*%mD>Wd6#vks=V8neAh7M|sX9urLdkkPwha%0yY&!WqsejYG;xJiTTUAe@EK!=h z1HImK7~ix|D=zjTZ>gJ^7h0*Nm5a=uf8T*HQDua|_L(4UIGHE+TSNg~Fqi&QS3Z|NO@H zgC`fpGRx(yXBOSY()(a7y}m3(n-3m-N~*P-(aB6++x0QCPnVmTCCbl_-JJS&${^nu zf;j2t$O=r$C!uG?<(wA-qb@0Ntwhf{^%R7s5wQZ!7KJi&>}=S@Oyjn_nTxqlj=X04 zx!rvq$2(KnGPTAnym$AcF$Uz>2PKcwx?oINYj?4N(tjcdgkMazUKv@~)XH|!cGGlSL$c-rqT)A*oQrvoW(fIKuWrfk0 z5wM-by+VU?dV<{H4wLjf1Mhl1Fs``>Ik}yT&G8~FuQ$ygan&U%ROQo;ZKO4uI?@Ypli zKH_H;;j!#D73o%I0Jd>Ox3=pgfSo2;94T%j&dj@BwCPl#IP<89Y2=pk2&-8cy$8^Z nTdih)rtq^0KkveM#I%3HLQQDkt$nM1YJlB-XPXl1V~PI-dDK4n diff --git a/packages/tools/test/groundTruth/windowLevel_canvas2.png b/packages/tools/test/groundTruth/windowLevel_canvas2.png index 2acc68b1d34980274710732aeaf3b34c4f465c9c..64c51430f5108ca1ad21d15f22e4e321c151d145 100644 GIT binary patch literal 4318 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 literal 3362 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 EHn+a diff --git a/utils/ExampleRunner/example-info.json b/utils/ExampleRunner/example-info.json index 535a3c909..551b5399b 100644 --- a/utils/ExampleRunner/example-info.json +++ b/utils/ExampleRunner/example-info.json @@ -90,7 +90,7 @@ "name": "DICOM P10 from the local file system", "description": "Provides an interface to load a DICOM P10 image from your local file system to the Cornerstone3D" }, - "local (CPU)": { + "localCPU": { "name": "DICOM P10 from the local file system using CPU", "description": "Cornerstone3D uses WebGL for rendering by default (if available) and a fallback to CPU. This example force rendering on CPU for debugging purposes." }, @@ -165,6 +165,10 @@ "volumeViewportOrientation": { "name": "Volume Viewport Orientation", "description": "Demonstrates you can switch between different orientation of a volume viewport" + }, + "referenceCursors": { + "name": "Referencing Cursors", + "description": "Demonstrates how to synchronize the cursor between multiple viewports" } }, "tools-advanced": { From b134b2c7d42c147028bc5d8b9f683c5ca7497cce Mon Sep 17 00:00:00 2001 From: James Manners Date: Wed, 4 Jan 2023 14:16:43 +1100 Subject: [PATCH 09/14] [dicom-loader] update CornerstoneWadoLoaderOptions to include optional params --- .../src/imageLoader/internal/options.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/dicom-image-loader/src/imageLoader/internal/options.ts b/packages/dicom-image-loader/src/imageLoader/internal/options.ts index 18bc505ab..9c5277c24 100644 --- a/packages/dicom-image-loader/src/imageLoader/internal/options.ts +++ b/packages/dicom-image-loader/src/imageLoader/internal/options.ts @@ -5,24 +5,24 @@ import { export interface CornerstoneWadoLoaderOptions { // callback allowing customization of the xhr (e.g. adding custom auth headers, cors, etc) - beforeSend: ( + beforeSend?: ( xhr: XMLHttpRequest, imageId: string, defaultHeaders: Record, params: CornerstoneWadoLoaderXhrRequestParams ) => Record | void; // callback allowing modification of the xhr response before creating image objects - beforeProcessing: (xhr: XMLHttpRequest) => Promise; + beforeProcessing?: (xhr: XMLHttpRequest) => Promise; // callback allowing modification of newly created image objects - imageCreated: (...args: any[]) => void; + imageCreated?: (...args: any[]) => void; onloadstart?: (event: ProgressEvent, params: any) => void; onloadend?: (event: ProgressEvent, params: any) => void; onreadystatechange?: (event: Event, params: any) => void; onprogress?: (event: ProgressEvent, params: any) => void; errorInterceptor?: (error: CornerstoneWadoLoaderXhrRequestError) => void; - strict: boolean; - decodeConfig: { - convertFloatPixelDataToInt: boolean; + strict?: boolean; + decodeConfig?: { + convertFloatPixelDataToInt?: boolean; }; } From 4cc7c63ea262f26f19083ef6fab9f50288fa6a48 Mon Sep 17 00:00:00 2001 From: James Manners Date: Wed, 4 Jan 2023 14:17:26 +1100 Subject: [PATCH 10/14] [dicom-image-loader] types update --- packages/dicom-image-loader/src/webWorker/decodeTask.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/dicom-image-loader/src/webWorker/decodeTask.ts b/packages/dicom-image-loader/src/webWorker/decodeTask.ts index 33918dca7..624b0477d 100644 --- a/packages/dicom-image-loader/src/webWorker/decodeTask.ts +++ b/packages/dicom-image-loader/src/webWorker/decodeTask.ts @@ -1,4 +1,7 @@ -import { CornerstoneWadoWebWorkerTaskOptions } from '../imageLoader/webWorkerManager'; +import { + CornerstoneWadoWebWorkerTaskOptions, + CornerstoneWadoWorkerTaskTypes, +} from '../imageLoader/webWorkerManager'; import calculateMinMax from '../shared/calculateMinMax'; import decodeImageFrame from '../shared/decodeImageFrame'; import { initialize as initializeJPEG2000 } from '../shared/decoders/decodeJPEG2000'; @@ -85,7 +88,7 @@ function handler( } export default { - taskType: 'decodeTask', + taskType: 'decodeTask' as CornerstoneWadoWorkerTaskTypes, handler, initialize, }; From 9894d941b82a299926f7e06c27341368157bfea1 Mon Sep 17 00:00:00 2001 From: James Manners Date: Wed, 4 Jan 2023 14:18:05 +1100 Subject: [PATCH 11/14] [dicom-image-loader] port wadoImageLoader tests to monorepo --- karma.conf.js | 108 +- package.json | 2 + .../dicom-image-loader/test/coverage_test.ts | 12 + .../dicom-image-loader/test/decoders_test.ts | 124 +++ .../test/dicom-loader_test.ts | 16 + .../wadouri/metaDataProvider_test.ts | 66 ++ .../test/integration_test.ts | 106 ++ .../test/lossyImagesDecoding_test.ts | 161 +++ ...012.fragmented_no_bot_jpeg_baseline.51.dcm | Bin 0 -> 83952 bytes .../dicom-image-loader/testImages/CT1_J2KR | Bin 0 -> 180916 bytes .../dicom-image-loader/testImages/CT2_J2KR | Bin 0 -> 121356 bytes .../dicom-image-loader/testImages/CTImage.dcm | Bin 0 -> 530638 bytes ...icitTransferSyntax_1.2.840.10008.1.2.2.dcm | Bin 0 -> 531324 bytes ...nTransferSyntax_1.2.840.10008.1.2.1.99.dcm | Bin 0 -> 250999 bytes ...yTransferSyntax_1.2.840.10008.1.2.4.90.dcm | Bin 0 -> 174364 bytes ...0TransferSyntax_1.2.840.10008.1.2.4.91.dcm | Bin 0 -> 145204 bytes ...sTransferSyntax_1.2.840.10008.1.2.4.80.dcm | Bin 0 -> 166802 bytes ...yTransferSyntax_1.2.840.10008.1.2.4.81.dcm | Bin 0 -> 126678 bytes ...2TransferSyntax_1.2.840.10008.1.2.4.55.dcm | Bin 0 -> 80236 bytes ...1TransferSyntax_1.2.840.10008.1.2.4.70.dcm | Bin 0 -> 198636 bytes ...4TransferSyntax_1.2.840.10008.1.2.4.57.dcm | Bin 0 -> 207050 bytes ...1TransferSyntax_1.2.840.10008.1.2.4.50.dcm | Bin 0 -> 70268 bytes ...4TransferSyntax_1.2.840.10008.1.2.4.51.dcm | Bin 0 -> 84452 bytes ...8TransferSyntax_1.2.840.10008.1.2.4.53.dcm | Bin 0 -> 82954 bytes ...icitTransferSyntax_1.2.840.10008.1.2.1.dcm | Bin 0 -> 531324 bytes ...plicitTransferSyntax_1.2.840.10008.1.2.dcm | Bin 0 -> 530638 bytes ...lessTransferSyntax_1.2.840.10008.1.2.5.dcm | Bin 0 -> 244390 bytes .../testImages/US-YBR_FULL_422-EVRLE.dcm | Bin 0 -> 889554 bytes .../testImages/createAllTransferSyntaxes.sh | 30 + .../testImages/no-pixel-data.dcm | Bin 0 -> 3586 bytes .../testImages/no-pixel-spacing.dcm | Bin 0 -> 58458 bytes .../testImages/paramap-float.dcm | Bin 0 -> 5249250 bytes .../dicom-image-loader/testImages/paramap.dcm | Bin 0 -> 5249258 bytes .../testImages/us-multiframe-ybr-full-422.dcm | Bin 0 -> 74881482 bytes .../testImages/wadors/CTImageEvenAligned.dat | Bin 0 -> 524340 bytes .../testImages/wadors/CTImageOddAligned.dat | Bin 0 -> 524359 bytes .../testImages/wadors/metadata | 983 ++++++++++++++++++ 37 files changed, 1604 insertions(+), 4 deletions(-) create mode 100644 packages/dicom-image-loader/test/coverage_test.ts create mode 100644 packages/dicom-image-loader/test/decoders_test.ts create mode 100644 packages/dicom-image-loader/test/dicom-loader_test.ts create mode 100644 packages/dicom-image-loader/test/imageLoader/wadouri/metaDataProvider_test.ts create mode 100644 packages/dicom-image-loader/test/integration_test.ts create mode 100644 packages/dicom-image-loader/test/lossyImagesDecoding_test.ts create mode 100644 packages/dicom-image-loader/testImages/CT0012.fragmented_no_bot_jpeg_baseline.51.dcm create mode 100644 packages/dicom-image-loader/testImages/CT1_J2KR create mode 100644 packages/dicom-image-loader/testImages/CT2_J2KR create mode 100755 packages/dicom-image-loader/testImages/CTImage.dcm create mode 100644 packages/dicom-image-loader/testImages/CTImage.dcm_BigEndianExplicitTransferSyntax_1.2.840.10008.1.2.2.dcm create mode 100644 packages/dicom-image-loader/testImages/CTImage.dcm_DeflatedExplicitVRLittleEndianTransferSyntax_1.2.840.10008.1.2.1.99.dcm create mode 100644 packages/dicom-image-loader/testImages/CTImage.dcm_JPEG2000LosslessOnlyTransferSyntax_1.2.840.10008.1.2.4.90.dcm create mode 100644 packages/dicom-image-loader/testImages/CTImage.dcm_JPEG2000TransferSyntax_1.2.840.10008.1.2.4.91.dcm create mode 100644 packages/dicom-image-loader/testImages/CTImage.dcm_JPEGLSLosslessTransferSyntax_1.2.840.10008.1.2.4.80.dcm create mode 100644 packages/dicom-image-loader/testImages/CTImage.dcm_JPEGLSLossyTransferSyntax_1.2.840.10008.1.2.4.81.dcm create mode 100644 packages/dicom-image-loader/testImages/CTImage.dcm_JPEGProcess10_12TransferSyntax_1.2.840.10008.1.2.4.55.dcm create mode 100644 packages/dicom-image-loader/testImages/CTImage.dcm_JPEGProcess14SV1TransferSyntax_1.2.840.10008.1.2.4.70.dcm create mode 100644 packages/dicom-image-loader/testImages/CTImage.dcm_JPEGProcess14TransferSyntax_1.2.840.10008.1.2.4.57.dcm create mode 100644 packages/dicom-image-loader/testImages/CTImage.dcm_JPEGProcess1TransferSyntax_1.2.840.10008.1.2.4.50.dcm create mode 100644 packages/dicom-image-loader/testImages/CTImage.dcm_JPEGProcess2_4TransferSyntax_1.2.840.10008.1.2.4.51.dcm create mode 100644 packages/dicom-image-loader/testImages/CTImage.dcm_JPEGProcess6_8TransferSyntax_1.2.840.10008.1.2.4.53.dcm create mode 100644 packages/dicom-image-loader/testImages/CTImage.dcm_LittleEndianExplicitTransferSyntax_1.2.840.10008.1.2.1.dcm create mode 100644 packages/dicom-image-loader/testImages/CTImage.dcm_LittleEndianImplicitTransferSyntax_1.2.840.10008.1.2.dcm create mode 100644 packages/dicom-image-loader/testImages/CTImage.dcm_RLELosslessTransferSyntax_1.2.840.10008.1.2.5.dcm create mode 100644 packages/dicom-image-loader/testImages/US-YBR_FULL_422-EVRLE.dcm create mode 100755 packages/dicom-image-loader/testImages/createAllTransferSyntaxes.sh create mode 100644 packages/dicom-image-loader/testImages/no-pixel-data.dcm create mode 100644 packages/dicom-image-loader/testImages/no-pixel-spacing.dcm create mode 100644 packages/dicom-image-loader/testImages/paramap-float.dcm create mode 100644 packages/dicom-image-loader/testImages/paramap.dcm create mode 100644 packages/dicom-image-loader/testImages/us-multiframe-ybr-full-422.dcm create mode 100644 packages/dicom-image-loader/testImages/wadors/CTImageEvenAligned.dat create mode 100644 packages/dicom-image-loader/testImages/wadors/CTImageOddAligned.dat create mode 100644 packages/dicom-image-loader/testImages/wadors/metadata diff --git a/karma.conf.js b/karma.conf.js index 427f87dbf..3acad593c 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,7 +1,24 @@ +// @ts-check +const { tmpdir } = require('os'); +const { join } = require('path'); const path = require('path'); process.env.CHROME_BIN = require('puppeteer').executablePath(); +/** + * Required for packages/dicom-image-loader Manually set a temporary output + * directory for webpack so that Karma can serve all the required files for + * dicom-image-loader, such as wasm files and web-workers. See + * https://github.com/ryanclark/karma-webpack/issues/498 + */ +const output = { + path: join(tmpdir(), '_karma_webpack_') + Math.floor(Math.random() * 1000000), +}; + +/** + * + * @param { import("karma").Config } config - karma config + */ module.exports = function (config) { config.set({ reporters: ['junit', 'coverage', 'spec'], @@ -45,12 +62,12 @@ module.exports = function (config) { frameworks: ['jasmine', 'webpack'], customHeaders: [ { - match: '.*.html', + match: '.*html|js|wasm$', name: 'Cross-Origin-Opener-Policy', value: 'same-origin', }, { - match: '.*.html', + match: '.*html|js|wasm$', name: 'Cross-Origin-Embedder-Policy', value: 'require-corp', }, @@ -59,7 +76,36 @@ module.exports = function (config) { 'packages/streaming-image-volume-loader/test/**/*_test.js', 'packages/core/test/**/*_test.js', 'packages/tools/test/**/*_test.js', + 'packages/dicom-image-loader/test/**/*_test.ts', + /** + * Required for packages/dicom-image-loader + * Serve all the webpack files from the output path so that karma can load + * wasm and web workers required for dicom-image-loader + */ + { + pattern: `${output.path}/**/*`, + watched: false, + included: false, + }, + /** + * Required for packages/dicom-image-loader + * Serve all the testImages for the dicom-image-loader tests + */ + { + pattern: 'packages/dicom-image-loader/testImages/*.dcm', + watched: false, + included: false, + served: true, + nocache: false, + }, ], + /** + * Required for packages/dicom-image-loader configure /testImages path as a + * proxy for all the dicom-image-loader test images + */ + proxies: { + '/testImages/': '/base/packages/dicom-image-loader/testImages', + }, preprocessors: { 'packages/streaming-image-volume-loader/test/**/*_test.js': ['webpack'], 'packages/core/test/**/*_test.js': ['webpack'], @@ -84,7 +130,13 @@ module.exports = function (config) { rules: [ { test: /\.(js|jsx|ts|tsx)$/, - exclude: /node_modules/, + /** + * exclude codecs for dicom-image-loader so that + * packages/dicom-image-loader/codecs/* are not processed and + * imported as is. See + * packages/dicom-image-loader/.webpack/webpack-base.js + */ + exclude: /(node_modules)|(codecs)/, use: ['babel-loader'], }, { @@ -95,9 +147,46 @@ module.exports = function (config) { }, ], }, + /** + * Start webpack rules for packages/dicom-image-loader + * see packages/dicom-image-loader/.webpack/webpack-base.js + */ + { + test: /\.wasm/, + type: 'asset/resource', + }, + { + test: /\.worker\.(mjs|js|ts)$/, + use: [ + { + loader: 'worker-loader', + }, + ], + }, + { + test: path.join( + path.resolve(__dirname, 'packages/dicom-image-loader'), + 'codecs', + 'jpeg.js' + ), + loader: 'exports-loader', + options: { + type: 'commonjs', + exports: 'JpegImage', + }, + }, + /** + * End webpack rules for packages/dicom-image-loader + */ { test: /\.ts$/, - exclude: [path.resolve(__dirname, 'test')], + exclude: [ + path.resolve(__dirname, 'test'), + /** + * Exclude dicom-image-loader due to a parsing error that I + * suspect is related to wasm modules + */ path.resolve(__dirname, 'packages/dicom-image-loader'), + ], enforce: 'post', use: { loader: 'istanbul-instrumenter-loader', @@ -118,8 +207,19 @@ module.exports = function (config) { '@cornerstonejs/streaming-image-volume-loader': path.resolve( 'packages/streaming-image-volume-loader/src/index' ), + '@cornerstonejs/dicom-image-loader': path.resolve( + 'packages/dicom-image-loader/src/imageLoader/index' + ), }, }, + /** + * Required for packages/dicom-image-loader + * so that the WASM modules are loaded correctly. + */ + experiments: { + asyncWebAssembly: true, + syncWebAssembly: true, + }, }, webpackMiddleware: { noInfo: false, diff --git a/package.json b/package.json index 064dbc859..490bb5b06 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,8 @@ "@cornerstonejs/calculate-suv": "1.0.2", "@microsoft/api-extractor": "7.19.5", "@types/node": "^14.18.9", + "@types/jasmine": "^4.3.1", + "@types/karma": "^6.3.3", "@types/react": "^17.0.38", "@types/react-dom": "^17.0.11", "@typescript-eslint/eslint-plugin": "^4.33.0", diff --git a/packages/dicom-image-loader/test/coverage_test.ts b/packages/dicom-image-loader/test/coverage_test.ts new file mode 100644 index 000000000..5693a6974 --- /dev/null +++ b/packages/dicom-image-loader/test/coverage_test.ts @@ -0,0 +1,12 @@ +/* eslint-disable no-unused-expressions */ +/* eslint import/extensions: 0 */ +import { expect } from 'chai'; +import * as cornerstoneWADOImageLoader from '../src/imageLoader/index'; +import * as cornerstoneWADOImageLoaderWebWorker from '../src/webWorker/index.worker'; + +describe('A test that pulls in all modules', function () { + it('pulls in all modules', function () { + expect(cornerstoneWADOImageLoader).to.exist; + expect(cornerstoneWADOImageLoaderWebWorker).to.exist; + }); +}); diff --git a/packages/dicom-image-loader/test/decoders_test.ts b/packages/dicom-image-loader/test/decoders_test.ts new file mode 100644 index 000000000..3bbc95301 --- /dev/null +++ b/packages/dicom-image-loader/test/decoders_test.ts @@ -0,0 +1,124 @@ +/* eslint import/extensions: 0 */ +import * as cornerstone from '@cornerstonejs/core'; +import { should } from 'chai'; +import * as dicomParser from 'dicom-parser'; +import configure from '../src/imageLoader/configure'; +import createImage from '../src/imageLoader/createImage'; +import xhrRequest from '../src/imageLoader/internal/xhrRequest'; +import dataSetCacheManager from '../src/imageLoader/wadouri/dataSetCacheManager'; +import getPixelData from '../src/imageLoader/wadouri/getPixelData'; +import parseImageId from '../src/imageLoader/wadouri/parseImageId'; + +import external from '../src/externalModules'; + +external.dicomParser = dicomParser; +external.cornerstone = cornerstone; + +should(); + +const transferSyntaxes = { + '1.2.840.10008.1.2': 'LittleEndianImplicitTransferSyntax', + '1.2.840.10008.1.2.1': 'LittleEndianExplicitTransferSyntax', + '1.2.840.10008.1.2.1.99': 'DeflatedExplicitVRLittleEndianTransferSyntax', + + '1.2.840.10008.1.2.2': 'BigEndianExplicitTransferSyntax', + + // retired? Do we care? + // '1.2.840.10008.1.2.4.53': 'JPEGProcess6_8TransferSyntax', + // '1.2.840.10008.1.2.4.55': 'JPEGProcess10_12TransferSyntax', + + '1.2.840.10008.1.2.4.57': 'JPEGProcess14TransferSyntax', + '1.2.840.10008.1.2.4.70': 'JPEGProcess14SV1TransferSyntax', + '1.2.840.10008.1.2.4.80': 'JPEGLSLosslessTransferSyntax', + + '1.2.840.10008.1.2.4.90': 'JPEG2000LosslessOnlyTransferSyntax', + '1.2.840.10008.1.2.5': 'RLELosslessTransferSyntax', +}; + +const base = 'CTImage.dcm'; +const url = `dicomweb://${window.location.host}/testImages/`; + +describe('Test lossless TransferSyntaxes decoding', function () { + let uncompressedPixelData = null; + + let uncompressedImage = null; + + beforeEach(async function () { + // loads uncompressed study (the original one) + const imageId = `${url}${base}`; + const parsedImageId = parseImageId(imageId); + + configure({ + // callback allowing customization of the xhr (e.g. adding custom auth headers, cors, etc) + beforeSend(/* xhr, imageId */) {}, + // callback allowing modification of newly created image objects + imageCreated(/* image */) {}, + strict: false, + decodeConfig: {}, + }); + + const dataSet = await dataSetCacheManager.load( + parsedImageId.url, + xhrRequest, + imageId + ); + + const transferSyntax = dataSet.string('x00020010'); + + uncompressedPixelData = getPixelData(dataSet); + + const image = await createImage( + imageId, + uncompressedPixelData, + transferSyntax, + {} + ); + uncompressedImage = image; + }, 5000); + + afterEach(function () { + dataSetCacheManager.purge(); + }); + + Object.keys(transferSyntaxes).forEach((transferSyntaxUid) => { + const name = transferSyntaxes[transferSyntaxUid]; + const filename = `${base}_${name}_${transferSyntaxUid}.dcm`; + + it(`should properly decode ${name}`, async function () { + const imageId = `${url}${filename}`; + const parsedImageId = parseImageId(imageId); + const dataSetPromise = dataSetCacheManager.load( + parsedImageId.url, + xhrRequest, + imageId + ); + + const dataSet = await dataSetPromise; + const pixelData = getPixelData(dataSet); + const curTransferSyntax = dataSet.string('x00020010'); + + curTransferSyntax.should.to.be.equals(transferSyntaxUid); + + const image = await createImage( + imageId, + pixelData, + curTransferSyntax, + {} + ); + const uncompressedImagePixelData = uncompressedImage.getPixelData(); + const curPixelData = image.getPixelData(); + + uncompressedImagePixelData.length.should.to.be.equals( + curPixelData.length + ); + + for (let i = 0; i < curPixelData.length - 1; i++) { + if (curPixelData[i] !== uncompressedImagePixelData[i]) { + curPixelData[i] + .should(`Pixel data is not equal at position: ${i}`) + .to.equal(uncompressedImagePixelData[i]); + } + } + }, 5000); + }); +}); diff --git a/packages/dicom-image-loader/test/dicom-loader_test.ts b/packages/dicom-image-loader/test/dicom-loader_test.ts new file mode 100644 index 000000000..cc2df9110 --- /dev/null +++ b/packages/dicom-image-loader/test/dicom-loader_test.ts @@ -0,0 +1,16 @@ +import { expect } from 'chai'; +import * as cornerstoneDicomLoader from '../src/imageLoader'; +import * as cornerstone from '@cornerstonejs/core'; +import * as dicomParser from 'dicom-parser'; + +cornerstoneDicomLoader.external.cornerstone = cornerstone; +cornerstoneDicomLoader.external.dicomParser = dicomParser; + +describe('dicom-loader', () => { + it('should work', async () => { + // const result = await cornerstoneDicomLoader.wadouri.loadImage( + // '/testImages/CTImage.dcm' + // ).promise; + expect(true).to.equal(true); + }); +}); diff --git a/packages/dicom-image-loader/test/imageLoader/wadouri/metaDataProvider_test.ts b/packages/dicom-image-loader/test/imageLoader/wadouri/metaDataProvider_test.ts new file mode 100644 index 000000000..828d88df4 --- /dev/null +++ b/packages/dicom-image-loader/test/imageLoader/wadouri/metaDataProvider_test.ts @@ -0,0 +1,66 @@ +/* eslint import/extensions: 0 */ +import * as cornerstone from '@cornerstonejs/core'; +import { expect } from 'chai'; +import external from '../../../src/externalModules'; +import configure from '../../../src/imageLoader/configure'; +import { loadImage } from '../../../src/imageLoader/wadouri/loadImage'; +import webWorkerManager from '../../../src/imageLoader/webWorkerManager'; + +external.cornerstone = cornerstone; + +describe('#wadouri > metadataProvider', function () { + // Initialize the web worker manager + const config = { + maxWebWorkers: 1, + startWebWorkersOnDemand: true, + taskConfiguration: { + decodeTask: { + initializeCodecsOnStartup: true, + }, + }, + }; + + webWorkerManager.initialize(config); + + configure({ + strict: false, + decodeConfig: {}, + }); + + const imageId = `dicomweb://${window.location.host}/testImages/no-pixel-spacing.dcm`; + + it('should return columnPixelSpacing undefined if pixelSpacing is undefined', function (done) { + loadImage(imageId).promise.then(() => { + const imagePlaneModule = external.cornerstone.metaData.get( + 'imagePlaneModule', + imageId + ); + const { columnPixelSpacing } = imagePlaneModule; + + try { + expect(columnPixelSpacing).to.be.equal(null); + done(); + } catch (error) { + done(error); + } + }); + }, 5000); + + it('should return columnPixelSpacing undefined if pixelSpacing is undefined', function (done) { + loadImage(imageId).promise.then(() => { + const imagePlaneModule = external.cornerstone.metaData.get( + 'imagePlaneModule', + imageId + ); + const { rowPixelSpacing } = imagePlaneModule; + + try { + expect(rowPixelSpacing).to.be.equal(null); + done(); + } catch (error) { + console.log(error); + done(error); + } + }); + }, 5000); +}); diff --git a/packages/dicom-image-loader/test/integration_test.ts b/packages/dicom-image-loader/test/integration_test.ts new file mode 100644 index 000000000..03ad79afb --- /dev/null +++ b/packages/dicom-image-loader/test/integration_test.ts @@ -0,0 +1,106 @@ +/* eslint import/extensions: 0 */ +import { expect } from 'chai'; +import { loadImage } from '../src/imageLoader/wadouri/loadImage'; +import configure from '../src/imageLoader/configure'; +import webWorkerManager from '../src/imageLoader/webWorkerManager'; + +// See https://www.dicomlibrary.com/dicom/transfer-syntax/ +const transferSyntaxes = { + '1.2.840.10008.1.2': 'LittleEndianImplicitTransferSyntax', + '1.2.840.10008.1.2.1': 'LittleEndianExplicitTransferSyntax', + '1.2.840.10008.1.2.1.99': 'DeflatedExplicitVRLittleEndianTransferSyntax', + '1.2.840.10008.1.2.2': 'BigEndianExplicitTransferSyntax', + + '1.2.840.10008.1.2.4.50': 'JPEGProcess1TransferSyntax', + // '1.2.840.10008.1.2.4.51': 'JPEGProcess2_4TransferSyntax', // broken + + // Retired, not tested at all and not implemented... + // '1.2.840.10008.1.2.4.53': 'JPEGProcess6_8TransferSyntax', + // '1.2.840.10008.1.2.4.55': 'JPEGProcess10_12TransferSyntax', + + '1.2.840.10008.1.2.4.57': 'JPEGProcess14TransferSyntax', + '1.2.840.10008.1.2.4.70': 'JPEGProcess14SV1TransferSyntax', + '1.2.840.10008.1.2.4.80': 'JPEGLSLosslessTransferSyntax', + '1.2.840.10008.1.2.4.81': 'JPEGLSLossyTransferSyntax', + '1.2.840.10008.1.2.4.90': 'JPEG2000LosslessOnlyTransferSyntax', + '1.2.840.10008.1.2.4.91': 'JPEG2000TransferSyntax', + '1.2.840.10008.1.2.5': 'RLELosslessTransferSyntax', +}; + +const base = 'CTImage.dcm'; +const url = `dicomweb://${window.location.host}/testImages/`; + +describe('loadImage', function () { + beforeEach(function () { + // Initialize the web worker manager + const config = { + maxWebWorkers: 1, + startWebWorkersOnDemand: true, + taskConfiguration: { + decodeTask: { + initializeCodecsOnStartup: true, + }, + }, + }; + + webWorkerManager.initialize(config); + + configure({ + strict: false, + decodeConfig: {}, + }); + }); + + Object.keys(transferSyntaxes).forEach((transferSyntaxUid) => { + const name = transferSyntaxes[transferSyntaxUid]; + const filename = `${base}_${name}_${transferSyntaxUid}.dcm`; + + it(`should properly load ${name}`, function (done) { + const imageId = `${url}${filename}`; + + console.time(name); + + let loadObject; + + try { + loadObject = loadImage(imageId); + } catch (error) { + done(error); + } + + loadObject.promise.then( + (image) => { + console.timeEnd(name); + // TODO: Compare against known correct pixel data + expect(image).to.be.an('object'); + done(); + }, + (error) => { + done(error.error); + } + ); + }, 5000); + }); + + it('should result in an error when the DICOM file has no pixelData', (done) => { + const imageId = `${url}no-pixel-data.dcm`; + + let loadObject; + + try { + loadObject = loadImage(imageId); + } catch (error) { + done(error); + } + + loadObject.promise.then( + () => { + done(new Error('Should not have succeeded')); + }, + (error) => { + expect(error.error.message === 'The file does not contain image data.'); + done(); + } + ); + }, 5000); +}); diff --git a/packages/dicom-image-loader/test/lossyImagesDecoding_test.ts b/packages/dicom-image-loader/test/lossyImagesDecoding_test.ts new file mode 100644 index 000000000..9c6b25d7c --- /dev/null +++ b/packages/dicom-image-loader/test/lossyImagesDecoding_test.ts @@ -0,0 +1,161 @@ +/* eslint import/extensions: 0 */ +import { expect } from 'chai'; +import getPixelData from '../src/imageLoader/wadouri/getPixelData'; +import xhrRequest from '../src/imageLoader/internal/xhrRequest'; +import dataSetCacheManager from '../src/imageLoader/wadouri/dataSetCacheManager'; +import parseImageId from '../src/imageLoader/wadouri/parseImageId'; +import createImage from '../src/imageLoader/createImage'; +import configure from '../src/imageLoader/configure'; + +const transferSyntaxes = { + '1.2.840.10008.1.2.4.81': { + name: 'JPEGLSLossyTransferSyntax', + threshold: 1, + }, + '1.2.840.10008.1.2.4.91': { + name: 'JPEG2000TransferSyntax', + threshold: 6, + }, + + // TODO: Not sure why this is failing + '1.2.840.10008.1.2.4.50': { + name: 'JPEGProcess1TransferSyntax', + threshold: 100, // Might want to re-encode these, since they seem very lossy + }, + // TODO: libjpeg-turbo 12 bit support not working yet, so we rely on jpeg.js + '1.2.840.10008.1.2.4.51': { + name: 'JPEGProcess2_4TransferSyntax', + threshold: 70, // Might want to re-encode these, since they seem very lossy + }, +}; + +const base = 'CTImage.dcm'; +const url = `dicomweb://${window.location.host}/testImages/`; + +describe('Test lossy TransferSyntaxes decoding', function () { + let uncompressedPixelData = null; + + let uncompressedImage = null; + + let rescaleInterceptUncompressed = null; + + let rescaleSlopeUncompressed = null; + + beforeEach(function (done) { + // loads uncompressed study (the original one) + const imageId = `${url}${base}`; + const parsedImageId = parseImageId(imageId); + + configure({ + // callback allowing customization of the xhr (e.g. adding custom auth headers, cors, etc) + beforeSend(/* xhr, imageId */) {}, + // callback allowing modification of newly created image objects + imageCreated(/* image */) {}, + strict: false, + decodeConfig: {}, + }); + + dataSetCacheManager + .load(parsedImageId.url, xhrRequest, imageId) + .then((dataSet) => { + const transferSyntax = dataSet.string('x00020010'); + + rescaleInterceptUncompressed = dataSet.floatString('x00281052'); + rescaleSlopeUncompressed = dataSet.floatString('x00281053'); + uncompressedPixelData = getPixelData(dataSet); + + createImage(imageId, uncompressedPixelData, transferSyntax, {}) + .then((image) => { + uncompressedImage = image; + }) + .catch(done); + + done(); + }) + .catch(done); + }, 5000); + + afterEach(function () { + dataSetCacheManager.purge(); + }); + + Object.keys(transferSyntaxes).forEach((transferSyntaxUid) => { + const testsData = transferSyntaxes[transferSyntaxUid]; + const name = testsData.name; + const filename = `${base}_${name}_${transferSyntaxUid}.dcm`; + + it(`should properly decode ${name}`, function (done) { + const imageId = `${url}${filename}`; + const parsedImageId = parseImageId(imageId); + const dataSetPromise = dataSetCacheManager.load( + parsedImageId.url, + xhrRequest, + imageId + ); + + dataSetPromise.then((dataSet) => { + try { + const pixelData = getPixelData(dataSet); + const curTransferSyntax = dataSet.string('x00020010'); + const rescaleIntercept = dataSet.floatString('x00281052'); + const rescaleSlope = dataSet.floatString('x00281053'); + + curTransferSyntax.should.to.be.equals(transferSyntaxUid); + + createImage(imageId, pixelData, curTransferSyntax, {}) + .then((image) => { + const uncompressedImagePixelData = + uncompressedImage.getPixelData(); + const curPixelData = image.getPixelData(); + + for (let i = 0; i < curPixelData.length - 1; i++) { + const threshold = testsData.threshold; + const difference = Math.abs( + curPixelData[i] - uncompressedImagePixelData[i] + ); + + if (difference > threshold) { + const modalityPixelValue = + curPixelData[i] * rescaleSlope + rescaleIntercept; + const uncompressedModalityPixelValue = + uncompressedImagePixelData[i] * rescaleSlopeUncompressed + + rescaleInterceptUncompressed; + + const differenceModality = Math.abs( + modalityPixelValue - uncompressedModalityPixelValue + ); + + if (differenceModality > threshold) { + const message = `difference: ${difference} + differenceModality: ${differenceModality}, + curPixelData: ${curPixelData[i]} + uncompressedImagePixelData: ${uncompressedImagePixelData[i]} + i: ${i}, + transferSyntaxName: ${name}, + transferSyntax: ${transferSyntaxUid} + transferSyntaxFromDicom: ${curTransferSyntax}, + rescaleIntercept: ${rescaleIntercept} + rescaleUncompressed: ${rescaleInterceptUncompressed} + curModalityPixelValue: ${modalityPixelValue} + uncompressedModalityPixelValue: ${uncompressedModalityPixelValue}`; + + expect(differenceModality).to.be.lessThan( + threshold, + message + ); + + done(); + } + } + } + + done(); + }) + .catch(done); + } catch (error) { + done(error); + } + }, done); + }); + }); +}); diff --git a/packages/dicom-image-loader/testImages/CT0012.fragmented_no_bot_jpeg_baseline.51.dcm b/packages/dicom-image-loader/testImages/CT0012.fragmented_no_bot_jpeg_baseline.51.dcm new file mode 100644 index 0000000000000000000000000000000000000000..8b88dac6af07a19fb9d18e782f3a3401b78b321d GIT binary patch literal 83952 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

lKTt~6tky{RUf1v4|MsjI0XWA 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

YOSG+P+hHa++ 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 N+5i6k-QWNK004_IqGA95 literal 0 HcmV?d00001 diff --git a/packages/dicom-image-loader/testImages/CT2_J2KR b/packages/dicom-image-loader/testImages/CT2_J2KR new file mode 100644 index 0000000000000000000000000000000000000000..822a7f6e799b7fa512e70d09f96021556f3d9160 GIT binary patch literal 121356 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
|OIzG2C)b3%G(OS!}N;(2ED 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
IeJ9*2o@&}+z~#gR5juNB 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 CN4bIk literal 0 HcmV?d00001 diff --git a/packages/dicom-image-loader/testImages/CTImage.dcm b/packages/dicom-image-loader/testImages/CTImage.dcm new file mode 100755 index 0000000000000000000000000000000000000000..8d534014e601be8540412e8b01e698da06714aa7 GIT binary patch literal 530638 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

C2h*YQ}jCuDOnHK<~;m#HScR4e_=Yw1 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ÙPzLio`J1u{+tz< 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 BmY@JKyO_Z45-5 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 NGi#>mZ*$G}{}1L?iunKl literal 0 HcmV?d00001 diff --git a/packages/dicom-image-loader/testImages/CTImage.dcm_BigEndianExplicitTransferSyntax_1.2.840.10008.1.2.2.dcm b/packages/dicom-image-loader/testImages/CTImage.dcm_BigEndianExplicitTransferSyntax_1.2.840.10008.1.2.2.dcm new file mode 100644 index 0000000000000000000000000000000000000000..6ba1d177a1c8a5bf9e2c87ff2fd717f2f83a8ebf GIT binary patch literal 531324 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

    J!C*0u=EL<rT4 zN`U3U{9hP*KFM{R#I|??Y#m?^yZK}vL1p1r+=uJ2RB9uuN^+hBBbo7M(rSPVyl>!o zGvW=%b1=W4#q+j8D!H|;ds2mHJW zw&V=!i`lb$GSA9t%gubB!!{eE|K(yY2caTUF6Lg&eGSjlxakIvIGjznJd1M)IPMvmWTCsH)ID z*)sF3h1W|k3uqotZ@~Wg<*^~IM+&6l7iTu>j(?tsvtbVde@d3`YJ&_7~ z^NfOn`6~?R>A^*;_HNq+$ZznM|o1-BeCyuw;zW0a~`8Z zHl3Wh#Yodt+&z2h*`a<0xP6u!&BMfX?uBJu-5xUJg>Ql@`g1ZJb?5Ie^UgG~Jm;uF zKTo80HRJIDPhdAA+U}b(vDsvuIs1(>U^>sG5?~;Ep32C112oCh$pl)`p=Yg!%Z3M^ z5p?{8Jg^Q<7R^_@v^(F9tVw(PtVbGXV;pDMx9I)!X!)x^S8$nD4d6u>BOMQ_hmAaT(n7S1?atX8< zzq4lOG$a2A*nfl3t4|=W;S^(UH+T9x*wt>3+tY|@pZZ9cR!9K-j@xOBiw8#hqBd`A2K(5NJ{LE<9mY0dT*^#Rw=RYm6lNfuC;9cgZ zniqaeKD92ky_!~8IGwAHXPg<&Gn@og4stK2Uy4G!k2T(8?0?5N+{$xZ%kRqf!HgH@ zzVR6L@6+m(>ocCw@fzdx7qnSA5PKswZeHFQ(QGM@oB@rO0WF$_F@6?(dx9q`!_TUh z^^t7Z#ge$|*4JoU?0hVTJVXF8fsXI7qJKsw9tIs>^63ip_SZ<7k2&7W_~XUE;=RQF zDx=#=BMpkDvVdnhjqHjvIWvc)a;LdD&Du26(u_=#J(U;4{{l|6RK7<}{lXdPvA>TD zFq8KVzkd+f#~&oW1E=}GcqJrEV{D5i)cZAwJOKH=4Uq(;ky9nGJ(!i0bNij^4cXqR zBem!%FuVnMqE(YMx-++Pp0bzn@;&5kCAmUnSvsWS51i9kEFt}pqsXScJcs!_p<&$V zB|QE9AapFxz%FTG)jU94V>KhfwOy0!w=k8fUlU0#Ew9IjkaN7q ztD4T0ujGiYa0b?XIV18U?#w=9>nj{*INNGrXu(Wkdl@9o4Kb4MD><68#L3Fs$^N#o zOKWWU*M=YP!sB+}qD zlweys7?uX#Iq});bZ;d>JS�DE6p10=sN0~}>}J6Z7h?cZOOt!r}}JD4=W?zcYZ zS>pHOqKy4^;_e&Z>GT8b9XY4_!G0gkdkT@aU*TcD9$rKLj5Y8h@8{~ZJ(qG%NAs+# z^Rhn1Sc)BRhw*(a_hcGRVKPsl7rxl@$N}vz=bz|~OzzK}9nZ_S>P+6sjd^@>M!UmE z0WCf2^qrCGLs0uMWB%<(Chr21dgh10;(K8K0ME>9p7!KOB)7A5jN&-X*=skyp`5{p z=t*q^HGhCvnXuW>%h^G19wdOZF!;xe@2k*`e=@qyfd2hl;R;@|{_Uy15tQub)0>

    meja6OD;(X6)yLWZaEUqJGDxiK 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 RPuQ9M$KOqU#+P>l{tqZ+G+F=v literal 0 HcmV?d00001 diff --git a/packages/dicom-image-loader/testImages/CTImage.dcm_DeflatedExplicitVRLittleEndianTransferSyntax_1.2.840.10008.1.2.1.99.dcm b/packages/dicom-image-loader/testImages/CTImage.dcm_DeflatedExplicitVRLittleEndianTransferSyntax_1.2.840.10008.1.2.1.99.dcm new file mode 100644 index 0000000000000000000000000000000000000000..3317b623cbf49a5d29252ca3dfde8c06784b38a3 GIT binary patch literal 250999 zcmc$_^;aCt6E})Oa0w9H;ep@;S)8B=5D4xLOK=I!;_eXKmf!?;XK~jMEVw(%VvFz1 z_x57De3vl>8`HoGmV7w|8J4|B&&+@?-jIF(2%zNQ4}O(B(;zKqew`| z$SD7)_9sdtK5l+)kq^Awe7wB8BHV)9eB2-YUH_i`qQ`0#%v_ymOb0RO}V{z-H5 z2@CP_0|W&D{~AL40^9&$5g{QFfZ+cu0siR{{?jG~CB*2%yg+?8(1f22JsdyG4=p5u zAtDfyuKT$}aw&0BBhZ$lhiR_V_ibKEvQNCJG$9t5_ygvQf%}FlPdyIFT^o#XjdiJM zBC}jqoH64cxU5-Xcg(ZM^>tD!Xe&}d1Z%#q;MfrQRF;=snx4jho9RcG*lDnz#|s|$ zTUW|3y0%LjE`rZ1CpOheF$6~bo#_g6ZHE{8E3HN@*NS&9jy~AX&V@>XHE2gAkgk1x zs_)hY)MH>o)Ac+zp__A>LD#mKVVY}ntG0e!_K4{AH|a6x5)Hh&VN)YtqG~Vn z)1B$r)&b^Z)Z$CJXzD-Jh^-pA7UVbwKINYyI$sgsah*+1VBqyW^fev=o1v>RiGMv1 z&U60oxvK7*EL(bLWJ+t!)cj`a(}KzQs)j@y36g^1<-@F60420C#_|5Ew{c7`{Y zB9>Nf5l5T%g&l{rPaj_)Y!laIn{G>oSNA5*izf?x5Zd6MQ%_gF*=czGV4_vThJ$&c{&@{9j6T;#YOpe98(mJ9(sVbp-D zh2i_>wfl~xvVITn{qwbL7qTsrJHiQ9Kl2Z7eS68w)0r$~JU6GLtmIy$Yv2R! z-8~;$pVlN5A0LLOz=2P)G_e!FQ#u-lncBTzy3yt*_dQ`<_}oMz!S^mnV;+;L{YNR& zvDek}iBQbfte4PQ0DNnTtxFH|8ZN$#=^Xb9+%UDIhe)p)@e!Z&F(P=@dy?+Ki@F#kJNa8$yL|Q#qdnKfM~-(?Oc=#tiMjJAT-xgEt6s z|2%E|$IF4U#K@4LZnytw>w=;Esqki<)Yb7h8De6Iwk>wG*?IIXqjgE_y$6EaIqw*= z)jkjbmUNNwKUINvbRHtEdukASo-Yysh;y$+MEmNkU)(I@bs8FYT3vtD>bzt!CWyE& z)V<~D@}NQN%(U$W9s~X1Jcu~xYZ@4~4tW&lc~W%FgF&7scA=2KQ*1*DK(RLe_n z#$lkU(@QVtaK`DUyhbeJ4-n+(aJ3cJYSYic8nT^I5VsqOI=6OMID=n^3Qq=M6Rg3V zrQ{2NiEDlIll|tLqJ=5}obNxGTM#2eUFZRBoJ^HMX7 zN#_&Z|3T#3fROlZQ9^bN!^^AVV5M1uGZp^Ho4@jB`R*P+1byh=GG4*+f)XZ;OD-7L>=CRSj;EbSP=-6y&&lR{+CCp`(`kzBu*~MXl0o9kW`giV65qUK5NE z_Bn1WUWhBt^Y*H4-_tRF*G|uXSV(Aw!dzsrx}~-dGF*t8D7}O*PPv-zREs8uJ5A!Yf^s0OqQpfPQ0hC zN?V6TEmcKkDZ=NBm9EgR$zv`+R@6ARN+-fItv|U63p2SWjSgRhQZ? zHGAgL))cSVgPcRp&k|>wVhA?GdE)C4-Af)Kha|9i#RdBO00{v*>$l^NyxyaF`Z?bQ zN&Ww;n z_I5ku(rn+7b^R5N=)SPKRrvG$75svExom-C*Y>2uxaazG!BBGZRtzH9Z7c;aokqZ*Sxf)cTLr{D{GuIrvN3T8p8vMW zWtv^`y&|Wr24}ru!f2DliQDxgI;W#rEPcQInct;ZEW?qqCaLIoPxi!LEykv1!%-n);nn!`^#;R$igYb2VUn>bc@4}fKw97kV{N_vFS+0LW&dfj zo(9{7YwQIwq)5suHd)2?%QGI<`wJ%(HLVSwPn6Aatp`7Mq(L@+K&T#8le+C6N|^k} zv(pY8yg-Of>sJ5f^a{P3(owVUJ(Fk$Avq56tN71H1`cg@VeBnZ8PG_^h2~Lr!vKgI z(-c*kF5_;pgAXeLzJ7ScPWbey6)+*+17uwP#q!x9K=Cg3CxM$+#e;(v*Wr`W9hW?T z%AW1hjx6r}FAOoqIz!J19<$@9aFeJ(K{*X_#x#lKp*Nm>J0>v@+89pm{ij?<1IE}A zPEhicmQ_>wjAqw!mJ*10wVTj~U=J>^B1~9;ZZaix7dYSZ`aC&g#kxl+93p;qv=$W>i zrDXIUzgVAzX-qEZl`%I0zL!C2&s6{XQ^}m$zFo&Nsg`yKd^>z4@N)00>gOW8=6NXjVu-;6qcsu9Z5qXj9@6Mu# zy%(cJRl!Dl{-Mulg-Z(lo4kTup7?!zbN#3bLrPP+;Qom5PEMj+hg)*Hd-80SW*4+# zbS?NfXB?jOygHC_x@q|U3auJZddVNHwM$JOg<`R9jxOS@=)zBq8e@<9Ur5f< z*RR;PR-2OE`JcTa z+q%fc=*IYeoG0w*5t;O_S%z8aJJWB+V5!JQh`ANx)b9r?!PL9rKU%~k_MzCg-K0PJ zF&?ffp6FgYZ4mejYI|5G>NYH(gBbyj`Olq6p#0G}{1uCydDMU7@m}81KhC+9Sb{|X z8pTt?|H~D`4DphSDYG!OwBjHHXowf^Q0`!JLf$vDkyTVOb2taRRPQ+xh}R~aA6(h% zzM7Jde^@)TjZAisK!R&#(fNFEk+-4GfPU->QmHX#(8v$I&l`1%;KsIw$gb4zEU8B) z_|Pw{C0A0p-o!Q1Oz`l{McGwEQ@g7)@iP{-FCPc5U!@syBqw8tY!JsvD(HNv%WBqB zjj#8Udjejqlfa5K9|F}lZ?*P#$SX7{{*JexlRX(RI~AT$0P+uBwTZ>Hu8mg?Q1E-v z5XK+`@@u!jaqy_CT0;2<$6m~|oMcYJp+N%w$A(U~DoIN7V|N0H9v_Y#kkX&zv1ZnW zym23L&IW=qdQ!ZSfC&B^L5m9cAGl_8Rc{$m8%+q$*KRwPxjOfG>?tgMB+8?paJmyf z^(`+d{2x;%*K`~}ro~DucS_6wA8SAiZlzg4DGq^QANKcx@GwM|&t-Ucd`H^HT z;89pyTyqgdyPPPM5=LEY+Wm(!cm|As!K+&V;x zZrnRjX1rtX+;G&1oGJjXWf22?7S{w57lMh(Cby%UJgaW?jY&gmd**!#WEj(%0b-X> zLp=3$!bF+TKmJ&GwoiJ|K1pPO6{vKQeM=#-%a=b|QB`tOigIU$c2JjOc{3}HQ%%a2 zusraDB|~dNPeAj~!Z@x=R~+9o;x_5Na+e!b+*|o|y>(dZQ!m?Fz~mU`fta&d>+?7l zxbAjmfy9oP2sE7c#qmK6z+A<$`_(xjQS{>Yr(_&EWcr&zupgO z(!@1e)YKgij?IdNf6t_gFl8 z8JKPf()lVq^C+GB%8=Eoto$l>iVIh07fb)rdd*66CFqDCrTYM|dB5<4y! zd2ST#xU%m`1MrvaBJFIBStqL_abNtGV-J)4xX@VRtz37eD~ zf4J)-uxzhMeW!4%t@uhi;bVETSdrU}17;W|u$|z6)c>2>`^xR#<*^0*^2e6(%lo6F z4>9F7IaWwG&9QM5VJ&YDKyi~Taxv*WZV#u$kb) zi(mOsy<{l7?R=bh?~{LFoz^A~hvx#3SZA5-l;i@08G{{f`YN7!jI`srIOcVWo)s-x z6&qgVx7zn$f6@OURCoU4>v^e()LF;2cLVCDbdL zP=QfZIe9@gISu${FU?>q#G~2q7jq-yy zEiPUn@Wo|z-=^)7H^D#0JYj!?4J4)9^r*WA7)&( zdV&-SeA(HAzD1*hldaX8T(IwENgd~y8|z#)Q858BYU~0J?fw_-%I&W$4%#8oc4!|o zz4y!SCYCRD}ZNaW~{yeW_Un7BlFtEyY9ex}L*0x+PW27bxsS&V#H(X9JRe$w{0IKdGI=Fwv@e*#ceg4`VsAA@Nc3LbB~v4 z>Qh;&Dk?1nQ5!~AYvoolH3&tR*S@+PB}0@?e5Nmt(^PBud`Jk4EnfxPjx3iuRP}M> zO+IWoQTI~o$M~9H5%Xt6OKEFobT43tm7Pk> z<0lE$#|m zlpZD_#7Q=L_Cl*6%*t9WjT%88gt@FfRpGVo&8PoDQ*_iBPu!7qz~1irQCK0PjYBc>=X&#CE?~USL!Oa zFZ(lu#EpQo3wek{ZHo%+660x)=FhY#k)I;t65DqyjkOwvSGZEKXgWgd5>wZVI-6YF zYqO+iR)?8CP0S~b%qJROGos!a@WDw0W1p_qVssRD?`nN{Nf6Ik?Oeq3Ki!Ul@yDYY zfZ9jU4|2Cb5MADl`RDfySL(YdVsv<&`|q2ATocDq*+!ReeU8j@?MrEvuBOQbu zzjfI}Um>F*@Xg{Z3si(G>$sPQ((G34_*{?;lXnQrTdftkqdJTGs7x+pfe#)LPnpzx zSZ9Nau%zqWr5p%B2xnNBDJgbNsX8)(4qMwtlDtdNJ^2nVKG^9^xUz{S{xljQ`s)%$ zJ06Wpt8v_tK9IJB(dYIA3(@4h%<4W?J|h5X_(!iJ+A6G)iy9j5S-*nQ2&xmuvREl z6)?N3un0ay5w97%`sHPkBCM3$h7z0C`=`3%lU@+2Ny@4ii<1azzO&}FR6${Fe_**e z{QF)`$OQvyBU92)_O7nne=%ZqiC=G@o(6f?#0hpu&~8{VcXQt9_K63c%eN_5PVJLd z0}Rwx{v2K?4vGT~o#toGq+5JjP6huZb-@#Q3UxLO8TXrZPm27WObu704=-!F>ne4b zCAE+#kUW%@XVflKW`|@|r)&sjzPd>YRB(qC|pq=f&4dCPN3@t)RTJnh_ z=R!QUroI?|U#uKRFMg}}YJAj~RHV7qwzbx!gF)T($IBt)7K5)JE3ws8;S@a&(ME^L zdI6*xLrEq`d~v1O94u2rlm2O2A-2VM8SSwfSLo<5WOLOw9Z9zsa-IyU5#|>^5z3_=RSFzoK?g7q*I39X=YMo-Wwze z-_iJK`it#}{NC^K$ixV^xmrGNgl{hTI(;x7&r=@}8v$SR*EiAzQglnZb)CDn)FdOY z3G^Jz!vnDD?ld`H(9p~$y$+A!S=@xfFxMhs&a|IV#)VV3@JIJ6-kK0at4MD=?$H_U zQP~`I(h7NpW&CXL;nMw+gebd*p|)sq%^y^aTvE);835Y5lh-~;dlkHe27V5x+Y;sH zN1oZ6f73IR$<3-Z>UcAjrLu);7oW0j|HEz&|L^-Ex|Lu*ZpG)72$nkraDh8i=29;c$Eo1T`)a;L9S*zfhR)MQSBn=+(1 z(qA&~jXNW`%h3$XHw9%2V2U{cG)diOzN@d9laYmQV+QRHwlkgjEN8az))vvYhAbdq z$_216Pj<j6C$ za>_43#G4WP-g5<|3fg_@hb-^>d^_abEBvi99ixF^BQy9YLhF#{LmoZ{6L9N|e4~2*bq8(ulI61wQj;b6eU4w)*>Iylvkc{ZDkTFk!5h;ysJS_d}i9gb|5?AM$i2 zU+@!_MmBQfO^Gpcw*bH`9~S*aLZ=DBHT(T1FNL^Gc8L#UdS@gYXxNO76Mqyh_kCTy zYjXNT73b|PMBcMSR8?%ceCY`c%dO<5REOG&hqLIvrr52aNA+yKDq0Cr+6EJEc62pw zFi6M(mG)!-k6N7m5zJKX?WiZF42O1|;0e=n6qhKrdFh<6@8b34%*7FP7??D{_PDeB zc)at->$4quEIL=hu6}Fv2meV8?;iKk+irypYO%E*a~Ie5vWd~u8NN=&np<)eUL{c* ze{7wiv~TIdCfGhrG`pKh`f@r)#IS3b7(`xol>P@s6Fg*(xj~Y|bD9FWcygCY`6$$asq`%EHzFP8P1i4k7BGFBVXW5*BBC?-J}RA$t)ors?-(hT7SDs}jN3 zg#g`#z*H%t{-k4>By~6da76aD^@3;x`!kLjJq;Kteb8{)MY=*fI!}F=KfN zz3JHPFJF6i>%46<^F^+EpPqaA-KW$>~9)^W}s}`T`4WnT&R({Agj5QcjBF>`Zznqta z)d-gAAGskTB{yhEB8JAJkOnA;bqCSv!IROZLMcLJ9n#3CA!v|Hvi z$4DSgIemF&`L0FKCn82*$>qV`WgKmacZb969flxjc$qhe#LTyoLV{`YiyV1cS7F6b zFJ(Bbaw&>LDJSN50= z$SLc;P++()z2)5Aruw}ur`rPT-aBL;s!>U0X0FWaf}bEcv?MHKGIggpTT2|F5`Kd| z89c{UBQ(*0(&{|#<@fP}B+9XXiTWELH_EmeKz3^vMl_lAyU2&;#Koe`OSvK5z3T@3 z?wZ}r@bN#NFLJ*b0{M{SZG%rr>Y|4KJmwYAe3zU70XE+LDNukEYq5!=5h;n^QE0YX z9pa8+i}wjfgLFd%{q9(zzVQoPlT zcY;a`lqXqhtI2+!bO#drJJR1HG98LH)Ox$#0A{pcYjmB^N=2_jCa2ct22KE|{a~5- zdP2;5y)3SrZn|M??NyDU#o^~w+9Kl`9E2^!EE#JP- zY;Z!Z_m{JxNs7-@XaB$^#uv2kowH%#z&57ZbmEce-PDLT342yt(whIr*1&-?J5i+C zq&ci^n|D#eD43HH>OW2WdS;f^R;b?nzAXr+Tezn9d`p&oFN1m&hg^OXC;BU>1Eo6x z+Oe4`0qHa5J`!%>Id!}^S_U%Q&ZQAhrYb6*$}ME8HkF@w{Jx5 z5~F(1^m+hzcSl*=eKorC)>tFRJzTG8&5!U6apCoMW52;_3k>LtzE~(Ql|D2*>%Yr^ zPTMG^j#n$AiMUJ)l#CS{;uo#Gk`W1yIeV6TKOEJP*WW2(fgxb2vJtqBco_1MdjGOo z)`VGaRZ-gE(cU0HP&;Vxjkdm&vG^@@(@zv*)n1bkH#)_h3)@d7e8`S(W;rQW{XZ^+ zff|rBePj0THKs|h2<@+Ha0Ny7D=;radFmJ?(##F;-gEeTObj-tDZvd4^xtz^`G7<2coUA z!Fn!`j^pco+W?rvUs5{mQK$oBX~1HqN4mQLdYiL=G>L3|C4V3!>YD5x7o_tg|PIo>-d;@&Z(M{?d#q)gMR3 zFPALqFWKIoHBa~Z#H}y~wSFlJo5hjyQ9>yTp%U*zM%Zfy$uZ>J?2R&Yr4QvMqnL==_}yeJrzxA$@anBYY$lbF2vma ztwVbot(!!j(6ofz(nyM9c@GuSluaeKIrMP(h|EMbJ}k}*P_d>ZcF01a&J4+y_^KU$++<;(QTr?b?_}Ve))r{{~Cfi3vX+aTf{P| z)sPVeX!pDQCTxbFfRkwUiS?f>7N7#xcG*XAH6hCiADegJxDgKW=Wba28^tMoZgArd zhCjHOjos{k1#SX%A(-?OR5h+FhEm&W9chbXzXHBi^F<&G)d@ZfQ7QEaR5!LS;`(#y z_(*eGefqNbNNbzE9ph#BZb0ECT8GvkvXSjxe>~N9>$E7xERx(U?8&x>tS!isQsiTx zL$t6YYfFW7B~!iz7UF?0e-Q2|x>ea2v~9io@z$jEauH>wES92{bOn-dI6=u%i>Ah3 zs&>Q&uzdO=-B?QdM$d8vWyVEH#%of%kq3obV^mcjJu}xiM|v`k3&Q;9ZVm< zD0dodmf?e5bo!P>ILy*4_Cp(dmY}%JPS3?yo&mcS86pAk6iE%<0S@Om^Q=T`yM%Ao zw=DOPzt{v5TS`s6zDU+>>eAj3iM!ULehg}6j zPD>;4O|bJ+x1K)`=AFJI6R$ta(q^FE)cF22bb5>wu_~@a_tnzq`n$j*m!SU)NnZ1$ z`V^7L5Fc(BTcL1(dl_;MN^HZK(4=9`uDOB|jF5^Cg#~}~2YK9@B;fIl{sBV^yBt%d z)w|Weo%fFJ;&T-{j}qw?Nd=+WlD{=gugkLBXTW2Yb(on&OJWG*AJ7O z^CVUBN${19o(%%$(np`Q}i*Xk%o2-1BL;I*( z&;UlQ2C$f!)t_qAKJkpcZ!Vj8(~b4r$wD4)n%ND4q; z_>7vD^(DYRpD8>6Op+}=kNkRK6#VUdyK48ZNbLXREv#rC<)TT(Ss-b)oml#(gxHr; zbfQ0HI#IZ)ym-c}OO0%*C6`hTP8X6{4^BsmVgo^*n6~-$!0sR|%!)kd&I4tcusf=A za<#Hj7^ca6Cyz8ABckeUeO-WwqFE6i*2nnpFHxi)^M?gQdim;K@VtIuI`i%=iQjGdH&iC~l*&qd}BI-?shk#*0AOSOm_m|cJ67_zRbHVgo+oAs4 zNxM*!gJkcwm{-*vdR3WyE<3cETtpfrT3e^q zYx?9Hc)Po}fo@mxAo_hWFWGAXOYrLF5wDrLvu;Qs+R!+fHro5%#u}Rt)^3Gokm$K_`ehFPXm9 z(#>6mLbKnleNf6dC|CE0Fo#XWr%icQB!`WeNvN*q&-CMwm-Jw@GXjNYvG5K(YAbWp zOi4J-y=jwrs_}B6pQ_kqumx5Pd_r-h zGmkmf03z{+r}X48sXzW5*%X3i8bG;J0;V9e{eqlPiNxL$6l)PtndQ5dsRoR9xRM@< zJ2>Z*WUhEz7bo>bp?ADSAyf{TQfK+kp6tNHWxF_t6mw3yG@Bmh@7-5lF}%z7O>yt8 zHJ4#jd);Px2Ads{wym$7hgFHr(am$o@UZ-Kw)?ieYI#+Ex?U7RPYit1-TK$@0;jGfXE*KeP72S(IT9W&S%S%s>wlUVF3z# zsenKQt-U|_d{!PJ$P@#*Ysnt#;O%uo>*+T@y55VdkUMRY8F?l7I2M`$`w05`;hl5K z>jmgs?jy^bd%{TJ%-Ams&d(PgMTJ!`rl=rNX2T3ip$2I!`u5M z`2vEZ3c3}(L7P(3hI~! zWJR}kd0D%z-L|cBAvn{qSYzua$(P@rjx@8HF2V&g!#Bn!k3Rm;;L`CELJ;~i;&%|~ zLs;5-OM$$>jG6<^sW8e=sJ*N_{2KPN@VQ;{-mq3emxlxHNj{d39>_ zulkD!1YuqE_nZejb>iTVT$?Ajp$`5SL~KC0wR_3KM9R-&9;8vWJ68=-%uST3P`7}q~UjIMAFlQ71m ziRVZZvd@?NN~ApciL6*X`?K3{(KJD40pHZ|L!Re5f0Pi@Ekl*$+i_i5tLXy?$)EQ1 z)6^}B&D+@*){b`Q0fV%dlOpeehmJHK-mbUHqC#$P{(B}Y*6p^dWKf0$9L5bZtb;g! z>mAxcRRhg`k*ncZ8@^E#qk*_zG7AO%T;!?G2$(yh7hq>hKiaXm=(N;5=g{vCSLXQr zaY|_Y)-8LurNd6qfcqp_`dbj)SkE$zi=6OBXdP{zrU*8rV{4TBZ~@ADhdt7O2MT_( zt{%RJJ0h%~!}y2PB?PObksm14+SII)8dc*ka(l@$Nhr{^O6{+3h$f3bH|jV&j=`%2pV%GksqX=r7V-iQb>qq4qN>PftyK=#B@w=pvTWxI4yf0)ik- zLDZ{3eJP;{+jMUgb^$sSX31H6dgTNsBh?q{tt#hv`2Ms`*AG^G`s%MyTXwe<-@C5) zx(r`)Cvd6E0QLD)4+a{i0Tf#c>2Y_G$qwY-8e`VUhzaMB4J*}F8P$~cHbsH@d-l7M zUW?J(w|AaFq;a4NNCY2=C4Bnb1jS1rXRXNKPGbGxL1L>uSmYEh#Z4l^sN`Ed)~a5e z&JR>Dk@0F*Ad^A>m?$r}>zKyV>=9Fr4gm19egwDMI~QSE-Bdvrv3RTo@^W2YD;nEl z4tZZO2ALSTa*}|4gDtYtf-*Gg#P5toe~w@{n|n35Ev5avdsaF{!?JW z;AMq1@OOn;29PfuLtgDOj(u8b;+w-pJPZ3CdqC}buFoeMtbj*Z``)vi3_ulv@m5Yh zLkp|qsDg}QkaWfwzs0<b9dQ2I>QC9a3vMg$SbS3 zUq>g(*hjEG8S&s%k7f+Jz#HnmiW@66s<*Mu=U*+Xry+p-dOQDuJG^C_c({HA)W?T) z0png18e?t%?fJ6)M}jK4%|%OAO;6L0=D5kHsYDV;8C1W8Eh4P6muVJo!WE~4y@xIJ zJapVEY5TAUmc^F^X7`BS3-p%8CwH^(JG@BdC=CJ5GW+3g%a8o54Zlmnl&9?_>IJ>p zXl(v)HG}3q5O=M#lN>It>@Nskd9U%p_;` zAOkoT;o!pvOLu!u(}ElE<5<>4S#3?!HV%lqTDN?pl6Gm;OIF~V6YSo>7hc!K;B1%xZMzkujGcc;K_y-aTG$) zob@8v>4HKWMbtf~gw&?7KDE&}Jeg`Wv%*2|=QlmKgy;NsDvx~pn#t%#MCOZi7b9_N zETScNJiyOZ8s=q@xs3{L3PuP@EhDkr#LFQzs|F5W_j9$$0kzbMReixDn}Q;4aur2e zKd}lICX8~vy$kcg<~k%|%Zn-Tb@MU@IDNoU|L`UL{KHV7&lyFO5KbR1q%%zLoi~C- zX4gsnqDswYU}Y@~HPMpRZ8Mtc2^)Ez%=v{#7T7#)dE+2W$9Ow>acz?QhwiqQ8Ph1O z!B22}bqmsJ<_ed0-?M!T)_VobW;3|XBt6zL)hXr#`tL|4tARVA+pzyuWh{fajgujj ze1Gy1FV?ThcpSZ1-Y+}hK@HVF3!U2F1$uS+h8w;-KY`i$s4vu6jago0`D#)F0^U)y zS%6BETwf<+yuWGuJ5?qod=>Uk8H2d5M5k05Qm#VI`Fx%&--nFrYJKW-N8yC48<_FA zTdjJDmFRrK#JK&u{V7q4dV(Z@5t*Y5#BZ9MdMz2R1wkledw`};>6p@NretJ2-RKd1 z7fVy1y33}{iuyq6vG=)1#C2!?M>RR(YM#Jj`@Fb5+n0fKB`7Z4z}~tI#+hq+m`Ha) z`lyY{Yz>`pn`nKl*?;9{?et{Ma{vz&{{rd?Hp!ZA+s*N#?kzsqlzD3-Uh4S+@V&03 zwSQY|OO(}r`zQ1-<2tzS{)_Wv0!NWw>g~O{1MY}A6u(kS7)sL&87D&jeJQR*WFUd5 z`@YzzqFf26u67c*jeAN^FDLtC3cF08RS`Z$z~}qTiwe;KE*u z&1N5Sd$z^}fY*1~;XHGni8?G%Bz1#1oucmSrOKqG9WUNh*#AT)6DP^ZaUOo821Cv( zZ6eKJ6kdNAq{ziiqyJ*!&=A3JLA1538Wg@ZbLq>VI7o`$4U8yvA6Fvja_z1>zS!+ zniY@=Bj@`rWEpE-pL`T#F@k+xV$9+5#J+ORvQRj@ql@E^W^$nI9Ch0?;DL$Lf;4ZJ zf>WO7aronn&}pD#)cZ#{hxvNQn#7UZ~fAeg;kDzWfhu}nZX%WkaD8^ zV%PHul|PGz(NfAuEVAhEhT;JiJaB;SE{4^v#{!w{Kqg#sY_Gag)#qjO+ybru*>Jf( zb#I#p6n7kYs`@;d0o* zk|fm5*9rx7#)g=)%S)?osgX94N%$@~hW3dsUs1KRevnQRB;h60X^W-1+`)yLJWX;h zj>?$ISKciV+w0zdsim(t>2S~9Rqiel$Dpg}ccA`R`v7RGY>lKcs{Y^ZH=Nb2r$Lp7 ztF>FbO)e<6>}4aqu{X}+cd`NziYxwbHlSepB1z}r$m82YGbQaa3>vE{|-P z?OxZgiJ_IlGu?F%xn3R^wG9{uu5aGCG%Nsv8IAmDTnnQdE-0MO+_u>`sj;H%f-q-7gQ(+aHM&#mho7 zho2aP1ejTAuMH#rYiIrib&tr(2qQH_AB3a3rEkesB~7N)y4T9kM%JNW%JEa!w$avy zGv@~l#jj0KTakPpO7R-P2f^|?8*n<`yz`19{)6w;JKQF-a2unmvUf(s?D|o!+G+w} zA@Cx8NnIYM^ef5BK|(67=mF`a@|KY9H>Q%iS7P^IqMRw3l^F4Jc3c97(EERfB=&wD z^8LcMO=_nQP#){Ke>S9xt(gA1+nV6F?*2dC7V`2O&&^OBuJv3vCjMG0P3$+TpoeD*$XvbVxqLesWTwJkKl1?5A|p zzK_dVICnO_U>UO6`y2(Tf!(=p`gMI@99uge;m6QaO<){mQj+=dRCB2xMQFt!uN);M18P5-u@uiCg#%-bH-6I$vel_KbPV-&n`R z9^T+f6{8wW2~_oY5CbL9W$R=_nb#hU5Wjfrn%(UHf&ri~^l#?vtp0Q%H#%{zaZy_K zQwMv+sD!0LUpLU8PiU2n8dM=9Hx%IdTKDc_q-@^we-Svzpv^e)go~YGo0Z;p+1OupL;r5|FNqUqL-B%`?2biWD{}>O|hU{=vX(c{uj{%N)}Ovuy!t z)f(S75jrVq|G_}Ra&#rNA|D8B<2)&T1X3lLi+c(QY@*P{El^aK&rC=(It4F^_E&x~ z+bpq-lBDPbIp?{%RWRj;(a!jS!o@u#uIt}tlDI^{dD)zFQ*G$11WOOv=;^@owIbW9 zPL~5VX97PDNBH!kD&kOb1hgnZK%$K2!MhR55oB=jaQHeZgF5Jj;yP?$nxjef!Exqg zR(~nvO`6JL;(2o8%9_nlsPSQMr!nhtSBdwxlfHa&DFJc4A11M1l!2tuWo8cP6;R7s zOeIgc#5SG)dmOOK{?{rLp5Z6Tc?Dve*!4b08iC;~o@@id zR3oz@a+brnQ{1^CIrX)ur`)oMf2M6{Rbfhw!*OTk!(q-`?|J_39U# znM*@PV;0f#w<|5&im1N%_}y&3@1kS|Z_#akhcTVRWuN%Wz_PJ{jqh})Z3rmu#UqCi zT)&t;RC>!S%9!`rMhnt!6iN8G+7O?)nbIGx~Ol{ef zsbG8McWh~U8Vp>^#(wpSU*cu<#7ep)^Xy{&Jl%IhA{sF`TI`CgUtc)b^Tuj^;b z8)PkY^GF}mD0bZ?oYsN!oSK_!p!y|ndX#QE(O$t^A%VwZF|eGTtyBViGP1(FHn;FJ zVzQltghET{71yx(D-x%d@EzP)Unxgopiav2@>b>xr{_gK%h|)|ZfS-d#=tf)wA@9= z%jLr1!n{&-)aN~!DuvGP(iAgkHpx?+Lf@mPNgJ%fq@V0fqKzYd8j>@lQC6rkgC{TW zZJa?{wW&wRn{K@Xai|-P4c~tE?HrMB>)+$8=*F0cY%Ux(GUWT-+)BOvWO0QJ(jVQ> zrhtcf@n*o^=bHVk%J!Q&0ab;G=s18p zA^04Y5(93& z71vkW^NJ3&K6dCyBs1~GJ#{&IDW!&X;jncKEpS|s{a`=3CVMK#F%}6>Z3Ed&befT+ zJ-x#({e1Q&U;vxzdlNxGe3T&PV;1p9ahLLGcgl}WtZodk zRIg1}(|g+8an@3&o zGs!zoRPN4O4kq;!0Uj98@RlZa5zN=h-#& zn7EvjVjXc=*9y0v0X&2-^%BX{DWt67VENFBjxI?sDz`qZTJ4_Jp$JD|grp(Qz}n@@ z%tv`)E)-r)%Z7R6z;Ce&Bmdlwy;Dpp-Tbb_QI)c(f|EB2w++@+lpX}{qM7-iIl+Kw zrYh%AGzeh(2dlUzv}vykj`Y?w<{WIXO<+}N&-li2^j5sK>igmZ<1Q546-2<<$9PT+ zH5R}I4kCnvXGis|5h?GwuGX({^w{m02RpX&eXJNpbic@4J>K&RX}Zv@+O9kbGMU)p zIVSX_*0e?|w&N0YG3N_T|Mb8gE03bq+y$G*x&y@z82n3XWTKzgi3QRe{BE@Yn)u~p>ly1W~W7}~sx8kXn8^EeVR`<4w!eP$s7mnh*H zF5K7fmb71?b{ntmACuBV%LnSwHy} z_98^u6A;1zq)8+128ck3b=u-nl=y!&F=6TRb6ua)(%Pa1)>bjaPhAe?7{cSv;T+7! zwRg}bW41fR&rO`orn5k!BphSvU<(uU)t+UjHf97beMXE2W{@;)KhtuZ^T z6X}*`7l`i|!0$Ay^GMdUyGjSF=G)=}oWZFaqlNEUHh%S&1ctWt=m?PO%vo=$*PNe} zK5=V!t%1+}6-f0Mi5rv83B*P$slCg6B)-9?*8UJ?Wj1c)d9Xv@IU`5TZ5Dd96puKw z&Ema8-V=Ps5bcv8?F%wcHI^!M*6*ic92Z{dr_L()3-3cO$+*q%TVs!1&GB?fe1~)H zq42EqmFE&ycmxw{UJtAw#TOYd&eeOZ$Or^<1+q-ZMC{p$I^i)^-Mn>U+)lZc0ddaI z>z5o1!@3fsFad^iRBVuwJR%aXYK4e5@PsV;8Xeh2(mKw13N7%dx-j(@yp6zFHx+xI zkBKt+o~5U{;UP>Yy|O+%8IOtetS9LJ^i(l9>*GF@sNfv@a_R9tMFSpjO&T*Ea90z& z0b}==v`4W2wOg6q>oF{*xiiN10ntF4?hnekGM4%0cw-s(GM(M;Tta@8moco9E*#M| zjPw<9k%1`1-U2Pi1ynu@eMnS2^T@J#xtE}}huGy6lHWyo13btnG8~IXS%9F;@IPy3 zbNnP!iFWZnYBWs`4Ksl0cFAZ`9AW5j!vfB)^#JO!T?t}WBC&I-AM=`$by=j7vO=(#C!oU)}=@*`BSUa1o$7UMTzL}RWlGb<~ zCf61p5AdXFJne)rzu-y|?t9ELw$2|R*N|g*&xr^^Z2ZWxWQHCUu{^4=qC+%9+YNjc zwC{bE3|^LE0$o@7+>Cba?!zz|$)|{jW)HT}%30l?%}#3bxYQ!44eFF){2JAUkDbl! z@;NBaBkv=V*)quRv!DSP~6c#Icp@{}iT`@xPP@yzhA%37%6EZ|@Ao&~R59 z@C#gQ?#u(MU<_wpZE?eAvPM{)KG8uzZaBivJaISuvroa<+C=8+9W;DactMV6iM(gd zW(TW~SDTxrqKZ}h+7g^=#qk5*!NQnuE0|+8Z|}reA8)JwUxLg}@LN;lI|QH4V4Y>y zW{bNkB9fHY{He3qLlVw3W=zh}3po+_j6HH^T?7_*=Y8*I%#evQ_MhOrC-@5k?$V<6 zj97a~d@|#FIhhIT*kf}P@53Clo@K^Rv>Mqhu}II^%;)-yE{M==mXIZxd+m?V;`$PI z!{ZH{&F`J#S%g$FC!qGK5fACF5R;7`5c?>%=@5?I0o9I=!RFLIJA`vE1jc$$jqeM;n$aqoxV#wzcxTpvxc zN0;K2zwe5uQ#oVLbd;`tJ_d*#ZfkG8R|l0xM@M z^d337IbLz$tWJOFGx-rY_YmA~jV+9bCdbaYPlROTO04IKZ!JTXd8<)?7NtG{u^Bc3 zXER?~w?Fgp=Zvm_v+e<7q-_R1XLAp$+^smjae8gWt}*go5|2;uS-0Hp9Q$5yoweu9 z^n4D`<`*7=-fw)4E5q~1@J?)2vMKBw;{`2zmchD!&areo-%YRfQH^C#jX%95`kElY zF_qRG*gGlp05|>0haRQ0Oz8k^bON?&cwr9@zKv$>aHbA?n*n;UOT?1Mdpv~Qm}C1j zv+)4URm=K)dH?!s_mSWf-~OJnuImGyLLa@LwE)(UYyjS;9e-EoUaK;?qz0-5YdiL= ztv(ru4EAtDf72Emk%~8|oaa-rjGyzQW6>%JSW<@WyK8y*)mlO1Y%^!|xGUm;34TY8 zrqK+B^}|vGdx95ZjFt)VH31v2?7n3^txh3hOka}Ct6}Ud@exM&^ZGn3=B>dL=V-^+ zS-+HmE@lDpoqI;osm~jX(G|zeW+Aqjj*L$=_H4=-Pt|;bgsvIZX%0s`V@mIYvV@!CJQb+d_w*g7USP z3H%A1kO5f$V{p&G2m{|SEdfv9l4V( z*|a{_@{m4*EqM4Dv3Q?z4AI~PI9$m)3&_zP;LlgSBe{C&9kjY$_lL;-5D9G)>90ic z4Eax-RTlJMCN<~?vhjZXAsmOU`wp?gmHULQ%sq5MpV+6vlTF=k$iMf&07_?kLG2BC z$e3IByl&e^VkPXT%-@Z^->35H_nmd1m~!Sjmz!US}z8u_~7=-5CqU_)+@$AgiYL%K{IZgWdwDs8yhj@mpOGf3EC(j7G8KcskuXoGcJ7W zeClV=wwXsWXLE{Au+1-!#Z&eTh{ZE{d0YP9&~)oGFvF+cf;VjN{kPcjiY$oDRyG2U zvw1agpUp7ssM5a$Elr7sa&W>0QXeAyV`R!^Nwbb+eGrI@?~VVX^;$8O+3@=Y2z^QX z)$+dw=;balKLQ&Jz<#W+;0-d6;j8zt>LGPJBN&D${)f&l_8Iw{YdHKGMO?t;Nj-*V z^90!WbSA|$`N3mneH6^5f6P6-*W(+uDAJ%h1wx@?Lnd~&cUw9dbMo!5- z=R~$cyuA&%@HV4og@(@YK&{HPrt)mWUY{V{1s0~ksI$Jc5y;#K{z;8(Yk~Zo;)`01 zU5-tkk_#SqUdq_BTdk{(`M?1cJt=wP38PJO1E*Zgh#q`aO=P_TPd#Vo%vS^Ep3`rg zWvn02smHW!2HT0pBttU%E6?HEpi5>RrBArFQ#8Wb;}XV5IK9nW_BhTOt7kKoEN*)v zoT62)TK9pB@cduXx9YmXR=V(L4FC(ioqjKC9z z_!T2GW{=8z)eSx7J{}6KLhK~oK1(i(SVq1ldJrIeiFh`^;AnR?fQmExd1?fj3P++&gqBw7XPWy>vED=uIv26dwPY z>mGqGhVU3FuGVHZw~R=Hx3a>fuV4k~ya1Z#I4AOmz0I?^Q46q?1kYjVY(BD6k&ro& zed26>ALCtYu*qE_h=|z?I-sCKWv6yP1A#v3l{$T@VLPREa2p6+~$7ejM9`RX+`5iZ43oU0ofNGCIW?;KpwmkB& zRl$>K;V&$Rqk2B>Qj5?=d+sr^j=)X7kZ&KzQBJ&1r7Y}+I}$vuUY}E~!cDIOFfe_}fEo zk5`P44BL=-oUI1$S6#AYj*Tw1*3O;z&VUh~fc39jy23N?tS)$o1~|mB&&UkgT-;Nb z$<`yZA{w{aWgWGr;1wF2i8OaC7FT(xi;+H{*Rr_9&A;38<72x z*BWzo)7kVKX71EK1w%r+WLHu!%Ly6KmcNsZvmSs}FH;eD9h2LyomKNpeE;+wa-ZWj z9FfHx5T#XQYG%%Q?0o916S?A#4Llq3`}aJL$L1LsVdYEmGka)-ExeEh)l4n1=QgWj z#ak-LGw2+jPeBQ^ugC>B|97!1#>HC6H8mMEmL(cEo4tJDyQ63v^nwikkSAW@na+tz zyJRaf?o+StoRM^&zL76?8sN{hWW1Xb_k{7cayBPq$@5j+ZP?HSS>g!hm(97m2E(%| z@&n?#7#u!zRy$&|_{Gku)pNXItH-g<4kIji6AL!RB1il-L;I^$J%?vHV1%4w0sDgv9UIKeMA?)`+3n|REiayCoo1<{bz8!XWy3u2=Ycb?*H4Sc>q zyZLRfc(KnISZ$9oBfHqr9_VbBz11f^LSy%xbr2nsHQyt$7=qE59ge9NJm8vI;IDh0 z>2X3tHAA24{9$dc7b~AFGzPZD0_QM^9^n5?L1PpzICn!B14~AM^=?Y>3HHg(SZ~;Y zkB?^53JiUAbuQZs83QBc5bToym=R9~==&JFQIGi&4c8Pcq4h#N-usw{;I3uq%eQDm z)x`!5c_R&HHDC#7Pzhol5P4aiydqnreP2%TvvovliNMuIZ{xL%k@hZQI-+}qF=&k4 zUeb9l_WYqf2vdxPQ19b}>`;URm?r3gYc0UbQmk}>%um>RjOEH<|A%ChX5PnGdH$Yd ziN-z-S6^Etdgb-c8taxKtu{~1GralQBl=6Z8msObqNfZ&ymB^^;L2+tjk~v=c{leO zs6r_x87h~^t;Xo-)N3@ zgKlU#>+v&U%ve_rn*l3En}i^`V{$`1;#-?5K1Keg*s}s0x9_YMmwL+2UCQjRHU33{ zhp*bG&G-)()mEcF!-Fv9sm(>Q1`8W7^Pb|^8+g1ip0MEtD}2fr{B7oJF7XW`w!r%? zJr-fMbBd%ZZna@lF7RD8cnVV(Koz#wViM~MSdcZb8A|?QG=y1=lnn<_a!;#PB+I%1po=X$WVe=v^u>*!QSclXm&vQmL zsOxSz!Yl7#A6s&cg|Pm9D{$On@R1X;92FkGgsMT~{M~of5pl>I#?Qz;T$065efX3b zPK!fdYVW2ym#Qz#!l*rDOg&+2*bF|8u|9og^U8Gb|6jt|wr)Blacaw1J;u!0EHoEj z&=cNifCV0spH8EouWfdJ@PkTT%9@V(O*%c zV(i+)XNIPrlncg8h^*Rtep9c(N_YYzM(`3Wd5YB;lWn(Z$2I!koH1*t;nvUYrCzyi zKS7o)Z?OR*r*2L~_!ae8CIC=>l#saA}4KruX!vgOlbv7SxfEV8Jh`@~JTym}m zop(vqBsZM_68EwARp5^M#Dxp2y+(zf$(Aqa zpRNq05I$7PS!eN^xrqlb&E`a&6Yk*z9o(j?SOJ5o1h+iGJ5jx`ho`FgUMmIfT&}(p z%h1`pSjHG_A`c_1&IpgYiX!h%lzt3t@hxng zys5uJ^Q6~koS2anVy7k^`L}NT*8Ou$M4E6XOT3$fvwlAdqfSk`;gx`kYNf7jM#WYS_}DMBI>?0ZCYT@Um{?e>zadk5{;_fh@O^8-3y z@_izM*z43IZx;hFee>aS-nKGGRp0m!y58O@l@ex?jDg8XG z7f^zi6+7!EIwjxIao@)`e@cvUh!1a7AY=4l)ALIrydyB;CFi_r+4|*Q)*!znczB;&veln-$<}Vce_L3i1n!yj zm}?fK)_czj&|jP9C&b=%iHEIHCi8sY5fT=Y)wAwnF}?jx!2&X8b%zs1bcTmqg9e%u zj>$ck|31M7wK`vwvnzDm1P`ThV~>p(vS9P^mT;CT5Wa$AT3@TaulO5+=^J`~>TDi> z0$VxZJ#=Bg+sp|QXKbv>&qHv9?wf#nJi+U+e*G00JM~kJ*ssmgJwOw7nTt2TC)guS zAHaZ6&S8(Ztb_cYfa1mQE)<*FM^hQ^Cgalp-L$|*IRq!x{zwPDBTJji;FPRgm)yPO z5qjXZ7UpmN1myCT4J5{~&W1?KM(JMT?eHlYzpIx>pTbqHm?~E@y z0h_n?qdMZ;Sq0BN9=gp|Rg!0Z!1x>xi;fuOL(hi~_|E3))bGyFFMW{3jH|Ob1!h>< z1#CfE&yk8b_(OpdsvmIfTwWy z6hk~_RIP~kpAy-IUW?Rt4yp?R>{af20?f$U8Gp|D6s3G$^Q5owerojAC4F@QXY-^M z{NDFj#4~?i37ND3I;2BxrUR;B*i8hhKK6*ddC3V(odr1lk?0SIQCSFh2d}4}kJ|TyBM0}`{_?c%r=41%wX!MXgj`j0SoYiv8K^8Q> zww5<9*pUZ_y})AapYH60>cEC^hi5{H8kKn-*>y} zz(098_Z*!7nRtMO&3V^WQ_===w{8s)OBV)j8-KNe4P@Mv6QsoIZPiXT7^@p+^*}Ls zWUHw=L1t|fPOv04*_j;RJHh#icT zeunqE@)o{!#?hG}-$Ty_3c>XzTyssHv4R7b(G~C+oEMvCugg6(J+l7X*^B_H6{q-G zXXNLO(S^t45C(MB&atK$R=>p=hpaX61cu~UY!NSqgt^pB3fW911_mkjrw>&2z zfZ;QBHji6OE;b+z)F%^*JT`b&A?VEz+$3dG*sQ~f@vo5dDZ1AfNo%sT*5B8B9f>_}S3)%8vF8ufXzgQ=gN4siyu{lqU4eDe7|S$bZ`B-YuBb$x zO^Ezse2)k}f9Z2#c6^)Pdx=L7a!nOp^N<+lId*6a|7YN=?~idLGZ2HyRo*U_$Y}zv za=>%7S|dXYRH84iyBFXEb0Q(*$Mw*|8Eadf!-&paHh-8^1@y@moDiKH;w7ua--nys zBRA9Kd6;M4<%}&PxJ|BMLdAW8X7A$nm*jnH?x7*pJ@Z!C(2}mt{b{e@CRZ^K&tZUG zIwnFm0~Z;>C0ioN0X~~{5V~;IE8z*b=7c;`OeRUAj0K#BF|{E9jB%|Zw$2R$aFAm( zsC8ac`TvL<=~UjwTx@-dw`ltg(9_m6Zr3sVk1sKLls>Ay^W_N3q=z-W#@x63Y?w@h(gvmR}z*j?}^oy`|4Qqvmy&y~1P6*8RI8GCU(%who1BXPvheFoG6f4s%$-W6!Ip z8CNrBb?FmwcN2W%3005Q^X!VsrU0*X1Y;pU(j#Xxif++p8CppZxD8{w$q}tfVnN2D z!WvG+`Yrsq*SwLO_%`xvw}{&LnX{RNtnSzHlnpF(33saFtmY#2F;gFnsaEs|JsYBl z8_ez#(-&YsO-|@5cJ-OIocDClh0i3bFw|; zx{n-b&&XqBDFi)EV1U)+r4PaHm(J#{&Or}{c#TuIEFpQLk*^xA&=fs9%BA;@W3JDb z1IDMVh%c=A-+0B=8P9TjA-2fo`z)|+Q`lo8^uUzkCZJQ+S$j)#U`XSL4p#~GUOj@1 zN12w`@Cg+}+CBdiCZXDGMVK^py@Z*UaV(pgV}fqE^cLP`+@66aPCY-b!Tr{FDQm{~ z#{D&L{WIkICZngGlvPI=m+~psJL2Ctyn&Kf-FoE(pbSH?f>znv;0dXB{D6CC6Cv%R zMMEsCTIeU>1x+lz#tldKV;!ESRS`Bt%lDnle;hcgl8Qpq^PU$V%q$J-9c z^bUMN9n!IqR`70{h?KLs-pz3r%gP zeF-;oK#kE7jUA#v=4g{S2!mlhR)=M_f6P-+9i-La52-E-{mhdQU5WIliaeb0Nij(E z0cV`w@)k43tL8y}W2XUF=I#sLVVgYD2 zVQQXhhG$?st4|rRV=Rl}6wkr9X3l0oJasl3;03Z-fF@XFVT$imyM^~(3UJXin#FR5 zmh(`3l6pNAalaijLxArz0M)2KW)y>XOpY)E@5?{|yF9fP7?|mSCi?r>wLP=wn7(|< zA$WpEaKQT?!zmcTmO8kzH*<4s&+SB2Lt>! z#q}Oj>A3|d4natoSd!3LKiM<1dmEf)=rcst`D_UfDaNN#w7Nys_nAkLQ=a{Oco`c; zm5%9;Wa}?r7xdAoFGOS9we0;eEPY0a&HWxTGH!gn8vkmD9kq_M3u5y=*xwDGJ9d$m zsS|K(?b7_1*l$MmE@0$Mu+dhjJ8;%Nu89T+8O0rU!-h4!SK{MX>-ulAXN{cAey!Jc z4jQz^o2=11A$WxKeh8e+yK~boXymJWb7%d5ddTj^XVFV!d3IY1SUa1eD`6xRRO(vB zeFayzV*GBw>{sk}iVQ!;3$nTKw&+x=NnH85fw8lm;0vBu?yS#uh21-HHka-cYp&-z z!$-1CH)n8j7S1|>na@0ceNZ{$VGq!K%Ac|Kd4&Cqn8jnvdp)A(<`~X&4;GDe1?&;4 zx5008z3Vggk;}Yi7ocDJL{X~mHTxSno5e*vt1iBT&B4%w%Q^8ez`)~0eP?yrC*YRG z6X~;TMQTr+%~@V@jwR0|gv6OXW_Lo|^g4aPFCd9zX&C37NwzDdq+pJ7eAgI>j_Hmt^{j&kzCnjBM{Rmx8o%#8cw-+gpbPppATsOX^Y7zJ zm>>UG_8Q_BJm#rKbnV>ozLYDFIP2}y0H2G=q_r6z0X%_(4Dm6~Awmxwk-|-gH+td^%tpbg>6rk^3_^9~z-(MAk(Y zj~NAu+$o~J>{15CQHbDusr z=X_4*zI|`sduQ(4$;>cA7#M;G3^NQcgdrnQf`}-=0HT;s2?{9c>Q7Nw1v9#?ii!!w zfMKiN_3hc;{`Gt9?r*uk&UsDW4yR9_bDnQied<%6sv6i^R!4t zUIRx~;G;%(k516k705ce=%t{Q4R^TZ8<< zviDP<4Bs5!{R0jD-$iR<{&JgBz6loS67RM{HPK?=y54UGPw87hhP-;896BZXtYiJo zFtpJ_6?o?==nndv=L$bD1?v_+sqkpdxmU$!nw6=Fct?d#>@P4Sw}2P0%H13u$2w%~ zZ!KW)IT*PD)dE-ItTN>{54QFhpNsm_<=}IR)Y492lZVk|Wx*d+Sfdov94rr7g45jy zHJOI^9@YZyKnGU19DGO_eN&6-q0a)abCwV4Vru@T_|&sYf(|52 zrSCMBZ_nYJ49Fzf-1BIdyw=8d*t>KwzSn&031UXWt4J5z3NO^{gxI{r3?4T_G;*Bn zY}+C6y$~H(+YOkXD$J=}#WUo8MKmAYkK%e3!ANT27zK5m^)8@KgpI+-Y*z@2GGKnmjuax*kQSa^b8gMJ<8izs4 zn#WJov0X#;V=(#}n7@JMWdlu#%{j1)cM7Jgp>j9munT)>9&8g^*#fI>FwJKI_c;~c zGUA)VYv}e%Ay#|$nz4YXkeN8M=~K|XhH2XA)8acu$8aKE<8R^#cCo7(IJb#@a+PHA$l&bLDZp|y@a9e8P>VQe zQzg>ky*PQQPzTcl*0|?^_O8vT?gV>ogZ6Ub+vR-!&nR&DJ?e#y4BGtWF6#Si(D>B( z{Svi?N?4H6Yie{)^c7yWRXM*^20-wU0L%*I4?||1EeLujIQ$40;>6?ewh|`VWKlaGV zD&$$sP>Jc_A8a=NJSgA@ir*43xgeKfv%dGI7Qy*Up8;c6@pwS&&KT9uTBq3bVtT+GUT-gOz(qV^mNV21IK233@en$aXeORvQ?snf}%!lZ`a}+)zW3|Sr^|X?0aEKp{M0aMHYucFNR&4 z3vG*E{aZ?W?_G{l=u=^iSG|>gqqC=#wbI~&XQC5hNxK(^>3UC@1hj+v8XFHkLu~yhp@mY3HdKTUCL2zH?*zJ+H1np`6f zaBV_`N}*4u9f8ubaM7KBPKtPgDc9a7UDZJxEg1L=_in&g)i@0m@ovC%u*W)nz-;r?$fEfR+q{Z)xzJ`+P8C+gfD3 z74f-+-B1Iov2}1AFXB5t`Z5aHx}#&~H+%3iL-ARtL%9BV>iD)@Zyq)#9V&DU{K4he z-Xho3tp6C3mGk7^i*ySt>+jj$Tf%Zu!~~xymckd;s3`hQh*cC}Rr-O3yk6h(upCr6 zb}jeBc90waXKe<})esKDDv(>moeEuIEBM?z6T!>8f7{~oi1XBweMiF;)Fuu|miK$e z=`d};BACsP)fx5A*`RlB;K6*;LK%kHsvw7?M2|*Fe9QEOw#l#N&GFbsyyJU>?Ruw1 zJMhLOsy91WgU^jjiBGmH-meF%5%*hISwVb0@Pw1p#1=e$RPpBC3F?!aEW(V!eC`$* zS(CF@6`$+kJ-an**5i5`-<|=V*5T~D_pn3c?BOwdr&bl@Fp*AB&w7Pw96ZXwZmbFz zqbAQ~G5cgW{QN8}(FR6S^=~MXHlN^?bkvmT^!rZG3{Zh3%;OIZ)V0=|zarjQQNe4jkTc{!)+ORVmMd5Y96(uo zD};A?Wno8F>Ev+rMTv}L%Iw5BtiQ{>Yh1H38Rjn5=~@e~+j!r>x_F0yZzm~$cBa9a zO_T2Yh~cSC@hM3e=1_PQ_l*9X2jKlT*->{~uf`gg)|&V{hytH2p?fiZaiMMUt9R=L zPQHXrtBo$T0G6wZPt~l#|D?pHP;FxG$Aea-87wS?j;k#`<*60;+a4%9MQv(`uTOK% zd^N5Mp+>k#R^K8M?ZaaXd5&%uZO%<2 zu7rLZYJd&{d8eNauC7*Z#m?{S6hm0ZVyE}y*H9rhgW}3r>~-w9#QZboLW@Ch(Fcp= zq!)M@-*`GkF>?g{%>r7=W9-^$Q2SqHVonKkaEJ`vwEu_63%r|RN%3@6v?eA_=hg$*j4aIi}x|ShB{+GvZdmlkde3ogGyk?Ia zv!NcZMYlmc@b}|T5p3cWI^xsNSLhwEldyrG@3LFHfcO?6+viSBELlb^lAgej3xDCbo8j6AK@I1hf!8#hhZE6S>KI(W0Pii?`z`QVrrnPGHS3h zL2I=tzB9cD+S!588NdP*c}Ew5r?2r>?Yf>2SA*G%dC#%hcty`xd_L`-_ztK{V5;pb zSnjl;kMbb#?uyg&hufrpljN4;+M!dV3+heLy)hu~ z+<@=%Ezmjf{ZB>l-JCVfg-?j7bM}kaSD87{b@Bt>-`y48<58ujv?Z=kbG&7L$CTPb z@jl(GcyHJmc)&N%+j-f~?My=i8CPE|Yy4prZ|b%P{hmKF%hdVMHEsCEj78wzGZ}6?DJ0!pwlpkOK@tt+OuOQ2Q8B8!3o)F}3j)ZTf(lR6_Rk@2ygCb)Q-lR~dWs zT!+grY>`IiR|MBr;1?bNM{pU|?VSCBe$Q2ZDUirKb-yZoJoS(_Ti)jzfpYM6K1sk% z!@A_)7dNQsF2jYi`0Z5a`SDj#M@Qg07RQ_tW8u;v=W9_1xr8j!D{|Z7o6F1Szt+X4 zDU`#bjbQ(qAip9fa)Z6+<^xti7rqn0`6bg1tPuD6To0QrcT8d#z&%?0JH(ar`6`#` zD_!&K@j~0@|Iu5Ho=M-7Tf)ct_8nK_H{o|y^d0gI*(v(9+py{x>OU27tE%|)nFYE< z8zJh}vE(|;&k9Jej|KbGtt!a92}&%(bvMQ5*|;iv!d1y~51&4~hL0|iUpvp=6W^54 zgstdE@BVncNsMiYtBpKg_q}*y{F7_=%4mL@_=;|*GPH;ezICLIS8P!i+{6bC$VA4V z_c2+<1OzaK39!zyeV*}+ay4p2Q}&$<8lVa4fgYOSHh-s2R#C<;_HXPQE9+ z8(v8{_%ZXhduR{#$-Ham71N;e(;?3KzQYFBWe#LpV8;J(R6M4>e1yj90#(5x`aomK zj==b2;K-`@<&^jqhcvlSnk=vaFJmWS4i#Zbd^?{{>RlF}+rC02c^7|_4Yi((`1F6D z9zEscG{vV9dRAl^#3t{Hd94AA?mQWr#f|x(Y4Cjrn?!{c-Y-q1<%B-oQH|Vrw7muR zm`B25?{F38@ShvhF6O~8>v9!mx*C$UBdS69a58(?yzeDBfgaGZ&6DthW8&R9J^vHD#Jb{ueIoUGc-BMx zoi*xPyXXoxsABcmMVzD8$Y&Fdq#1l_2kh@N5+=Nx%Vev*%is*YXbrzH!ESP(a90Tz zc^~T_s4DDP71r*sT%_mQ^RG*&?Ao->d04%9@r|qtsPEfw`Lq0_%yrIlzqI&Hp(eIG zhi;%Hz5&qZ{QG3iIj&MW^e0RmjSuj{Q@r^Amey=KhZpmWZr(#!An)m-C-Rxg zP2L^f>eT1)vg+}sAeb?^)e$;;r_@|4`Yu_Hb6x1(DB=%yP(S6!dH2FJxg%r`#{Mo* z>*?y%J1P(5M6P}V+kZoRzTz?{Zw(G$8TPovq_`A}sxhf^;#0AAxgI%etsQhHj`_;i zgvF^m9DiSYCy&+7(!{|MXQV8?EwUOagA)*Z6)#c}-?rt|{ch-DUBi3$T&xC`Twz{K z3u|n`i~G(Y&k9F8XP*pJ0zZ0%>R_*LH&ow>RLEVi&>?#JmcJI|*&wo4f=;i8UZ5{NN1%g;&5^yE z&q|ZU^{MdH@LJ_CUA87ZPt+{8O!r1R%!8{^d$Ddq-yYf}n`)3H&PqGXk@mh(t7GQy zH|ykQJ)X%58=GeFEFs3?u7NBPA0ML5n)IITUsU1&S~KXXfA_fz$E8}PqV zEW5${iE+4kcAj$JBcB>)l`v<5b5zuGDC?Ye&xm)j<-t-tayH+B?V7!MP~epC=Q$8% z2~FNQwq3^aXT%waR>Ck#p(1AO5m%(%7 zx#l&lT8a$9>xir3lU5hV=M6*jf(Efd-Z23k6jAVbe~)h#Gau8z?`?y{j#0axhFVgW z%)@6mx2PNC(U5Gw`mK{e^~q?AeK;q+9c=~wXng7%Sj(=%arkT7ka{J%42M*silJ}v zs9uXb@f}im@omL9DwF5M`>k!F`8Q%uz?gG$nEZcAPQHx~&S8@&Sg~TL%a%aOOJrM~ zpSJK5L+U0=p;xz06j>MFQ`ZSvu@Wcq1o6SA^tp0-D!zfbMqH@jb9!XMt5l!r!Tz(@ ztZ&7uqXejNUaEmTI#Bewrl&9MfS;Ri2&V&cKE$r_@VjHONuS#9+je}S$&fg(Exu#W zrvdeXCbR`I?_$LbxTPIETRwrzxqyBA!6tEJSI^oMw)vDkgB|X_P4wRr-|n|V#99Nt zY>993XyHG$Ve_3OaZN&>3R|1nUmEVC!t)-0{ZA7KeNs?9FzijdTN>WA1^&+yHCNzh z525(E9HhTQMP~(TTObcx;;R+x*(bI6rjP>D+KW8X1*)<+=9Sqq^9djWP(XuTg))CX zM}L%0EOk{`lPlH~@7Zm@Id0=Ud{V z{$+~YHl-b^0aJ2L_hAD(NE?q(7VkngcHOY%w)pgc4l!^7gSAPr2nNeyx;?hx zr~&hS#-PsAu%<(~F>L2M$#?h2A=bd69rj;XZs0SAw$0^|KUkT?y6iVut zZw2HuK|6SisF@8tMK$un75;S|&$l{tQTTeUzZ_=lOvPt7nqS(*_G|~r0=|1EuzIGU zs)dZD610%MPrZ)P$~S+HV2bP=TERE_oRbu_fENDpI6O)hEK$P;Tb4IZrP0-1W0XZX zaV45hm9t503!x_EoOGTn^BVoh+&3HosA72*B~QQ*U9A6)Q0F+-x9c)XrsT6-%S2A^ z?q7u$tl)LMcINvzm*7-(#P@gkte_k=SH!Z4sDih6w1W7|-Ue62``)|*K9AKo(^tZm zbj9b$G&w=uIo{=&p2lX%f#=JItidfLi=B;$;(OvcVAx!8>aqBokTx}k4RRRs3~Btn z$MZfMTLUJeLPoGg9?;}5chExC^>m#fGco3E3nj@ZdVF@}Dl&>a{py?yncuxjrEmi_ zWKDdA@kW>n-XRwm^6JJgoLkiXr&RN{$*r@&CmNbPf&Tv#mUT{_?GPSd9=v3`%;!Kf zhTayK)o1Ea;PmUEi9+OI3+Y-WR^1Xl+|;16mr7unkW& z2>P#)JXBxJb(WW2aI5|Q>(=HpJCp8nu4}{r&qv$Lo@rsjC0N`&DkfEsZykSG#?m~_ zR`uxg2v0>{64%<9xUznz9ZfV+odAl>h%V{=b7RVmd0xkt>7(u>*r=b z@2=tZc{c~op@Buzh-K?)A9nJ0$TNMGzi)`1QX%v$R9RGF#`kY>GTVXeTMIoU{lF)T zI9X%zZi~;SnF2P^-`%4+ScQ4Cs@yK;ZdXy{NxaZipo49C14rlv4Rf60e4S#Cu))mzvT=IOz-nd;wX7{0mj|WMvGehEV10RjINdNS;`f>{Za7w zfLAfVGiTVq=iM2(fCilbvhS^s!8>DA5#My2=Txr1u^Iz#5{%$`rps7!7iEB972{~G z0&CVew>BCC9Qg6Vi$cE=(>JXo`Jr(ckFTqHRzy`ITMi`6F1DL{skD33uL;k*@=VlE& zv5!LV6d9AT^H!DKrE;;KY8)~`ARiBPX~YM)qoVJrNq105%26ShBLLpm2wQx3Dwn!_}($& zY|A0M}Mg0 zx;x?>t*&5faFQJ1~U}$|CM3<{q#;ynOE1nTJ&Z~2!y?d_)W0T{tX0e_z=gH^zHc;dG)HmNI zl_U4-!!M*mMp6XR`nKmLF(yYWpWvVSSZW6pQpG06uoXSjKhx0FP$$1%3p&IKd1p7& z|Aykbfi}Vna@W~;zukza>sx>)pnS8#O^q&B&|_j5|CabZP@BbjmK`8dx{s~n1Bs4ER zA2lt9#OM83o$ok|-=aqP%Ryi(iU?-0^AsA(rQiW_D7I2y`ZQ-_7X0VR|8DRvK20GF zM^u5?ToB*YkmLDVwzL|qa1-P`;R>{PEw0@k5E;tMoml04XozdlypmxVQ5M}!R(vYz z9``MV?LNVJw4%~hL ze%^P%=eVC$0;b~AYD)O+3X1&+KGrL`zJIsONo#Z3dSLY|=iRIS-m{+P`MGY;H(^Xe z6<|W#8B%XA1|(kzy4Ow6g4Y5&A+|N?#4U*L=h}uTtB_&#v7Q=sI7BDlJB90DZ{JJQ zl5tS`_0_JLFrE`Kfg$hLJ`CO(eLZKfaqG%COYU+ShVKj-wLMe;d+H^&`S;qO5H@|& z2{>)<6Mtnx0`QRJnt-~~Lg*J^wpx!L+6 z$gF|)ZGp84D7&|a8Fn%zJSX2Z;x(KuOn~{8WxQxzd{gn3_!N&Er==r4JEAPU$1RN~ z$a5upHsG50en;1S7Kq@N@zYc2$9-GeIz2yqV#^t}DOSmS3>`e0IWcqc7@|)VKeqr% zp5yx4rr~}0dY=zC2sXJ1qAP{!jQQXxmTq{gz?od&XDLpb?Mgi^-hn!WHL4Jk8seKM zth3a2^R@yzlhPCC8*DpxfP#20PKg*(;sm>e=R(%s#&2}RXN}fE6)TNbsBuLG_^1gU zpb{8~F0rKyX7JwImbf;204weN34J)dwJ=A=cS&!EPxc+dCK!q|d)p-AACnFF{YPMS zpG@M&e?X>gtjK9teT&6Aavp8OE}u_P{#cFhN*RF)_OVjy1TbBYPXio;Uj99v#V)V# zG(PzRu|Eec%@O0wW{%^bY+{E`FJGr`eTy37dHo&Fx++Y&C}KUwL$p24j;jWhzj^fn z$B6E8`rRe$KNT4L1?)V9J}67Q>^QN#Oa73<@7e_6G&!PIR*T{qu_oRi7wSF@VrW%- zYf6zTya5u)h)?0DaNjK=!YX`zFQ`XGM2ZC-!8a#vNCquXgYz&F-``dXxV{X>YAob7 zICYi^%{(~YuID55etSf*6XZjiFgb0*eplx?~`|ysQWaDxhwSKRDw#>D}Y`2FW=->3ALp@6@dyTYeWv-CN4U! z<9p-But+^Tz>u6jBd$X0Qe&II?$tnt-gz_(QFM&$nWxwyhIaA(Q}Iq>%g;~n+m>DK zQUU0T?*KffabzF8%8vSitC(1{gH2y4U335^Q3+nDR%*QgC-wggZtFZ!g-7(60BdB^ zYgDg%cTIt+T^GAs!n(@hvjKg=*Ey`=tlIwxyw8AZ*CAsvjmtdIJWXGQ;cEN$k!t^k zna?n*@&7mxIR)yU!!}E7%37tZCp# zkk|0q;4-t^A>N@UzNv2(jCT?Sp^qK*#pj4j$uwHxoo6lfdu0MAhj(iiW^8JTpOPxpF!>83~7h_Zw*T~25EwFI!&bYYLNTlEP9fI zP2L??+M4+8wh~!whA6%Q`pXclQeeO)r)V|QXI-Q3%G^A?LnYX@4I+T=1@KMYcFi|9 z%MD_Dom^l8i>wo$yd$oOI>9Fq^+Do>sHdE1V~K`HlnAxPyAH z2eK&8-Ft5xGRMt|8l_ z@?h~zz)RqO6v!@5?42iLC{qba(S=ta7N=p2GVlqmzcfsr#zws#V>K}N#ZWnIV&#?* z^a2y;dzj1;55vdx?pIp(#5bZ=(PtH4SZcibK6BHo|0hKrzex3?8@fo2fF@F~FkbuF zf`>?linMiz6wrU32=#(lGC-?eT`U!*3Lm59RKZuQ5=FB33yWe~pF1 z-U5T_NW2CTUk6F2+0s_IUujpvx_uX09#5JLs=cB3G`S^u+gswZ_zUC%_HP?Z;FT($ zP1`5GYl5JQoRSW>J5PYZa&$M-Ga4IbI6^F9N|HDf-- zrHguJAig7@Dc z%=x+w9oa6PU>i>Ult%h16qj%4>2g1?4-0T!Z>C7II=|Nh2b|Hd^g=zf2zz3Gdy)6W zcJb7?9zLNhg*K)Qsd{%#5Bj1`P=D1pH+`@` zm;9~IqfCfEH4wIM66&GWX;YgjVL3jl!}x(+5KbQ}+kg!mQAJqeTyNkBrc?)ZK@Zz{ zN=`HT<17`vD^dAhE0043d{S@c^<*Z_1Es#$U zJ^H0saZ!BUjz^*f&(r#huLJ9z)WFOmonY=Qha(! zF2ib%g8z$D0T#&p?I*{n%O4@a4#oR5RzhaBLatWgEBolXzDsEKcg3gn)?nq#%C^9A z7SXqO6|-QiHX6GgC~}K@u!*1X4(I~;on7%_sMn1_9#;}ACR8Ju;(cFf{JNn`^TEf( zCytz9*2yk7-zOrh&_B=ut7K3p8(*8D7p4Mcm@rfMoW8SN{>D6N=RDO&S9vjQ>VjMJ z|JWOUGd)g0i50f8MZ64#$0{x)~}KEWi*O3z-(!$g!|;c zf?53g!JO_I8AbtKHyyNh2NSE7nf~eBZ!P?VGc01W4e^bEZSn0q z74cnjJ@OmhDB22@%mal`ol0Iwe0O&{aQ$`;Hn1f7e3vbNqrmW47hj*R*1$=9>i7Ln zsoN$-nRaZK6Kz`)&+6?O>iuW%0Vmbwuh!FIdH-4c{Ce#FdZtiaO_lLv;1Q=NBW=d| zD)YC~aR1A2`862(V`OQ|aAj?3e{~qHb07eFFRtP90kM2J@PC%OU(Oz^RVw_KsU;ti zN1+eAly~(qVz+hp%+dLkMe)%jBe+-!_}5g>g)WnURJelP2cBX=Ut3&VofY3wV(dsN z*kcF(H9_@T!w*;39AUlB1#y-C0QS)9yG;;5G1P{3&<+;So#rGR^d)Ebi$$~vrBLs2 zmiU~$7irkcT{6W1RjnPSGA!xq8RAjSlg(KkV>Ox-JoqZLffX=9owzZ_HJH`kG)>3l zvxA4QH{AUbr&5*N9u z{h-6i5|yUZ?5gld&R7hH7|u;qi4(GReItq=06^MaIJptMzvPs z0?(tZ+NDxyy#ZO6zC%<#k1>PFI`=Np_w+LQtQNUCCEmSFYL4g7w{N02xQ=Rs@7ghz zHp?71Dfl zD)2o+7{M%frcIt#28FHAA=E+bQ6y&DwVUNJCY-}2kzt$but3)1lO=4vz!-1lQv(YD z<*#$)&C-t$r%E79I}Z!w^*%{{pV`0FfH*VccME*J1OD67SDzE#7JC>bU<)Pa5>X+e z*RH1Tc@?ce69jUU-(Dih7)QGOb%g-VfWYUd^bAAwB@MH_i?5wWskudO*(!`to!40n znNtP-o5g;5fd^=YT7QG7-WB+zEHO4GuIwvd#SLl-UXSnLv9s_+2OM9AbL6_5D)(tI zO<te9h{}2w}+))NmXDEd%T8-e+%}0UT#(l zaGm;(oAm3OtnPsyZTtxpJFxk zYuHs_jG}MMD(W@8SfkdmJWwCyC>`GOJpN(!u|5)&%^Y}to{Iho?{o@8mq8h{Or0$S z;#lz&;4vT zU&iQIwQrTEZYN@s{G>;gQRInpDzivE0FX+YET-PPE5T<{+l=so{ z9q<0O%3hkRtsMAU?+7%O*;(GcRD*3-(WXwhN-cP@tUh)XzG{s+^$?3Tk2wOnc~`5? z`}Q4KMe&Ub70~>Y40VDBDdL01Fb^wWmqNg9ji8I|fL8|OCr!>-AMfP)Bkxo9?{r~+ z`b5i?9Ly)%2BrEo-zj>P6JQWmtU|Xi0s~eXP?@iG5jah zwr|G%O_l!y{rq~h^e5_Px9P{nDF(P%9;^R8Q9nMG{NM_-18YJ3Yl`cOiT4lG>vOUC zfca3fw|sq_455djc#jT)b9$1mpz3%PwTP|ojB?ESzEm-Qp!`3E0&o$vk0IelQBRzu z?v; z#XYWgiz@1X9+A5E^rSQJfEDtTDt^P>)qS!6+e$PcOFT{mHU$Gd0)Z~z?R+ok*Ngpc zpmAyu=l1kfU4~j_j@oHOW6Lu6PK%SUgSsXc?7NI7PGQxJ@IHB8e2Hl=O>temYjyl; z8I!bxwxGseaP^9F@ypnx)tSavsI$J_zuP2|9wV3Yy#WPSqan;-G3b=?)b9p?Z%l=% zOa?te59NV(169T6l69yrb%`fAyj7LF-BH0dRy;s`G7htO+I+7WYI19Ee-rux%%XSE z5pIG_$Ecwu)S-H6dDjq+cgXFpQIvn3Mvxojc6qwoDo>SX%D2k%I{U?BI&e46b1c(~p!(MP*T-`S&N|BIaUOZBl=>EE&3-kAS19LgeiV3`w;rq(cz zTC0OcFJP-J7`hZ!u1{X=GtAAJ=EY}&6Q$!E(ik=OL}_wAYNeqAU5a!fLr1wYl$snuX;T~jf{ z))uMoX0Z4rR4@a)ywAt2NHef2ZCIJZbVW6J$L-2_Ps%db`veg=%{lVDJtc89rSJRm zsdg#qvx_i?V{`!pvXT})dRBbjLxUV`gy-?eZ!6+c=e?V!5n|Jj?65DssjnLNB=0$? z;lny)2Nml3S=fy+SAGcVwniKu1U0}Iy+b|B^77n#Ol(<)-`j!jvr673+<1-ebkO{n zeR_T0SiZ;U|2L|=KUZ(hl;_Bc{Gab0luJsr%lm2;Tnz-+X?bvwm}vzYI)Kws;Q=UpM=kS zHso(zT`5!trj5MN_Wl2LJ51%y5qTOt*aU4_TD+@zQG9ydF*G4fvcW9f6TbCjLN?un zkMDtlY*xHQ@@4U@8X1&0CG6j4&bElQ-i>G4p)^&K3aHPwx2$tLGvYf2i`b8Mnmhg| zlD{p(v-Ra*e`pooRp6&S_pb$eod>V1^IUy?aa(*3_warlSqX2~0moIv=Y3aE+4$5Q z@9kZK!RQ4o{YhB1UGC#MeNR&v++%zE$xtJ7C5|y)R?EAAuHUQF8XvEA{bY^#_sEOY z^6!;b%PZ7YU!peqGI@dCo-NN)4{(>>^G3bzd9~sv>A%mB7s_kZ!rvgz(9d75pS@dt zUG9^MqiocVD$#=8jzqK3Bchq;A<>`9Z^(a=pOEk2v2W8X<7%o4rX3vVsl8Y&_|cmC zU#g!U(wzT@emu;3Yr8#Mdz%aO!VJm|;|4r)PV>24TgwEFqX2BdoGy^fbvYrvt$Qw1 zZw*o8z{^wkpg~XwRLGdCa7YtQK?Zf^L|iHATM&xWXBV*Bbr<(lpjhs}KMq6ZXGQ&G6Q5?D%civ%3vOA(P5RSI^ggrf zciYg+`{zC6!JNzmN{X)hQzecV0xrz{8sNUf&`F8o3d|ZB8Bzk!C z(CCur%ktOqC3!$}C@Mu)NB2bUi9Qs4fAka4$D$AGXK#=0jh+|X7~P~l>*;;|Ts|W2 z)4y`7dVuT0&LPYCFHwuXn2&}8tfFs7->ZSE%nPc(;U2{s6xhm_$1i8F5APmK(?{pC zUvpT~5C$MaWXObQlIHhXK>B1y;Bh zdO~~#LmHOC_?j(r`8gQ65opDC&ie+zc3|&TgI5|-Z?p_^8AVqQe#9(#n}}#$XdM-E zT@vz?1^xO8@%@9RP%#)Ux=bwVh0M6BUVHm%*aM6}MY|}SW~um@J>)~>bdySJh4Y&w zyBTp34AZXSm6x#7B{~6`yswVCC)5Fbi&7Dvo`N?v8|b1LOj8wVVCxIwlk1D(-Rxz~ zLos-ODUl{iT_#73xX86^g1meNe;(G(<4>Pn{{y8~9gLn0m1ExxVcDQzlTCi+a}6q> z!V&o1r^X!Yo@?`(hUoLh_@nip%UJ`RZWHaj6J!IH@Dv!}9E{yM*}y*eqeY(c8p|!` zf3e#0jp_xyRjvO{jq|UT@7AdPI`so@=i_@7y}wkW_7Ca5?@`PB8TqVyK^_+6qf^nH zYS*udzAJiD^sMN`(OaW;L_Zk)O7!>9Me&ii6Ys}c@fGoUT#1jy{~rBwbYJx6(PyF$ zL{E&S(W9dOBHycj>s!?Gj8PHJWAzs+@{d6Oi_~{qk#Pv6f$!2=pb~s6DE*hw%BHD3 zE`{oPg$mt@ct>@QJYbAkDNCGaiEsB_hsVug9|dX*KCvlBKYk`?PRiI|F>pOTwJ{57 z>2VIyM3N!4>N`*}aJc4G#&lU##J3)Mx7Wc0w+&vygj#`R?;AYw2C=S+mfSR6K2^@D zCF^8C+b{>-W3|M&u{k3n@hK-hfp|xJ@_HX;r~*4(hs~J%n)Lu3-s{tF-FdG3G8zwK zV-NA_)HXg?3;^CY_j>L!sBAf0 zKVxrv@~819OPu<}P}7}9H=Tz&?BLxqylcj#&4#_a4b*)tIMEK-nRN%QfSY{B@syL` ze9f3xpMw<|g7Hhl1812kAo*>$;+**8V5>r!S~^XSrp2B|=wCP+SY+#+uvx|vIhYFA zqMA_T1YS*btHOCRRaTR&=$rgq+i+mLSv7d=TF}JgHS%}WYi5JD^DfU0UT~eLaSYq2 zfD#*DqxSF0c~kLEiE!TMzX1Mkf&2}@Z<4VO#b-sPh_GcWY@SWDJ?zAGH9Q)WTn23y z#CLGIvNsRsS|07`!ejzh(~LaRUMa7=(kLTx}&p;9xE0D ze#mppdqKsSB^T}EY3i`d1<3@&;yvaaDu!j$0&eSL^k}~4&Zj%A6Ej9A`P$U_r`%@~ zF3I%uySzWH`dfqNAE;kAPnK$%!A{B3HP$~zZh`NAvc}-+^#3QT7kHZD|2N7z6yLvH zeo{WE(f%XyQTYY=E%{sdM>!HTqZ4Ym?~gtj{aWA9_oYozOX#$5q!^}xgQwe`^2c<}{Lxl;M3F;`m<(kAliy0;S-%*~YcY=)3uYPUr3SLKJy8_1YnZ2%(@ohU^)mdhW z_j=f;(Ip0VsIKL}e_6bwZ^Sqb5}M#8m&xPO;#)w<;eD?XCt9KU?!C8dJcM(*2Qj_| z2YjFhZgTyH{H($m>xKw^pbT$dWsXa|Vq_>|2TWJvx@15BZS39u`oUDm5|&>PpJZAm zI`qk3Ecfe#TxCQpa0;>=kn3BR_$8!y$&;86UT=w(qO`ilOg+w|2v0?SV{{y#wD|6#1rF!a90y$UfQM_!xfovU&( z^5Cxw9Ivy+^JM$pubGB7US&Vm07Pbt&%R9Q8Max(E9hr7#dkgUJijK_IWGs37E;9E zJav8RzFdX3ZIUsb3VY6%;13(b@fN4B&Mk*_GYg7egY{d1o2vySn(==&x9ub+eL~J! zL8UapH&{fx8kOe|T(QN>gB;4xPEZRq@FqLdQA?qAF+txnWdGA5v1UqE*!>!`{|vV2 zKDicDG##wWco(1c;7X1vuk=8x;}$c7HS~GyX|y~WT)8w?u1s7n!NvGSsyzH!PJFww zW4NqTgGMli`lv(oXccVHChli>B%uRT=xm@)D*Pn@%|)zBD)|F%SunH z{qKjazFXDuzgyld&zGmF)jwWuXHW`UAvbFLf42GnV*p+uZ<7znuPNgHq8!$ke@-p` zSN2RHg+i#y_Km#wyudDY z-xc5BkO|8C9;mVbFR)BhZGz6$m}QbB-}B0HBTS%N5ufvJI#b_1(BNcRM7J3(TjF~m z+st7&4)z=CGdV1-1Gc$o=b7-Chr4eP1=`@;HC{u9`GZ#D^FG)v=wqMn?Zc>)s2Lt* zkDKovI7xPLq3!*Dym?pL9PhyZpV=YPYx1vY)vItAKI5T;+VWrr+8Q4-^#3*RsPp8F zRTy&L_E09P^D9&*4|hFSE-3qY{QWM!RX|xXrrWDSbk1V8RXC;${dTT3wC=Y@bzBdDbpc`^#56Ye}XFEI@RJeYW=43eTJg?cPZL_vF7@>DiXL(eZWbo0=EC> z3i5#$%gf|-dY_NWFUp_Fax{&e7rhf!@2{eV#pSpkKQ4Z2{8NhM|1gdf~6M?CW>;_3NhkhCTHW_2eQ&0}n`kS<%Bi@sarF zqFbT|L?4m6^c7#C2tZ^;|3AVzZ#@oI!f$p^G>z|%iv_M=hgf|W8(ai4mtp#>kFZ9q zFh#Yjk2mlREVs>7s-ztdRv%3#*SZw(|nAo`hV`#2Fk1v=b=cPVgMd=ta`{eHr(mCu08>rwCVO~6&EQVn8torxZG9<3lg6W_Z4`$0ie2Zb*1Ix0blSmUQP z@u|Qqs+W~8ZK|38w8)%u^Vw*T4a%hAK*VSHWu zOpW_*i$4*6DgGu!`^{vcG5;yatCF`Q&q?k~?ow+%pWL22BYCV^{*CGru2GM0d-AyC zjDB{T{{MLW{H*$bTC$KF)m-39@vkZhn2moidRp|r=mVOQZ0cEk5Ex*dn7>D*@+?(M z!!%|UyRhVW;=eIEbL4~>x;fkQj;sV-m*cb?*lvt!qV-oRj!85D;Saa zSw6Lhy0=Y*AO}a#Bcp49seQ7tF~mL*wM*5(mHA`*(jvOd4k&O4&T|aA1hSlR-g@B3 zF||V9Ch40SEC*dYvn`LaGgvD3jYAV#XO5m~zI515Ig-_sU!}o2-!KRL~ z_{N?piV*h?2bF<5*_wCgWnpw3{TGPG?V#8#lg*dJx4ru0(Z2X**D8JK#W062L%&&` z$87}-*pLk)MX*LGFiJ)81MdcMHq+;TcY+43$~)oAl%Ge-?&m=`zQ=njSa~;C{0Y3q z0B&%NywEkcn{)w~+IC+aCvTGX%lB#4e>>tVt(EDeyqv&({~92IAWzib2c2hTgjVLza^h$#XQe=jGI=OvTR0kwigW(*4`mN*7yt&06^Vh~? zZBlS*OMJIQOi0jo}S7}tG5whxt88X>$^clfyZy-Yqpu+v5UVLi0|+7j^AChf7hr*f0ukOb^fO)@_(E> zO&&u%;8r~o=676+wg*daLcjZT`F8mo&HM+^i=z)kzaKp+-i@CdzbpRv_%GrIB}>V= zM*ep41da1|Xv}|W@)Gp{Ka{*wZT)%4x2rFBy4w1)H7B@DKi-)II&ysNf0e zEAG;-&nP+Abh()jmos2mPZr7VzB*h$+&l~NO*UebnVs1fCz*)jxhG5vXS{LT*Z zdsBh4--HKTWU|S1T$?<0@3S8I)PIJ=iXPg4Dd%U%{L=}Zy~$tbQ;FOpA~~nh`x>!- z-`ee0$R{WsDCAa9VQr&`T7pIC5l2&Wg*Az~DWdI~_>|u|SiZw=q{Me(*TIKXuGjz- zP?4)tfE~%=8%-HH;98bJAHI(>OQ%`JR~Vu(PcU zGu92P#AU>w0h%diG)C-nsKGF2#dl9yb$SIYm~mVe+V<_X3gYreS3~<-!E&c~>dWB& zR?*=sg?GP)C(Tg9tzc^-aZPUy1lRx>AHxs&+#QP!$FZbNsK*}c*KFW9YOn<9kk@CW z8GLz3TuJ7FPM_iixb^NjTTjNQb#J?Eb5iLglkKCira34<2I92ORyjH!} zP5Ml4qI2*x{mNI-MYIk3zs$_{lw86#u_g3AX|UP=El--<(zc>*VUszqy6@5UY3(&) z`)OivmcIKAw?0>62(IXW1^S%X6kglw{h7e;cS5ho5-jYL6Wt1P*b4k#74JOBNG?=? z2gHFP_Iv`aV#2(5AR@6D+ofCvBm# zv@LI&`1>~VsQSd!MbrTY`FlA`VrYr)4r+wQ&%pgw(2Azv*P3t;-Wj&a^ResW&tgoK zeu-z>rQ<9IOX>N6Z;e>sT>2)lq4>0!KKXnt^mcf!LMd5nIkIk>2`B1$#gmW2dQOE*`nWt$ z9wv{_zjIQ3!;gqWXQP)#KM?&xv>Km_-xGf}{-^j@GEA;cZcv>6M#cOuN#3ln|E-Gr zzfbM_b;)-mKbX8tGk{kl->v_@Sv|s=6&*ZRKmU&8JK+f4r2gS4dXKx*OFTzW!1c*y zayYp!{<-+|@pbV+{9DnRqx~p~KA_L~EV0<$v8&Yftqb{y`n<1$l5_!xOSJ%sBZ zyIHhBN5m&MW!V2)f!`>>4tBs@RzF!LDA5pUbX=%M&7lRSR4g_kJ81~)-U zE%12;=B0+k!RpX#$*(R=MVMpq85>Ldpz%;ndHk)mV9~!A=XmZv{vzs7dpR?YCj~l>htnkjZc$ZT|&_1?zoEmxu&197hm==0mV}7mPnZmnxpGOyj z@4Ea3Ia{B1b3&hntB>;fh@LUFm}@m87bsCFY6bORDsaao@x8pu=yhsDjGQ!r(%7{= zo1C^h|NFj~9QHrL54&}zdBr7aR69%zECqFm)izFnD_twr$a|5<40vCnncfw zel0p4pN-!X|9bpy@gtI>Nhdj(+^qI{r)KxBP>X)4TKR{QcPQ$Aw|;yxA786^!Ateu zpGv+L^#6wB9wPrclUJ+#->u&<{QqpdJvlj%%q26)pTs{D-yG-SKaGAgdRkP9KC6i3 zc0KLqIQ5U0Z`D`vbUFoYhWj{49KVUph1T7Ct$wt*BRSs78Z!wC;Id85PoDg~&-E&W ze6CFvUI~5FYhbi0lRqstT&I$=B|f{|=X|B56n@8NH?&}f3Lw)IwL9~VN85?Oc^zZPq+5j2sY!u`(+JHWiO})NTFKppl)sAcb&)I1f^&2Wo?+TTA0(Z zM!s%y{d=%`t_W?D!)K`$wqamwle?>Hy;eLMY`KU1_d_p6gLk}3RmeMi4UH^{Pm5n6 zMz_Uhx@L&xU9=vHJcnA)p!qY*20gF$me<8M!%z5Wg&f2CGnROq5jdiPQma5^qQckf zVcMT(L@U&%+nmCBU;_G7_`5ttmAs(Ov#P@B_&%QrIFINlqtQ z$!hYq)ByUi#D5gMJ-R-6Nc16jzTBYJZav3$YCiH*CXzf?ecD;3qmAGcTBeM z(b+H$+)i2@W_T*TeRU0wlZDUO=Dh849^5k($x8>s>=L#;40Wp_*EL5zS=UUhMO|?X z#J5E^ibcRvR6a`7ob%{U%xbnkewNv66Dh9|pIc}9MpnbFl)B=j4j!Npn8v~dwf{c6 zmCcVUpj_GjZTrNp?GPgu>Gbib4ZfkfhzCef?W)1w8DHpKJ#CO)8{gnF7#FCv^aIoD z8^Fs_3zgL@GZ{Q5+6l_zRZw6)=!S}*i5eVJ6+N$gHXnGUHkIcbR-2{bIN@)sq6qd$ zF%9wEzE$z5v>9H}Q0hT1;@bn;#3jQ#Ys8xY9ABH>rz*+~JC_?FoAv#kC#W?I#PNF2|t=G+mDw2@xO+ARL(`e9_8Z~#6KE; zKE5=mC{lk0+}?W>$-gD}9{u<|8vS1Y+xKm1*{{~G-on2xRLg&>e*Zi8*{edP@M=W_ zPgSdba&nW}z3BpOO0HGwzcINk$t8ame&A`@7_g@&>tA zBmZ;dW%3&R`U!Fi72qk`$Gih%UtjAP>|z^F-JrhX9ht5XPLr40skc+H3wKfw-nA#>IRyl4wcDGx`2*zpEc(D8d9~bZGBFn;oL37IyT+zB7K#<@qJ1k$Z0r=34ec; zcOeI6^libmQ+x|PWfec@ik3Fn!iB2?+PigV`G6Bt^JEpVeWR_Y!~4H3F-|`4TmWDz9MxueU0`=fU}&rucU73M@ejf8S@Ccon|C zLzHrj;w0F+_j^}ErKpR>upap93H(wuO#B+-W6G$4doa&^#dl`?PggJSM2(KS%>K1X z`XtO6sG*{I#Qj!3BeqfQ_3{UDKKh&JG4YSZUycuH#J^6h_s5doOTLgieCGJfoZgPl zTr~5Lng2-sCi&Ck50cL$pHBX>{`^zPCzD@Iel7XM%~j8(+DwriZnJeiO06dJ(e4d@*3 zowhx!zJqV?N;PD9K8t2Zj2XdSRjB1S>X@JkG)Ccso{no2F+Wf4R{MVjS+iBm_Vv-O zQdE64zNH5OZV+d#l<$%+NjJJPdQbF+(SH2NI8GYLm5SG2k-RVY^W^Z%(oA{ghMC9c z?S`3+nStJx)eC&{%mZeUnZH#}@UO|ABwtMatNMXIOMWH!Pip(Wll*=1@5w*oCH^}3 z+vF?Bm-YWIsh{|nvKR~RpcirPI!j?bOb(I!Xi6NWzFL4NAy#9MRtsO zs|%Y_7oYCfrkXM&)>xH)k?UH=pZLsB-xSjq-vm&nYpBAbuEPGcL*~{Dzc=E$775ma z#?LoT`NoNn_?D*yCXyV?Cf`8MWm^MG!Fd?2vO%Z0d5t|Le@w{!I-I2m3OJk2?psD} z;-7tQ4n4prPV5ph#5UlIMoeB^0^AEMjM$wSG}YrLKe8#bom({k%%vA(gh zK_r|b66eri`BWEIP&VPvYt-glv7h5?RIsFFu3}pbHU%}YmMmwY88A{F6xZP@OvQV1 zeV=s`)rMWmpz;3{4B4&n zSkz=Us+HWTw(?~C|GDxW&Gh4FGkR_Gx#+TZExsncC;oVRiQ4`%lRJ{{PJUgjdS)g! z)18^joY32?GiPRMGp(8I%+Z+#&U{6G_HW5wC4Z^t;J>Jq|2{GQGy2tMlHb&iGV}Mz zKO}#rkCDtgbS75J@K5@6GV>SeCBB^eMe=jWYm>Xw4|J26n+d1CRiN4C`%B$3N7C8~Qz?@Y; zQLdP@lau2;trDlZ;=AEDu+J|2JwCtNC-$yk&4ZvzS)rmk#)>!5XwQo8aIo(z<6+7{ zKicI4ct2-DpHmmzKudf=-6i_{)94dT>v95(a~rfW6yNw;5$`PXUCA3{3BIqy;`bg* zoE&Fl8IPZlN~i&N zhLU$r%k`)RUr^yR6~KgELmXkr0}zo(ZXC9=t`!u$HSuOf+l0VYu|9Or2zpA(2 z*2w?6>Iwc>Z-1cqz@IAy`1j;r^nU-M_xzjWKE(k4kUVteVtteaedI?fhWLE)@#NlQ znn?1K@m+B#{^RKN(fR1o=%3}^S23AnKEK{8~ z4{%03-`&jHtA@IA9W_k{Bw52YeM0PzscPP-HKwyT&nEOLedg1ku^5QYn4jV$Dk!sD z>AwV%Qo$pSiOt^KUE}vkV1O=No6S%YDg*|(#NXV<|M%$GoWl0xI42|W&>q^Yeesz> zZJ2+nh@apbth0&XY?wQkhx_*(cuhKCPjEJeWQVpx=Wyr)-XXK}UB>QVyu$I-w*N}l zc$gs%GCi_s9jyDY#FVE3c;y;$Ztuo4Z+e_+%O}Gm>->oYbVg@Kr6)e2*Ab=Ni_iM0-7dLwpylvx9~nysqKfJ_bCaFzC^7_41<{S?`l{^wj9n(ee0+@q6Rnj31ah zQg4gNdUBO!=g&#roBXt9?Vna0|D_~WtbeJZfcY7j`8$pGf2KD4?~3eyM?d?+6Q-=EfxpVds@)0z|fv0{TiQjhRg`bdANpM5d;=9x##T&B1D%xI>l zXkt3knOU9rrkOuYejs^jQb;})Z^U0z6wr$*(R>s~UzE>kHt@6Z!}2EeXiw2-XWFS_ zM6d;RgD#_zwZ5-w<@xFZZV{imUV?2Mq6?noig};Nl|!~2 z>ShB}L^d~c9(|ov*AGWw zuF(Q~_dYmh;MM1^s`XnI(-5D>W0-bI&2Ev}ds}?k`U1M@0gSs}3A@)EdbuJ@pW(G7 z`nxJr-&|W$7vH;);T<+_?{naqAU~h_)8byM_;sJ7UnR#k{r?;>q8V^U30|Uy?;ix6 zq0a$cr>{K6CI;^@SRu04h%Ff@g(+mK;0$N{U9*uP_poZf33N(X@y(syf!3rt=Ujdj zR4~K~mI7nD&biqTpWru=Z0J$ClBjT!dz?`_zejFYJ9&{jkADpZ+@b$IRbIekpEt`# zHQ#SU&xw91s>Dx^KNQ~=A4#f7DVa-FlTos-9^j7TEy=r*wIHr;`DF4@%?o}>zy4$W zyCScCpVz-s>FKsfCX&pw}o98N6$E${w#AJo5l~K!(4NDW2P?(5GY} z6HZBv+JVQN5!t{vO!gj%?^9^OR`jU`oMtXyj@q^H5xeBNRv|vA(Y#EpU>8Q)IzIFA z5dHsZ6h#*QSM>cbF7RqagQiC{o+BUT&Xj`^wm^p6)xY%BwEw(bE1T(%XZm3iHBFa_ z-x4z$wqUk=W787;s}G_+#k;cs7Fr6P)hBIbLORSEv{{LvP4nF3d5^ zVc!Qc$D61DOR&;I&R~{Y!__Gj{6`~T(+Vt2gIc5GhB|qWdA5^ix~j0*8=SH&YLQQr zm&@xk2HvLDZ<{x6*Uz7oJ*dayd-&P^48>slOIezs22Tc#rR*)`2B~;f7Z`_S8e|A-o9VI`%(Sgk0epG+&=aLWTBYZ@^{-h##LE$?}*Rz%7xr(6cj04 zVo8<^Y?aeDBu-?x&XbUpxiX+ioqZ6xh0bV%O~WaB_TUV1k8|EYmowmOHQ@)g0+VQ# zutS}u0p_!bC3~SqY=_^lu8w{E%ga30Iwvnf270M}_c3HMzFDzJT-cL=_{OrncqhsV zy#Jb{!aOlk4t({j-+ZcVYu#WMLZUxH8b>TiL( z!S@RL{Ip{9mgG|K)mnp+>=TY7I}p{$HS9TNV9XSpUt@ z4@M7(Z&Bp``S_4V{vD0^S0vk-`)}yKJIRw20lX@CL-Jk8JJoW3R_*tf)#g8^w)^`U z^*^JL{a2Eo(P;lk&GA2`_Wnt={&y*6c&FO>C-pbplDvc7fcGaqq~CwHqJwuSy8oE^ zg%47LcPHGnNu?p#RHF<*_ioD{jFP*e~4cdSL0ub zZi~|D13s<@;7#huPNVoW^~fbm4Liil@S{|Y48fn%Eax67-_;Od2B0Og?vdv3L8mnU-Mh})r_%ej!2+70Qoyoa$?j0mO0)07=Q^zs?U%_X zCgL;3x|}fI_&tHQ_6@DJ*bcl@AVvq`oTI_t4P!+ zi}&syOm24nRN>jLz$esT=(2PV)$v+oG{URIk1nqvLl%%CqiOM#*Z2nTh2A~nQKS%b zM|G}=-FqaytL6;Z$3zN&X=+j18G}nl=*hebysNnCZh3>eQDglbYA3gAth|Z|pHEjb zaHsl!x69ASL!uj__eJ+bYw_FS-;IwYCp6xlNzN1-a6i@ zD*yjqd#z)Ptz!cc0=K)n11^`#r9(so6FbHpyU-B}u@zJlMNvesySroTjxolr(fPgJ z&$XSuzw?=yALntnr}jSk?7iOodcWTC0nP~*%c9>TnSN1n|2Q%IvwHN9B>5^?^LzE) z?Yb|Qg7ryS3a#ZVP6I zY>o794DNMLMFBg20w0~`Q|evp{E8L5Y95WEHzYDNSEEN8$s9!_YMi=SKrC1en_fFU zTb_$tf|b;HD#-4%u%en>?5D0GgH?z3SHn@X;rT_(XbT#>1)kPY*xT!{NljS39()$d z-%X$f)X5sNNv@Hhs2YoHcBl z*icLyoQ3=tCUj)#^To-)x!|Nmx`-Ywbmggpm8VtOLO7S}h)Al530u+#KC=H;qI+u6 zIXuJgBI@z)^RVSr%%e{zW-9840VD501s+5x{UHTJ zFEQ&|pJp`T{OlGqR$W?G=mcxhPBp6@ghKgaDNA7CHd_Sfr2DK5Cr z{pOmI6O+FtE&e?Jgb%XyJBEEFXLG{z&>tpA4;&bd4tvqPe^59poEgpyOC;m>E53hD zl6$LUf0ZP8xo)fV=o-Cy6@Tv{KKQGiTd&U<;n;9wI8`3R<;21gU#WOtxwOGe z+S`5ld#m>QWcVR`PkzBE`rj;5AZ@U%w85sCAEX~n&=IMR2@~r$lu=#d-Cs`Y9(C9 z*z;XSEw&M_z7U*Nt*cEVxj6T&j_OM_S1HcjtVvgN4S1ebx)ci18e=(Yx)Be=qV~cx z?#pMDN2F&VvR^K*b~Jy-a+TYVmoj>o4DD!HyvUMmnj{C0xEt)>D5^r1fgS@IunLbj z8#KCUnaOy>S;#~)ueF1t`Ts-ydlgJ>?^e*rRCn*LwQc`Z&m zb86G-O%ah@6FJk!CsWG=?8yI61xhH7&*Z0D#yM?K57ZEG6v9lAgAR(_%)c{5N3>!M z8LimS82ghdU7RsnijQBDqJSz~WTK5$qzP1qF-FXlkN;;`KCAWZ1!Kk>x0|GYww@iW zs9>f0$~7d%CJ!b9{2~5c|AWs7JB58DsdK~LlGc5|nE#}JuI3fHgoI)p{X_2$_>SAqi zmvq4OiVLonC-A6lH)~H8PrOA|;kU3!X1&b&;n%Q5CS<-3-$*|!kY}=4c*-BSdqk(O=qJyuFyrMA(Oa`x&>mn~%4c}MB_g7KXv&eUxi`~Fo$WSvf zRmaNDqaxUY-``D!VGP~H#Z(mHd>TdnbOitJrN5TEt$9mB$WxAYrLcMAQH3)f$Z{7W z>Ex<{J;6Ml{$>6qB-`bF`A{Xbel#*R2BX%=AIt&DV2Uoc` z)zFc-AtI@&@zE+=WR$JvidsiO%+N#~KY|#f(nZG3-zP_ul9?>!^Ch5*MzEh!W;j-` z7D~7#<;Z(c+KrW!VpFQg{g#pitfE#Gdk$+j56$?XBVmHCBFh)Mm^-mH?R0;%Qsp6Gijy==t%o z{l*1wy8fQ6`?=Bqr$`^1r#+l6xxYn`!Fk%#t;7?Lg}bE{R?5S8QQLnRK9>%8R`(wj z7knMw4^QiJr-z-x*5Mg{tS|A8DSG*vJ6+euCIhbvdU;L#T~pd%2-$jD4~CkZqu+dl zbmA^r@kMCKM)(q@FN;|FIE>L zvuhpevjXp-iM)L?TBixrQ5pCwv*{hwAKE~?HKB2um<3vgH`qaZZqFv`xV zTx310($((ZyE<93=j?Ol`0RtYS8Mt4Oncv4gXKyhR}vq=fSl zJ4XxHODldrOWNtzOuQ0#G52)GOZv~0f4nnuy?1om>AoB2-+kQ0?qTPWQOTm@mt>MZ z$3N%2;{AOk>xYJuWaW=l#DB2v`(w5LBI`d-(t4>R_YuH9t$Y3$)c~+RNGDl5nA9-MRu#*5ixF3S239zDV2Lsi@(R@Qn6x zy|%ko`}`0L;hR(yo(=DYx20DeQ>1W>zJI5%P54q;tIXe*Oig~!?-}zizVO(=uz}8! z)dB|6XO%BYw_6$q?Ep)ElPJ>6^QSA*{AClv+-PZgB9aT2dd5iH>wgtu8Lxf#J4yFQ>{O?ExLwpTHF8eqWMda;r zb?&B7NijV=C}mwJ#mlZDe#@cjww*H&Cve6rT}0T%JX`^pgkmy_ks+m?D_DfL77@L% z?lY2lOQDM_0!1!P6pl0JiqPBT_*V64EulWmE7;tMTy#agi+uqVWI{{H7nY_Oj^8Jp z=A?Ox*p(Q0igG!E{4|zn0sCoOe?8=O`rHip{O9O)u-3y&dHypb`xBYfyN}|5`R*3? zt}9OVOm0qw_@n*Zew|PdW=k%uJO5zmffMQ8GseD?CAY`wm187z*DHFzj0pcGN&Xd* ze3RSd*!>42nJeWBJf=wC$?%Gv-KQXeD(tcITg%QGbr#lJ-sGHP)5#{B9K${SRd2nJ$$N^ zNIhaz+Nin}VlRymEOz(Tg34=mksqcE+Y-AlBO1G#BA706xn-b{+hG3bVjUEd>mCIP&L*Z=R6iaDhd$y*oAlkx8XU=*jy(sR#1$>{ zEsfH7XhTkhkUeTZPxRvjZ=mCv_&?PEah`ED$2$T^uEEETx+wNzWsw`*g7~-@yI#cV z&Zb&W3eIXoinQs$-_OO@Hm|0iUzzRV?B!fE#c=vH>hU6Kk-4hWb1zFhphlvu*!5HE zB9nOR*y~Phyh&&WS(Pd*a4r?$$op8&5#*ttEgzpvjV0=WQoNQLs;s$0hmrlaHN}%x zV6|(~{ACf^ro_dmvbE^&To?NVbEyi9KtC0xSfSYYZx+ltU&qVR?<3oPill!RCP*1S zR=;%Y9_|qNz~?IRf5B~>%t#g_ZzlEr4F8TV57T6auab10DycXA?j!N`PgU$bpC10x zWvMTe)SArSB00Z4TrH_xA$h$^+gT*Pn##Xr@E(^oxLb01k>qrl_IbW!eZKxK20?I@ zwlbgK3c3TW9&o$%YFg!L{WXlyL)zPY(jRy0(WBbqqtXM9ujG?W!f2PjCe$oS$;Tz99l_tFXDi`~y8`I94 zVzMcvphoSJ^>~lBHhJY$Lcgk7tulO%w#t&ax~FjXNpy~t@>Q#fE-O-V;s_)Pj^fX+c&W4hSPyK zh3L3aexT_dn+lV~``tvSrDWQ3(~c+Op`2-!_p*X2JA_WForW5JA!J6`=Z3h z{BbU*%TX|M7YEG+v`o(y>G2Zn?TWBa`rvkLf1i$JMe0r53v%c=MH3I{^_8Fp zZ_#%yS0u4(7!Y3e2l;;{mnV(M!?I`%DT6_9Ye@%ely+V=kXtH7V&}NSO7Kc&9DI+p$(vK^)zIhR(rr9*32W-2kzRYdBs0 zo$!s>+GwGhZ3{2=@4%zBehHhAGLAfF3H9+V^xY^Ixdd%WNyGn8{)bWZHc6O9 z@6iCHyc3%`fUHF=UU}@uGz*#S;-ro$svCA@hu|qUavrll`VS*#I5F)L$mZ&e#&^%< zoK^8HHL!vg(IF9iy+RkKbhVIiDZ#(C>t)r4STl@zBn!@jE;OcnIycQLG~f}Aq%*0W zNT8V9K^yxjW>rN-p6F9pe~wMDn8>WXofMJo?q(5{wz>KgD^i+vA2i_U=WiJYnf#j6D)#@( zj|?;Asb3|Dyhjp#spRzRaFRTLVPKbq zpO9WyrT?Fm2Vm8Kl`w*yPt?Cyk1x-4bEn?Dk#AorpQI=J)8F97_>YrAlMRyV-JUwz88m=*8)8Rm zL0x4LAzL14yv~C02py#J(?SZ%>`yMoF8#unA)LV>}IaZ@;v6-dRh9l;- zBhB+Qp@)ZIL+jF9Ko!1iDS07d;prvwT~8NB%-=@*SuXNlK|Qw@rl4l}Tic1+tFb|b z+wTS0yBWFjW<2|9VnxeWj3xg+1ipweW`cJS+1u=}4fWa#j@Q;#hl{v!V-XpJ=U{lV zTI}p_5C;D{96-UpjBY*+PYB4yYU~WkFiItEYCK$F;0Z z(L43vKgy{{#K~PbDXy~?WR`U+j>P^n;Pp3hwR$A)#<{(Nq<^L?(a!q2GgEk`QT2^% zFU3r)Zon@wEi~M1lXke3x;UMzkeos68I0@6vNyBbsq+2zAivbX_3z=-{_6_jpt?`vhzsx9WBC{?F6a^JV2N$A7c5%fqWiRD0FhtJBGOlxT8qYPP zQDQ_67c(8KoV{UCoL=&2rTYFBut6Qvqj%S{d?M3` za_Yy<dMKoR8s+s6T9dq0d~?bS*zTAVasXt6H&c_+#9 zKY+Y*fT;zUf#bb?# zpg8ZU3ns`CkUP!f4=Y_{2A|>L{DMZX11L_B8h(Kh;_nR%;qX zeqaQVzyv;DOMR(<=|P4D$Yw^_M7oQ*{zr^pTZ6TzO>vkNu;mx?dn)jGvr-I=X@F+x zBZgxtpkCKP=A?*BSfQ?Q#QATX&iu(GdytiO^EJZPkJZ@-t!Jo2J*g$rf0IZk+s6^mkNR9Vt$u{$>|@B5L{lBV6PM%W|;`InD(#-8o$` z|3caL4pwt5HIK<^}F9_Yc>fT#Ia)HsOSfst)F1>KOUR?z?_&W4~RTx*xn|NN{#Vy+3>hKtG!Ua0c z1=3C@gb5*phyAI3q&$FW$*=AT>D6}fUR%NdUO*n%bfYnz^rgCXU)g`-5S~SDuaelQ zgPLGHexl(|MmFrquUbU`H+5A3}!TP-$Ioy0l@VBCl*S8Gw;=A@p%99n=P^S<@4-l@>c%w_uzE zG+Eyr`$A`GUz_N=x8o=+SGKc0F_86P{_Kvf23fH@eAEkVWUl@fy+E^EDN9BbS{ zg{I2IDS-9F8kN-bDv{~}a8=FN@A5Qf(1cG`n)=!KE;0a=q?NclIzns7H#DK4%BU_F z1I2JY8S5?GRCh+XNwUC)D?+tNyM1IFYQQ5{reK<`pv7+EwB~H?o@HP*=bRLhO)g3i zM%5g3{KaKd9P?amYAJf%3G#n;2CrPpZ?x>>Oy>Re%H|y;t9PS&&*jMaKa_0i4^-s* zo1ZADwLJUF;W^pv8zp(mBwvf<_0N-qHPnt-ZF_Bjo*T~pI(_b8N#jy|%5E1)7FTH> zH=!fWlSE%d7vR;z2!`svQP%xR>6X=a_BU#q6|&`bqDfZh)vNVwH|hD^;VH!q_H8%d z{og^4;NALrhxT)abisZ4<|VpaBoAO-I3^qtwhJS|hyGIE?|)8CP6j0Rxf69Z%@^DT zzrTt&%_>4;$e53zLNY@>(w}uTcF@@#O|)E#CXcg~%~LSmt+A|&au+9m)UtBMz_}Z% zPIcI+Ch~n%)X-b-_=?kdVhPqG?rC(I-?nKWc~r3aiM0o!eTq`8Q%4T2hhwUyK5pJ= zH(o;vS;l_+O7r`trJ2Sq;(|_m==L;cQ4jNf><}IX&Y+A*u#x@LScW2dO_$c1RU(Ga z?cA!hVjgj?J~JL1V9tMC1C-+n*Ae$L63c9hHMQt{B-tv{jBPGXVyJMD7by!(-cBVo z3-o*oxl)VKx28MF`uetEPJEoCT?)ppnLJ+wh`b6cav}NDIQ^rH8gLQy&srCGd`gM8 zOX%&fs~#DHVsB?TmOdZfpb33bOZLHHf>FeEm1K?b;9Sc|D?Ls4{JTps&FeSo-cJ_M zR@@M#Gndk-KTaCLX4_7eyjG>t4Pu8w8P}(Y+F)gRR!Y-sMFoCQmvqYU?p(JUYp$4S z5-o5>_G{Je4DZJwZk}7=)=6e0*CrX?=NJ3$ePcLG_VjsKSgW%?hg_Q+Ul7icj9sq( zPXXz(49mVS^$(VT)p>x=EtdSQ1{rWM7{H75=^OC&O~x&o_lQ2d7`?GnzWifk2CTlf zN}sY!-gT1l)kF<bQZRU1vj#I)VVkt-6|}Tn1DDId7py@I9O+F7LpWaNk*o{I`UG@?)}v)7uFfcL#oFG1%b-*thDzah9hMNc1vt zs9eQ(q?X9B9xGD^I&fxM{~t}f(SuE^CBxWAo~NB0xFHaxP}eLb9?6G4poTnu>|rj` zS!looSg-8o}qTLu>LumC(~R5 z=};J?UsvlQH{P~XQaU&X+rYn5iuN9$cMKI7=eXsejmuM%e}#(^@nW3chR;*UyO#AI z&Gs?78++_yUvLrEEY|lU`YQHqHFDK|=bo&#*vVdP^b2=u;Qg83d;dzO?fmK9hxkP|*K2bRh+l5~G~GrS==ds-2|9pv4X5V0>q z)+~R2y5!uv_dBrvH{r2gr^n0b=(Uc&RkHQxVZ*OiJYbf5Ie9$G2CgJ`XZ<~^&<0k^ ze@yp>(Ge#9PfGvXgLm+-j^aLPg)8YXdW`;{6<~rd)OT9MaWUeibXZnre`cKy0i-|d67QxosSp98E=R%Aj zwjB;WX*4oz2*D1##YtGg5%m4{>pSY`#3^Er(cc`0CH`+u28=vd16&#GRW(@cLcIL~ zESqtZj%3roLGv7QBicpfYTCtk*@ZjS93wnTywD(MJ<qQJx{g%X+;;WzzF!TK79{f{3H6*?Yfzd|AaKa9g0D$8t?$GFQrakUW1{I ztaISFaCkT>oE#38M{=$n?HP8{tv^(Sf#H2cGH3b<|B@nr4U^UGRLQjUJdCHm-8gQo z_iq-t5St%ttl<-xhj^O2rn!_N@#<_ABTuu=<0=5S7S(JJCiKmHiH8jI|+$71ZTAi0Mi|wzt4W zYSpB1E>85DNQ_WQWupvFwiZU`dN2X~pjWfdEA9BbHDoYHr!i|06^TMU-=2PvJjrA+ zk&S&*j<%nOB{e_jzbXIuoa5Y7I*ZVy5!Gy6JVU8e$NHKvxkav9ljhOzyjd^*P@T^~ z)c8u_c&oyW+JuIY+NOZqK@<773KwVdWl=MaGrPCcwgt#=AvoV$a5|-2fg(J!S|W~! z`YCm>PrDE)El&OaMmjml$Oeu=GAmLnN3)B};^kf`nTpJ`Ra8F;h?sKl%lKQqVNtS-;gk+`pTgnG_|jx~pZ?t=n;$&ge|Ct)>ko>iJCh06P&AP1WNW ziU8)jqurnMnF(O0o2UqMz`|RCe^*OgtqqKI4f0kG<|6Wibfj3pR^o-?lzqH0jX2BG zykP@X+9tF{3n-R2sil?cK1f%0f^2X*c+whHdk5<>GLiSYc5tFY=*zKcQ6Ca*sDrqw zEAeqGBQPFsu>&^BiNwgm;Q49*2h_)J%XRC!JoH&NI8~blw>3y8vy+pl7RQLYR=;Y> ze^LGikiUz(2&2(Zg=r-<_EDBe3k~JWjYiuI(s4zWmVEGfUF2G7$Oz`72)U8i>M>ME zMsm*~>Z?eRz0nh>BEM%@&7q)nD*0PURF%tY)G{KcSZ%Mz`Zprg#o%#rxit~-#j1RJ zT2+jB#Bx`f<`|3I?~Fb<9P1vE$Gvrq+lVM4uS|?1vZ;cWrC1Zo4$q=Ow;L<1h_z8n z3>cAqb^NNxIX;}Kpy9msbBm<`tlBhF+uq~8aGNC!$qvc91rna$VNAd)0 zKi19jkTi~U{@*EWvWWhmGng87x@`RsituNL*3hM6ogHR`v7s_lgqF}4Izvy$3!nIp z{M-I+f1^Lk@9b;+*U6mon=XdU?|EJrrEu^#=3CRR@eK5sXXN(+{{ zj~+p*h8eQVWOxwSjLCSxt?-*Pf>f(aJ4MF3IQ6Q7`QldDw9ZlUya$k_n}FZ&-{S-= z2j6d#S#xv+8f34_u%DJwwMUWfzlQm(QA0*HtnxI|okctl{re*7J28_V=kFBbb2kwu z7lYo8vtC9LzgMORtn9Rcn+KB8e4;#Jq;05pM!wHlKG8&6QsN>9PgaUYiqm>($SAjx zl`KjtG-WB)w+MS4YZz1Ifgeh?uQJ8|{yue}n7tL^W0d17%#bV}CS9=|QD$A5KQ1KC zSd1Mh2OVm>mN}q<#=4{2_3~gRYgOFj{_aL3drH!uPd-V$mye(COMRBlNGjI%+xQW_ z#E+KP&#%gBcwV2oi7fxKlH~hj$)DEi?}Tq*`~5`sujOI9B@Oeb^ucqwzoDCH z2xI?J3*8i|qXYvj2UO`*EQ+43pj8AbjN?^3VE* z{l)$izn^c@?+yM=oq^4hJKaK^N5lE=EBT+J|98~?d%4|pj?Md@O+Ivnw8PHw&Q7IM zVvf#w7x;|vpugHvD?BR20!MbGdQgIfDd_+)+m77VgS4$CvaFy!otxH_a)|6|z#rtX zO3TwpzJ=&5uLezpg7R1Na0gxZ3w z{VCdGEjp`_9GR{B$b1mFhjT&rkD&@_Yk3OQ(y?$5#W==R{AjWh7E}Cpq`#HiLKB|V z);fZTpeo|L-Z+D`%EeCn4i~5D~zYURBL}@lr zA*&{$GWjeZ251LEmrJZaB<<#pb#j{#9l6FD&?pVWcXcW9H%9D5F6ys1F{qS&yZW>` zWM{RQ+Cbzch*i5jMVRwsSsIYyG8daMRHfNFqxVBA$dqrZQZ`RF)#Qaw~N~+#r^L-*gXc9DKEQI%SCT}0yDE_R_+qX*`~G`Q7& zMFYg?sAbeOim6x^ktHp~&&r}^-pu)Kps#5Jzq627WH7q61nz@+GV!z)V6l;fU`jamT=|T zSY^57j*7rI*5O-}koW6$=eoz;z3yq3o!pdc;(PrGeyM-jfA9a{fABxbzqi=9@fna$ZU}LB?Nf^KZiARH;(^bWbNP6yYKS< zH%#`hIX%DXJ+s~)N?UvvlFT=f<2NMlFG-4*Q|DhS9q_ok2FvtWHQ{RVcorR4rte-! z`T2?$o`Csh1wB1CfdRB$fJMmvQmPJD(JNqCz-6G3u9bgqhWvot6$^|FCE+*!iuBoE z{1o5sJAHxQ%6}^jxFlJc9G(;>8zrB(tK0#S|D*K(fv}$c86M<4r3+>-4Shebm(%sy ziHgyVaL34Jut?wX^SxBddtu$ICpS|INK|d9pv+R@hG~`BIdnM0+rgX-_S%f zFa}A@;ybs)hl#wUCEy7gV6f{Z|Im%kYMHJ{u7Mtb?dT;gMG~U#S%H5$EzL3y{IAIW z?>YEt`gx2kXCU~>MzR4GuM9@!O+WS1B^|wHvydC4jGb|AS3X_1#^Tw6mpl}vq?k1u znfCNHrM(|{Xpsi&brZF^-!pmDX-Ce`6pz$ML>A+PPS8+UF0zouewzw1uhm@7i2STb znLJ~}-+*o@XRoF^w|6JW=5*st6!R@*WE^YU?>yphLQo6njqPOncK`#_n{s)SQ6H*B z{%g~&rXn;}mF(2T?n6cTqZRRP=1=ku_`mrzLP40QIC-*S<7txbIiWOcDjo2uzso=9 z-}ArvKZMN`HFxL}JISBEOp*Gp^8UBXteg2E{4=bX`KO|RzlTgF$^68ezKVQ@7E#SRjkkwJn^wy)5z5rar==EHgfvLiOTuNq}2LdQQ%;PxiyOI30v5^1g(jU7}^RUp> zc)w*jlFi)~;Qh;CT{OKg1Z_E-hegpnpCHkov{Za4YBbAbAlpeo8s}6 ze?z|VEB+h5QOFNSij8ka7Z2Ae3 z-ZS-gVK^}yFF7`Z;X=K0rjGe2@J43kFVG`n7rTm{Bhv!c(V2V$vqI0&mUEaFUJVD( zor-Lx`w~CGf1NB&{*s)Q9G@JT?2@!3`N=xTEABRTp>)7GZlOC*e-D$LKS93#c9L=9 z0@_KMV1He!@=B=@=F+KOiuSBcJMn7h@QT;1o@#(q4`MwqmupvqPR!vL zN1*wKlP{@B(L)7vBQ&P-!L!LQRDqKm3Yu#hG8~i0+e-dll7H|t9zv0%bh51U@v_(tQu+TWY?4_=w@ou^%j&;MH2;LG z?E>w0PUx1ts0mf_D4L~9DvUv+y;kDk=N|DbQm4cXEJGZbCSg-h%V zy#FJm0TzVQ=qE5d@q8WIar*xxc?$C-`Nj);tX?@O#TOdKurY%zkhMQf?^)mQavhOz z4c?>p;9~82roLrTXboB6JH z-3oWVyG|P51bO=h!;E^o+eh*~S9j~fK24vvSl7)E!Bzp7Oza%-gX38>J>&)=FQ3_j zHe&h?n3q~pBzqg{Dc0?aK=zDI@q@)6^kZJx@Hnw=Er*VkZg9#GH(E<4$aohgjufQc z<9N_~eUjBNe7*z!cno-k3B-?eifhL4S|9y@V{^^S>YeZC&QsDs~PXJ-I-_fcup!K&GD zx~BE{6oMGep_-RP3|&LcARC-ToUu`rR$H3E=38_$0v@pr6Od=f^E_s;xclQrEU<2Dx0`{u+CmK`IH9y znqfo{MdTw2*>8S|2#t)hlgR{I>^4&?u!pr$;$n|coD^;GNUv7!CvL~&%j8r=@`uZZ zK95eE%jGFsSH2;2@09%8oDE~~7#n_7X-<$L^5{ycxBzt_L& zfAAYh{+r~Po9yos_LlwsGmL?!(Gg(N11vLekEHihSVb<9^*>3zgjM*@qC@yt=?RM# z%<`Y6_x>#XwI5t$7t=p*9rrt>2NvqR9p&9L>(|tUe@Opa?6>n<`L~jrl0~|`k!TY(oxMl82c?6dA-^cAqZD4!Z{w3}v#Q+D&8jfRL zkoEucP!qJZ(UW=sb=+&P=y8>H^Ikrco#@5Jwf*~SmSQsP#qjRby2#W&8XUkjS`|I$ znK~C4L~2rN)y@RhI2+a^(on$@;ENfH*J$fy5?#JMaAEap%@`V>4Mq*KUftyQo3vW% z@r-AK95CBzedp7`x^;qcH#9;Y5vSz^Cm<`8={FerP!au)|7q-B0?$`2xwFVuT>+Ng ztn4Tkd6ly0ZLP=b?kMU#h$!12=h?EUv zn!CbnD*M*x-|~Be+Y}pH=FB>1te56oF#8vS*fS2@3nb@N;R8wT5`Vk@-ftq`JYTQO zk#z1SNxMlAz~kD>ZE$L>(AN8esi7gP5uT7uy-3o%x9{`)x=r;HeV2S}%dx$he4cFR zNBUA}fP?)d+VkuFH@`(FmF3@FI%k1A`T6+$=jdq8Wn##+^#9(@_gMFy;d?C0XP*Cg zWciE_>}2AD)Ai}gCH05Nf0!#N-$josqB)!1;p;#mU82t(pm*971B?L&aI-Yi7$5xG z$b2b^uVcUmPotO4uKpPMVOm+6jd+lw$v`!ysDa20-$N%s9!Rq06g^&wci&6o+0QDp z?DA9)B9^V&F2!&crg+0T@BrN@OJ_NDcp}*d+p?c`CZ#hVcF;Pr=y$5V*E~zhB=^%D zWLb&^I*kUBg=ioPJwwy$yncyJPmOs zSuLJY&@hea90#(Ee73i0^LhNeH!2jP)7HKxudmOP+ zDL#j7v#ab=LGpHTfp3*yRTr+tH2amck%uDdnfn%!1^yn zcP*j&_ey$+7U(xv9B>-*0S?zO?I2%dKWTv@bcENTL#%3Wu3kGR?5aqnP7%Q1uyJ@# zI&L2w^I-p5GQf}aQ~dh=^kjO{olHsgS5$CrvTt%oGA}tQ*(d2rijvx7Q1ZFE(_JI0 ze>!|1M@p8Cm45w;G{JtligRGfZY6)#3v#=e%*`k&aif{))r!B|K+dNZMz?p24WtZI4Ze{BNC9vD>gojl>5HcqBW>LU++uFb+F0 zioABT{1e!!GR69|!4T5IRId`Pu3dC%1vM9KOQWQG3UfQhLJKOh(HyMq{@4BgNM_Nj&3N+tTW zgzQ5(TA&yos*c#Mff{WASGr2)@*sDBR*u>6wp80?r4j!~v_SJ|&r$?GDh!c-{Iy?SQc@h+Lx(KYA**#dQI;bj&B(_ zqFW`e*2VJx^THm28}Q-q6y3r%fhD>UHn1i13|^<-bF%hfdgCwpB}Yrn50tk0lYWc& z5!b^NbeVqJF*^Qz0Fpp$zvXWBd&&oB^gH^){A~ZV?Ek*W!O3Zg z2Og2m`ZRe$p26G6{mJrVmF`DNHxwj8k{{jUZmC-+nK$(1S#E(l+s$`>V$wtnofP9? z*o~6a!Gx7@Aa#mell`&Caskmp2|8pf*)OZUjl)AM zCX3uoFI#iERcp%LHU=GF9F7)~Y^QC@>7pCUl)p}`m|0+CEU&(sR*+>Vdch3!!yVWL zC$vqfo(htoAAYbdJcc>c0h{%HCo+`{D_RH9z$~yh7T^9S69J5qcnFBsQglx(HT-RK zg`v#FKGACOksYuTZ4X!X6m)qjbKd93@*nSB zb$ciBz$GU+q8iYlUIjbAOnw{o2eRtNtA?$vhQ4zdI!L_cPP$0XRb+;~Sr)FUb0hpGaSQ zNFIXq^xs6!ka7H8MSbvM{W3!Wp9L!5Mji1Dvj6Al`3;H@mP*GR7$%0IuuWJuyyb7z z(Vs8LKgyr&&+sk&q2!e0>g3Mk?&Qhj!(_0Iy3*$Qk~gpj`QK3zVp9{QA*U9fbr7i;S6Cl>T;0^+tVT6D<=L}Jb{}4Tsf%o5 zU98hFlCb8~a&%(F>$u`$xy{sm2kMn^#1?g|rjitYS_VF(6>MHN2p`K$#!0=6WFSnE zjoaNS*-=|{QK_D;l{gOGfhNAagAS2u5QOG8SdY9R&c>q2y3q^G%nYlNezDa!Q{QJA zX|k(LJKp}U@?YoTB(xH&b<~j!X?KrdeQc6W7k*C;)^b~Yn@w=b1I<%M3|2|RUqP%L znYMDNyf=WbC?UI^%hic>vWOLk+#-c^JLiD;i4&SSsHjJ7uHSiIi_+>#CFeG>6Ex7J z&`f2ej9OwI(^=ZUWi-$`Xe{u%$#*=(?M#Qcc^)}wXG1;6z&zwUPMyp`{NL<<|;|n9Lewx{tf?EdHy&0Yy2zzQ~#O& zyZ_ifCXKMjpDu|y!0#ffIzxJ3mT&MA^xC!l8NX)8ge^n9?0wcQvzsk?k^S$(HnIfFmlPi+h(g7d4``vl&7M{le&M}CfePz1)~IfK27Vy161+zcJqsiE5cbje!}_`*8Y zU@cxpDbt25ikL+|_XO5@H|U>QCOR0e%nWclouCOjWIOf-@z;ibZ`q{DF7m*Qal2~^ z%R`Tsr@Av0PQx2bL}QI-R%R0nM5SabOlORxUR4Qe(*I5R$AWsy10`Kd{GA7Cxrt1g z>9g3W7o+zkd?CX>TkT>!_ea>%3e!%xGP3W{t`{KXMX&)Df(qCiWR779^HOA94A=HEs;epP9V8+)?oLo9BNnv9->&T3Tk^cAUVX}6;TQN5BsKH&{|Wvt{sP@i z`j_jyb;2fL&9HU|iZH(L-}-<0MEhzBow~Kj-3D-TG+z2e{UZ~O23=HWN#x7Ylu{!V|P zKib#JA9ymEmyAy~N}hC=yDQvsccZkxZ16#|=v9jh;k|IF_2b3%VUv51v~kQ7>7wRe z2Nz{MNFD1wHdc@x_{YZMF;v4s(8WI5sAd@!sg*3l7`~-Naz2S#Vm;MLIk7V-}f z`8q^eU?{yWc2;x1?$?m%Y@|ZJWs3N*{Q5xfH0H;TaOo^VaQ-9F5v6GH0&u(q{9@z# zZzK-SM#nUh=WnK$wgFsU3)-WOj7hhP99(tyN9H?Cm7Org-M#4ZXeLivL;j>5{XNu0 zp0R3h9>pLs3wc~kKEZMrL%|J<Vp_1T*k_5|$pD5Wj-tG$}5lf^aY%ZU1?w!m0y$d9XXG$wv4=dlL@*R$lzrJ%A z7siBHveSz2t{uY0|U*(rd=9l^(P=gD?I;ck3DY zHM}3*3SUUh|BA%FrB^=>KkEK-SS#}z9SYxsf9U>+{GfZ`A-`F_?kJs)F=74inT~jt z-`Ibd{F3DO$?{nC@`vjeyyO4jw~&S#E^nt=-q5&E8=4dwwSpu3RME`7zExV_*<>Gi z0^hj@-SzHjc>zc2DolpKr;BKL3{(4B(9ly^1-(pfXvSVvk=q~VI$&}eMaQ0@cP7z& zGl?94Ap@uB(|w@JZ6$3l`LcTQL~?nfkl$TliW$fEHsG(ek&$XgimcPGgWmnQvf@^$ z7_H;n1zlxwK3R5Sjgi(E##5I1z;bC?&gecJ85n?BRYy0r}VEWOjrt%r!gJZqat za0pX}Bi8NzBL6KevJSO@kgrW=Rh5z1&Z8@*iwsyJ=zq(NZH<;I#RhlLdr|7P!Vk!D zrD?T(07#$FRmA)qoc}ljq#V@c_GurU4%}s7=50$K9PFiA~^dN(|dc8qWN6K)ay$J ztQV5-tE~EOlJk!xS@-(qWk>IlC4JZbCJpcslK-h}e-gg;nJ_49p>5kjAO6N3;c&$u z#trZs=;4>(04ttD(7-js*mrwG5%_si~|FK_=$#RTgpPMM%{ zwv+su9mAh=bSK~q84~F*`A%(N+pt!+Ur|AhbifJ8*2&xMMR%*a)SbvA1*@F(;A>B& zH^4mce(-ctK#_DJndX7_;|GkFEVh7n8%tC$6|XvG>sz#1#?foniKj4L&-+~!>@QR4 z4W10nua8QyMVZ^Px;n`3Rge!Jt@o_MaeM5%u}1IZ4wfF6u4mToygxohvG%ha(?9IE zEhgAg-)vckJ|;o7P@yOQnXnUCi7b$4&Gg8OLT+rj`arT=-Tx>1UqR--9>%K<`ftlP zGquzntC-JPM4r8k{^nZZf&wDt9OkHXrdD~lL~iG6)t<%uJjwkfvgX&pigkL*%eP#&hb2L8z^Y?hd-q6hn1^s3Rk`JG z>D?fEY%%w%`hO+3{PVQui=+?skt}qCX<@QrgK3KCdnL`?vXw<)W5xUL`zPf2zo*;h zvZ-&80UQ>xLW8#1J?yKkPsHQDO~>%6WH@Bj&-^Hf{w4e&vv%eeJqnq1_1A3q4`Hj! z#+i(ydMmxRz8$du9>}#(<&e)#F;K z@v)<$1-my++f4&o*oAk{0srQBFo@eB|0V;wQhlGHZTq#trlB9^G8epx8o+FNn5XOS zF7z_*?T!FDex&wdy^aU!TgDQd&XSGVp33BGItQ%6)B?hJ8na}^(O)#0D4>eGV-cQ7 z8MwM>u7rZZ4FSKcF@aB$1lb0g{#OnHXc)Sn62#ybJfC_HMX?vZHmwzw zqIqInt^ux*$mA9)kfmfVTbZJ_n>$+P_)y9J+>}{nM|v*|sXPw$MXd9TU?u!{S`ik@GVJYFdoU#R!3kN-K{UWAk9T{>`=!SQ#b zJb$aT8+zaJ?&s=0pNiZ;vYS)GBzg6lD=zp!mVOOM*>8%YN9mn|^{HjD@(;@&e?bzy zc4iC7^`OkiOm3zuGbS@CQ;=!MH0l4sOiiXFlam>e$=7=$Gu4^;Ou62#$qd%#x6uDX z^mo(D=JEsnkl9RH;8$7s@1-ez3`yqeVEVv(ho7YlUzhd&tA5A((se(D4YgIsyrpw- zY}iG9z;FIBf3qT$yZnptP(Jd5W#cbmV$sFmh;4Ss{W=3SrQiv96UKe;mCo5hX^@=o ziejBH{)J>-(w+R`UUhf5#ftHclBc&H5y4LIh3pKc&{X}u9X@wIeY%tI6k?Px0iQl% z`Aqt4&Py-&P{Rt$V&aSSAML9BnMbiVS)V^^W$lE$*;T8oUwbx=LaPYv4x)TFu>Iq; zuR~!pI@Zn8Hb?6C=Ew&)L9dV3=Z*Wwf*}avM4w#x3iIe4Xr`865lJ?< zqZ0HfsY}WBi<-7!Z z-07fY&&JGsGx}St;^FFHUahk>(bn?EX)&7e7@2A3}aBvz1 zXaSSItrPD~c=(K?d!=;7Qt6w+>BXNV8`-2=hi+YxsdM$&7bTVdkab>17JNh5@DY;j zEXnlfOs8bKMH*m2W`|5qrZLl|dxP#Rdc9ANN;2*GOi!jtk2|Cx+O<_Snq#o+|8HT< z%m$L`wKD&Z{QoQ|UsGD)@A4&nmQMIu7T+R@xAga0y|ZyxqQ_It-m=GJy4{|EbDf-barc^*6$#mqBmAu{R#C)EVHuLe)O5jm?N z9*A>*YdC|QFy(H}Ot&f|H^%v9Rfm&D81CY?YKbg5Tx1z)C-&;5_SpyuX|`MHh9@hMe1C`Ukv+dlviuO!xK3BpdN}^S zb;w-^TJ9Wq0cV1pTLk9U=5gLHnSKSvjwhI;`=H)68+SW7!N|RPH+(!F%96gO&l&gj zBa#Q30$^G7XLS2OHt~t@wB+j{G{Hl}8MiYH^knjh#?o(GUoU7cKgl|;D+|1(Jap?L z{xxixsmOFos(Uldvirr7>)K4KZuYn#Q>u5HS?w8~oaD6K6i58C^elKy|nUcV(j=kJpKujL`wr`FE=EPvoWI0X)qx3aaQ zc#W`5*en!=qnSAJ3LHeYFsI-;m`7~h=p%5HzDic%ALJiil%AcXtvchTL@o0DMR=p&Nv#A@seZf`Pi_*`u@Tkp?y z2k3Sp`#Dx?>TG!#7wFNM(g2sbtM&X$eeyWHZ@lrwPq4_HAq{bXTjH+KGn?-|pKm@z zF^WwzJ6zWPQoVMZK69#Mc@L_Wg)sb1hIw+NEY3{5cd}OSXg%trzo`=x;8eJUO6W6d zrea>1My93Yz@|wjb^M$1-%3x+mM%^xDnoWF>Ai_~x&}IutFWAn^g53q3s#J!EKbot zhKiaF|7t4|z6CRIMiTw!q*$6-y8El)*U7<($N5<~(i%ftVB~!pbGBz$#8QVrt7^kF8@4>d#B@^E{_bOUM6$78D2uhfR^)9I(w_TPe17Pfh^&humV4$&wmi!(WgIzz579U`;EKvMeXAiy=(coPv8XlUR!^s z*EY&*BaN`8BKxiMXzR?-%rHILL_Yp7S@$h;&yufSkjaxisFKG}Ec-uJ+F-Oa!Bpvj zNqTj#Uf)(yZ+lr++pH(uvYujt^)f%{TfT>ps+jz`9^2*;xIR? z6)x~O@&i^R$0w7Mk;%Hr-`#WWes`l=?(TLsy9M$FuX7hk3;e~MFI#+!q|Q78lfE5b z6q+XcIaiP8(7m^ZB=r#ak4H;W9IEXuk@Q~fR!ZI%>wcMJ{BAwFM|$QycZ*)R&E2cN z_v)1g^v*TzDfg~>OGogEdr7aorvLAgXL6DB$jSHs#(Q+K_PSKZvJ*8j^YruSGO8t} zI7FW?uX{gzcADOw4Nl2y<#00K1ysTs=xMA1TRcg>X0~40#;s@kV*gh3-w2=GNUGbh zb7^#H<7>#uS${+9q$*2s&W$M&vK91A9o$@75QQ5K%1{y6DIbvGrnaJsVgwb$*iT=8 zEakv)T1&@JA&9I!-NAE#2w5P7xVbZWO z!3DPC&&63LE%bD?;0s29^z0yWWD^`GNo%i{yqqlb zf7GhGM$-Butk^4I(l`k=+%xE$u?|`5!k-T}zfJ8lCf*yFqIaWKxnXTqYc*e^SMFn) z_9|^>d4b!QrT3vM+!u;?zmXJuA*udCvb3q}?MCvh*Ok|8Tt8n(vVJ5YeoB)6rJk)L zU;JlD&(qQ*E8zXG7{MlXe4zV7aQ>{;qgTnveGli~2W0Pmlw5lG@M}wc6G`j(8Osn1 zkTx)X;SbpM0n!BZ@(+3y4YbN<7$qNIk{)-+KNzGfHjozCIFo3*;W|#Iy?w9SkFxw$ zIrxXPz*_p$I`R!%=4)6>?$B?Z7j_T*p*ggLiQ&&WBUkJ9oAA1B>< zsdVgxde^plOkU5MIyYbH41Fk1VOIFSpX$f?P5j%*HPQmxCzZ+IWTPaLgye7TarcO1 z@;-N`ZY!h{&X-2GRJQm;GQ`I*@5y?M_QKllr*|&J&Ku77GD-9U+U_~`s(VO}o^y}6 z*WG8x`1|gA_lx_+{V~at=dot8S+Yj5X)-+7IvJ9bBo#?VQk--rGm@fYK=M!bmGr?) z@&`-E;OQ7FZF8@_K_t;PdE_E`ioFGZ_c^l!7whLitqPnm$a(!6^e z28L& z>Y+O7|2?4ZCR2;sPgl|A=N(4IbsVu#HP*i+?Z9k$vr$9(4)roB~@Q>>>y zIX9i*-kr{8G=$$&U5yoPY?9@_@dwH$eNF4`3HbDGl6^WI?z>YY{pZN*zEtblQvjIXU+8>@gCGGpNGH6RvU|-<ND!x$fo~?-L5S?MmpPr-RUq(&9W{+8A^6xr3KTCt19ZJIYeu8_-^Xuf29zI^8e z?po=Gm6G(w-IMy%t%kCN{#rB{Y0g-M(CKR($nIVRaN**`fy zIXSr~S&*EQ+@CzG`%}pa$*Ve&70I>9WyxXsY@u|-mdTIuMvl`uJwSTqG~~MvjLbmf zVz8wBM7=*3q?yg2K3<=|Bm&q2IW73Zk8F6 zh=IDasEP0npv~TeKvW( zM)1DH#MgC5eT9DaHXxV{dt({55iT!f0kb}?Qobp6LKqgI9}eUmnBjJ!kN*Ijty%C# zo&vt24L_wnWfp9vgJ}%dupTC@PeqrM34MRXbb3hV(sDzW+J0`ZkBh81c@a+81Z=*c6`gB=L`djWw?B1$urN zJX)3yFc!Vb@C#mm)9+hJ%(t@X--Yjx?KR|)S7$0ES?fx+EJs%%S*uN10j(PJvO`VDSh+1k|NvB>yp+#Xut1B z14R%114-|%lILGTMmpy^9Z#NgKptK|o3v4#ZpFIQXKEBPSdL+!ynu}qQ*4|uo#LfS z)>cdqqmAJl_t%PA?w9^~fIg$+!=8$!PSa5utNAmM?FBFnSjWWibWC1BC-UWBD2$yf z=1HHCxAVG=F=Rf`HfP9-2;nV%uRq?8_e1?p$={MElbc~2J1RLcnU;)8rbr(&NE-}G zwn~0;AG$Z(d+r(ctb0^ae}j9+{pj9w-?=}?ny;6PkhE`>)F)$-=A=EDnCy`3njD;c#E3D5SzS`muhtKY$LW9sE9iFF#p-xA!GFqP6{c z{*mMWefu`a`?4qJE3UXf5y5bmxDB;Fv+2J%NM6F8TBX*fVCdB&#@XqT%^!LF3S%BnPjjk8(q#jINHOPelbPElGMWCE)U^&tm`;Ba()*!H&b$CLZ z!~m90=%U^_l?gF36{Ss0bE}rmJy3Dlu{uY4gZ0@7JZC?csb1u}i}PrnzRgbWCaUiR zX)s=~-#9#{Ry0KH7U%#mHlE|LiF12NTdyzey@p@y_mhNuDv5YNE7Le{7K7+9=A6^C z`W8w9oK2_v>H516Z+5w)>nEcrHZRqCw&fybY1m93W7>UO`(8`3;xk{# zzxY*F*GUpLlQa#I#9Mq`qNqDpk1Hj8g|ep`%A&5F`9hZPDanKR63g`eN<4t;i7G4y zaTT5UmUFu$)m?_>}15eQBN_!w=F2FO!3??7=5`-8^pd z3hdto`tCyMp>pY?GIUaYCP)5(`6`1HH*6-4|4V&#GvW!$5dMl+kS)!yM&<`;9Lsc? z#xcH-Q*}-k&_j5?ZkNcTIsv|cvzRtuy^;&`t1P#2F&rxP|1HcZdQtm$8x-Q>I`{jA z_AnrPbDM?g+GRMbv&DgjrHgw|E#~*AL~2)Fn_!BK%sn+dlau4 z9w2gPm?b~WT_T&-Pv$BguXVM&6U$0(pxYn83>~huYV*^#bRA^cYq6j+n4K`lyn+8m z`ESIh9wLih592@?SRbnh_$vTU3U~QctxgJj!cq=^tNO3z^1!3mtJb z9s4Hc<~~j}%Q!Y{s_x~AX-}e7c&((=@?JJ;`a4UONsa`XN(#@qIzEzxJ2qLRLt|bkyCYgkR`uh**6~hP_Yx&F41S@pB#+7u5&ddrO z-(j596Tnc+4}YP9axtu46&+7aS!i zJ;cxS&A!3s`we~YZzV5DnjcK=OqNT&&2K+7S(Mx(dwy5)aq>&@Q}Sc7z8|DdTQ}k; zcvg1sJ8Dm7`P2M4{!G8fKk8rbYlVSft1u+ggo$B~Fe_9_|4f4w?a$#@MJ^|kx4b}q zPY(yn%h@ONgqDyKp7*Ewt^KOxkYsno5>Lr~b-+6~NnXMAiV4bzT#b{m&)w%Plt=E| zIz$7zJDa!Zs03J+%A$q_&<0bJ0%QM?C$)T*a|i%CEeX2 z4N{6AjesbiC$~Ti|9Q`Q;$?q^nc1`V+G{=Qx%;}Wo5>32f&%ZD zS6w+5{yLJgx{|MYlCsY7q-*Ng()ic^NSaxlUvaKKT+d*lNJ$l#YlGv}}clG=sS>EsC6Vh46 z12oa2kvx;;N#(@2rBLTrMta~^&;WnP6DXoK5G+wT&7@wd9>w)=%e3(jSPrD}v}9^@^T}c1p%y zi*`is>b*Zjxv@Fan#5J&x^bttLwvF1xxeK6VV&m^`6=$}90X&-8azb%DX&n?7^I&! z=-CbMxvbaS>8U-{I!@v>(l7hMfno7*uJ(C9>4CAqR7r9tI^0g7CeTZ9t!Ga@pxxUn zC?uKmbeW6jP%fpPuhqNG12Nwb|GD}9<5ckKbV)ZL|K0&xe;Rf98uS4*hry(Qe2((4 zcV%n;w%3kQF3gMfD@iNWV&b=vyk$6_EHBEr^f{NH3!oBRbdBieZ4DdCNia7V`F92# zk(Yt0zgIT;cJLNmbWL|_E#?J_gSEl_AV(2fm9R*dFFY2!8~hyP5C2xY_G|EM@OrR2 z*d|>tO`3D2w8Rv}0}o5qAJY+TWTxzO^mCl6RlO93#tUFyx*R>#7F^$jpf}so>*Q|B zhooUnmY+8@YOQ;^TDv}rVV|$NIs+b$C#BD4>bC{(@%7hk^w(_3;8MO;$_{6FHQte2 zc?MUu&)z)x>$DHnGQr2p+`F__Um!d1W1Nv>II~w=vhS>4Y5i7+Sh|*UKr>1GS(2~1 zlCoB^qhaYTX^R> z`u}z@74QSS<2}jdFOu#g`Bs|gFWLMLbR{22R^PyL-%G7wm;CPhlISY3|K-UJR+ao0 zl}5^+IC3eT{Gj;U*rTF}J%AHBVt)NK)pN&~YUT+38~GMXCFw)R^v|F}YK-K`xzxe* zQ7nTmZ6^NJLSm?iL<|f0eVJD9P3fv5I?H3!O@Gw6zpJ&#GM4s_`^0y~*T$#Bt>TW7 z-CFX_3&!8jZMZSoApd=Nw27{%ALP6L8WoYhUL`&^zEb+*jQDCf zo&NtM|JC5mYC$%yDM+IWiGy3wnO_5K(vfb8W?=NHgOxp*oV{m~UkHY(8u|aqbSSk4 z@mm*$k7gj|YGK{8GqhWQG^`nv)R9`DUCs@%lMs#CyA{Od&63&2f0r{(b-1zTt$EOne=>LNdB+0^u@xUM7TJ-J4)k6w5ziCl>?HR zrBRptR(yu@apUJ|3U3Qv+5YVw^`3@lB9V?-wvj5ZIr}q zmj>8PH_dm_FULUUxJF)4K6Nd9{VreppSZRn>%#i2Npfa#cG6zH|7nu6qIy+TX@jP+ zx+Rj&u{7=40_2CHpl#fu<-Z8()fZswC~?szFt0vm(+B zmGu3exUi1(d+g)o*O3d!3$Uy@Iyj^wEta$nkhGhlY%%rIne6w0UTS@onaU;q31^Vf< z`0V&9c?`G8o{yC#%Jykb(wS`4syRyA2ByLs2X9EmUFBV(ySP&K-MH?N+7~OehRgL+ zUuG=yqoz4s{||sQ)z{@p(KxJ#tFcRU^&d-vbc{cYI!7DBv%;2P$M6Tmv-fJpW+#}Q zra1R)?aBtS!*wKaw`kwigfYVv?~~|BclP{d`i~pP;#U2Cl>c&h{5n}S-Ez_{W#sYK zhC8hZ%(*AQ@qIGL>C@;DEU!lm`hQM>#p5(;WzGzig+09~%s%e+YYOV84xKbjVgE9h zM`wC*8pE)Dj=cL@z(8CE`thcqn>?WLvgLbZ-&=<5!#gDPFNfdA3$Laq>@>x1S4G$9 z`{`P(GomI@si!b~Opjmnb zcSu z!W(&0UecaL<`pK1x z$@Gh$1mB|G|1KOI*?yvTKmr(B|0);;=L9xuKTnl(8H2E!Nuyt5q5q1D>ntkDsyEi7 zw4V7xmen2p-@*#;mX7%r8M`l$<503*QRjD(&cB>~s-o{zlMJ~+BMFKn$H{Ak^bq_8 zx3PPR!^E=)-;`{7M#&_Qz-AbpN>@Zy-Y4p>b0uLDC3%x&Q!SBZ9GQ!h&W6)$k*>fo z$}Xmw9i*P}slM;l-Ec3$MtBbQ>dIf%yL%`;pG3#id>wBYzQtU!3Y%at*@>>q`c+Fo zQh42*znQBuupU}YU1cI`XI-@r6qq};&6M~AbCO2kF$|El7$>{&u>25LGiS5zFQcg^ z=*X+2jb4qei89fa@XoM6_=Y0hJDG!c9oEpe_|90Wb7hko&@pr!SUpF$4Zz?wl(ZI< zjNKu7_rFVjBY5uW)3fJkcIVUiQdPFPB)vY_d8+00Oqn1D+J_r^L&i_vDL55 zMBvV3{oBEnQIVsbM25dQEbA@v_|!U+SGxvW{v~)D7t?j^PKhDGl3-`>RZvD6@NU`P z&%&IjgQUHCG&5SEIP9m$EEc~roze}RqJ~i#eH|VM zcS&zdk=Jljcx8B=^g-varu6Ff!B4>sc^0n+uP9C!4;Ew)pZ$U&jnTn7!R28T&4@~B z_kARp{7!bx^0Gwt^vU=kSaXKUn|xAt)Y1N6$-krc)lB7ngSmVkYgd0Gnf_4w?n7pB zz9m~}X03Jl-}AL!WOnx|?M3(7?t?AxmpDgKUQf2%xZIPZ16s(Mej5K7*Ojbf$ged_ zTFUZwklZ^KXrgGKbJ9uARz}jk(Gizwr@uo#!EUtB4Le$u#y^qJ%H!+%ukZgLV6f$R9v52U+2_Fnx~U|kCuAgIK zn{}y{y8iJcwjq1O+V#LvU`nl25|Q%72bPqkK8&>-Fwjfm<* z`@?&~YT;+{VY|xGJ|4`ML|;I!jVB{_qGr_|Cb6^0xEBW*)IoA(Mw-jvE&1Q%{~{PT zs>94%lU$;Ee#)Z_nxO|yXX3baq30vErvDTDO{U(KsjmLweyOMRJp2kLnyXkLpDw z6kB~6eh|JIZV$J~pSVkrRu}1mMv5$INGqI>cU3aHK5P*-3^#@kM3tqV*HT$_E_^jJ zZ_MZMm_Fa#eWR&OkJbGg0nXm2b#rALMDiVfCh~M$Gy6iva87N%Y`!OT?x524hW5%# za&iZl)OT3g!cl%cJqpXxwn*AZ%A3li24T zzKz~dS{}e&vWuHQ0{Aoc#kumrOC?eAt|Wh#es`APb-nIOFvjllKdiG_t6goJqNo17 zDSLTLet!`xc}1N?1H~GxB++Ll=jszXN{&5;=uchgm*AG4q5pAP^Y_{!+9 zrutr6@2@~U(^-G_4E?N_rl^inSy%m|G>MUp|Iq2M8?KNZdQ8Uu_k`hF<#)M?IbF8& z-?C`d4xV{51G_s`p29@5z!>;d7L#Y2#Z0o7b=~VgS**wEZ>E=ci6r(#t=0zmHaFv) z?S%V$9$0OA5=+UPPSN@JvwIMQ%+hn~n2a`_&z_>sU8CoXtQxNU&=*d%8B}(M>oq-OgDZQpt;D3cB@%6~1HG+eYNu2!F|rA>N|o= z>qypjhQ8cq=WK9aV!C_fUtJTQA9t4C$i%-!pGAAg`i_nsjV4B;qAL_ToEp`RibrLm zF#0BZFI=tI;Y3&@3ZhG*VGOwN~FHqu`UB_GI=tb#wtT}emuzK+Rt$tBVl z1(T0CmqXG=wtyc{%R9_;@a;?zTTgz%c);&;4bIP%lrB0sxlmHvGPxkREICC{M?=YS zZGEpTe?CsW(x-f__c(j$ZpLl!2wE2&)iH|7Q#p%{qFOq0>x>h00~APH6LdFFF>ns9 zFW6)HlrgIrgTt7n@L>)cT%*ziEb!wM5r2Nq=9UdofNj@7IpwZzISTPLQS;sZV-F z*ER>fn4bD+wRXiWUF9g*w5`$A(WkOWTZ2Wx+F&}kze|EAgW-~?N0|KC7`Z%ynFAMt zwzuqF0F%%i|Ev5L2#N)jB;9AjbkUaVK`XrX>>RDe^aGWmtFQstyH@nVXJ-I(rVf~$ z2U0^vs2&uR7RX1>(3O(;!NH{9>0l~z-JYlWsT)&VE|HeH8E&2t!HdDM;OuZ}_;uJ& z`tHT3Sll7LR`ToanNjd)82vej`pzERDX-CJvcj|B!x#q!XAEdMW9k-CAzB5e-f%3z z2x*W9R6WiEKc?-vIE8h1&W=GudhqD-l_Nqrzht~LeG-V zP$Bsi7Oxj!-rOjwdOW^1`7}w=uao(Dr6cwqnG@=sp~KqwyCwVE$OwK8uHhrtzqU&X zPvAEg+jCKJadMtC%vI6=jyqcF(OH(gv@}!^N$-!+c7IDpy{C7+q7_?CjdO=I%BTAL za?&4X=b;6w>h*=`4J@JWxnu!LYrVeH3fO--sL%gI`spQ@#rsJI^wA2>&^@$p&_9i~^zg)emmJp#)mp_B7w5s#oUFdfFF`FTu-)8J7Vi~g9QXN)l( z4P(;;$zv90mQ5)>(*7a^C@b5=YV%@2-Bc@+isMUoh=#r*Z(5_7r-`jhNQg=?7nrd?OCq> zI`D70$H-F$is?~Buc}78yV+H`o@u8LXi)Kb@&9 zeS;@paI8_i%z_WtY}+lKeok zYThYLI|xnPmk4nZcf#1PspM5`0kiWdmy^YD)oVI=@%dEl=F^WiHm`DjpYGg~@-qAA z6+6MXII4Bkd^|dPp!UmD@O%^D@0&zM+CIQseUfX=fh51AEO!O%@e11I=E=#Cl`EyM zRF6L-U#^_J4#Lk}FE5~5wvr1py5^hs1b%)&S@C+Z`?->=-zD|mNG|qCW{m>+Q@?#7 zIr}Xxt$4hiWbypu49R3${dAJ#t4y*Rrje~!a!(GcoRm(VPp72A)ADK6t}np~ zMT);aAYwmAX2KE5VQHgRsaF0VZB$J%-d-B!V)+)ABv;LZ(m+X;ldIhPT zt@|`dS2IH1-88NHWLVOsG39hYUXRr@c;rWf@K`0IZl{AKI<6OPkxE^POJmY08 zeH`m`cD6^0>HT_^SYQJ^+p|D1jKRZLj0dm`1j#g>o2&OtVoKaIU`6d&E|=d>BJL4Q z3`>R|ON#E3&%7iUD@k%k@la`jdt__Rqwas7ylUs+9|8S#5*%6oll-TO8XAI!KU-dd z8G4$*bl;At9?kORbhn|qH;XSU5EKEoQ$|sLRl0f4%i}8emp;1_{Xq`}{em%6>^Dim zR|iXjK9crZU_rZGF+gv51Fy*HUlqO>7L2+?E20vLvWKBF}q3Bqd{{V~p^m;rZ) zet%wTGDUY`B0Lv8q%R-C5A*zq$E1^=!e1MU{7=`{SiG$1OtgE0DHpHMr|(Hx?@H$0 z1L3cl>Um1IHMAbLy`FyShy}=MXbKe~XJr^8E;tY|l)Td`(RK zp>)7^(g0uT@iQ6r3i_O8vdw2I@^7oJGbCNVYKKom?wrATUB1M^$J)AsTw z3e!30%9u0yxjOn+T8B6Fb(pN+S{Qde)VWkoTI-nYmYIppM|zry zKY2D@%3`YgE6`u&WLc}vbB=$HjyF+zX%JH#7ib@DqM|W_E|FzAu5$+V4A;VZw2&Dq zZ_?}p|eGy;w6u9<4`4_eW4*P3Zv4fU65`d*p-`z#0kJ$NQVB=4If z``d&4`dXmhAJ^Zmf`!d<&4vXVf@I6 z{Y}Zs%V1s(N(v9^`^);Asl=TF(ILHKQk0?hu4bi9AS=9kpocJEsa z*?N2F6(x<;kPWkAekwh)6QtdXK;z zP%+Q)0uiYoaqfi^~%0@1jZ#z z)xMgb-SwbeIY(DI3op@`h9%^6?CGx}AG(!0yPA6Ce6S0~DbCY#|9{Wu3c9pk()%V8 z>nzkOmTTut0uj1V&sdwhr_cK;DiE~|H%R^`VMDvgmW~Z3!z*x?9`0Sf7W~R}Oic8w z+8h2y`LD@LyxOwpm8jr1f^+mDCSWv&|I5Dq$;>*wTF-f&PkVTNJS+Vw`5xKXMXux- zW9KaX0@?h%!B%>$pOYWp&gx5cn~7km?(9F7i)M8l)cqBEH-KMCx~JXZUG_}=(# z#pw@_{dolb?5EJbLnPY+Kv#{!S9%iEWgm3J3^amq_`RqWk7K6{kx$S?M{*WvI{DoB zd9@;U?;VjISdJI&ocJDkW;PSME`+ONvX0(Ud%>SN1njAOj6Qm%D@fm&*#6zJRsoon z5+HCallc?-w8p=cRc!0M?#kPT)Sox$Qx?I=vr6w?4{z5xy7TtwoW7F8r$qg>n8wF_ zr@wg$z;f8b%nbYj^~Lw)anzHJaTMJUUal6B%plpJwU~kx8xQAjPI689Nap&?y_r3k zXVY_ZR?gXVNG?yhC&Q9$Nv*VOI$cL`o$`>Pg2Nzyo|EP%11DG;{qH(tQzHILr8C;o z|9`f8fK%y1IthtxD#`vM{#vW?B{h$I+Rc{Lb=u_{blsn5mCDQR*G{U-3#g^D{sElR zpYR2K6)Q-P^*=y%#QFH0_(YqK8E4}sA>GsHqF#*-^;+25-aw=`n^<`oHNu5>(aW$F zbHLp%Ws2DnqK64Og6Az-(s*|&a$pVE36?0FoTMVt0pf| zuXO)Y7K=4N?^&gHdtbY@yiJ<&eVxPCQU2(Rux^+M*9ARgOZ!R!2L><5(yr3?8)fZ1 zBmFT+;o0zyy6X1dOaC>@E;5xl&O==|w~4skue99m{O%wlEkf?MYS z&@_+hyZh{J)c3`~+rfcgNAQd^Q-7vx-X3(3wwfEf9MlY-48IC5k5)!S;|nEE!{NIh z$F%wTCC{FdF;UWfjiQ0u6ybN%I(L=CJ*vB4f8MOO_eh>yV=>cCf9_I0Eb#y;t550( zX5E-dEHz2LJt3*>!IbJA=<=buhb!RP*-Sj~ES7jJx_>q~nXD!s#o2U?@6)IEVaja} zYJL5=H%6o{mo;`BtGFy`0m))RI@${2`B&4Uf-HHcC^t^Nm2ABa;^ZZ|fG28~Ee6H1 z5f5MkbN9ZMmHb7v-4Xv$eK$wWH~Ng#>=mPi7Sc^*zJL#@F&ar%K@wGuNW8A>sC#Bd zpidV{dUop=KP1D_$>~j*&oj5BEkG4Dme+ns(l=S3e4d=0E>4H0Vg+VeMc8ZLH6(LKo7hia?A%`VP*bBRbaGc-C8Vjf*93 zdv!hL8uF1^>s>{q6-#QZ%w6(#>|Uq8_$GXCVK+!bxZb*PEwFDyHStpQdOJl}+A>E5==-o#DmdUP;ts$=JAH zo#cOAuu#8096TlO`bJntFJdN|ImsUSZ#BTfR12@65_cXQerDCW6u!T6;lj$s{Wk;; zGA*}@j%_}`hx9r9z!+Q)PvYIu0q)JaM0#gOa8UmJ%3u-Po9@rQDHsua8{80X4Ld}u zqC&FneaOGsd%s`S{!Ynsf619MdJjmtoXzc_`*UA>L;SD!4rzfqsQ)>$I}_yH0IdJx z_~(}Br}XM4L0%H`fZu%Oi_l&^To2~CzWa%_8Wb^ZU#c_1< zjikOmmC8e3o$r(Q8snM8`3#dhmop>pBiXOAlBoug!wTBpRE0P@d#~hFU1V3|v2*q=_)*(sr!4EHyB{%@4z<9o6 z(g3;AKjjr?l-FndtiQcZ{?1sngYv2iBr}quNtB*QZ_5-<&zHS+9lwsw@1|sbQYdYc zj!ged&qzxpM)GVYe>zJt^`rcm+Oq1cU<5o(Qh%YeMm@>yW%{Xw)%2OJMmAOq z(m}r$=NvwlW{PChx3kKwo2=$sewQ~=SN=nNtyoo^MOm#^5k(Du#TB$l#y)=`t?>$e z(S9;uW=>zp@0RjS=!7lgXxw-78mQalWIC6T9bN|x|9QOl>2yFWm*mgK_nSgDMif_H|%KsGn$MImiM(Tae{yE!c6koR6AlrlZH2ezBQjwlO&Cl8Y z-Jq__#rQF6@fnDVceEz|NCzak;t%xL3a(%YIqqTD!A0=HFJ*4jL^z{;{m(OLd7Sh~ zMt7}baxgwE?in2m`-Wx1BZ{vb4a^I62VY9Y*2~|15ahf$#`*_SgFgDc=)aZ!JK#0F zK~j7L{`viqaQELBLwtiQ`~8aO@6>C|hj=e@iF-3Uvl|{jmXpZbs4YPEwGW2NyZ<40 zL*MTS9?`?RYEQ{C$qAQ-*GEU9_PUbUSlunUT4!4ymvz4*zA?T3wJE z=Q_zL(g?L>@!RSD+AsxH*H=+}PCc!Gql9WnlzgHyJT8fUP1ohJ0hHG(nZ|DUE$!jb(lYDJUS8zUr_W63;Z z@78>JK4wX)yrxeu4&ga47R%`OT1YgwhaQW!>1RBuHT*&6`Mq>>uI`W-lXGA}_?;PQ z`=tduJ#nmd>I&*fqjjV;NdFR@{cL@HZ~e9etd^%Te~7nqK)d{SbZN9Bye&+^<3SSE z3Y&xt!j|FZ@&pzHYZQO4lmES4-w)`q{=b#~+wc`U6Yo~|vOL-TUU~C(NwRN-AMr_j z-6nf~KfQC8Dx$ca$#*v~!}NC0J$J&N*H-V?8wBCjU=}*UGueg*p9WWiZ-wVa+oLj) z@?Ib_Y*YK=z4xQ0GLU(=4`9WglB_)`pWs0 zac`pXG5n=3I9($#tYIG4bBnP8!AUZm{%>U6l2%Zv4$y{{pOF(S{Hw_=HPggN%Ml37?vW?>YytPw$$}{NQQCg^o=ZVgX$R_!wNk&-e?8q$$-q+@bfU zEbTvWCA{p8$*N>mlBONf-O0e@c3J9N$=WeV+Kox+^wRW-v{$+z9g)7GGd+ULI@kQE zj=f*b{0I^QO+MqK?{#9)iE%?fOMh^06%XXVN+!>s2ok)o;evUq&Q0RZ{U58NuCoJxQN{ zWBM+3rer@Il)LCzd{5{9f@Jay=B3!;Z(@$IIfkAkXJbzx%f~d0%FtZ;h^NxOGar^D zcXSOUKln8Bjg9V}K>ltcHRS1VHZG)=V3fm)MD|8mAJuu86Tx+joaA?|uQ5FnwO~9l z3bVSjq_4d&9aV2j?`@!?u^0V~lh`Fw$YnT=eNLLR(Ve2p_%!HN0|26}_?9khTf%M0DdV#xb`@&*= z4U^OE)bqv|xrg3pzYfev>Ihd>o4gr_7s9r4ckpUZF8m~zBH!blpr?Kd!+XNt!XD9y z=sI{Xrb)&xjjxm?e^~PEIrI-PH@+(|_5J$mqxwD>97TU5yFYbXNAA5r+K-a#_Xg=T zj2yru{e1vE;seO|_XHm@nMiCls7vPnZTEXgisqA_8G#g!N2m0X%s))_U=YZy`#@rk zB&*nuTA$;-dD6~H==U9u9bT#(_=E0oMxK5R?fP1v^_<;y#;>R>Ty;r7CGNKKTArA< zn_k}qWT?EGrclLRKz(_qe26y54awcfwTi7Tm7i@~Z&|%>H(6pMjjVUZ;<>n^_+2D* zmu&R`Y8l_)i=_Ij<1lTMASYl+eK^@C`LCMROCOXEf2Phb0%QC`+#orm=>Ng=t@PXU z$@B~TwSmq#%lsM2M|D>8r?_@S%A#897hV=N`PTEk@cBR z=D-p6d?qr@#;fe1{pDQYWMYA-a0}RHTtUCaOsbF0J-9BhL+A1dXiD=9{G~gQ4|J2W zvPE=_t?AG#sFkUkxO?*=Fd8*=){U5@l0j?lCJq=y)akg=nBZCTV%mEd3yxt3_}47! z$qTwKQSzdsr)E4dDjF>fSA|LRSNK<$6NOPpeQgZ4gfGE*wktdw?*DJ(-@Sh3+-xb! ze;d>5JtON@*vK6XnE&%kdJE2{FZW9LK8+8m6x7d~b?$iqo!|xU9sC{ShU0^ONsr8s zA22_x8$BB}mUPb`$GVhC`a|)p@ip@HT}vB+#dqy~1Qqb8(tWKB*IhH+=cai+e|6bGce_>6_nOiR zHRTNxhJ_qQddLv<5hZ9mXlkW z1EOt?-mwSlg1ZOJ8@!K+I7N}_V)`m0DJ&!j^BJ8c>wh@enG{LiPtHj?OUpRVR#3an zn7zl7Oxh|PlBSuJ>7U6huz5PdH0u9v?Q72+C??4_#;_eZjz*H~Q<(=+M^{!>uS=5e zbuRWn$|Cz^^<}2;X3`A%>3u$+^Lz$>dk574Ys7+NNAu~Yzd-)lqJ5^TdXdh9Y+lw` zk16n%t2pf9J+x(=T8 zE#wbhf_Y^P2&L!oGP3*u3(@h5@f5~^+8YH*XA$}0l`sx2)q9;W<=|vjnS^?kLb9f?B&s@XhJk4nih?W=0?v& zFGp*m|4RNn9ldQ(Te57P%O*@1F)r^O>4M88$7UkGQO`AzyqmZCblCFGqhjFims4xF zjQ-hcgCW5u!AtTTW-1;T5;lnTMdxcZSAnUXBFS<$WDk1h9?)0U_FljsUvgXDjxdwxJN8)*mE(0!~= zHmxe!-F>_6-K(eXrKABGQX?-bTkGh5mCm83&i8TYym8>mrps1!O6Dh@C4VPB=>G%B zTgfZQ^U30*Z*nszneSy2%`(^r-1!8o&_+G86CR(JVGcMFJD#@YDMJmSm40%q-93S~ zCtoH1ByS|!idQH+m(D=`2f=dnrI?!SCcykI?n- z75R5hC*KaYaklGkCoF4+U|}`xc_|DDE6^>=@@l_NGp}Vjm7%xcN;IR#i_BQrtam#G zF$VKQfc1pp|NfZEbw<#c*{AVBH!?xaoQY4w7sS`bS2H)MJJNM=+%Y~w z|6i#%dZeDeFYXZkSMuK+Zl610w!WBYef2^3oJ!};`AGUjc|3U?;KXRp+kEf}Y{Y(bv&6TDzB-)-W6Nc5kq?{bYgfqnoEc`S@GnE=2DAnQ8X~ z7`{8>f9dZ7@aq@A05uVW#zHFFgJFc6gr0s{yJD22e;dY!BF)6u1lo5$$& zju-mSap{`jlN@0N`M>_;{H79PXS1x6k^PZO-OZwkJ-2IAPy<%GlKQH|y>E&Pd7r$7K6n11C)tPDvP7klF|y3(rB|nyr>CZM(~4=n z^rPh6WLq*%UO<=RV(q1Wq&G%$1-*1<$H10t&Rh2pyEFY4S?F@i>C5Kn&Zax(6uNZJ zNhT$Q)3WJT$q4Po;*!S*_TW#ocirPxG8vU5Y0dP~^z?LZa=m1>EM5NfwI}OH<|`As ze9I@)!TQ$&-DoLyd{RJB><9S3?ye1C3y)zca$oXET8&Uv(L6%$>1r3!Pyaf+2<~yp z)%%MkuKxd}_a38<*uDAgg?Hs_zh1i)>0hXI8>Ce*dec=8|Ls%xCi$?S1(`ZfO`lm6 zW`r!aK#+W^*LVi8doR8wIxxQaSAE|vnRcYH3Eci_D)Mj89lQig!CWdlYjmc@@b8D$ z;8ods&oO$PPK~#TWMXQT_GX$&E7oNXG}1Lyf*-xQR?vQvyFgqaDy`M4BOTfTecD*B zcMh~36_i$5_v1SLtFXXlZDnumzGt)tA15AoTvG6S-rsEBHleH5VP99#xxACEgQ;ZL z_hO|ykNJSE%S_4tb@ZPb6lV5uXUX&V%pW+LIT!U{?==Je#Y{uGkVycof(DBAuabxG zSTHGA73_jPeM|64@LKR`kS}ZSB9RBy{Jaqkdo?A#{HV^d69HRP1&?Y0n4NleXy{XR)2AwgI%F$3_fZ_T} zPkamWb3Fm_|0#5aby9Y+_9(F61M+&jCXsg>2`+OX*pZFQurxa76Y}EK;JNd(9LM?9 zu)eNm8P(#Pzy1G)eEFGUy07*@=g_}0l6=#8?f7nzy~oo<={i~8X^Oz_PH&Mn9;Ck| zA0}%R4NOiR)js(W%+he`Srf<@j)p~iDLeF_qE6eLn%YOLvzR7`j?Tn0z5L3;(ho)l7a+p7ynGI`;Ce~ft6I_Zl3h;? z{3kA+I7{{$oky;b9A?VdI&%N}bj-EXVJC1WTp{%wuvhdr04M3Mu_GQ=AZpTGSeF$q zi9e8EQdb&Q#6MzBCM*n}+TY9~Kfd<#(-DoUyF*qB{)Y?S4*#1*ptba>s=&F+Wn)-f` z*0nJHqh}^m)g7xyCFu{H%ZNN?pn1B_56egHLltly(d{F23oQY|;9S{qP)|mOPmZmhuN6BJI*D#%8i3?peOmh5#+d>m7Pc4VD+W=IyCJgKcH#aC@r6UpL~?;l69_?yry$Ae{4Tp;RgBzW>b@#0g~~3 zNn06ej+Jy4jq%P;mgJj-{}RRh|0JI$hmw`rb%k}TDmuHOinxD?J^j(>>exE?T*BreqL1T`@7b82le~Ha2LC`D@C_gVuETF{J)AxA#6cqtza!Z zTNzYn5&hJZ$q4qDIwV)=9<|WxipyI(SL@td=hs+gdmP4yqq_3V^fnBM?~N~2d_0S) zuaRi(b{R(2>Ph`%OZF^X#3RX1Y}E=bWiIRsT1n4}UJU=_5~8T}|AqXwVD90WaA9|b z_qPp9_jl^~TG9dSgK9xtB>!@_a(e`Gg7<>5;T_?e@V&5J)Gb;XeHtCo*SpbSJ${Z_ zON!S}4Kcsj)w1%p#@9&)JS2I4RDS>MiurG++j$r@m40OT2f>Rr7JF;|YZ?4>?jnDQ z9PV;5?n}rbPoxeqjXcR@aIRU-{c-dLOou0C1UL@khP!fP=geI1_iM9y#udaYtCUxI zB;Ni&;!9&Z2hfA?G#H&N(yYg*r+KQa_k-E6oa=Xv-7{{?%o!r*#dIfa3EUfNAD}dI zFn^W*xQXrpV||U|u9wtJ^JVVItjH|PT%Bo|DVy1!K9??&2I!MMlwO}+mtLGUNo%FQ z%4^S;nBn?S>Xakp=RHp}H5ty^mCOXGhn*=)Jnr6ua+2N_cmv&&Z<23i-+xW|>UZZO z3uwnSl1xW>6vIxnk&kgCIgz}dtV(XdJFq1^m2M(uH5!n~Yoy(3lu?1ic}CmRzmWFB zboiKyb2k}Ldj!8p@@@C+o7ZE;$M4#YZ%AUd;wQM%aTl|Xf00HxE-5?)L+4v?AldhK zmf$sJk-U;u$#<3HdGNqy>Dj6GI;;2@7^SM{;Ocl=?nyWecI0eNWD_{jTfn4Jj_OD; zdXVc#7TtY#OwyiT@|~l*^e2nPK-|aj9-^hQ@ z>np@W@3u_mX%C;Exjs*apXX%hhns@Y!OkFmcttofd^P+cEE-)L&5M4Gnk#a*$LuKn zKG~-+I@@RHsvJbGOi$^q?$q9$>vPqat3J^{HN0$b#CUFqYnac1NAK41W!qH<_8tw zJ&XeTm+dajc4S&Z43W-V24dwPo$|lNF=#wj)=JUMTSE8W@?M=fT`nBfKkM$500USB zp1w-t)t zu{6L9LAygA-kjS=~D6Z`l2i|H#X>Z)!%|S0(XB_~{E~g4y~X z!NYzHCX~%oyEniwz8Nm_IZRUCNZxLf{;~mPk@w&pb=PrjUjIY(>ntXtolLCKg35*S z?$spwW=}tjn7ckcLczS=i~?jkO6Zv!eQ!*6LM>VBdivW5>9M-l^IH0Q1tzVOhJmT3 zeky@QZ>d+f_Uq1XM}3W$d{9|OxImxXf)0u^^vc3o&DQ8B_f)m#=SoaMi0KgVjHM6Q z@#YQQgr7T>3iKR2-Kq2wt^zGM6yCT|a2`y{V?muuu3$_a8gVN92U(V}4f1Z@`@iJ> zBv`PUF?Y8SJ$*HTqS6MVLql z{6p5cj8@uu+Et#v<$WJyg8UwK$Xc|(1km0y@a2v0H51POW^g^BV~@nk7=y1cFpn!} zG%Sm*p$w%fXfSJOUEq9gZ)%4F@U%aZ21=P=RZMrtd1}kEr(6fg@1Sn26+8{EB)Kfd zn~}Wa6U^t$f&Z>BSUdCM?9la@CG)}LP}(%-s9p?tR<`)9nu3@i+DT zxbCaDPxgU_Gp1=Le&1HS{SCa%x%lZY)KoBYR>%k zEZbRdBUOcOpcUOqZL~(!bloR|&L{wzdILS$GD)cwOob=mPt_x8D5+P~#dj~36v?ZC z)Y0pj=Vcrk@X3|oFfuP&GY}9}^*QZ1ir;%O5r1KPhBi8f)8T69#Jr@+V5iHllRV#f zH`AaG!qVi?oL39qCPE@G?Ee z<{Gv_-`QNI z=45(Yp8aFgC+xlVC%0#`%>(gGie4V1gRhGock6Yx^Z$cX0UspVw|_89dTyVt-FfC? zOq41HX3lsv=U9pnrKyX>ECIRIh4MVzMM`@JEyz#sZ;4)8UxDVF~w3{rT$-(4%c>w#g2am_LOzy7#F0L+%-zB+J(SB1h6lJt4uSy0cOOmC@tmI$X zwU*h^@Qzo>W9=)YYiF1ps(RkhurB&Vl@4taM;3~57Q;F-$!?jY+nZ<7%p2s(N zJYp3kMV%y|e= zGkFqKltwzEQ}mp3mZh|(>Pw@11{UcJY3Q=DB8TCJ*#c^2Db~(=*L@9-E2h3nyZQyD zHZ3Io`4t?rK5R;I`nU zpkX*U%!&F$A4av}OX4e}OQw=vGX}pqcIck?PMyas@f|w;<#2G`k4*KFWZwxE|4wND zSM_h!>#oM(jWVS(Z%h8C%U|y$ zt$UMJtB*A49r0zX<|Df2Z%9)*AD>FUlp*RcS4Tb2ho!Z%y2+>ClFXA|KSgKgJb~jB z$5j=z&(BP*P43VhF3%M>Z*XzaJsFZbncSURsiRbd->-|96h?vJ{AW$Eq9QM}-c`RB|q{}`rV^PHGr=q@NU|X0`JL(GTtv4jweiAvl z+LFzBTwPi8n`0s~8P_6KXhhDgDV<4vrV-tZrNMVvPc$deYDe!<71r8*O-addJDov8 z{oe_cUu8UlCX)WLOhc(hHsw6>5j8o|*+gw^bk5cV&H=_cR@P(uGjb7_1|+$la&|KF_7x(AQo zy7+3o->T2=hHmJ}dEN|9#tfqT$2qsVc~>v}))ndRF8SY2+?>K@=jwHJYNd^}Qdwl= zF>1rLK%G0!?hMoSa7DQmze86&6W;9?sO}k|KLWOn9`ME91?J!ZeX=uw!@(3xBDXgJ zE@op0@05NRN2lLnt>cGrM4qb<7#1UHDv&R#hv!%Z?t0I^HOrspVteLQS-tvq(5vpC z{f!yf&JPomijTheXGFn zuF}0TGrz0uuEe|6za4LX83>1k)ZpiXcgarrSqhieQu-jbQQ7|-B!)SW?U&U+-de&= z&;noHtcWdm7?s_E=WFEgmz|{;s3Q{;oGHCJIUh_;9Z*zlsM^_2EirkDqdy-cga5t(MlQ zhF;fD`_3%sabj+0cS3$i75{5ptGj=@!cCAxLeGWSX0U$R!KBooVAbyjTQ;4#+O4wN zBbiL+?!;$6&Gr93G(gv&TX1)9sbT=n?>RNNDflSpAJ&XsirRysa|cv+Do?iN_s0Ly z{ySR|e3xYV;`lsinrrFNw;s4ryRvh90sTEgC1aj+@~9;1eEt0nNnbBIat9-AgYf&! zp0Q5X>6uUk$f{PR@1?H(uS~RAjOtM#d9$7v=V-ee_b8i*@m$Hjv;+3Rx;hU_F^hTE z=A0NsPmvjbd(bCftkLZ{_lM=lxC%K4gyC?ygv<=I97MOHkY5$K7iY>we(XTW#M5lD z_4Ue}(?9WX7`=Xi*Vi3w&J&m+|9eU0FVwYi$rDxr`&C27D4g_3-cMi1S&=(Ew^8oY zoP(J&GoPok)3J*BcgyepF)fv8py$SCUe4^zyr=J5(pPi_W3{4PbO&6KxHrBgK1=d{ zi|+hpUHLId^tU>ff@Db?CE5D9D&b1~L&@~yR{j5+_S;ADk==uA#+e`D@}PptY5gim zYrUg$E(9mfMak4;QPMw|EU)2F?bV9(>9>=GDlH9D9!yIcH1H?XNfy9e;|x?^GO^DQ zHT@O4BJP}d5#6~@sM3E%CHfHDVtcUbo25Tqk_LH8mg#M>3GaXx*@izcRXf8R{L9H{ zts~~0OqF*foFAK+J$RVzpRc9WD&pl=*4{Wva_X$+$%?bj)Yr+ZNh9gA3w3?2Xr2OZ z;iZzpli)UJ&m^UGMD{h|MmSZk@hnqwAGOwdjnOLwo~H&n#X6#r-hC$7{92OtRv`L4 ziM;_G(GB#s)AYPO2(MVVJakC58revHbA6~PJh8>~TC=Ft1ifKIm9s2AXni!ZP_lkApK()snsmSwSn-EsldhJIIbXj$lvkg6 zNPoLdTHz|mdru_rDSG_e;op;t+~dqt>P3cqv*N-Uy6%chw={QV0o|?2T4Q5J%`;Vn z&bo3`c#I?aMzUE_tJI7>6;G3PrS^#S)Qi-VmlGvTfVXQ1-8v7En{Y&AzUH3beTGpz z?LiLZX(qL-&FfA-4)e|*+QGG9wJnBcndSEQM>{(oygttE8TWQnJMTy4;@Q9TeEWR( z`WYtPIdkOfa~oYziDX1_Jbf-_T<+l9(z$o!tj!e9EJ`0tTc;h<0qM4MZ~AfiYg#`u zI8!p`@|=@$zQ{Drv`)JuU+8WQMO$^3Cc7@aQo8gBIv>|blHBhT;-{Ed)4e7obbemR zg8JkE^5*YK9#8t|74L(UJxcy92h2&Cdq+R49$Cf2tI=S^sgG*zl4bg zp7^^**8dIJfRCv3tpIuJ4DJeY|BGQTco99Y5C*sTI?h4K{%&$V<}LpkjB+ zoe}QdD?{AZ7`BHd$vMnCuc9NiV^5ZoBwq}Mx&gU|Ds)9Rrw_9Ps1cu4ZL){X)?So! zk>BNAQboSXDeU}u$@kKu2X()`q{rzm*7P&7A>*}c=W1OJXmyMTuxEI?c8Iyw#?$R; zUwt{q(3#Q`4{7IQW8QIO>i(nrw`Rt0cf|mMf+pdw;ryt);>+9gsw-sQ&(u$k<56^z z4Z4%4^Fhh_ow7ssNDJHn-`*Ya3a*v+f0^EMm1N4DZ4ZO>>8dlkpG|ZVJc8<=@e0k;o7?+gD?8_OF+adS$ zoNhU*Gsn`q({^c{^jK0jy*(X~PE6OQ$I{`MvvOX^*^zTiPWQ~e(w@4m^>j^blSkZL z_uz8r-^Zw^jAVX@r*ekyj5sT2)}ew#CiYftOa{vKKPZX5DKR=dq#xI86o1EMbY{Ea zbZ3tk1-Fn z%!TkGuhyQ;LI30u0k~4~kv`Rx{H;v&TfrQ@EmZ&a(UbEsxqq{+t_5>7314g@9XY;} z?wOneU(-@7|0{57?9%JaR{SA-Kz}P{Htx4R5q?_`w`MnVUGz+O_N~d>x1%eg7J1rs zLkDF zj=u)?iLu`!C3E+a=~@83-Z=F~;2fJz$BLPY9@8t_xo)P!CnSUJwEd6r@A=j}f)&BR z;I6P$^m%l;GpE5*B zjkqVZcwa;%Ad()))!i$A^$QejzM6-#SxVQyxV&yTvw-)9E8LSC)}S3-hkBQK;vaD_ zdR;2O%wRl8MJ#DqxO^+amRAEbdp#yqnbX^>oL|Apd4#!G))kK39Fy18y>9~lS4EEc zNb+sEKc`#n_c?dul*)NC(>&8FJ&}Bp98UHpMbcZ-8`87V@#$@uK{@B;{ww#5oVPQN zrFZE_@6+Y?k#_k?o%x+w=?C$_ZqxmIm28=N5nL^`KVs`&g?eNi?c!Usv(C~UyIDK( zcenrwBwr#gM`CNvJL02Z@354l$X#zc^a|Jfu1a1`-j~O4tNfLD$$aU9wnV$t(Z6-5 zjn~puhRI=OpD%!~b~=3A!$42%lLl}fVAaITg~hd6-!VaWkFH?_d2CPNS%W{ei7M`T z7y(}8jy=mXFZXn;rQh#4I9SYsVSivJ%n2_^gE-q|wEHW}_;lA@fS+FtSt^PAwk0yJ z$IqTOR*ty58a}|u`kTA-iowWHOaAzI@)FLad$Sg^m8$68*TX+JT}LX<1jF*!A!CA0 zfy2z2u`XR69l;tlBCpsOu7o<&6g$F@;&|Z<=^^tYbd=PeN#*|nz2Dh^>YRB)j?)y+ zpsMaq5!UaUxT(&tVjfnoa&k?;Nk^Co*4Ul5_sG*cLy~`+toz-1?jqTCR{^e;4Z2>R zGKyTnKuPy_X@Mu`vhzf&d-d*nCFR%S16-$fchjyN0-MG_GIKrg2cFX&sic)IhTrLk zr#4v1Fmaq(0gh;2byd2kPQz!bOK)ja7$_Ps54#LLKq2g20q$@)_NKE*A82npOON0r z&}kdsdp29_3tE+rnacND>~5H%TJZ+-=~vaGG|@&Wa{uM>aQ$UKiPQj1(jJ?UonT?q zk3BT=*cW29Z56mb-GAFKZ!TZWq-(M(U6(UB_h3#Y=Y`B|nL?Ro(pu@ZOxtEArC(T{=}W+zrzH2OxkK5tcUkgRlQyJex@YgkUSyBho6%L zF90glzEByh&t=JV>}T`zmPn2=Rr4P@?S0*mo+%PP5S9!#M9;%5vtCE=RaQx!Og1Eg zB>#^ltCGFR3rT++rJ~+j7AsZ>ZnK=k7!0$d&Se)arYB`A9n}kUMhX6LS?afiwT{1O zy*=CL4W=D0$>ZgJfoTj2n5FlI?$0DDOy+EVnwWnZoE`IZ>}||V+?&V8zLq&Yi(ycH zLGODJPJy4|lEmQEh!>sRJ4ZXEKDGUFOdM>kdt(c8p(L;p9SpVET~{TS=(SCW6w1I| zWV}OLBKwA>Oq%S%-mjQ6V5Y8NT;ZM+> zyHS6;U9$Xup1Ddm}&iaCNpYQ}A5bD$3nzrN5VCb!$<_sR~Y|B3-!drO41z zUI(wUusmURfPO05@*)%6UZrRMQyA`lhMUE8*J7Z)8c+wXMHa1`J|#ajhzejs>@OC< z&q%>9Xy{lj!OTunZP=CE8nVj~`>7IKcr+m)h%sH9m={@OX z>37M(9H(EvQ z$oBI@Y;<2cS^u8NW61-__~cD_D9hwWv;x^;rr~^R+dWcTpbIU>PN|saWy@Efp*k)acQ_!3+oQ< zhRtH5u6r%{{S`z+b0xujwVGR{6P&qs)u=m}`w6g}o7L#y{~-T;f>lA0@cr;W^cd4e zyGqV)k-dIEp1Zqp?~@0us)-k-t_={$P?(& zACSlEm(2)1LVtc=kgHGYeioooQiy5N73nfBo`+s&6su_4Py#O_I}Ni0xZXxX^z@XRTXGBL zR?F#{sg+rqo{^rPo}K=nIQz|Hb+RR?mhMS+$Z!|ScT2u2a|dPerx$78G{o1oKa@#6 z(f#ZxZF>jn?Y_UAAPqi`KhbwzT|zXJf?~I&YQ@ezTXwBE412|>3R**WT6e6ybZ=ZT z+8j&^GSN)gWp}py89Q_Et@L828)`wy_Vr&U$2A*`u?$`w^TxjzXRBq$WK-%>+iM9Pr@1V)kOZ9*LH3RG+2xjH(A(R^*O?4`N3#vGwBIsH~-M^Dp^ zaL+*p`VSg{#LP}e%2p2Al1*+6KDik-%@N8aiqp=Z)>KAEtE5*K;h3JZT0~YLmY!%w zywF(t`ZMN}u4Y#0OZ3_-lgy2Q@oW!0aKm7-V57#sTx-G~P6(obDw^&chs zJ`w(nr(xwbfBp#gz8=!u{fHTt)j^3gCAO(dj9-|{OjUZ>TIded12I_{3tv=vFJE3C znltn#;!^NV*I*WQ3-m}CJh+hDbE(9=nOQVZL486g*1aT^tkUd+k|6kt!eLR4-Cc&s z7|p5No<%*kDLLHg^zqjwsw+ztr~rBQ;;`S8MAtY+TM#Ye`Fx&X{i~wiuahmAX1PUj ztK{60`6iv0UY9mbJEtef<8PT3ON*!7(n^_fITdsN%B`EPPVTvxJ+c?JKDF6TrKDw! z=}s@kk2B|y=LD>f^!!Ek;fK6_yb5T<;$$r=Y9HMq`Mp{@>P{+5f5*l$xXa!XLw<=p zpQ~LwJ$x{@BiI-Yl8*Fb?4PtsCCQ{#gQLG~a=kRbG*}4k(5|mcd|C%QTM2peZ^0C5 zmJWO1FA>EbrsA|w68#EU`NF!AbG2{Xm0t)nz~9=*zk>KPdUGw)d0(a@=mY&f4@TrU z+(}n9}W;rW^Hr8GJqq=#JllckrfsfQa021N?Bu^yf&%&H&q2Rd=`y zmf3avs&F%uV*k~kFRGGWbGFvrbx|XD-Az@EsK2pnxU2OYh~S$ty)c_gY^QfQo6rJF z-$`*rYkUtg{kRHQ1ATcq{zN^!`c!ZR&MnyIFf)*M(wVwbXX{hEv#cH3>)Aiz`g))9 zjh2lQv9)ezMRZN6@Y+`WthF}&@+B&!@9OHe!kF%CK!12_2Ew*B3|{gH@K-!X1U&WM z<^S>U@+e34d#PUa7@c`$-|Grm-yVGby!l$r8{Q_H{{Sq!mq|O=st;t&-Vn+39ms!A zCSrBZo1*ssJl;M$gg zWu?o5wk$!u_PC_l+2wp#Wcl3MpBo`c)=gpTQGf@tE#*?_GwgUazweS=wk{hZ|w!ys#`E*`p-!2Mc_aS&Hzl@hA zw`Gp!G|D|S=eEpS=@?1-o#}1qEoql@PC7H~mF`HVWqRZQZ$Oa0oR|Ag?$5cab3RT- zF&iTrP1ev6&0?`1PU^{2%(jA&JxYJU`_%0#vRfR7v&_qk2y^9wwjZ!*W+75{)LS$X8IXkJC2AR7D^ec~RFn`@bB@-pXO zeEWF%yUnd>RM7-Fwww=mfoaL^3tkTf@Hv<;=fjxg`Mo>z$?r=8l%gXcL)?j0;ck55VJcAj_Ssj6*2`qUs-)JAL38rGhg z=ns47ZP>dlz#O-R)4Yb(?=twvmi*zm(u{-VX+J4ae zDoGbZLt@$s^jV)s@7HDqL)GL>$<%hOxa-xwX(h}~J{vau9%x0Q;a9?yu#S1C>!hzA zl_x&#-{pT=)CddSB|cBK|8lT;uJ%6w7xq)It=vx6t}A(u!GS!8ir@&kQM%``?`HXi z?f?^TKm0nz0Xz)Oz8AHC8>It`C3r%w|Acw6Ex|-I09jt0j_N9CKqE9Q_2tQplwz;d zVXl@fkMEKDIqKtQ*U9r0azNyo_sMLkmGL&Kk#8vuD}GtB2Svc^m%>Z0OQ)tiICp6@ zqHnYcv0GiVb``L{rTEPH;Qk!4kxoxnr0=Dk3xV7wa0~M0z$hQF(}@35)Cgwa{K^ zN}jE;zS>A4Plu(gEq%GC>T#y_Qay4$?(}iY;9l*9a0FB%E^JM$=}aA|BR#u~uoC7z zJP97ey3~bFN7H0?LJ4AolGJ@YF|E8L(_IB8!K%<6ebIp2^?5`XMk}1F=N-v9^Hp1` ze1+cscWhL4b-Dw+Pm9riR$7|lOr1$l&~SyZidE$wzO86rI;>JdnPWUeYq3|WwFb6A zM*!}A>xX@}9{o4@AHkH-p0epz%V#&PzmL|ud)~y;F=U$hz}|72WczAG2j=IS%xqM5 z-HxEQZV)-C(Xev$VxGzfYKV8i#bfl(bohCUN_tqY*$TG4E@+LKL`IFte74cmwV(=E z8$?Dca%?$x=H)=t7exk}!n5JpOeeZrJK%9uLq}AElez(tPzDB`n)vxe@c`-}<>la; zFH5%2Q9^U@M-}vZZL+?N$wsB+3`b@d6NB>VgN{Dy)$Q9rgdglx-D&#xhpd~^IGO`W@Bbs=CYiUx!rRg%l$iN zWu|OeGx-QKo8y}L_(VU#;IL0$d#IVePoJInblu;R&5;vZqa2$L*>xP3Bb%nQOv;oSAT$&>Oa zIwL8Ku$;y8syARvGScK7`8;3fT*|_~XI_9K`t1jOp8eDPv5^tSbPi@xFowz#jf`9V zkPZ&BRBeFK^dS7`6F|8?4ZoY2u7;5bTnKN%R(gc?6FJPmOV|v9-zKfqC(?69a%6OG zTEoC_I&#(kPczHFot;v4l2+&(P#O)$Ks$rqoV;5}e8`T>JZlSjs{^rL4LSwR0_Rts zUD%2kz5{uMMr5(=o4T%8OaC_~Z&g#DbfJE0K(t>5jBp#g2;&j&P=s|dQy2>ASZ!en zGdF8->|#N({pH9m{TxvV?<} znmV2cYODUb{NLq&oc!@#p!m8_r_1K)2QV9XF_X-*X!(9{RU6aWLz>_bW@Yq+t*X|SWbr7b1+O?qu~Yc1fRQ@@HI;3V>acr@;(b7IgT_7fO+gdX0!oOQf-(fYQmFJ z8?EtAdBz^=yDBirISU0K-GtMK}4=B5F&Y#OrS#`+XO z<7X@PrK#SOrRrLOtYbZPO9Lv%C3KeO>ArOWBU+zM(yTu4-23lhcL05({roL_tme3= zlAM(u$h?yCch2UVi*pWSZpoaUxh=CZQ#|LaoGv-%=Csb4m{U3ThTM|5m**79tkNCc zEh+Nc-)wKe@5~C_1Q*rb*xB}-l9q3&U*sTT86wzRI>(w4^VX8|4@@Q|gOj`9{k$3O zP~&6Y%j3g-SD*13QQ}L{yU2ghpmTUE`U-Tuk(BwF#$7?S(J5toi&^r`!}S(( zE#A^KZeTL|B3N#xz{oI;{?!+me7KBH+7>?#PxEqSx*N%{U0+%MXoFVCj6e;D1Y5&) z-kD5WGZ6T;`=`L$pM+imp(Q{FNoax4 zJJO`9*xRTx_R(>i8QW_eJBlLM6&oNbf+7M^RTQL%N-s)BdM}Dp`PTZ~JD+*LkaF)i z`|R>Bs}!Qo_!sRZ%|a>Ow)&{tD|PZ;uL$5y{j68?zjVgG z2%3JBc8;6C0@^)u2x?Pf^m-2|RRd$)FPi5UqAooX0Kz0=psWoMHs1y>!L$yG@ z8v9v@BCU7fnp9Pa^=kESxh(@XHmT2+2ZkdX%s?r+4`rzDR;R{S2es}7WEa(S4XzIq z;NDY>N_NuQrVW*#o^ZwN^yhk7Rye^t{t0f&6l+9=%QCLXd_}ALh0Lomvon`x?98Z^ zc}eE8nG-XoWPX@AJ#$Ouyv%DdM`sL;@7Lb3i2mee{iao@cIqTtf^XC>C?f2|H`INz zjoQ;XX*Lz0^i?UGL~*wsD*wgdU*Y>O9_8?Enlt_IrIs1K%t!CB_KD>*U0n%ALM*|P`HA#*tvga zaQP7{r z3%Gx?g1T!rZ3I@M1yM=~mBAihlI*Eg4xCamx=cOw9rIt@)3{WxR0+&U4Laua^qkJ3 zmb?;7%Ulpq)=+as{vH~6RysEdW(fGK_q0Yw=p_E%`nQIJvAfsm;~t{-`_bG^>Sw)* z_x3|N?=Ox1hHCyl=s#Pl|5o~V|A)SS-7~Dh_ZDhe!*H~CRj=|6S_LC`r6DM8k3i96 z3-zeOQ3h+f0;&p?U|1J{mvQ9ZiVj^fGNmFA)OmcxS`~w|_cjM_TbmwX9{p6u2D#)z zd35nh(YrIAJBj46hCm@q7V9rJgwJ0Cc5602Z`5%my`q`mo#{d5fhx#_^WTc7w}oEa z)xOHCwt8qb{27%Zk4S{wAlMhd%X}&|JM+~KQ7 zEu$&9l%?yj-VQS1Kn-&P)qX5vNgVIRpE_o!1I5XP z11`{hunLQ*^?!wq>N-X7i*WJVsy$$P%JFw5c*2kH?0kn6ZRNLx+8GyXjNU~9V0WwE;XBJB)Tv-ljR@lhJJ#${IvkGbuY)D`5V{iM@yawu|8A}BC$x5N zC(r*E7~(t8p}8lzH@cCo{(Z_D%rSVBeE&u8+pnR=^&y?d7g67T3f#tQ&EImI-*$M~ zOuSi-Zj1F4N~q0PKhtUx*<|AN8M^}N$hkPj*XOwwz)ESr+O9!<-i)ZBCJ3z-DfRgl zumzi=#$AJRKbvg1ExlkPE@OIlmB0kJ=2jOZQ4{u{4%BpO@yu#5AFN{KUVjYI$Fur3 z=Kem-;Gbc#SWUV{s2BIhIG)id^UBPBYo$M&`S;AX_5bH|?!S`xpUitRFV9TR9G0;n zKA_iJhsTvQ(kCeDnxhl&C)^`{#nU4ZjMzJcu0Xb~GeR*pmn^9cSK1N9@m87@7l+rw zy6}$X)8*m*@DI*jdkOv)ITE)M?JT|16h&oKqmgM{QtQ7kadDzT+TYV3&>rE=N>!K- z>8Rfs4VkIWb2Z;@S9H;rJh=(;x&tR>0aec4Gn0mRlioh0gx7WKc(=(kV=E7h;lzDQ(lbF!jBb8^OVAk2Y67Fd>b|c$!fOE(G~k zAD_dPV0Jol4qpte*SlXcxCWik4r)U+z%j-pj8Rwmg-uZeCF8kyYF$z`w#I%e?b3!kQ#yWfF$ZK>Em&m_KN3-3qIA#Px|(}tDWh1WId&FnkR=) ze@(~vzzE3JbiO)~3)E%jZUDBTfb6^_ahTCMuCv(%wHr~FGx1uignW%k5xDJ2F!!o+ zYWs=wMHQnaUGg0Ax0ZBe+ky!-x34~kEbrzOnES`I<|>J9tXY(_Z-C?)Utr{I)gKjAHJ@_tA%Fc6gW^ z{;N#=F698-;75BTj_WtgiDJ<<0ix=M&P%mhVS{-gL+PLx`KU~Po8T%Q@os{ z27vVddg%W9qw-yy?tK?tuOnx2bJ!{!>F~8ABIt|%V-Zsj;}is&#T`9)XhXS(TYmC#T+6SWFg>#Nx~rJvE=l|yOPIy4Q@V6-EWvmIw5%M@>q zMI-%vjn{mQX28?=tYYqscn7%7>h*tpba`|$3fUvc_&?F^`2kv*BXz3(8(m(X<0G`D z@1uV=0$k>Bm_Akocoi*%SMbGr0*|g|Q`oJcWE1~H3GDAMhTeiBX3xY;I#-e>ZU$Js zWUV%-)XiMbF}a9OC%if>Q6)k9CBHPr)SF{@LRFNDdF z6Dq)oaeuEVd7!)Ms2_gF=v9DM$L zC{Vi7y#Owe>rWe^D?*ESb=)!Ijf{mEKPl@km06-aplN2O%&wXBG7n}<&$u9CdR#ib zO6z-_R^=FKSzp8Rj@Y#t5l40a%l;=wzjSoZtdecE>srn2Jh~IcqvV1o>7uCr?(jl* zD?A+D4xcIeJcax3S-O8dC0vtVsi$KVk!#YICk7@uCz>ZZC3+?XC;pT8Fi}6PRrZP!bd104U-Ez?S94&!13-veWYWc&Sa--LFIu*fss}Xo6V*)_MW!*bz^_yLQdid+yIDi5OwE zMnAO>7oMdkiEPww96`_9dJMT#fg0mQ*jXdg3FdMVv)dG;MG5g?W2(ezx$9=__bV>??pGS8-0>o(ECY`)TVT;D0r^|ztnb&K|af1!Z&Io{Gn2|bI>@FOYD z$#+0yKBAw#iEf`&^B>VJa1-i%FQT~lGz>&n`5uIM|318%cT$R*R_8DabWda*DSN(E zq&pvxGsdX4bkn%EPB~Z%(2DHE`BF&NwGo`D4k>4;8q^JPQi>t1>B1y)t!5}O*9J9| zMJJ$0&&;)yeEn2kP}kMzKmP$rJrA|!0?vYBkc9c@3|2tztq!Oj*Bx8I8nb8XKCPtk zIQp#8%v*(O`XPI5}5baiucEc zr}g(;;Y(!!|IqopP0v1CC&m$+Xpd;UY|&~P5_OGErG1vT4%f!UxI0~+cq%bI(J<|{ z^sl1cpvO zbT`}KjFc4)YX&Yt-|K69uRlZ+a2B1cDfIJ}v77#gy7vZ;H?<%v`Gv^Bn5ZC2}RR0BoN7aK-EhEpgm)g#H)Knbz$5-lcBPSFC%~8kTQQ z#rlKL=1RKs82@peerBNdz^=NJu3(BBEm&>fa{c6G$_U!%dCE(9Ou*a-175O}I^O1~{J*B%e@7zq6Lt5F# zB3H9cpc=AWBen-+q}6&V=Fu46Q6^Zc-PP6utp7W}Up3qM4I!eS=5^>$&pRfW(!V7o?7wrd7f-zITj6qil9zrSfd8z`hYNoG_DsgYg zT4^mhrd8<5yHb+@gSCKaTVps+Jv63C^kpui)`&=|38=`dlwNBioVFWN*Q?G5w}78h zOeEWYwNnVvt0iiT$@+gedIyzpXG`iYW>NEX{V|CQuEKk@q6$<*o!2!#JJy)@Q%P&l zezWGZeMgpMGS16*S~0+98H+L&=!?)B&Xa2dUO87i5%^hQfDTXMicJQAjbmlUDi z9kyu)s2bKNTF6WFJgRCJ*sM8WkBu==)9AyrM-tcS<7({z0}{6+9#4!&yqcJqcqnao z`qs$RQ&*Y;`uKlF*&w9b(s{BvQ@*}$wY}atx%%o(T+7X(hFT8vz*Zb^gI*yITuT8= zE$d{~C1bXl;3=)^Z}8y$lAeh*{an#oNylRs`rygBO7g5PMZdQT*b8G4>~6RnruRa$ z!sn&fP(OfoI7^>&llFlu*0*(hjN|ANuGKp01b4?O;hlJ@uAH0)8^0}iU1QFl^U1gS z!|Q1Rp6F`rs#ojX8-fGRfd}O3%V7O(cg^ZzP(yX~c`Ld`<`VWr&CYCuGCaXH)CvZn zN^rY==Tb#e-i6ZeD|4T@2Uz2t;E?NT4)i$7d8fvvxqmGwJ*WD3OE7%eZs2?=IQ@RuC@10mj zu9*~b$BmdZ-bu3PJ2Ym8Z-Ay<0h$9vAOVty>rx;Qy&rU@Qq-RMQGM;Tj`lO?ew%l5 z0`s=ciO7J5bp;AN0y)nh%ZXQ|3}(t_}C7F8uHeuDw1QR2PI{;m5Ecd>B3n zJHq{1{TsE{7SnOc2hEy518}|0*qYH*Y5h~4F8vedC2mMOmv}w#TH=#Lm$Y8#muZ(M z0D@>0GUg~Upw*<)k)Q}sb8H6Q}($ex|4 z8Tzxva=+I3PgL{GLi`B_kUd(pWx{XduS?KmI>Ef@K*rNYqtc)1`)RtOt_N7bWjp8# z|HdZ0hVy_kQ6AUhIpyctnbq&y{Bm%)rL<16Sy@STPE$s!tzQ2U6vCPjFVxe&|H|%g zHE5y&I;{m@M|+VS^rTv7M+G~*)`nNsf{tUZ#^7{ROP^KNd$oY?YE^Jo`mWXPc`hA9 z_Z9o-RkC3X_tvWpqV8v(8{Xtdtr2fv*E4nh$hOI(Jg{n-JN3^hLgA-yBE!|Dn70Jo;J2 zp$~(f`4$>OkLf2LL-%>4K6_g0|1nPg`*G`g6K~F!!2-P+jRoOdgZ^nl*v|FQ)e5@0 zBwn*8p7O0yXGF_X_dP$w$ti(@YR>H``t9cB)h7q2j}Ol=oMdvT7&Ze%(HONyE4vK< zQ{9JpO;^pLX4Di~G8@~bezqCC{f1OncBks9m2itNU%RKWvVM9B)|z+6{S26biCCva{N%-Ej|!l)fE{nZ~*nvRj}ID z!))wIwW*M*hpSe-(U-eK*LZ`QHa1~)il!zLnbyVEnJ<&&hw@>s?9B^ym!NizENm}jnEbV6}6^&HY z*w+TpY>bq%r~WW#jVZ|2wGPyEoezGdE>)I7nC^q9ME2BL@-CeP@5-ayA4bf%XmWNy zou?|ymJ^_Um*D4pJjD#$2d3RFOLhjb+t1I62&xi=6_H~P2-k;OVDTTr8OBb)yLIL- z2Z^{%v)&l0Ot|&g+)1)Oa*@_-5e(jz%s_i@q@mc7++7Ch+Rx*pa75n(_R@t~_pTQ9 zf(_=FuoHP^C+&U%bw6eqxdPQ5b>yaGJS{a#DW zJaJ#bO~}lmXFv#;|NRphC2b zdVV)%-v!|c&C|ZDm2Ud~Ib<#E={*h5O!G++lwVhZ$IwEv^-Ap#y~8u;2(*n)gq>lQ zX2Gw@fRi~>J)$CKEN7?%j*p&8Uz8}(+P@IT_L~!TByLOGuD^#Siqdk@&!j(r9#{t2 zDrMmWltbt4DqUS0`qBe+m4orMY0PS>N0p=*U6vebDEa6$cc9i*LN?r)-K-BtSTl(( z(P!nuesZW?`g2Iv<_g|Uvi+JMtV)I5`ihlA&*;Nhy*qe=!(HKJ#XAq`9IwaOX9SU* zKn`nlSRKx*?NF4SLX6iXc5Fr6B8RNAHRIYxU#kR@qcx}dxta-s(3od~l95VZQ;8U7`JE)ESZxxslGndgR7Rnve49?};dt`eHP>z(cSeuE7-`u*&EZY zeXnTMC*4Ng#HHNoo=Me@r{N9Q*Vf2YqkYHVSUOGfX@8Vt-z7B^nvjXtL`$YRyMZf8 zx#+3+DRjpztqa}0VrsPJ#O9@9w0bD*M&O2W;c^y%Nz0|KQynyS6W*r*kwh`tY^~Vg zdx5}g38SMkOs!UQ`Sb9DO7e%?=}+o!7-eisQaP>opOmfdfg!h5Yj&1KFR6X?rtbM; z{TZd%o1;0oI@F5Kjqi$w$ImF<|7+YYZW^b@^TYq?`B&C;?}h(xS`o%Na6Uhz^mt2P zly(J&;yTpj$_=m8=`&d8OkZN}wv0qgs_4cYRM$A2ub;kDd%%uxb$o5yC9V}$iiZa4 z?UsT;V*KlQ>?n;i4_4^ew2b~pdnwUYvHxGS?jK7GN&G_@z(2GDyp*^stxtMI?d;!c z*3|+vQHdPQihv_ha^wH=Hpik*KIyE#5p zU@}z(W7+~-M1AnS?LkQ8gMY4ypK3n!fkaAIr;zHnD>cSOXR+2hk)I{q>RNygs;SuL zPw?1Tbg}x-ooPo^pfNbhHlPTKQYu5qT(=zkRcna&-CcuqpUG;aIh3n6ut;YLW8(N+%j$)7sQ3i_}7NF^mXSNmGp#mYff6JtV%FX?i=kI?&e*@ zEbPihOa19d$EpkSsH@h?m7qb|Q30!kH&PnjB-V}Y8zzPKmegF zVhnqLI=>;@tUE8KE1weWN*|T>e4?ZB{{cGvA4uGjxFT_>;{Qhya}qD6-ILx%yIZz) zp6gJgc7#?w{6WvQiDK@1!r#Na;c1<|!@~QDcIxXjt+#Lx&X6kr9W|cLO1v&3m=s<$ zRrR@JmS&*s^SQ?!C}~yF1ytJhYlkhyAFLH@9_xp>YU)}>E}hj1DFr$!NmbET4rqsShV)xhn`%m})Jd>Q zA3vi%@exjHc#t5G`~)zuTfMd#A0a3&<;{mRF8hZW(o@TOMH`SdSc_uh%~b|Y%f zC-KHfXwSM(JHR<)?5)8%HsieSNM>0~=2Dk#a5MO`)is08q$*-YF#H+5h|9!phf(3e zcyc^M^T-I`^WmJDkv@>@)f%&FqYdf*O&gNvt<3+N#9&4L_vz0Si5nA-CpIPKq&{9Xw>VCx5aU%QmNp*czlaj;X( zQ95$7bmA^TL%I}QTkE73f)i}WiEni(`(T-=?x-u1K7V$P{}X(f3bSY68b zj@?fZ@L%fc)pF=|+YP0qW>izffoITl@Lfej7gfomz5bul`hG*FxxKOe8r_UCwtdE| z$Tkb-mCyD4*NE<4g!}&lo?myP_i-UFCwl9y-w?YN!Sp+()skh*2n$fHqP#rM8SpZZuRL0xr68P zz+LjD?1_VPt;O`z^BAEX^nnJEjo2ZwGEC7*xO@CYMwkbJ@$yg@UlV_%mGEY06WL$n8CQYY|O%z@y`0&C|a6fBCQ@TB*px+TO zS@rpF#B<5STY+tC0WPpDo!D-8cNt|TdI7Z#_vzmMU=_c(~%r%>lkVtt=N zRoHujvDTlays?eoc?)&+cl13o{Qnl6uYKTUDgpL@`BahH8m*e6xIbm%{#F^coGMgc zTY#Ku!C6*_Vp1`q0ZO2OI&mqK{q`ufaQs{qEPq8X0~Ju+ z?aFL#2YRnIn4Tu|s9oplO+~@aur0mCBu+Ky6WNqLgLlRxy4P2HKx6)+Vwf4x_-LB) zbf0imuePqwZ0&R}X(Yztzw#b<^i7;tnYzn!l^K7m$n=@;m_GiV!hz<%(R1YDy6~~6 zEO~J@Iyhy~GVR8xd7;jubBP99Qtjx@m3K_3?zN$Mnw!EW*@wgx)$UpiE#va>vs#%S zg|2bKxTi*-x$gE#ozwr+DLz6mvwQH@>3SAN%hPA1ok`43OiFx`n2?y7_$sk5@l#@D zqC(onw3F%IMctL*dz}pl?}jhKobXP#iha^3jsDt69@6XGtMmVI{e35qi2YctEc{1g zb=ES(s{d26GFs=1#%%)(#O*jE`FXYD)awFrt0uk8GKx*6YlW<)XH|t+(*y=zGt`!> z<#~(l$2^2P!+qiP@J(13PK28A>F}fSfpb%sjGZtj)99*Yqd(jpG+7bc-ZtQ+d!fZq zpKhk>xjA(3ipe(eby60gzSSGdY2%RGWt&j1u0=N1gQ%z#YU@^5?yJ!l44O3AA*jK5 z)SLRBwbES4+eE;TP-rCl-I@qZVmuo3J7&rrpC z5YErt(XHAOZq^R*3{}E$sT%)CR2Lt`x%C-k1$Jb827J%QS}#5y_o3^bo#N^@g_~E2 znq>tlehsL#B^{SLg5<~{dujx(BA*I2FDoI(GIt4e}8Vi^>Dj%()pfG@=yMLwg^O!HkX z)#`Wke+>#(i*(kH)L4v%VL4SN)`pZLh$E~1ItA|2+UQ9I*Ua-iL?GQ^d9(%-a#XwI zYMeW)fwf+HS&@G48gL=~we~L6J~kL+2e=vIq2gLljYb7M|5t?$!)%t}FO=7#%*)_iofx{#`4f99=x~60CpV ze%-04Ho8nXbW;A%YtGS5X=dMKunv3mQ$F4M5*;+7KUY8($Vj5~ID)P~Q=tyIZ>bic3ynX@zGHo8jlc3QzB>p+*e zJ2NGZ*;XD!m-_SyYM~cpwyv|!0dVxQQ>?H?V3{4Uw84QgM_1x*Z4b?=5^#-424ucg z>p*t4c0@zYL<-0$kK$Xjh&^hbR%#Jkf|{r#Cly+oQhjKMlZd-Jef1pvrU>$U`dO`E zTU9}0@+=ijdrbbW7~lKXT97vzAJW>kGSA1X z=P@9!ztDVt4@W%r{qN9fx4!DX6cso+Fh-PCNUOyrc${@WFo7uU^NgZ!-m@4p;Qc*d6P#b5Djt^1vHuv)9bZIxqf)46%W%_ zFAlTA74cZT_c?mKf%@}*Iwe0+%>J78r1S8@-4~q~4NdEtSISb-v!OHUAe~^)>p+W#KjJ zqs+AzuGy`KC7bFluF;hZ(;hT8tO~2cu5dK$4e4=u{H?C4o1W`RbW;ALGgcY9Ty$95^^Z#CG^dHQ)ryTNrqWf0>x2O(E z@R8PcGrjfzs?hEd418H@`W0pP@1tJvA>Dtw_&$iY$FuNv-#{zuZ}|8b`}2%e$~=4*jGt&h zMWr{@>hAPe>v85cp(50So?I8y7Tb^$Cj0LlKyqipcx;E}PKiD{hssbMNVCS^e$2ev z1-oO7?s7lAh`Z6V_wIL+sz4p)TR!hxmz=H+3Tswdxe!IXCa8UGrdMo4^fr1%tKpG; zraOL1r}|gg3sz{hj>ctSqOyQ3=cZ^#LO;IBaODkhr z8hO^VC!W7RbG8$A=E`2_unXMaZoRLwr5*gqqPyQGr2^FfPTIxv$-2Tm?5f$;hU_Sx zSSJIG;RvMoV6BA9<8gYgziKt~j?W8Qqb8`&-K8A)BgOAywf-MeT+y6NWL#7>x*`2o z+K#jXX@8`}>4oWi(?3ifteI2-@1-lJ&i`r6pRXrz0rjlE=^l!h^B;$e$_pOQ3Y@C! z;BJ_lmBFze&x{P8K67p1t-?Mo)a4J zZ?&uL0@>C&<;vLv*5{l~*6M4Zqk%G~R%Jmle?BVEuzq>_)A@6~u7i8sgV_i=wL= zH2TH#7jsb`t4E)7SLB@L1TK}oM^>(>NrsU}musuWZN73S*WInHx>)^jW{djzKr${PAB@m)+AFgI?cAcqya7@mR@sI9dWxOS|!H)DqY6dgZcWHEH>Emnk z5v)45Ry&xLDHnl#d<$3VW#Cb*Zo5R!Y(r$M>U^DFj)z8SOzcqe5xn!IsPC6UVJ?f# z#7;aej&dz6bcdI*vU{QWY7f(8AYAw8J+`HI`9JD+a?tB(3zn}xSjd6&1UrI@vKDzU z`cOUTbykHxeLAX$BgDtyrg)bk_4h*c_^f73hJOCKaBFx*r{o01|IdV{!i(Vrot&u4=E-YRLb6T!@pl^U1a7`Xdh#ck@8!vc>*)^cY52BQ|F>aL*cqa@S$su&S==?Q9WPPF z(o6S$NV`WGxk)M5-R2?ILA$Iq^}ZJ1&yzU*3hV>*^!3vEz3q{+^+l*I)uiH50d3`4 zR5S+A`6$NWZIC`(MQ%%m@vm?-2(o<8EQQoS?8jJxN>7H?`&vEm4Vr1IH3GkYac+(S zSSj2iS}MwaSo`i{;Yq!RGnN8+UUleVRi|=fu1Z&W{nb-CH}$ELxhmipI$LMg59lB6 z=R{itfBZN7nM>W#3?Q%BKcjl#ZM1oYDcYK(XnvSh|1Hs-iu4~*gg+ENfY)IByoPGe zaP1SH=}CS;tZz4&vUG0UXEh4(Y~)U8#o(2gM(w7o#w|BwvTs(U)I@U6@ZH@ePO!Qk6 zsQmUK<}E;>*N*jz@l;*GXV#3GsB`F5jl%?VCgy{xSdK!LeO9MvEVtrJyHg|iE&gGj zq0un{jYE4~n_nA+lW2Cu-8EL#j)(@H-_ zl{a=|wHx*846>hA@kLsRgNTg^V6nP-I~aA(e3UBdX@;eT@!`DqR9GC2guM8bV65Kl zTD`aGoc=JptSI0bMFx**Czu=Nh5PhmK8h}jnnaDGrcsBeXLPkj;BeGVtNy0&U&RV< zYYtwm75_JS((PG0Mdb61!au^aut3p7U(NR;%D!)ePf;_)Dyh#7p2K-sL@ZGl7I9{b zM#abca@PR9)V^AjA~0Apv@82YZTKQ>$SjiFlx}(+C!!oQ2Ah$`MC5Gl zB)H1IRrgUke6Raopc&}wp(@w`pXF7x-+Q+;p6W`TYz^v+N&H4J=zuotHjSw*me)sX z;$tJEv(dMz7>p4-6dAwr2l~$Dr2NEM*-7Vdzph}NPQ2}rcgGVt^Z%oD{xn*?FQKeF zMk~sCuIB3vkM7p@p2kPuW&ND1{xh^PR?)#JgFdtw)5d^zM6cK`8#^_V7wFw8Q3XDw zo#1zLzRHp(wI-Tr$&9K;x3mG(JG=f>MD70y-T#I97s5s5|{;iz-TlJnZ`2DH+?axtC`xGVGgXFw+0jtfE*{hMa(!o!<_k2`j zdk{S~VMR0uzrl^$sJ+^%Y~%6CSOvn}jwtzX?0xDc-J{#kweU$$mw&fF$DlpvbDw72 z$YlE~4$q1YhW(*J{JZ|`9-&~NERmRK$PjK8scOShs- zYNfHW@JGzr{ipVz_q3x;3iFl!SBY!ICGpkq^@;%2DBrnGS7mOcBkf#Hn|w4$Dr+VL zI)ZuV=hOuQ)DRbmY!n|V(SLJK;}6Z49g#cg9dJ>qjaF1T+9x%rSd|cIWr7*21y7|w z?{GA#Ku^j1qSD~_92@?w8DZ_k{W^oKQC=Gsfh)M@!tNLdilrDnY$5To`&KpB@%xh> z<M4*1mH;iB-o#(4?#shyg~pX*=tNZhGaaa7k(H;hHC z%V@vhTIa98>wSkkz;!S4dfuf9_F`n5&=A~3zXN~dT3=bzxxAa!#GTXXX70_c&^nxm zZ}}0l2Y$x|!aadpbToXTU!*5k2y3bXJ6wNoe^#0(N58;`o=X*nw!;gt3n~abaaHACKFQdS;syHyK@S&k66Tqf#t~ui;eIro)s6JJ)(e>0vc>uAgx2 ztU|_Y48Pa3J3$#*4Kq;tGGbr~yVWu{Y*w$@sGYSbKid%^ zUm~AX2{<}wbj!+8pTAx)%7`#o*SbJ)&z=zCg80(-+PG!hAl?~X)tWNu#`?l#QXcU& z(dQ~bd8<0>rUZ6k1Q*LYTm`zu)^m16=AiC459QuMw2ZBZeuR4SaZsRU|8)cHYpiNF z{kHpi<`VQ)^puBAWCl1ABOm5ym-9}#m7KMNn8C=x>*#Rx=czWK;%L^|<$4<4^{bK- z`?NH++B@)NIv-oWs;C01@*LF0jR~+b;zZ4&>6*vp+rO{b{iXgMP3&b=G<#AU(G~uo zy)+6h=;VJKegFIQnf+Cs*T)-rGH=7^eF{a7m-T96^~A=(&|0H)VWoz7`qw(`tyR#5 zv(siRlzX%2OE|{<84b%-+6T6y>Nbz`kjMXJb3^ z&o1y`TYxjMj_o`=BR z%swR6nE(UwZN1KP_5*9oe}X^t26(;h>}}Hu{WcZ(e?l$mCB5g@jHL6i?(mk4P>aKM zjrb^y;9{^j<;dLHvv-+u;NH|Gn1bW=K3~vv*rGks5u0`IT}wS1B~gB@$f8^Qe;#=i zSYZX^2E9N~_CT4w9*Xr(g&)Fn<>lXnw{$J;VHs2I3c#h*%U%vs!c0X8--MMqGykJm z)L+lbh};?)`~`PH|RTBOV+8 zZ$Oa0@6lZB0KVZou&!-EU$#a|r4Z(91D${Sb)Vz({LRy!43lgGn3306`{VR1=5a=4 zkOQ2f>&d51QeLa=2R*&rbg&NUIjp3fy+;2&8FdM_D6*NPY-GA}n!Vb!vg32(8{$Xf z`{GvdF@5JMjhlPoJG2X=gFJ4K@|(y;-N{^Av#`#f+guS%8oMLfOT8R@o7SiWl_EB& z0%F%Zq(8JD?V&b#E-2#8dZoQOQ%`9-6{5=s3#jd+B<(O4@~b zxiJS9p-6ZR8s&}XJk+HkU@TCi9m6VLondgaW0fSG!kRNLYA7rIU1#2x#KxOo-OS=F z*~X|Z)!hAASNw%WxEk6uR(dxxbd*-L`+k!Y{XRw3e}|&MC*b(Lz>2Uc!v{ErjD*Q+ zZA#Z>*HR7lnYBVs#_A+TqXhoA&I~Hy=xx~EJ+Q|m@OupxZ%+S*Bf=4AeXQ+x)>FEe$wMlKtPpNuHqq-W=T-H%#p zUx8-)8ZYF@xFLN^2k&iMQ+*DPW@oS)wedZlqC_!4@8OxY4z%?m+@?O(PbDh_A8QPf z-TN{)3p9e!nooUVmR|KW7!U4C)`rn(&6^sq2G+oCS*=(6ft_hRRqk~C=0^B~U&GZ* zs(Bj)R7ADEI;>{**^2NUD1bXqo6##~Pk2@9`e&W}Qx%uz!e(xR%lrjIk+*~=718h4 z3fZH4;C7uZ_655RHsSfo4W86#KU@+2sIWSu>uevdOtcM^xKbz_9*V4sXC$!^4c~-1 zaliPQxN3Yqbs2lnB>8Gh=l~=UKSg9PW^NzQ9C}Zq>PoBCzUJwfea>?;J7fmlKa=$& zy#}k`#@!X)M_0TvG>ewwbLuS$2LiugQ|69W`Wj^P`S8DAKiJy%h z#9jF=UD2=j5A2A{Av_3T<}{f^DJs^k+mt~+wz}r45nsEbn&cktGv=WPokJGZ7~WDo zeYYd@pVR5wt<`I<*43Si>T-@3;A&DIj;eJ#jKEo`-NLzyb(a%(-c_J(W2dI;Q5P{1 zdN7!r9^i*vNpk%>Qp{0T`}nQOiygwq_c=Q2j<#Qh z`SS&Cg9~(bC-tgF@La7#){+BH=A`zWEqKx%*4$32GW@73SkH4fh>qJSv^C4&gwztm zPXTrMV!A4w(OBvU6R3n%(@KZVP85-&wepM&oN8t_4`g75i>kWITE0NR1 z;hJ!XqW=wAB^&iqFDptIrXAqH@QBX+$HM>Vw7*{~X}Wfi_2FCXAqA)$MpTx(pBt;3 z^d#-8Jti$KA0G{4(7`Iy-nB}jdP320jQ?64BGWRssN`}s&eBtR4Yc%|+gHnLJznGx*dus~0Ho8I5+?+pG*bx@tO zOVD{>5L@6v)?AU=<+`VVdVa<5l6~r5MjiJqxLZ|0w^&yt1Us+(sy)a)wH3oI&C(tC zzZ>U#S~KV?kScQ{R~@(N`OMS!S)tX~xuY6^Og*XhSVPwIvkKtjRJ6yz+_nG0aLxPC zcz}$=eZ|-pSIej1LbG1a!JWPucwpHZqcW)UvQ$j>u|po!pFJRS%ZPxwSO=av@^)>aOcH z?Kiha_eJJPyo09Um%4`-J%t9KT#^b`_SjggpYRM{5E+qO4%|mBD7cdvg%xnqX0YFU zg;vPclq%m|ojgm?0r^QIwSo$v)o(Y!nXU_yt08EJe9oaZWJE@oG=uNqc~@L70Bqh1zu zBlGD0r1Msl2&XaU;=S5EUejych+2Mqy&2sMle@1;9h&?`RQ%ZO3TrDc{(n8TrZxgeKAX8e+mVh!%>22eieG{<){f(<0Nc=K5sAW zaQ38%^sZI$__1<~Yjj54L@0##_kSef^g6KXk=+>ff))Qx&-hn5Ms`8m79GLGWxM_# zqfB8Z*P@hOkd17 z*}WX4)-`B6IQKdZCoGrFY(rLj6Qcc2VE^*zzXrPhYjs7g_1U3dn6C3tUDrsemcz6Q z45hO)6OGY1nkA>`M;z3XnXmO|huOI}%)9=%4RwN9;L$$8OLi1>L{~{12N~sW4wiSG zwYvWoSot5K&_5HOo5MP%n$hiTf88xkx9?6FN=D>P)?k9zy|H zS3UgEYk}wJK>V9eH);T=jr!o#osIp$ipc}3-H@EFgeUo@?s$?$&XK-P{V`}mKcMI3 z*lVKhc7uNZ0~}+l1U?7{w|=z<0~^M6Lh2vr9ySUJ1|_GdVMCZfHtm>kz<>k#5&D>1u%=&abf zz+Y?p*TM3L!fuomYohJanH{YydsvH5pU!4Q^f~?PHb;&mkI)79LmzviO?W3jnQ$R;2RiDpX;~AXh(4!v1IK@^QW58z`Sx|Lj%$ z^g8Y5XHmoHOm)I_KUZn&UG=F(agCn+K|H)R&^y?e(xF_BXLnLJU=A+cKjWKY1Y;#! zVmA^4xYqbF=jCjD#Ry@?OI!6yTZk%*h$&%qc7p9#6HUE#AkpffbW%*W(7Ld7ajY=c zeLw}cGq_u$|5?hn{7a4EUC}*soZd{;NqtT%#;;~G-RUW4*KdtZ zpb}l4&YZjF-{SW1oyKm8o|kJnOSF6D>#m;HuC+iBK*czY8^wd-E0zC0suc15(CTQfHb)3{m zR3GQ;B3N`)QfhuJ_-gr-YTJJFV_d&7H_QrBJ7F(-<^7`ZS%Fvk4*1JwxawT;%$jJ+ z6*7k%HJKL~X(wAi>^+|Tr19a)HP-KIZN7v~xodgv!^E-H$xdd~9{e+>>mHUyWp$Na z54A&r4zSq?#$}oju|_e_cyfVv@jGxmdOaD6cdx0b@v-8m6%effum|>jW7b*;3jJ2) zo~QSktU0k&PvSS6ww&XxqVlnZ9C-)&>)!SDfO@G4lcN@VNUOT80byX=#u&Oc^Kfri z8d-0At7hO4aN9X#iyhFhGoH7%X2ng4CQER&aV@2g)t60Qsx?(rU%+8xI=9uvr?Hc}aV0dMH{$=)XF&W=Z}8Ye48e`?oVPHk|C{@zCXW*%vo z;Jg1`qiN@&$$Czc^{+X&hU|};hliEP%n4h=;czItVbnuo?i9m$a>HxbwzWim;Vu2|2aZoZx6M@!*oD1logrjj`4KvA%K>nObFhf%=0S z&O>QrAQ-q}sv*Y7{v}*XG~&D^9X5dV;Fp6@GwU`-DSadLhu zWcm)wk9I!)I9lKDqSX05b-uS0|G$cF=&N{AJV##rsqXDt`qN+XWW2vw8>2d?v?5~m zLeK~`aMiRD%uc<>c5ril!g$;p#VH-xZ2H!A=r~L*?tAw14b*;)MdjdOxRz+%*zY*X z*j;9p-g_d^wYw7|wOdWlRoVC9TPkiNQ6~DBmAhT@DA}{A5O(T`e5>bYv{DXva1#_n zjU+L1+P*_&^;2JIcX1T)xptNx+3SyKw#=vA_$E3iFX}y~)BD&>{W-8()q|~UMD;Aq zODiW>Y2T_o)3tsV;ta4cvQqIDP{-53!0yn`nEUIVa%nWN+&3+wxiuG08`ryB&;5x` zr**~V-~zrwcUB%^E8eLmG z+-vQgWWQ?fpUd#+{aka#+(}1p=8w+ODB1%$$#Jg=KKFpW_9Ob;Kd~Y|)8G546}y_W zPwUj~(nCONjv@kZk9VhLVi(=}i;4h#57pv2ac8Q4w<`aCG`>H+Ic^w#sZnXH(X|%E zS*^_<=nZe8D{c3{pK%^rMGay)_|a2Z|NCIIl_Gbm#hfgsF)-8QfS$2c*q4A5F-BoE z72NIQYlk#z?Z;!z(_&ruNi?~(C;~PMwGEny4Z!}`U92Zg1FoC9!qZnP{yaSycXbB9 zhd0;Y0_|`QgZ;LePttdImsV5-Z>+9|MH6nsME59SnwV zwV!@V1~OJ3<3QfIoBsyaHI&$Vtmc+`dkawITZL~|Ram9JfqKpY(bbUix-~qdeDucZ z!!d12@p;nX>P5Lj2GRk5qU*pG#r%Co8)*~;9l7;vIYHN`;L{>J^ZF?eP6%3 z6m526utwpcFqLdlvN6v1BzLa2mpeB%^Xs4Az3wS4Q+Nhn0IswXU?e)^3| zVOsRTqaq)d+uGn-8>L(sleNVE0wBNyO_~uKgX*$B$hx3GysP6hE>l`1l zYpy{j#>k&VXociZ&8`O?zb+j21ilK!?XK1?>@JG6K(@eS+ld?CaGh0elZ(BBE{mh3 zHHtDX()#~i>p#RP4v*>D(}T57?MD6!8L0Q5NW0hp zJ+Ub$SuRFFY+=fg^iSNwYEm1lhRR-Klw*+0$1U+CAal+5wsoakb<* z6yXnl7GKE2_(30yYQStQQ51Itnk7x?5#^D~xdUa79oIjKf|WyZ(bc;%x;y&6=s(J$ zt>@v$*Sy~sHO5|Pujw9~xs3*+@gXXg?`Vv^!X>r>IGx&5ma?g$SgXi!zaxxv?b^p8 zcT5r}L;Zr{!EXE=_oCE%h*NMA9F4P72~QH`+V^e~JH}?bs=Xs6H3dgguY6xI_!C-< zQ}pCNz;EZR=t+I$-BgA6SKN5^(L*YHXrIIf8u;KX8AkV z&xbW$`NRNysOvWeC7skpZUc_J7EIY(T+$lAtZzn*D<5P)5fMZ?lmwC*oHcPfDI~hD zk86UJ((8h}F4n6x!2A1Z&Ci<@EnKg6OoU%>{dV=)dKRD151Wg>)AwM*=23SwzG8}= ziLr)5z?FTVyEqfoLE)_cz135CTE>Cp(?_YMonWtCX{`3%(Hg5WQDa@-b~5aV^bK6| zc|LkD`n&#&(%eed3VI@Z5q5+Vp={hJ?hs!d-xfa~e-TfPUyARJyT=E^JKDE0gGc(b zW}MyIazJFCCJNY$hrr4dJ8ua!^n*nC=4u!{UMZzLSS{>_9pv8DIx4)@HQJ)Pou%KL zs}I*f?1X$8KDm|o0w|yII7%9~&^D!URS3^}u*UNejqMeR$1Vj0TnuWmIlHYZGXpgC zweE;tAg&ZuhlLkW;|qt(y(x|Q+{n-P}V34k4OHv zH@YplFS;xGCs@BH^!NX1A9zonc~#j_G|6)Nk<;~4PN8q;a%@Laq%th+BD97a`@3)L zEWp(k`?Ku@GdLf9{V`qfd?GhjPnNM(mk|4>5d)s3JL#xlh2C$PPUFvX3c9NPIr_RY zsIGjguTKT7U}fQnT2tTBIWq=go7TR)QGVBxafE%A%rXm{b!(8*1=Pu^qPUR98E5T~ zqttOGYktns_3r1%Mqxgj%rxU1u&wx9B7)*OU zJ_mhJsjp7`xCObQV;cJc)urBH7G^C_O5H#dB|Vbs!RBd(_k1zla;KxZR1>F z)mN-LB77NEgfpQ@JTU&N*8iRHWAQ`r9q~))<3wNR0$tvj%zqH~5S8okqcr2_5V^E8LO18#&( zW_`C`^b-|OFuO+M*c7+Pi?v?ca`N{_yR063343~42fiuDfE#sRk7|dozH>acJ}75!W*!g+BqtNUQ7e+=a=HQW&bwoX_GY4+(PfJoAndMh)>ZD;In-i9L0BZB7R3sy@jmc zTlSWjAnE7fcjMeOEgS)lVr2Jz)TSDuBv1f<%8W`!#qQAO693oLzO_(u&a4#2_{S8Z zx!3hGh~l9{@)O}coYr2_i1^BNit>td_M==q0o}FV=>&g6Mf^w3?JwaOO~iNC2&9?x zFh56`;UIqA1u)1v=^0v`q%v1kNvq-ztj(mW`z%n6c65ACWAZI(0UdDGZmnmT#7uP2 zKF|@~O+B0`dZJg`4*YRfd@u9K0-I3pKL-cId^&waAon{cnznxO#YaP%rc#)%jsblclHT&K5M8=)blrfa+&tliePGU z(Q+-P>&Qd_t}MR6R!8{?#kmoB){`_-+-r5mekGW}4>TVi!nI;N)yI_@p)*l)t*c>S zS~wC4;*z+1+$SCs-w+RtpNwyf+s2vkvhb|#tSYRPeK>{AfC+b)c=TubP>u*sYW_LC z`jfeM0v2g)og$~{`Izlu^q{pF<8S~bKpB_-IgHUUFdgRME``^*kZ$=FJ?V;gi&|CD znl4s#???XF15Ug<+}4mV8oL8bb@O^IM}MU&QNk7BRz1y1I0*Cui_}{GvL3j#l&p4G z4%M|fX!|y$Z)>zjf4!Eq-;2PEHlwO&EzIt^+L35~y`ysSQ)>PJvMyZH?a2;^5tx#KNrsrzD(mwQ|jlWsM{$wp5?_=h?{iGTA3NeOV<#*s; z@W1|BQ}FZNiG6=_bx#|pgc&*U9of2jk<)eE)6i7@8dWQ^ia*dgv0v^kcA4f>B#L=L zz4Xk_L%Fo2b^>Rbt}%Uyn!uOnvdpADu|audd(=YD2jP1m3}Md{<0PA=@JMxtd0bH% z2#2^mxlS*%1&Tolb>v=JgD7$x@zQXe{`5mDs|i}@W#HS?hNWd*zpHy&iQ5)OTTz=> zME&+1`Xevv*_cH-UGwHy)FfWkzZdA^TfE{Q)Bh{LZ)u2$)4DFlPVw1h|59xDTZjzwJ=GYyZQ1(9Gwu>e^6I?TRXRIdFeXaeYea z2UUj$)EC6zUs9Tn*0gk9aJ{}_rRRsjfApO}AiaupC61cQ1*`l8?HK2yHgP3-SwCM|`%XGfIJ)^&uj5+WN$o+S$U;BB&)|Uev-&W3onJL1 zCM=JO-x4z3-5}Gq>B_#+O8taB)_4%cMpY)c!$xKqMX?fe-(j$5=0gp@Il2#>c6*<6 z01aWM?C&}CzJho7u||9@tc#z?D!pse(X75%GsG^E#^W`?vFiZ*lwz=D#neLVbz)_z z67mCM+peH)c#(eZGIUwmvJ*5$p??5=-96b+j6@rRnph)6B};JH+zQ%s6WIOnFh+-I zZ~hR+H@nHd5j~7L)VgRtjL;92{o7$?tujVqZ%?7UXgsblIJL-KT9V&x)E!QPbM~fU zfVat$%D@88!oB1>D$&a{lEZMC9;%<2sw*i7cZ9dYPaz{Ni0!^~fBbYjE}j}si)ZNn zcPI*2t@&S;r}d*|jhUgVV34c;&vFHL#lQ{i9Or5?)Ihf6}B$bgn zbC^Ut=ICGszRkuAP3NRu4Buy+o{KA~KWPRmKq+S#^?c8Lv%SvZ?7CH}d?``HD)c=z zf)HE{igE{?@`JErUW*>k({?9*6f^B3z0y8Z)RUTn2YKDfnkyA?Qmw)nXvWk<8r9yQ z)-J=rx^s&AT>+JXBYNL2bVm#Dk)2Le`$swzyR}w_;CC=e_w9Hv9o|?0*dX`o)}hS2 zRIjiS4x4wB!}{4NASbP)I7G8}9P7k6|JPJ7)_`)&f-}>QD#ST>z4v29_M|st*OEW< z+LPExCQ&o^5Pb7TJew6bdz)KOlRd2qox41=6SL|5=YVF<4t2q2w!_P=DZJ}eDV#tj znCEu8>jeL|3kpWHQ0y;3?fw#F*8kF6yjh1vfc939{^TB#@QUX}edKH@#Is7_R-j@}5wb>*-<)w%74nxnPr8h}~t zjJJ6X)$YT1lv(GZDo!?LV1xLP~d!{Nj5z9N;; zVRe`nCWRNZ`d`zj|5&)67~pSc!M8!rI@#&HUcWbxy}Km{NMFaEG1aI)n^$p!YWP<4FkCTQ ziGERe(2Ixkgg(%9+FyLAuKJPaQOz`CCvLK?tZk>(Qv_1JH7-M~QKf5& zm#*=p%~2$@f=iC(-6vEN$La1SvAbFM%N5U8q9=5(AL|v5NA7M`O}PR&TeX+=OwjGK z^!=^e;m`0Q$Lrd@rcyZy^w1b;2w#B^vWw73GI;OGm+I+Q_aT>hPZ!qW1^Q?ShG)M< z+!zG=Gk#7b?Hg({@9Nt2YM#}>N7?=3im0boCjP8L&EF1i5gPa1U{NPs_v{vClxatl z#(IMg_U9#34qM=&=t#Uf`$AXph3-@ot+akJDi6cth}PkE;HD<(?x(P;eUGZ*4`?k+ z#}&mmruP&Nyn=GHm2VEB7FPpia0|L8-f{A9T&|`FdOA$BS&A?gz|5Sa=W7)oYux^d zV(v6O|68Ivs8KoBcnbu#6?J2+gXgsa90@h!-dgbw#*fD%;;}mYUx@FC`^3k>SK(#l z!biZyFGpKwFUlBSphvn|ujDIU04Ci?(Oghyu8_K;ZEZQLg7-l;upl*3ee_wmaEwUD ztePsQ;8wtEIq2>>;MjdSDvuUfBPzCCKw-5;Z@8V-;uYFsUkY!9d$rytg&%bflfp=y z`8V;Mt6={PN-1mh(T;o-tJ`|c|4^)OE*_EYYBd49nB)_5C(H9QuTRaVKDkP5t%TbZ z%b7bihPvNau%;7;u!kx``#&7KCuz3Mq=NA^c)-_EY`~uh~Y2JJGFzPn@FkM+dI z>3gd+16JY3?B3RodXmO|ZAJP07`m6I6j^14Qq;MvSY)i;alGov!Njz7*$(^?wrL+& zso&XwKHqA+ntNcLBX8orVgKT_tfbDkG&IK-a~~1fQTnnC$*^)#%z{Q}z;;1ZFdMF7 zP0rt3&93itr89`M$8fLj>8_`Ohkggt-(Ef0eDplpfZRzBN61l@a6NOV8k+C4iO%;2 zWKiBuzd?P#`@#QC!PziIckA_9p%I<*_vwOrh!Ev@oTgW6s=kI1b@t zGQGL;&}DlF#r4O-h%haTg`4%ZR;d*u2W#!S%JVne#)?rIEXIxeYQ54ciWDwGx8**) z#we5?p9l}8bT;!sMX;%6!dN5E4%g*^EA<;uo|~jKG>n@6D|ER%V@HFl`$*635#?)R z^fV`++prK-pN~PXO-|La=A*YY7ZjeAY`>$XdXQeg5g1VWz=r$+^JSyPyFRWU?mszB zwxZ#ws4~%Ab@0Cxb+rdlY%RxShv67{r5>ZoxsbEj{M$KXZlA%~*%j48EpQ-yM;Xc> zf6%*?rhA>#4`>d%xCyGj4M4AU*59SVF1>zPX5vP6uC*y`kWq?=o*@DnuQ~jV?t7u` zC=Fag1^VK7M0*FQUi^Z#y8D1uLX0)D>=7_ezx71)EF6kiU?(SQM|p?-_ZsaI2T@6^ z1jnN({F>(U0s7%cbqPKNg?e5`-~+AEE6!y%o`LV!SWwB+^*#3q>;lvgJqUYJ{7&84 z)#SapI>%E1)ky1wbi$pkKdiuR=nD?i9P>F`kQ$X@ebp*-{m{p0iK3M?94k=cI*PJl z1#nx|o!Eu1#ZOfH-`6a%Kh*trLX1i2tBhu!9tz52Q&f()sZvO4rj;Y6H)13MoS!@E zt|uRWWjB-9;XTbDyIq?xk4FQ-2Vp~~9QTYbjBkmb zkDrKdi0_Vv#S`O?;sJ4~c(WpFdozTv1-`W_J}Whs=4hOZraKIRuOi-6Ct1PtExhqq`F&_amUTJ^NNuTX&~^I*8;?wYpYDwbA+Q z%n4VZ*V+Oy^ssVG`^9z9sGmc|)Dae2320^aO3b5P%>3G_tF*Gq3}V$uy4O#sXiVVl zKSu{_6BRovotQ0tKx4X`YQJ$HRlq)1hGX@!etsHi4|AyZEd&L=o?7!X&=ZbVx6((h z#9mSp9if(Zq@BarZ;q&Id!?1D9wMsvp6hW3W-9+53unQ|>0j|3s{yK~4PzUj6{Pcd<80A=J1{Z|Gpbe>lt>;e0Uw( zU^i{k9Ze!zH+$NOf)8spy{DD`5sDwK3r<-y-%&;TRq-dOte^5(6=0N@QIt&w_atcB)|z*Xs0I2yy)PG{Ft{cBW2b+=gJ`#1! z7j=TY3ljhCJK9K!sx!dAIjO_rey#qCEk+bvN@p0znVPdZKn`47`K6 zd{faOG9%~+JHu&>??P$_RwbPQB4$y_(|SG3r*$YJZq=2~(Vfhu7FZe-d^NCoNlcEF za5KPn?tx|Ey>&4s;v0Arcz3dMi2WfG;986Xb4|s_%kEiOqYKPI zb2b0xe%J=b=<75q2I97LKF;G8YqYxRI-=m7&Te#(*Rci)QTh23Cfosy%R;SfqcA?x zta*`qe1`7qBb_L3X!bax|3!0P104BnQJhlS%unGRN{8(lqeD?;_z*{_$L*tv<7&bV zP&wx1+Gk)RnyYDgZpQJ>LAB*$_yq3d9aOf{KRg${4aY-4+%LXfF~CDQ{qK!$Q~ZB_ zd_i0z{wmz4b?RR8H^dWb!7J}ZWng2f*LavcGmV%h3wOT%$JSdw*;QrR-$~BiH}3AK zxVsR60Kw@7I?zCH8fc_}1{x3U1lK?yNJ2=6ySux)ySsb7Ie+&y-+1r+M~z5TT|4{i zwf2&^<}}W!4h-d`l#yA3+dg|InTn^gcM|^{hU;<{to-&F_0bkAk3#b$up3rKO(=oU z_D0$K5@jSK!lbY`Y*gg(WO!LV;GOV`;`zU5r`|w>W=yd8nw|^q%SU`2UJ7sN%%2^W z>)c-u&gx3D$4z>Lbqc2P>8ihE`uW9-ZH7o+!eScyF^Ars0m8o5qMft842nOS9Ducl|LA<$F`+lN6%Rm^r zjb56gy>Tflsh882uL)CIWte2!frGh%$+y3tt9AtyudArRX354*g0fjg@4!#G}8@GeA1-O2e!VzX%+ z?+UO%_Mv0p{M#l!nD!qj_!M)YnO%ygco(sWyDsL?=}9lZ)34Lu4nLd}1V85q%)G&I z(sXnYT>VUlwsO;}OwR#dDyzOb+({4QrVK8?mErcRPg?cT>`Se{4H=7ENb7T$h$k<# zYqJo0y00uAe3$O5d7oW7o1i_>8&wF`e`djv+!fX}=hl;S?MuNr=4IZeQpSU9rH?)n zW-L!+?4}pBPOF(6X7jz+`9}J3uI_G0%&cQn=R~b&cj~mm^?%QDFGUTrUU(u5&`DS( z-WorOAL{GV_<8(Rxxi!b#@IM+m393?*R`8<-=g=L!X0$4;&|f9=63Xltx03PLuZW5 zi5;uMz?d!MMc1=8kVy zTXj0s}TL9HFMIF5+zV*b+2R_+3;k% zQ#W~l1t9#g*yYv{^qfUL{q4R?TacEXiZKqZEt9a4@4#_uASMV%Sls_gTAs*Y{6Qtd&Aw9x7snR7Pr zYSPm@sN9s6ML3!nN;d72&`j$?L5mH=-&u>!RnW!EbgUq@KCaJ} z7uFLaZgz13Y||sGytpiLHW*=dIHMqKoaJ(&jV{K(^ns_(F|sm;;3{w&M5_gx03F_6FSv9 zhF=xO_fbUexc?p9olAA*|5KjfZ!llGWA{;*6Nc&cX2X6~=YLYljX7+1i8o z|L!odID<3q|6AJMMy*fOzrRxN?}w*#)Y=2hySZ?Sjs&wap33h~7<48x2QinbfOSq+ zG3Rp}-o;Y%s46m#Q;~^lqh?Eyjh90;qyRCYaSM%zR4<_h(hN?xHq@uxi!vH~1+$`a z;BzR?6lH0!{3WTwUPwyd6O8$+rPHn*z3+PT0NZ8MHCpQ#>vVnHbq%YSf9yeJ`DYYO zJ5ghDe`%pUeFDB~HM4!A!9DhZ#m0?5x9-{8uq=);Pm2UWsnMC#9Nb*WIoYCq3U+5kG78>iY7P59r)^ zRCl5dHNkq!1~=EeEDEP?Az8|L`X7;;?Fi^O&jC$_<8K{}s=5Ar$FqT2 zJpm?c12yA0@KmpbJz-1Y`)qsMOoYFOT{nkXotXl2jQ9VOeS(Y^`oCsy( z{qeK-ivDgNA5!%HfX>O5u~6I@zR+51hvWJ;rm<#&aa#bYaeI;*wV_jJOjigeU|n!+ zsyJv(SCcCRXL_DlGseo*OV3B!;_FbwDMP+ePPyV9`OsXt#sX*&7eslprB?ZRGO|0v z8#?Vj(C57mCK>Z6oAIxW-swi!{y16mV#NecX}3Nmuk~H%sm%Uo#RvaTEMWGAx4{c6 zRU|P>8Nn>&16D*BCI8SoJ|2g}e5o?2e5rz|nev78;!yc_^8@rFmUMpGS0{cyI$c9_ zXTG6Q+X=-VGlCD*zhB5Yx)O8trPDi@v$q#KprbREZZ3wo8N}-#{eLnz755H?z=yC( zJL4kepUvr=S2nj>_LLhmwUOY(-~^}zR;Pu&N;3t58+C;RFsiPS{qECeJq?RwLHMZL!?V)iOwgAbQ9YZ?oMSe!@(YPIolnCZ zW}Y_ZY>V|dPVjlwq6g!BqNZ^a% z%)drE?O{4ix9MkBP$g_lC)B7yv%clXu)r5ZxhEI>n*(^h)yBu>RIXuaJ2lWYhQpabRk_! z&u}o5QdHbN-W#8Y|A@Eg>o4(c{iz)fDWble%+ocTl~krZ8GMkgUmj+33xWJCOXa^7 z$k8(NemzA|K=;$kI@NWpMVYOt2VZkVm^sQTzg`DRgxT$iffy}M{B3op!#b5NQ`Y6a z-kZuq2Fa>l)7oBxUg8blgslbghJN>jEc`|N?*sXZoAsEtW$C}^`~T?fv=8qohH$Ra z8O?WVGX1W|;eI`%uk3$8$Q7@QzsJRKZfu%*KXq#=XKJLbez5NSI{fgkq~Xcl@D(l7 z3J#&OHX8fw#k9`5$$Rv#yMgI87H|UW43l*i`zb#Dl{oolI)oN2GSL)YB zI+z`5E2#b5TGy6vCtRlAcp~vUd#5CNyA|jw6on1LT5QEbnwi^vj@d_yYBrd|aKKJwudbys;dw9fSEQK^QYgNsmB>!eGjeS!t-RtI zuq#+T6|ysNvL@pt=fe!(_1a8_Fi_`OM;~E&MuEgrw`*kymG#LF%9g4yt(Sx~bVGXU z?zt;C2d;pvoM08u;<+3x^0v&|Hzty=4s&@;_V+E}Ywe*SVS1RS6KA#J=Y`5dAC~8B zOXhUB_N*Di?x62{6S{=f6zjkwNdxAg@@aKXYB#OaXJ4ZAxd6Y*Tz#r8L|9Xp);LCe z%^i~xvOpu64lw(?Eu)06OIEy)YUezWvqYqHx1_y4HMQ{n29kLM!B~ zC(S-kTA!xkwz7h|boxIeA8>oTBoR+y2l@eSClP00fOjX z^2SYcFCGNZ(N_251^sTI;)XrpKsXoj>iWmUDyi#Ie@`__?Nb(XAiS){l?@F~Haz(q zdcU??t6Z)`A7mUA6<2g;GgZ5T^T)e#tRAx(bi@hm$#jlyEZR5pdVi2d=#8qybf)^o z!HqZ!l^d%#RfdtmlgD*Hq#NPtGd^e7%d~D@P<5rTck98WP_b)FuHKG`yW&)|3R8ut zL`~5AyUvi$QzI_LtX7$jlNr)7s9RJ**S#LNnARx2)JJLfQrODMa}o_*%tKmhYRN;riS_^=c7pwax|{ zJ?zzb?$-CGsj8hrZ^Ey*6JBdq6vxr!xA*ak)Y`KR$>DU6Yz=cX}_F%urU65yZO=oI;vEcQ;$nCq!6+atTGaz*$y6o~gIR(?#GV{Pr3 z+u{|jd4N?R04tQW4$D?pZ;8 zvzdzJEG9?S>T%AQchONbFUMw(;MS)bPHki|b?IeT_#7tO(>xvX$n%fuv97N#(LFF@ z!`F(#2GLoa#SGT=q=8P$^~#ZBtQqel2e>LWigjX@*f>^>IpRdw(v{j#hv5QQM^7?4 zKHL40;+grm@*(XJDlw^86s0dCN-J~H7lVztP&hy(ako~ztM1%Bcy_b2D)qowUkrOk zU38M_1Y^FQ2yf|3|3X=PM@9D6qkok%q$k18(p6lqPt+>>6YlRHbgnz{e^PhhF0FZ| z@QGfrK64u9&`)j(g8Z*=xqd58@rwSuq3eGo^b4Cp_V{HilxmfFDD`9N!&ITvpm=Ls zqj$Fb|B>Olw+7B2DmK&MV_yRb>nPD_K6-JkZFnV0p>OLBg3rZVy7s9=1V7S8{4jYF zHE}CEjfFGJOq_%C=X_#5*oyE`RDoyRxX&GWr$gkc*@z(XgVklXS$yQs# zhL*-Pc}m*6Db>JN)IonX7y4(}zz$rXf3qJB&f`fLSWvD7>Dm_0+8SQRx@2IN>6KQ) z+%*#Zj~|rxyqr9d{4;q<@y~B?20O3KtNVN!Ci>AJ5UgeKJ05Qu90zk@Ci@XY_3v~L z22%-f2JC4dbIKj%d{}`Zf^GT$^OMWbZP)-?+6pkVi|BDqVYW zb)T#o;A*;A{_=-qRQ_CRn*dkBmmrYMW161#YJr;gZPfqo)%kdf&h{qg)7`1luwDE~ zk>W&I%2l$Fs|-1pLp$MNE&-2CW3m~~io0{)g05*J@RN@zFR~iz#q2%Dm?`C8YhgjLim4;NCMc%X zqLbSYmbNRkM^7Zy!Yu(V`vzI^om#nvLH#|8-p6&pv+7mAWw#^BeMeFJXxVR%FjBVa z7^96&c&lZ==i{kZPHF zDfNv!!KC=3;sD!!Kk)kiaX^m0=J@Xnzx5aM!JMW zw6?8urGH^&wIE7{F-<_z~zw{}Nr5_PyA*}3o^uH>xsIeT2O@I~<0|3z0_6ZX)C`p&C+ zB{}B@p?rKQzNAxPQ2aFB5}U_7@mNS=O6TM)${6b@4#*bwD4tAb1l3^6-6sE40Zy<> z;TEh##j+G!h}*UDMirPD&8+AXwYwfnIwUV?cPt=|a&EjSaTa|HcF0}wQ!Bx8tkb8S zs;lb^Qqq~{V7h~InIqc-UUwU;TBoqQnRKMS1HC$&ICdFW#9hf1vY-p0R;(4v%cC{Y zl{^xkjQ7U&I{z+>2X+2lqtn*7Rr4+t;QTE>b-EzE`F8X}Tfw2!mf1be@;t>1R39`|CnkEyB`WwXww{saHd z-QlJ1x;(+f+sc(0uo4HF?+gjlV6SXPX1PF%uZIVLYh|zPb*3{1}*_ zBgEMGnSE`6mPb`$iF#CE?$FxZre_q_ryikwvqtYeg2{p}^!Ip}9cRF3HIW=};cNjb^_f4^&Af(b8~r{9Nb5#X9jj$lfp2d0!wFie+O#*-aDuZ*^E5f=?fOZ%@x~qVGZp z&Gv3CzmXuYoo6i|s{c-px79D!N^W7r4uKC|B`;uR=M|h(W5Hi^hZSKs%8$+u%zl5V zPQdZuc&MTX;D&g$qM0k=9r01cH`U^~uvjPK3$W@t>Mq0dVI{glEm2plg04~#a{jY= zjI%z+H=bN}7qS%oE|>0TOf1@a z+0M>0>skedEXVzY=tvg_*W8e5vRPp(>ZhmJqxoS-w6|N0I#LffGt7B20xjMmdd{_U zj-9d83Fbr39`?_bGBEcw@`)t zR%7@yYGkHjva{cdz{Sh6zAysldgdaV={i=+eup#p+Y@$(AE=_uLOtDlZbss5 zBa@#_m$M(rDApeuuAloZpVWSw%+%TvxIL}0n1X{LKWKSRg_VFUxGX*(ghR=pj3Uj6 zTtL_6G}VdK@-JnX z{YvXAmVyJUEY%fb7@LItp-+P{Ah(9x@krPh zwuQYRrMTdTcKbWpeeSjArz36^+M5+qH0SC{pc?8Pem*^7qt>XK?A|;On?T4c0d2E_ zImt1g1p2{}(4XniY1EHgcQWF7HOvY|9iN~AyBB=vG3InsFD4ZJw$7*x{)5@bQv^Q_0Vt21{ z^KTW`{}FnJF5ydgq08WC%hH~#qKw#6-L0^D*N1ECdF~z5rVd$?bG87L$ue-b8Hbny zO^+*3Gp(k$?ix_!_sNI6BR?}Z%vT=qwKATzu~%FcFT|Tt9aC3f|HC=^M}S4ys_XQG zU{kR4Rvx~<-mj-P@p5dZ4G55G=%6>iQ{BSqW#{K954$yr+ zlF8(oDz2(a-0C}OTQSq$C>RvY;A7u@6eiKLi7Ws1D<#1K)C4_Q9)qWHNoDh*RtmN0P^| z{yj`c%+vE{!FT2vw<*k&y5gOnMn7NPbTphobE%N$hR>@e>PpARCl0``ZsjxgD2k%S z(FT^^OF&!{*NMDA9`-8jzwEJc`)n>Yr=BKD5ZGdoOafYu=r(ZMK33(stx;8d0km9vgXFxQD>Nun1iPJ1b7~d zh}go^(0r|~S#v$dW2|`>*gn?Mb6rWla~lemN!Uxya31}b0x_TGei z-wZ77kGdaK0*rMDU1u#_+jN~1?g{5Wf1@Dru%owDiriz^g`Q1{KIl#=w6;fceYAqv z=S}7HL$r2-}!bUMm`;4cK5UP0~i`Lh2vl6R8-DC2uA zc`o??)!aF{lSZog{Miqp{s^5P*N4Z+(k7w9)hmOjUr!|9X+h5imcha+QhRMn1-}J* zt~F7;doz`SCwUvvu_=wRa}E04rSYT%QO2;cW7R)9UQMZ4*@qo~Ln^I<_8UqFGpIQ& zg2Qq%sxD(u1?$Ui&CcJGsR+;Yk3pkn3B9|e#HQBnbOe)w$o_zAvmhurM@fhExJB9* z_9&;BWh=nsqZvid>e=&|Lp8qNT}aRPpQA_OOe}lY1ioiwh7){_?ptNL`C05gt5{Y8 zxwn`8v-wD~z)N&cW@>I2Gci{RzbYPVtw=vlT&vj7XW?r7IjOV#yli}FSgD_G2}eT_ zeZNRwo5ShgY~X_Y#73Pai^7gjK3=Ct;VZ3bUXUA=IiCVO*@ARdo1=Jc_0LHlDQ2Js zZG_EArinI#3p3AgFVukN(gWBl&oE0rv0m_|a1a0QP?nyt7#st=Ur; zYw&I|!$DDU{OYhDl&5Z2Co@lDRK%s==ZzJwoZ;8F6qV~N5D@$2lZWd3eXn z9H6`6_o@UN`EjtnyO@bN3a)k^)rT`6yl0{`uo<*?G0yOMpmu7(acaJlGy_Tpn6Etd zXCCY7^rz~;*3y`{i%PmnCw0fxp*enl$zp45HN?wT=KkiCRg3}C@HHx-#)JMw++y}d z&(m1F!1&fbl24KslDC!1z9OIY2EC3C(5y@|J?{alVot~u9peJbnHOae^8^Tj1Qb9H zDt6iB57IM|JM_%snTg$W)$)*b?;LrbMf%JUBy4sNk!N8XSk1iZApL%CVysgMm~`{Q z{81k!_G2*FBzlf(t##3hKP}&~Qr15>)Q!zzEuH+kW#d&9=^s)Aurr*Jm7mofIiasD zVZHvBCms)n^>r{D(kU7hH6K+(ki@f!2u_B=v8n$5a5xLT*jI9p9-i5}v(ODH%jz#9 zvzn3N3NquHdu-<2m;^p-hR*P`qKfMUi}baU$Y42q4@1#InNP)Kncm|(ILq^T#@OVu z$hxKgq9?fU;-(4IM% zTF-~da6Z&*^25&FOlN*S<>iCJ7y5ceR^zV1Roaa~pW`q!+kEm0H)psPUDqi~-fSk# zQlKmIgAFc%f3-sBg`}Qhmuo=Pv>)n0#=+(bTQ^d1eFr@t7D?ndNH7jZS- z3scGLz67^AQ1{>5&r-<20fp zN7w|nTwjzA%&B=$*5ip`^B0U`2KsE`*k~twkk(JJM)fA$v0lmvK7cpm9eSCLAXdZm z;j?2IC{y=X`Y>VSC~cTtbCjMP*nel00X!AP%deG+c@^yxjK_3Ui6WW8x{|ZqS=Ge32$+|2rKMCbhkD8{vPfj8(q#-L%l59OaDNj{kN@6q}FxXvQ;dghVu ztDiwd)r4`jB3VEOCePl~$-iBB)KB{NneaD7{dM&mSAvRx%r{d|OMUJuL8n+Zw+uVK zrCy`G{;p3iq8u}wbi!_^#@PTR;zwm5*gUyZJFJ$f(IK=Re3 z@==irZ8eY?^*~qEghRhHnj~p;JkROwKu2VVta>)My2H%M9%cUAE4CR-t@(PsLF4;3 zywwP%cP28~Y?UZ84s<7mafCh)O|G8WcS~UlJ*wTYl)Tf^=$>BPtnb#rE-{MHbH~OoTn%43#x> zz17gNtw=Yy5;kW_n6t!=1GaI+%$ZJ}rA6PAQ}@is*QS+Q!Y5^W(xsPUf-tK=OP zD+_QGutNX(@69^<&xU-8`I9&|^imExT|VJ2@sju%lYogV!`jG>S$8F7b*X_mQNiGx z-1FZjnN(V@wezfrnZ2wZmClq7!2rJjoX-Wc(}sazu>Rx_7-?3LCvL>@j-a(QgUY|> zwEF0o7vS)pub(=eT+V&5!dGscu0v$?r?i=(BAzAsf1y}39#;0>Rk`sKvZkWwz*S{8 zS)JE0n6as5_O~j4^N+*edUA0G%=1+O-TSgs>8z<#gr0r3aKG&1YAOb`G99PtpsvmG z)K1=}qvG(>;mTNCo^!muyGb!a9W;o`aaznk<6?hO67}Q8!8PQ2!lOFh+n~>SCAgw8 zTCwe{+&QYDCpZ^IY9+?&>JL+8I<8pn7I~K&m6yC9-VPsx-nxgE$G76@SS{5a`!^o` z40=Xq;4ydKq5<)C8iVf|d=XCnTKZWRdY@(*z5==>dC8*9`;o5g)q^d+5fSZ0 zdapKAMYC3cGRw4LJXTOm@{a{MygBHqa?T?CZ^%d66Jr6c=7qfu_!0FEgFSLO3 zJjkC5gX|lTYW%_jVH17*<+A4kp-j9X{x#N=<(JfM%oPtR2iPl{J{h)R z{RfmS=7@U~|DO!b5Y~iQI=7q^oYBAb1=(Zmcy$~h3-Sq3Fl++dzZS&|PcCIgeQ{B8 zl6mj*FfABmK8RVsO~lDw1M_a04>_&Fu?#Od6`r%1APEZZ$J@?0{doBy&ARD@3YM0cI^T+vFnVeKY)_Q?@iSg87L6PjDKaWBRfZ zm4(L@HC+~;iLdI@EDuxk$(~_8zYreKH4$@i&rTf2rxhWpQ;Dky?zKobj&h2pUKS^2 z&a=e~Mz3z7)^sB?7EPZIA01z8y6q4P28hX*2*I#eAU1Kq+D z`*nJs8k}=wi3+Mv!>Ed{Dgpax4d&>wP|2vsgrIf6YGfGaeC~{b!=xu%lAV&z@m76c z?(7fa)^IF-81qf$;{05Z!mrHzm?3p#l17V_LlM>|nr9jpqb9IXyWSHTw@E&39tl3gluH;6;YQcNABm^w%>b_RwR#pb~eMBJ_>G;IVjbwhf}i=Gi~e?%$~$I5e!2Jv5J3$$rbn%CVYadY}FkpFpFDYESS%P{v=RIbM$8s zXbN+muamu|h_&~^hq6;^ID47cwXR&I=`Wv1s!31|H{8kHi zfjYqXe6y~lElTB{d#pq6&C|5iVa>gqzPY=PC1EkEO5{+7PF`Af{dwBNx`fz8sJ6sD= z@+#_(mr|W*%tU)b`hGQGOG|eEiZF*!hwguM6mkkOone-i1Nuy66YY|Gr1;QF%YEY@;LDv6{_TYz#6y8f-)c-yME@#m+ z7!6u|2Fe*Th|I^swy=WwR$1;|E!bsG=o5IJz{pawp)DeEFcbS+&;WB_5jmg}_Cit+ zElp4M7om$(MC*Tp?u+NyJek)#{1A486FSLPhkYTNtf6o$5o=)e1@w14c>tM=GUNR^ z-#6>e=}=g#(pf&NW_5xy~AA6F~$t)pEzo|);cpdg22&{K0kEDi$& z?JRvEa|?mqXYp{13FZ{M9&2HW_te5yTGz46It+p1+|2IA`FDd)bu7H>J3$SNlF$Au zc{O=1`9wazsP&PswwM*#de`PHJDs$UjV%qeV~bcR7E%syPWFF*h-QH@VsnACrc+r9 z)_C(gXF_OMD7_uzb&(_LH-qHQ972N~8=1==CLxst;HrI;V z>9OX5xkEmnJ?O%#^%@1>kgf|;ZZXiguJATwipI+I){fbub(c3+tEEj*IHcBb`8ean&$!B0k{<1 ziZuGKQfLbDtO4Gt0m_)JQRJpK>8f0D6w^_=e)T(2Fw0GPTnWO z?*^8?J4pX-=udyBy=GLSHDrDV-82^N?`34L>8o_czlJ$5&*<3l%^g&n{C8zW1!WO@ zOPQz$UYL0?)=>tFE2pC!>Xx$dTG!WqSs!M#7pLw4; z%t*Qhxlz8ev^@H6vgq8h0N3zJ$$rbr2NZ}$We)*6Kc-B7tIqy4ijYss;`1m^F3)4L zDdx|s|CQ0RPbvba8XM{KZxpNOH(zV7lnd)*=btHiGH%KUMfX#e!p6QCUR5J_S8FGD zRrbMpvX9>VG3K8(>33F?>didq09aFcgY9vrcp8&Xdu4A{2Xx2q58a;!k_VILlm8@l zCr`*Pj7tviS{vaz-2=bC0cIx7CGBM82SSxtNB-`NGMkBEa+s&+dz|w1XLWj%W}3(N zaZe!UAsaiRv%4;esChYCvxhTu9@fKPVl|_F-iDkMpQb(p&WZ zJ7q_0sohtZHY-5fAJA-S@jrk9}JE**MRYsF7RewUYLD!LS-7#okP~ z9;ENEgl_b9=I31#_6atPx$_-z-*xn_?Anr*_RUU1Q#inpdEo za!$Uj6@1>#1e#*=7cnbzHL4cv!24As8z_!~z;RUFSD;>Jg@JUmIfU7i0s8+GddGA0 z{Q$DhsrppbnspW07613O)65OnSC3e&Pj?u$y>;ZIC-gZNlI_ofr+fxex_PJ&r5SFI z(%GEK4B=)tz}BENGbN*q=1HnWoR0y#Nw#24$|Xz_o~Ac?TJNzA9P&&iSFDb{LaTE| zr$A+0yEUWgF-ckk1;2dC$^A+5%Tqoq`#($%xSZ^`2w8tVo$T)U9Z__@M5p9tJz}S9 zV|JJs*2)K@;;FDVY@`FQJDk$v7Ab2!9;(t$s}@_zgRBjGwbQeQxmu_9;Nlxht$$N; zl6pw?4By)cxKQSxiZBK>xrMNNk3%_ND(IkJnOf=zB5f^r@KH=sc|zwbRpZTCkDYq% zzmr>&_Q|8VCmoZQ^~dUzOJEW5e8nW$Km~2$5RUGmOkiBYAd_tr@wn7G4$4DVf`50bPN{viN7hC;EC@&Nav;Qr56uo*zy$FEFxf6uGYw#nu*T5 z$|JCgS^Pbl*l#iDDbI_V`Pdb6PbeQw-2bs{oJksKM_jMmqzx)?9p!0yh7IzAPseTX zzxIDEdSjmAs2z&YWw=y-7YZqK!!Achyds&Uv5R#xIqdC}26mIiy zAePN_W}QjTraPiriQ3sD7*Y=~{kx0Wz(hR3YWDCpFqzv?26s;=TQ~)x-?+(abTIZ( zEn7|h;bh{NueDD6f_kKpA_u?~x;|A*cjn&kUKpd(-4(tII^S0-n?J7ISU;9kL~PdB zE!rE)Wfv2|uc3PwuJdu4^3`Eskp4{8&fP8R_oKGx*@vm2RgnFcRMfCaJHNF)*$!E7 zPf*K4VS9H^Zy&KsS-L^#8Q+x|?MU}NC&-(Atw&EnGtKA0G%BrTV=%VVa>W({lCc!d1^GR$WY;q%HiKo*}Szue%!Q5+BS@&`a(3^;1kJiMo#0srKf?{zo*bPcBIT1q|F=HN~liD>q zle}nt@20;pgV%J`#-EcnuwVX2_hb>8lUA#k%RK1@c;Jiagzh7MHdDDy*|;0F-7O)fR^nioqnJId zitt!?O(#eVdVxjIhVzuv0XnXp#@tBlb|pQ|B}^`uqhSkE97W-=IFZ!R+1Np^S3-O5 zYMuFSgeOsQ=ny)||1MXCWe?mezM-{zSQfHHuiOB2x&mP(F@|gVrQ}Ttgn4w#7NCVV z9j^H$U<+r$IN?51ngRL<4DjbbPdb~Lqo0yPcWL=r^6*64>p7wWA}LGPx~*< zOtL%6u6&%A_b?B=d+ha55o$r*tO>~48sKj#%2T+*QIjdhhMCE)5>yZiqlH`(U5m1? z^jRg!etS0iemJM@4CcP(!i;a$tDGsD>Rw ztzkd?vr_V0)#!PZVLG7-QGadyJX^3L_fjUz#&WJtMN?=A`T9goowT0mPcZ#;%dpk= zk$?Jvi4xB+c2)%T9qeddB%kW^an7tfA+ZiTU*k+2aQNey9Ay_p+NN`YeBF_4>8`k6m7AF-BcUDbJ1^V-ntCl+)kw4syP*4K6|p{4TShRQ z?Mds`(5reh`G@|zr?cf;Qj>i@k9xxzJj@uqTT!jRIGufF1Gz{Ucu}gFdE+7ZuC7G6 zO>~OgMpS#XvfYwQ;q8WTa0|L5d%4rA@Y*W;@R<`*Kgv46fr~ zrvF(h;%=hxoE1U=s@wTOx)-q>UWBEYS*f%N_~B#|e4JC5xH7Af)kj-}=fk)93=QHt zF~^_ze;afs-SaC*6)in8lSQ?vCbK%Vs3$d|np6WO*c%n~r!|`#4U}gBr!c2eO?bQt zVSi;{gxa5(^4LHgFgnA~vW{ua)AUtNQ6Vc78o}<-B*QkaU3Ti}+PSd58e8fv@;MZu zW-(KHLTi!}WXmE@F@B{BCrc;V5_3!Q$P<>r0q>5{G~$N^vTS?h{2BGE zgUmoy)U_R_i*Jv6Br%R-5B<;dM8FZS@m7#5#B^0D>QV<$DL(}V|3q}FJtbBZJ=&9S zY1o2tQXMHp^|>U9=T@flBzSGb|KGqlHA!*(TG@0qS#Um1!U@`$OX=(#(APHY5TgTv zY@~W@CVM%m_dqI zH|h#1F?W?G?1!6hk?d(Zr|U-a6ZYc|H^G0f5=JFY_DukP@wra=H!_OUGeKegpveFE z-23y z?fX`$NQKcjG_rRelUq^Q)EGK0u0d@953~cef+0F7T!%lORKXsuP!wDb{RHbP=Z0^x zGE=T4WHX;Cq8hE$_4L#W@&IcUZ`>aq4R?pfLuci!2f3~paGZp&2ezn%usF}9_PG-r z)k!k`(VS84Sj{FsHD8_QA6z>h#r%jP*>PwnY)o=8AykJs<-?&v{4t*U^Zajk@@{kn zYQpr|j&tA47%e~oG$E=l4X)o>r^R9as09P0nPjd6k64{-p(4l=Pn*@E_g9JT={(ed z%>ObCpS(EZ*>~!S%7Nr73)j6TFpZZqZqK7{iB&(eiEOcu2WRidS+i;w2yFdOYaCX5E_v~vByoL|3_OHCp797=t4CY7pw z@Yx$1)LDMmT%SWT+GA-ILeB}zAOk-P0(L&p?N+8-(wyq6!1}GH4wWrf?K{msSQzfZ z!(almX$@yZdlg*~#Q#UY0x*qpNd;&HX2g$L1@SwdFte$FZwzYZh?<$Fq?K9OI0;ubVo z%ER3=U90T%9M8^JPn5TvndpP?dpO37XqXu{WX8&VVYjPpGB@%zFZsGWMs?OJ#= zYA7X*f*=GK{Ajx%L|x&BAkxgQ=RDPT`mc2T zkLgtUimqr6t<7Rkbo1feos_9eRn@-Q2(H8vpa=Lf{QlqQF!PT~?_#30 zI5|==x|!$T07|PIJ9fz;604G#emKM#usAbUoFcBuPiH$1JJRg?JBhY0z!Pu`M!ozf zy;|Mx4#mDx71JlWJ$@Z9W#r_3>IH6{`3XL#P-wY3(r zxx=&c-9ebnW>DEm*94Bz-?;E6H)sWBL(aejG8(3p$>g;M(Chdhc}lt1H!w7PrGL%W z{IS04MG6QGNREC>xCerDO)-0(y;hoM<)S0J#XgZ8IY^VIu8; z@S#@HIo4INYrHr1R+L{^ex#|a&z8CkeLe3!&zzVsa*|@xFBN@$gc6PMo;$T4e^b2U z-8q{oz&a`c=c)RgPD;R_oE>J8qhyAAwewub`zstUgXMc>#ajQv{%g|nXvDp0iCRVj zxZvxo(LY&7y=?=ZbXNx7 znwyEy(#-Q2<9{Z}N7pbH)%*tfjb{K(q7-SaOm~o05(5lp#v`pjI-dGq4j967QVrh+ zN?;5pgjdqKcN>@@Tf&OYfU~bVOtg-)Mlln#fCwqwU6>0m#VlBAz9-NBF*E1ydO&B? ztbSlVzw5Z{r*$RPv)ILyQ$egf7q!<@ z`mAS@Qsi3=nZ-2gmm{Qt=%T0d<9*bfP9|y9EhAEm+$aVPJwflJkY3B`A*GqcFcZvw z^wmB*ExSFYb0=>sr2W2*$)B3C@})Za#)ZD&=g?b^NKeUZ(ND(eoF5ZL=`-XUZyjwnCkxqjA;W$;yZ044QbHrL=t?3utto?Km6*4m# zW`i%cFnT}sey-*eCiAQW+l$p(~S3kzsU+Z%*6I4ymg*FB! z>YfyW{U@DM6F^-cbelxtGld}#gnDey5ddbp#zPzr#|I4R6mTs7phRn8NeU(M>H|7L# zRmEq(NqS;OQK>q{JeAo9i&G&eqR-%r{d#%cf9c-0h_mDU|HJ-kQ`Iv9pcZxg#`-Kp zwSU?Y4S34e{r^fJ|Fh{juBO^kpeRXQFpsWwA(gg?ocH6jGPCLBTl>;e z5Zhs4+@yQ4NOs*9KG-R6$4vvpKbJcGuT1x*b+~(jLYNP`q?KnzF!?h8y%SFXbjA8V zOkPGK`9I0iNk@IXps4c|a?Wpg)Q@oe{isakV^k79)o%P&{%4D~MYM2)n7=TK%Ueb5>UVyp1Tis;+z!b&l*HQFGAIJ$T>NnTMhlvPSp#Omdk# zoogS36tf%-*;0aJuSZl`L>73Oev(m|MiO2Q`;WV7_4U6-@co(b=?b*s zs(}hBMBLg8?0O!mQe|Pe+NV8#hOD+Q8q?(rmW0zKSQ ze?FGoch=vZldCyKu}V8-{JN>0+Nbq9YBGmmB$u9RVpb0+q0#p@r2E{a#L zCHu6M$Bdsn#dU6j%isiT0(szqs6xe{Aw8^@zvXVq}iELoxj}#l~yG8Tp8lIw23q`g6qdVY^Oy*Zfu}V;-W%@6g$KAry%f zzzfz@wops?!q0k_yX9s6p->d68vL+6yKm;ate`AqGrh<~ zFfN-P=3VWE;ozA)m*8%P@hl6qzq8=th@j^RQ4Oy}MqQiP)hpzYpU^#>8?xdTaeLgN zyRbm9z_YT+I#^jw6zGS7h@GVWEyiwAvV~R5Qv9mOW|;O`r{u-t0qwhCOheCrS!H<= zz$}NbjB5Wz>QHHZ*$Tw!<%mXVDMz0j?upg@hyB;mXHDbO$}tOVByE~Cr!?qYBebib zuG10*Z_ftThgqsFowl0jO4s9AKx4U)oVX-oHs}#8VX3P%O&2$tia_#@s z1JCAoX1^CQJ++;Pe?AzJZnC_|TA_I; zgn3G?Ka6Bw>z-NNJ3aCLGg>FZbSFFMWdBg>>r?z=a?0;@uRqRk{2FEcx@`XS52!hKq$3+Qe;H_i#Cq34-5$|rcrJdIgt!74qjX#YXwVxHf4J#^OT zK16o^g>36*z3P9$PqO8_(N+7kvSTy*O;_B%UNP~eut@K?S9w9TST5#|1!L)0Og6Gt zalo>$N8Vwa^5kjq0EZP7l#UHzMYsa9$J}wd{LJ057f*f{#HzEnx1M}y4%?-(kf-%2 zUe?vr*Qrn&Mv7+eusO3dd&Qmb?>(a^-I@Yd!|G5{F`toscgfcdq06%h%!PS_r^&uQ z(aJw5%fBXhSf2Vj`Qc9T$KO+R-H1lL`Ph4qIUi1p8NWleK2Bb5jq;&f@`2T3(P&=d z_qBrNWUNdjtR;KYQwixQg>}@Jr@=EcORr>3Aa`O0&=LMlKI#znG6%?6_g%|_g*Bgd z2gMdQGO^!0+^aj%Chm(jr1r*q@onw*-Aqbt)jKWF6`H+dJj(Mw>s5!Lqq|qvJ(Ybl zMA!Q|3{^j%mU>RlHDbuK-(DG4lb67-G(}!v6Eow+zn@4vt6W0YS0y~9JJ~P3_`l+R z-=~If71Yg4@wt=kzgx>U97V?{AM@pPnYMQovh+n`%R<4U6buo0z{i(kvdFBzRj7S=>ewuS)wNU7I|&ngIJkN<_)zHjx| zPWt*DYyL&gFw@7=^1E;As}l-oU+dA13H~5Ib-%@V!pGF3zR}M=VTPy|oFhx<#r)1b zoD09r0@!&{8HB_xx`+GaA@j-}{uRDbj6EOx{XWHqo>Kp}EIe?J*TA5ZLLa3%97uQS zynI}d^GCAtPj!aA5nfaT&`H)mFl-2$Wwqv-eo=OHt1R&s`Gc7{|2E2&r-Z?Jr_r*9 zsqzEAD7#-Aaw@WK7h5VXuBx*=yJCUU;hcV2IGzprR`?m>NwHujUsYAc}Jn?D{IuAy6yPj;6&32ervr~~VyG9S~ zidXgOQ}ybbQJhaJ($s=2&seysFaQ~kX$;ckio>3XEmG}Mo#Pl;oadhBa`$K9&3>U9 zG8mlG0(b`2!gZc4SoLr{-Lp-)?ltsE7X8T$Yt^Z9iY6D)JKRF@fO z)lz;{KkkY@{15wYc=8H(4YQbxtD~=y{OkGu7GyF7U_LdseqB`L%jqYT$@1K-D@mWT z5^Ox?=V*odI8||Tc+?y)9C;XRdofe~&HJLg=PyN=6UC!X&!v3GvetAk6 zyw!cb)*c$A2w{X?-L<|SK?M8`|NKXK{OfxBr?8p+h^qJRTJv$(v-LH;7)Rf zlF!J-7lj$}Ek_i?pHVFDI{5F3h=N zqJV!gpV61ox`+JpTe^pxb*~2Cd#7pD8|nn?sjHoW>h3gMe_v361LS+!Xs>w&t{gnq zHQ@RGtbexj8)9IBk?4dXH0tQy{6J_m=7<- z82!v0ll@qi@j<&2pQ1HT6EpK{T93)m%U0MUT7<8|6|vp_vi^oAJu#HX+Dn5`bM5nV zVm3r`QF&@5t%F*HDX7ZK0#ud-*XQrLTAw3HX}DgRfgWznzt<_IGe7yYT7?3z_?nx@ zRn=C^C0-M5=NYxh7qY+%wAXWt!@NW*=yx`5t{j!^B&^gP7$fi4A2!sgbQf$xW(yn- zC)0FTv3=sZf=_SIK^x&UkF^}C|jUH1MKYI4r; z-;$SjO_606rb<1%V9u?-@ z3|t%z1kd!H3?*YT#r0+a$}g)fCkxN7M<)6^zrL#?Z%{`+YoQ3i^Z!-{x=uf77SDty z(FAcnvN$}eHRz^UBlM1NzrJqN&c91G(GE;zOVq=RAaSkYHuNK|(zU#*NMRLoNPQJi zya6*t1AY48x-$#t!7c_>umVOlvjxo8n%|vVp>zKO{jXzkU-F>hfRE9(G_S(X@(-U- zfBA-)g0-@iCgC4i4PyYt$=i(6)q5UiZ1^WJi5X>DgWJ7BJMLh;rdgT6 zjaviTlPtdfqnKMcmbjZ!lP>2)8P(95Oy4`c?f{DZ*-$6uPo0RB;?!^t-QAxU4rBSXEzyb`= z|Bff+U?y*)=Pz^>+) z@znhK_I6h*f3iB{?YjFlsEB4UKbgi9mZHkqlx+VB?b=&Wp}Ux~zaCLQQD%^g0w}}; zwY{+!*PZiEL1%m`>?qc5G`eUa%rO(RKJE^iUAI5#eE?BFuD`#))H{r+!+u~#`Y@9^ z7{%kC$i?UAw`mrSe%S19s1|*u4B=&+EAKMn-v#9V=lb6VI!&I}8S|L3f#>z89gSv=q3;Ifjr0Ca0&cC533K{XIpfqol}-%wM(L{a3x;Q%&_LNCu`3R)1QIz6Jr&>_X@v-FJ*r>>)zZO`pdpA zj@KxHzdGI&3&nS}+Kw;^$eM=BuByo^TqN5*qp1FbBH;C5rJ{vwXnSO7Pn!G7SfA|5 z{MRUw=%JkAC+(RFp|oO=+Oqq)(Y60;yF}j~~P*;t<`TY4Cb_&ievt+2+z| z!!-G0diPHiz1%B%YNmVMQGV(xed_N(7JS3^{pmAK)H_wtyPVc%ove)EcAfTH*vXTa zdszfOfai*h`5R(7OuyMGuh-sgr|WJJbEQse1-B{UxJ>VnlS-G>+GpvMu=>OV z>QP^#pEpSFYHo2WOHL=7G>&?v-uo-`y81H}uv%8|zI>eVvYmA%jm`8-r|DA`fp51V zk>jVKLOc|U=KSCG-$DDw%$^S@m%M}6>%YGHGB}14T}2({`5H16TpI3jQvin*6+XiovJpUFykmT`&JMPG3LkSyjRcWl?D* z`U&7$jgnjjAIlJa(pPutAIaa7JGIiUf!6+&e%LZ>)N>g>=x%q>zjG9QR?x2gU2B|2 zxy#-#S6|Du8riiLTVVzorj_hKc2WtYDQiboKvObbFdBI)4DIH$Ge4Xw$esh9PgQ3f z*wpMWR@P!_wHWmTM|O9}!mii->K`tb{ijmT$dgW$hkF_Zjg!n2^nwG=xab+WT4(mI zES1pCxJIkHlu5BEviV-T@AoL4{erfv)ItN;I7J0PtYe<>=|O|f({RW(D`*PLEymc-MUK35ZP$7TsO0^k@k z!P7H6k?i=g%jIoap-y0Y+-9^l=7Azz%^ZZ)Z`LzsI$US6WBN|=jNi-J-Jkyz^v>(D zYU9U0(s!Npdry?U1FQGz$-k0EWxHuF@G@5aki5Zbdh{n?fIgAkKd+xWt4F;=9q}XW zy^r9c`a-YpzINPinJR(rQh#cZYZAvnZS~pj39l>OwGX(7_3j|Meog1#5ZPadKBs?) zQ{@4=#9MWaFO~I9Q{FltjM9n!fp*OuXurM0%=ssJC7HuZ zPxAY&PX4VuzdzI6TNP%6@j7c4GSRz7d!kS*9FNHp%$J3Jru$}n+F#|59!IC@mC#wQ zK3BfMT;Q8!Cr3k0+3?hmBi^DI<#&0VmD(w5U`X$R*25aOam>Y9TxXz>J9p?+mdlGY zROFB=9trF8-6mPSQAYFhiKa1+T$Fmlg|J#b9iXeK85UE08N;O8d6W=5D}4f0#}H=f zZWx*IlIKCro|0!Tj1@HxNE_;qX1c1WJJ&q*)c>)6^MD$o zTmgP<8I)hEwu3RPrtcLuVZ}(bCi{(;@6Nl`9QrPJ6*=oR9uV)^)%=V(0_ZAg7Q4qvioo3 z9_<1FbP$G+^-PR-Ze%_xIRjCZ>aIQVJsEmuI{v>fQPo*HH9gVWgGYQR5AcTmbk)z^ zmZcj{;{N{IF#dcCFU{w&|952FuTU9$Q{Lg9$>aLT_tgA9(%-$A7wDnyUM7loBzZ!Q z`%HUqG0~y5&yC8xE4(PHeOey#VcD1!VE?0&wx_IMv+Oa4BJu0v3$o<<6wNnN9zRq2 za*QlufKKC&^c?d|yrOvZ1Nroq^xYTXRA?vruMzX;x%uM&t#`JtRl8%dKGU4!>u`sx zw7s(T0&z3kH=|_Ji}kt#^~(EY&-?ZL%kuSBoPR{;)bj8>nt`6txJ()QL;8ACXLxU& z%xmN~R_M9el)66?O{UbtFwQsJi|DB znjdsu?$lZ|XQs&$;r;X~!(^uF(DmspSWEU$kvdC#@l^(ElX zE)Q3=^@RT>Kl4%i4%E>I1rY~z>--Vv>BRWG|1%5(T z`@V9%$@1;}l^;B#`0f#T2XhQvN33wQ?70|-CF}WFP4JXX{zYgZ|vF_jUQ#_FYA=(NM8S{c1BP5eaytyOa8nwyq}*? z8GKjv{igQI7hwEcwV$BX{!;tv6;7ImnKpe+9-tEw=zMuBb6()INqfg`Ufz4AL(wV{j(VuuA-`29_{B_l>r-FJYMg- zNw!`z=8m327@_y?q?lt0lLeklD5V%?vmU=)>(@THLVr5y1lXWEyO}zf_v18KpD|ir zX?35Mr+tNK&Nmd5y?_e6dplNieL+6DGid!m+Dlp5ox|CMOLZM{Q4t^6!`MR=)9K6ARNks>@e~dM2o|E zGj}Q${zg8htyapF)ZB3nU58TWJsi=w?l}T8`kKEatsMV{&OGB1PB9@;1xDC;;1K7^ z7FNUjC=q^ssD@{N_ zb`wb2<;h7jSy#fsumW|nw3>Ng@IH;`>052+ukx93Krr8vxs zS>8%&e(of2{ynBe}U-gLQ+M0_-@(CIN9fM^lLVR zTVtPiDrTjsr7EV@#~6deBLbHN0_*urv20%?zZ3QF0O>p=>jT01;PPlbREN2(y3-t ztMk2wlq0_&OZZfo&PDMi#bJMs)s=INXZqMv$7a)Z6mM0U^I)Bi$j2GqJ5T$+nrv-1 z6R_@o%+kJ{1C#oGd8hRm-pDDhsglG~F@ zlIxS3wIA}PU1v6?D@uj|VAxT}4 z+NNwhyIwDwe2Xi0*2F9oi)t74(j9Ow+WaAhlUyjMxC_>j=~W}NilZamPJX(R{J2qq zt7M(?LW?*d7E7Iv%j3ZKh+emjyjFEo1b4`*ZIf^NSv%q@d4q>!_g!_)zNp>URrmi7 zegB@m9~lmXW{OSjY!jiO1=fIqu3r(aqW~qZFU6WrESlXD!hs zjKPSPezJehm+j`?)tuGS;7>B{??Pe}fO&A6gR}3bsO=f;uv)2&Icxks?cZIfhRRG^ zz^i+)&h+c`l|}^`rB{K@ZF%ZB1;A}wM91!G;{AuUPVegE>LY7@NWS0!S@y?Tz4!Ig zxAePvv}=9#eM{a+k97 z_q9tpDqrfLnCT_G#y8r+~5n{C}jKb-0z)*7kvC&S%rz9g>2Sps1h-5)y)i2#A1yl(a}m zcXy|RG)Si)jdXW+HyaT6e&gQ!`JMMY=e*at){YfV%sFz-G430?m6R*b#{W-{xO3RE zBh2<6%={47K*#Hh=DkF_CmH(OqIQfXO*^^RamCuruEhH@75)HffLH zE(#a#PGFsNhr~nqp|I_2fB$BX**y{)z$r0ljOG4}llYK&KjRDSJ+`XytRtkH_yqd6 z!9H6=?3kJUzwv**NbB*>ppK{bil`HcWuuh1zik(gEw~ z_+g=MpCyNn@HvRjt^Q{bHghfBsIO~;lzfVn{0v{w*PX)mXYb_9FN3-)`O;q8)JK+e)U6lxM163yC}owQZfSCawvk+Pd_P3#s~; z)}c3IC6Ws>>s_(a)LLgyOV{*^!JGV{z7xQGcx6o^E_z$ogkes ztYWGPIZ&OAts~}CMNMI5If|$7s_M@T5y{Z#tV1_y4KHfNz%poKlX{z@m-b`B;Sojt zh4$x*OeF-(M8ZLSPe?y$lnoRXZ<*c0n?fqhA!LLM+9Am$G>|exg-x)O19`MY1{)Be z{!9eWO0NuH<_D4GOh<8cYX{NzK|1kYYqa|(KKUbdprf+?*{bqc zt{Q{U!lf999qGpB4YjIU&_uSR1E0Eq4f_aLn8m8Vmm8}W5AQoz(MJnLWDL(P+~HSPvy9lBUFyrS3X8^Q{}=oTH4`k;HFxAhp=n&?0&b@;__2UJ_W5}n&345Pob=XPE_0RsTiwmSJ5dN zeoK1=S$O4;YU0jdXC7>mT7WYT$v22x01}GpoA;yFVDou1>^Z)yyxo$D1AdSwwi_`FW%f zZ?^ShnPp7QBO45iqtlm04*J_AqhZ&>8+OsvkJzBLSJ<)yJFY2K#pC0IT z+2HNqLw;5wi~L$0<;}JG*D0t+%-KLlOU>~z)ny@S2H)~(`QVeF4AEvAj=V-_qEToS zGl<59^6EF(leS{0Zm-IsT0xbdE_PuRnwF9=Zp(Nr$J0E(?_?(OjECgqC4VU34{h?Kb)DXukE5?-(D)ZSk)er%f!?CP!!o;Ve0qVP87!1sgl< z4dt52TtR;`{4%0O*q*CB&g`xv#vg`-vNefSNJ0lZovr<~A^Mxbqd%HdjBK(H+FhG_ z8A|q$#8>gnxu$8vGmWutHIaQ|+sG{rqf6>_o{#;k%RKZ~BsW;q8e^Erxk3e6F9g@E zuQ6VJSLgP4p0*n^Rjd7nRS(*k8Tp=h9E>%HM#MS}+q8=a>O69H$X#We9uRXGE`ViU zk;Le6h+yKPm1FTrB^cxA?i}Y?t{sQr$dRom_vYNjPxKG^zXK_IiPg1E+EeQ4IVl{! zK#_Ph;e1&YT|Cv}{Dj2`e0@KKd70(gFyB|m`JP~NhG|dmW7$B%1b@o-9~ZXY?!ef# zKX9h0nRQ(2H+Yv%8L!QKA;88FN{=Be7&l*5B%v8nR@t`?r$@|>XdlM*|4RRJs*g95 z5PU86cpP72 z<}n8Qut^8L2YJwlNOoQOA%~ z9Vb`)L3HtuScOt9>3wGH1SAj^NhTo(-4pZ7VeJx47Lrn5)$6s^{!kxbdzz`Qb%u-;5)L-PlIA)?w{tV9Vu`>krunyCKM_ymlRXER=M zAu`yVV_Q#f3uLYWHl-Z4r7CBr!Py7$iOWG!^te4S{Ag^VF;f~6?_+s?@2vv1xGyZ9 zumw5YPE0+L$k}i`8lX{g_{^JrGqxawFrOX>73hWdb6 zt-BwNula^?pYBVC*~5&!f^edYiz}x1D&q_F)_78E6)B;3i1MgD%X-37^0^pdrMF7= zeEyw?X%U0MNm%iBuw99<eUff#u0%JHhqKcoR%JPQ^v1Nf)^QQ~DVVqcH%@!Cs{z@!DTV|sw zV?Iju!B_!D3YWol2K%6?BlzAyY}_mED<@a68Hv3kHq>YQ-bX}m#6@Ecj1y$Nvq;QP z&Q>77)fj~v%&s9k82a<**VwOX(D~@%l|7*@!3SLL4q^4oPnXr&-@d_R;>1qvi#y? zfrTXPcZ6DXl#JsP*APt|_1T4lUm1Vgo=D@J@T-X05#NNbxTb%l|F+WpQmER7OcPfK z_QsGM9hpidEPK;3>(I-h$2;zG;+Wb*_>=MO>#?L)u=>^U`~%Vb4m_9g&M@Y9EWal+ zs)z6l8{B1KOC(3e%VGNm`M$mtqfo*ZBxih%w2wnR>T~T@J6<0fvYYQs$6HnszhGK% ztrZcY$-CTNMO7n5WkzYl7#dquR7ZvVxkZ(r`-S{txNx?!`J1AEp~U2^l?B+E{s7gE z^-#S}E4)p0V$I6v`Zwt8XJ~tcpk(kd+Fu4AULC7YfuD612{cB&W+>~lwM0WGoFNRS zerUSw4}Qb9N@Fo9V=pXUXh;^&o*CVMuXu+@_ZPC}GmJ(t|A~LgC-4vOK2KBubYIf9 zNV`+B(4N+eK|k!pdgA_a#0XW~F3vPxv99558#k&UDpkNrw8sL^;W#C*uip}F6=rNp z_>O*v?@iwRhtC*x36J^i&USc0totoxt`D@c^A9mza$#^KRF^_Bp4QR#T)3Pu)d?CM z`KsYRjA$7#C%ooc6T^Pti~2(3E8EbQpM*bPUC7N;(>R=aoS^lg?!3}~Sv9s8>lUek zoXo}dX5gFSvD${BV|4<_`0JE*pf3?!+rEskv5v>GPEe137qYST>bV$5G*=%>ZMM3a zdI7qKZQAe`%#!TV3T@Qv{K2T7YG#x(u7+ zAX0sbS8j;`$WUMtXiv_tb3Q>oZ@7CtVML*bg5h24&XeF@>3_b+_l4$@N&fvkeESDl zi^!%LMzdvckd238KF_H2|1TMt#;WKV#A62WeJ?Qvwqec(k~vMr@AnX5-0#S-RgE3Q z!&?k+h&j)PNBR+&?1o?J>_5W-S_XWA&-KLre?o*@0~uP1KDbJ9u`o?|&DfBi206H^g^Wgi^s|u9h|iBf+?kVjD7s(GC|1Xgm(w_R zXHr(q|(b?ZuJP8sFC#ovOqq#=5QUnv0E% z%I_y|r)7kjZD%^FoxYv;^SW5!2H4qgitWb>(eHP(yaVr4VN~leo{hC4JM1-bOLt*1 zuEl>^F1AFSe@BI!`@7JQ(oMx9I`r3)IQ-w(8X~izy%n4-cLKA&3F~?k>pGV)KB8*$M=n0I zUcuM!_52S+y!nZLV)!%Ii00D%&PdK7qpa#TQuRlvN)YPW(_}h`K}wpGayOqwnqb_Alsu zRkXjiDp7k2QKU0b>P9SiKJN6m3w>&zl}Ng*|D4FSI)qk#WX~NxM>Tt0?>L27g?V1|3IDhafSDtUNxVY@doK#ban8@;!dnny|}m% zx}n>{(CwLM>;bn+wOccZP_5smsqCB80L(!DyAlN~#L|x8l~H)7UG6cXy@qe4C3}1i zdH;w~e#Q2pN{(Ua{${hp|rpB~6aedMP$k$xRKNG){sdmhcS+T0G^>?Z`U z(drU13;^p5vYNooyl=k0JrXt!$+A9+TjH}atkb31Uuce|w^qGC3(inWl|!vKTYcW? zAasE->KieX!i`AunIIjO@`P5PzxJQ{q{KUBPbX-ECu3vV31P2+FeC1YEB!VyHb>pZ z(~;-Lf%VY;#Mo|i$M9d4WnJaxbK<8BjQ&KTv&72M>-xh!f7mVz!b?ck8S(1g(n{Z9 z;k4e=TA)=~K11FN3FoQmLeB}2I=z_fJ|t?L5#9`wq5qHlcVUU}FLJnSWbwA&H=OI< zz}&9K7L3LkR6~+$a}U39M_tGb3}dgdc;VABkMCjMCaWfCnART>s`KojDs6U&?{>DZ zTvy@8f78CoOs(g4d|l7oRo$6C@o2@!j^x>ptgC+T6u}wOTb8dy&Pz(YzOE{(U0mJ;WjV{C6$ zYxxMNJ0&EEgjh)912c^LkA(Dw)ONFvdfRs*cS5NZIG|1P9ED6{E2A3 z2CpyDe)vUoZ2o~4ny>X5)5?L06nYCWv21oT&-^&60g8tXx>9SY+?1t z3`FvFU<=H5U&8tgBMYi81noxn|9s-kxf$4g@LjDz{jHt5mqA)&tQj8U5ZZ4Q)(2GM zwi^q&0r|eQuYDw>t3mZI_k4^4jOoPXekk#bYbFc(I zBD00jiwx>{Pbc16W6SQSTKwALFySEmwmmu5V)>Pl}hCBEK~kzkdW@yn#Gm zC0D#uG3_SC@&d135Mua3V&YWJkcCh3IIfDI(~QVbb)Mf2q6^`)gjh0DtDZNmP<8U4 z=U-zxzQJym$KK^&1U}HtRwc${D^XbqAJY#POXD!+Y`N;OQfm$SnYcwVYXAKUqT2_I zimmw?-dzSp(|mSiw6TD&M>BACH%QSPF9;?BrQI?eljG<+-?yPCNkj?bAOl!wW9 zo_V~oo^f7+t=P={EfiYS9>z2+exs>>AN|im{Qs%{5*f|m*rSlqi9%*O%?vyUk}&QT6@2g-Zz#6d0{&$kUx0~saS=~-D4Kl zU_q;?a;z-B-xJu&R>{C>aM@A6OmaDNI9Vm+3|aADYwZ;JgfFUK?wX*jM=1FQD7IMaAm77#~~`}tMj zrx7E<8-AIe=ht)0nZ#yo{0L^Li7!LkoE95k*1UjE!)!jnhA+qVmy)+isHidiSx?(v9|Kcd}6sFva&t+y+UjNy|g;h zNf|?Dt?2d>QbRv%M9rWwb2*UlPJowqrv1Y0*v;1Nu#i@-3gvhkc5@GMJQB&RY@x>O0OLF1v|0CA-u|z$~)ZKazImsw~ zfr6@pD~67L&ruCSbu5ug8=oay5{?Ov`Bj|J*cWUC^MBU`)nmK(?Yokfm~_h<|6EFwA> zM^0ez)-LzVr9e*J#d;+4xru!%`PROJugCBAkeYQ!@EA1VAh}UC{|oY3jyt*-&JNd; z2UHTSN^)U{6jcvW79kTR6K^78X* zM9_iAOB-HkrCQ$+lBpJGuOa>${$NyZa93rT{g6UKZZbxKy{ff8BYf)3!Vev$p5Si8 zsJ1p;Iry5Wp{MGBx@b+YJD)O43VT>3$$IgG+z_iz7OdFU%w{trp*&urh}Jv`D1S`K z{aVFz6wi!}fpMQ##J3K>(w<<{|7LV8+M2@nPe!|jFyd=mJTx&2QPg^W+;1fcSno53 zZ->48HdkGk_vwWD9!GP2N3qE+A*i1f|JVj~Q!eAb^zL^TEqp&BjQBKs?AKyLreIMb z!drfUukW+^>v+<6X!8bUehX6Z0Nvh>XNT>&eWfRr)MfPi7C<>JeD)mSkGZw3pjXYdKcm)k`%V zRz37R`9Lr6KOPKH3V|Y-unJ4z$5x8p{1I{Z6PHQSXvipsdG&YV)N|w}$?-}peS80d zFX$8btJu{Kq?s9nmSr3k8I-FhQVsnJRZAFCXLcmh*2Al5_Dn|$iBrQ^F0(SH<_js!#rdrjPv0-R`|L2X>JCu6!*Re-WAqfk=J%5k2v?f z#p_;iHHiE_3oC?w_>JTmMHzQP_>1^o^*^8RedEdUTNjwI%-I~AQ$OKeA&XkINGz;C z4eZoj;>+de{c7&QX1y6R`ZZDhUaaW_u|uvRzS&7mU^{>_dFK~(tacV!?F8&XBF6I> zv%i`+^#GYyK;&3i_)=N?2JB{iEQ)oUMfmc5vo9L94*v|_jz|{~5$+-S$*V}KkT?fY z=z49X-;ijm1~{IWFw;823N?RW2$J{I=eQe5wmqTY*wZHHWn*NgrS=7TqWvv}3Or7G z$L2-)$g7MM^K2C3j3I>#BL3VbgTON$rG0RtYKwpQ^UNDhXR? z2cW%hYK93TWE@fHI&~}EP`+hVi@U^e_BcqQev8av^D*{iLtyw=mDkC{0-lgKIs?*D z+cm)Mw`Zj0AhCZ*pN=tVQyJwUjQeutDL#I=EuK1Ym^h3?Z#((jzHFE}Y~WWA1LQzz zPm2LR2`fd6C+bfU-t$-d3w({klEn0Lh%*bJ z69rT;OHaCdu)@I+3Fe<1H&}z!7W4Fd|wf&e$V?wk!v<`Ty1Gu2Ry5E%N z|IA#i=j!GP8QWI;W?++yU1cu3>dK|D}SB9_v4q&w*05u*RY$nZ1wig>52uYv9C?7RCPeMuksXMKvs zd+45Z@9P`ze^GMP(%1{{9}=G)b~ni$?sJTz z_%P#19gVLWPaa;4`!icmO&k~RsB)$h=guLIodKJ1(X~TcTajPvBRAg8Xmlh}$S5zo z8L3;zj9eGy&q8eAM&$ak*0wIH&oH{M%C81-#9BJZ#qnPdr?ldF?_qgz=?<-D>zZ&v z|5yEw%p+8f^s4&EFS(B9jKlecx}TzHcg9w3K1MHpL$?jDVWyDhJ0NRg(PGQ#+H&vH z#I?FsD_MWK>BLf9w2N9=sAMI0bY;9>@xJW|&S1PoV|7blVS5qlH|Gvg`P)eGcw&PG zE~77ot|l)$Z3Le*6)MvYMXnh~-NVO^zpb%!4hq zD#bL4%&&->+jxdXXzieWP=QZc*Ge5#rHoOBdQV~57$4YP^=Y40_wh!diZ2rX^EUB4 z9pL>P!khS8yy;O0hX+;JWV@K-xZ3GLo;3y`>&UcK^{RN_`bf|;eA)}F>ng_2*uBlJ zw)BhrBcCeF78VL0_=7$TmY_2BV6~6%!|=o(Yt1^7s;FLxv-q0&$U~t!<`aK>eqSvt z7?C*Q!*DtA*jB&F|LF%3!Ii>8T-1)_Uah-646J7SjIg`sW7Dn%+0^|%Og*4o`MWVW zWCJ|MbhP9hM(-N4vs8?_YsK`l7wx~oH^*T?41>bf9~R2Gb|Z_NSv(z z7}BD31}?+bKf?;-5!+c?-_SSl!+azEj?d@|__WGh-|^M35I-Tk)$rmm$WJF@=RS4c z5dWK{iRJw39jO9nfW>V|oq4Ph?i$g$bpT}ccd_>5P4^QtJ2TRCM_ol{ z17jXIC+vYoL40AXCuQbyVNvH0aTi5LzQY#h^0zovLscRhAE4pqUH&(;KVM{2N6izl zX&PJIV|5bU*Sf5A$Q}^C>yw}`bJxQSR>j0}#>=Xv=A!X4d5q`Y*CKy6$wc?NGuVh- z#GhNS{@swW3S##zPgJzpB`32wiKU&#_pQ?HoNMF{`JH~gUxJ;j;w$>pelM0|J9$AC zUmUxz&foVQ`JEBQkJw56`My8E*^0S~Vv*gg{$1<&w_deP{4~s5>$tL{c|+@TjI(ege_S%_!4~{K)l{ZJ9({y+JYVgfs!N*vDCS($}+E5?KGz`IEiY8`jR97pz+9N&xlUJ4q zOV*g3rl`}+@QS)3^%KQqw3d6E&)?G&pUmX!v5B!u;nDIcuQs-sCaybCS0?|JFXRIs z>8!G#5D{!Y#_zn37v>8SkOKrn0WrdMVW;pqh{-;wuYrHqsueh^$o+%sG)9;^!jy`xzRakqF+;(v zi4U-h%~t-Ja85&sP2obV{cjQK%~nN1yHwp|T-L^S9vvNc{<<2_Rw9;Yjb(`H|GKMc zW29;_`Z2m~8RtH{(@VV&xLYCK!>c!Ga;Obk`l^(9X|fu%f+ zM9vW|u{~;Fsb&ayeTRGE3i;2`uOIPIL;UYpzg7N}GOCx1q+uYe^CPeTC9n+tU`zIM zw53GShK2tnBm1VRp3@Rn*>0fq_x(V$-hjBGo&Oj+64yuf>+z(u$mm)V6}`u`=GJ^z zO}4GXM0aP^Uz|n^J?Ze)hKW%UJ-qC4qalfWdd|GSwL%^qAyvjS9aH!jS^oFvUm1XL z_*n&})qw04~2Q?fJciYmRTX|m8)fW6gbLUJ>6##{m1E+eGj37ydpott zUc(7yMPbgX8dMOT_E46N|N2S{=1JV3@(iQZ`E! z%Tr}1b_wly*Xw%F4Z?=YOWbGG(#F(mT;Crve_s%f?Q$RZ320{pWFj;9Yi<1h82`7A z8-5y=4>OUm#|`iJm%eVeHk=YB55M<2i5zlkhrtjTt@|^+DlHR=qxox>#}^9|Mx>8u z7p~`cANWpw3&)S=J0qv*i4r#p{bZIReyfT-7eo^;aU$gpsZ>{z6!QEz5v#aSJN z%QQ^bPi7^CGs}lLvRNj><+Y5>xZ`af-@5fm5~sJur!7Smk0Xmy(EBgNXWEoZb{Ns^ z?^p&~v3}oo_S49oVua89bDujb9=;jA9Tvc*#t2XNp5z6&eQd1mQ}?d#;*ZuXvP zUW#E&%A-YX-5M-&On-yC&noPH=JgEB*aPt;q~J4O;CHM4Tl$}aZ(6m#v3#Uelw`X@ z*U2*D37OOCj;)n6s?Z!xal5OuZogNQui zg&%~4$vrQTJI&|wf&WBuYWxS!v6DBohjboIf1nCXV^v%uRyij}$J+uR!+%UndSE#EPfEy4SR7J+-^1VB%n~kGt*+;^q-o*EQA?N>9 zJ5SBjP5dLir$5J?jNh7|T7-V$1u&%AnbQBoVhvoYF1Ei_^EN;$6Vtio?YwqIQu~xM z7~9E4?Z;Z(fuY4(_McM~qlP?JOck4-yOxZs;d2@nNPeFk&rpl#w4!`8mN16>(EEnWlXYF$K5KtI zGe@;Q#>X&9e5{lB=0IjSI@*^}_;JRIX**r<#n+jiSfsa5K~K4TZZY0%xKI|m^Xf>V z%+2`o3q+!y`ccHF`-!9;qyJC*Wq*z_eZVUl{UmaOwEmht88YUbv5za!&x`oMp*$wK zHjF?{@wysLWj5j<>jnQE3p1S}q z;qx1?O0oPV)z)++0<>D4oZ`^Ri*_~O6=UK0=->1Ikyg)iRalx)<9$OMJ7*ZRl;ZJ7 zh=hEHA0LQD?_``#pto7be{x}gt`Wyi#eyDG|MX?<*^vH@a`*eNthVO+Hg`}+orHyy zakWDdjPuqI%1$$41&RA-`$5b2bBUKB&A*-)}ye(&pjOW6-IdaQiz6=a^aUI^MtvXR!t4^RE(q}d2 zd&Eg<+@o8>QM3$Q`CS~f%Y-yG2Mc7lGRuWsWW7uCwd1x$h~}r&b+U&~tRTwR9T*?P zMsdO1ApTE6v}P;jwlkAayqcwiK2@4X(stL5x_j=Gi>dB{1paG(+cyk<4ZlJE-ww-! z^}-S1;;?fVFKkcV*c#dKL`+v@^OK0fYpSd38-*{z3t^>j9Z^|c|B53%Wqv!NH`~N* zXf@Hlqi6HE%4_O}-=f~UliIC2qB=?IC9}G8!veH!@<+ix%+_@*@jq&45Oj1`nt!K=S+wDRLQe5wVJ^jE^; zs)~0lkCm;6Mf)24GGvT@Py6#lo(WzGKf{p!4r=AeR;vD1H*+-gWJlxL>vNS$uyH4m zf!i)K5lnO+&ELc(3{b7#-`xFWca?V!YuA4}qgoCdRD>)0irKda<9qibcT-IGs1>;O zLoO|2`yDZpbp#D2znV{;RmNvSYNPo~NZngxvBpC4E2I6uKSb-B@|i#VU0(><{Xtma z$F#z4tLev;yBM14c;?<#;#=YYmLqfTi7&IO>&998VtI#SeFhNkC31#uF%ub@EcDKf ze5W#xR%DRGT-p@U*FG$yO1T+sj_;jI_0>2zV=tX2$g ziPsi$oP%Npw|?;>JZ=ULwV#%TG5=7UEW?pwLt?n-TH>$12)`q8%^Jog56DJ5&@mhx z*2jx|>yP8_8X#%)$yFN>$)&)r4G15EyNDT1`=7DV$@~jqiz|#^QfC+)i`7*%M_Aa4 z#8a_e3{-}yxLi0^CtmMnrd5AY79oW{4&n%3{-wCA3~6?k(DQ74+dAhHX|*|)v%Z?l z>YcF|V7Yi0#{?7c=k0{p(1iJEi*0Vi&lP#}zj!0{2ANq4x-0ebmeuR!3!B!gQ(g|S-8Gd_HXD?yrF5uZ0n=pgi`8VR~?pTD8T;F(}ow3U+g`3`s?|h<2;ZtVX@bf}t zUg?CT8A~jE|E~Tge$Dh}ScVUoi+#-EA!VIs(ERJlDej{|^@u)JVC7CaPrj4eUlN+) zR;FZ--n!TxbXB^i$`Y!mbn*Wca|p>`ELkG5jig zLVnu-InPPVwa%9gH-u-y9$1RSzBVHs=@Mg!6Z*;M(Mv{nmv$xo#%9eGo4VPxSwg2@ zAP(y*irz!j5*jmhY9!KXG#b#;oEk>?=6zmWkPC5|da1l7Q|L`HY{)A;{&M4u7m8gMFNczr;u1MauEf5iLbAZ7L>=&mlc;| zCtmqQ+|AAKR)!tc0^R>c@rmI-*5^2rgtSpjT-+}MTO)X+m6J=_$Bo1Bi;F3?vLWXG zoBE$G(h>db6dUOxbxm&;_m=H4#p6s~`+t?hLUm46eaFcFGWz)3wecs-=edpuU>+89 zsrYEO5jRcax_{>S+w!v(_g;fLw_SjWTw8H|Hg zYoh_nv_m@#dpkpwDV?xBbGX`G$i%C_y1cKUb<@#9V+rnzr`;gD$$nxC`W2a4gNKdU zDG!B^WC&z&@M&j|`q9YRRH4wc#QU_z>zHRBsfgfb)fr6WTGn&Cv8pWSuWWUKP)99i z?WexLW6a_;F`sNizc(lfJHUU2JZ1cD>zI@CX#aC{0&PI!jUC&1K@XuZN!1-?Jv_D( zmrS1EO(e^Z*+((f!`vPBIhND*w5O4|p1=;=^zVf;!&~9?aCMGVA5s_W9I-2n6*raDS8vpQ$Ub!zn6I~rmPbO;w;j*D zSW08^x-4$l814kKWL27%1H+a~{~F^tLba&IsdGb>7Aag@cUJrgRyS>3eJhxyjzU*# zqAI@z%+?^yK`Y?*>x{0>QSIL` zJpMf%kKB23f+fhcRk~erZ}~5LRX@>R^9jN@ zF3(vB9cqg1SL0h&NBOb%bl=0TnzjFc_d2Q4;#2j=|NGjXFLH?(+!jmD7Kk0&c3>Vd zgQ>LJP>9IoSM4fC_fMUn)*Nv+$p$YFiG0U(Rp+c-uy&L9-}(X8xgFfI#XVz*vWK8= zU9bbyR0UK)wy6>pcLp{xHh#sBFe(xMZ^Qzu@qgpxm-@*_YHi;SpVa}6RMfZT-HZOY z-%3m{+owi0J757O`Ru-#yNf5fD39aR3wae=wh*7%Q>;|kIr~NTlH6o1vtcY0e`2xz zBu~lW3v)NKu}_s%Pi%Ni(cJ-|hyEtcr{2Vw?Zp~CM%WLx#g&pwt5nh5Lorg%#X1-p zb+I60kRvFITy_-hSbtTq)uON?+VtYP< zuF#7nsg?YS7Fm8~x(yvjF(-H}w$waM5WF%Ku<&MGqI6_BNi zuB5MzPWQs9j_@mx;aK5Ke!dkp4=05?!>3`|h%^yNBjQI~2-}7U!<9r{Y0>`cE-u;s z6#P*()jMruB(^g;hOIPHvHk|(E$`)8p9IN;8}U#+>9p1YjZHHpGM++g)7gaIZmdDJ zW@GiGafL#fPxvl*__i_I#OALr@Pt)dDaQMldU!8!t|eGY<8@og3>zlUFh;PADms4= zw#y)~A5Ibv`&^;*9_E|()UBOK2s+;(g@(5oINNQ=Andf7$f#je+iu`hqS9x^*+o9P z6K}S_Z6X5rk|?!@?7yn2k-;UE(J z7j|Uy9&j1dqxQM4hy|$SNBiYy|5<+qD=->QHPDapRro|{;{W|VUYId_%q;ZtiNj~e zW(xm?&*rzef?_|}Ayk%IX#64dj9W$D)u1e%@1#rW6MMrR{)6k=N=~+h-&b8F<}{99 zs4FauTw4Fo9gbr>-rLkW+?njs;>z#P|1D_UO)(`I=H6Ll8^$y+mPqr1pkRXWx_v<>QoyAY%l)0{CRyhO$?iT%J(=}ssgx*>kZoy_5zNQ~iho^`e} zSe|UF7qRPg{QpEU*i}ABSS;)k-Vd`xq>OkR9uK=A*#n5ma(lxjeMt_yjd-*W_in6} zbGf5Ms;*dqMjF@PvEYO_a*eIh>a70ezsSIlb7FACxwJN!1G!9!X2(UtQ*ft;`Rsh2 z$5mfyqZ&)-b~%N9(oo$q*5Q#rl?b=gYq62D4wW@EYzFJ(`c3@Hwr<-`d;V56JWKW1 z6U4y0oiRv>h8Gs1Tp6ver{+G4yE~35?#!MSL5i#3KL-%`kH!+rA>$s*UrUwC-gG&{ zuHKSpe<`E(kH6xhg|WiB_^T;I1!)LA6ZvF5Bi1sGf9Ve6^XK95e#9E|Lf*gR?@?$- zahFpV*B^1VFZf*+zf+zoD#l$V)cW8%!my|;9L26&PjfWJc<)N1GvD#-$ajixq@Pq# z_^zr8GieW~G9zXyTg|Wq))(~Cf29BUB6n%UZ(GJ}Sv9o3t4H^{&-4U5XK z{WcQa*lPb3#;Xch$#%TxWObeWO%ybZ`|c~gi;=>nX~LD}(n_oK29M>`Ht`qOb2$TvTr_jR0NCUh+UKWTV!)hv6P=Po`zy#`Ccr}o6+xg1BqVpC>lJ9 zKF?Jj&upR1^%f@JxA+$0n4Kei-78$7Q(_%FgM3ZE@6=b9>bF>nFUUd7=XXUe7mLBd zDvTFs-Tng6`XzK__v`(xtQx-s`bUc)bnVZxaY~QlXHK@mCz7BbP#>c;0t0?dy&Wf$q4`L zcjCtqghRtU;kIx#c|h)PystoH7SBI&fluX6AbauMbu8d^?N}JT#%^N$ag5PI?#9;o zj}igQ!#B5Jw1&z08bVDRynSwDH5pobRXnY>FX%bePNA^>$?s$8sCW=Wv1pgX!x<9Q zTV!T$D*8;~jxwX0Ro7{qT!w&PUH*p2X}!O*xT3wnd>qeMTiv9s{q_-K#w9XX!!tBa zGUMaTEc^Y8$32bQVMa9pXR-?QhUjT~e1TO^+j`(;BBn^5H=IX?@?im*kcZA!1<-y* zZa)7PME8xS@w_vJwd2AS7{T`~o0!BgMu`h+rZ|pTA%D$WcVzE-EWo#Dw{;0NQpcCs zgA6us+W*P6?c$HN+Jzqi1w;s;?l5U%Cu`m9Z{||494u zMH-jQLLpRG4sb|2G!FwqKTn0t%7g9v)b&93Z@6g4L{6U#CCCqJR&){{a`%(OvbeecAy3E|84)2`09+` zj1{n6^OM+ELkw)||L`%<|2kn&;($Z={$IHBHx;!)XX z#ot5w8)GF?DpN9S=1N$BRphm{j(M5uDuJgp7V+PO3}&pp#xn6uP%@~51!#awcUMjN zR@E8rWqj^x4{IHA*jwzNt+Y>QJ%4@iP4iUGx=uX^#u{-*JmtrD?Tl6^PxAj2u@>(X zlAG0R#$*0-b9Eo6^C!L5&QrRW?xCvmt^aM7x)qj)2f}K!Uok`0y>CeUE1AFfL@8#g z4=X<2tX{sGs)u-}%BN(^Vt3VTu3!#I5MM3vo3H|l_!%=S8@A{1Zuk$@ppX9!i8n^B zXMD0ZWBi1p&cm9`5bKFy)J;`ygR!aEy3q`*rg5lRwqslzd%4e7oH2zs+ph^}*y<*) z1%@4<}7}t>a-!iWI>bH+2rlZzG z9zSxoebL-KMDQoo!#!|>KF|B(iQ229`4!OXhT?;1%l#G>>wRW%UKJ%)_((nNMa0Tu2>i+U z`z>L-Cve7#d!M`7tJ;ed$iX>eK9P3UQws&psyM9n??2W5hiJMnn3<#)_ghSkm{OR# zvBdzBAIWKtRojK;K6Ro0$6a&hhy(g?2er79>16#&+y?H`xaMyO(f$sx_DJ-uJk}!{ zF+f$0V0cT}_p_Rw-KsgVN&{QbTl{(-U>!PoS^SpK)n%Pm z+>p1l_8M3994VZ|VV8wyX8bmXf+y-Buy3SN1#o^e>?KmZkM~Xssphac`R)rJ_6jny zURZ^@RU26Vk24ip{mA7b>#EQAFZFYYWFPx5%p4{UH!utHeN*haF=cM%lY^1MD_ZNH zK>Tg7$5zH+gSdA7P@FMSl}k%suT%adPCDzvx*ZrR!3(bBEZ1^f(TpM0rjZx6J#ky{ z$RfV1qFBD{>Pd<#CWutpA+Wga7H6BzJ?v9&!Em9eb=9802;l=-jdnXRyL1$5gH>GY zQ3c@z^)o!-3?C8$Bxm-WYJZGpA`w?$9GFMdHFB0~O{Ey1J^DWZ$rwNc-jHazy3nnR z-+m6BEuH_`_xA14|Al@flDpXdiZ4usEJt|ba@#_7ya1`P{x-u#{{`zYQJBxCIN~>0 z-+{6aUt$IF@-S?$vdl34V^8XaKsb41nSUxrTP!sVNR#I z+V|A&`;|IvGAV0J@E_~{GgX@zp7cFpHd~E-Aq=?Z!XCcONTninHe7?H;)MTOEB&*@ z0MiI9U!?o&r>tp)@E@1(u2lxN=lyEh_xPT;yCaX^+%{ER|Krm8%Ea{pkimsS`(T^j}D&U{Ggk%Ws`l7xYub(12P2k6(GZ$2=bX3y6RnoWz zpI8qo^tu1R*CcaD?hkS1!oq+Fw8#90xD5IVbtjSklF#MwOR&62gtKC7e+!Xx!wmc^ zD8;iT-hDLkypJ-vi_sJPUql2t0iBpErr6&6UWfLYZk|K0 zqquA>il0Tau?mm4OS@iiB%d!77d%HxjBCyMv0}O-s#Tn)p5gP%Q6RML>#x@YGN^n1 zQec_6q2%mP*S19kj}_w{5Sqqjy?zpHNK6#mQ{1=7eR2HPG`|J^KiGH2$}Yqf{EAKf znT+cKpIPj7BhdrV9>Y}Ff=&CCyBx-~tbN@HZM%9$RJmZ47uS%?7qV6dR5R|#_$`ll zj2$q3C&R1CrM@Do@JY#R#OLpl$c9yjIbqNz*Lt&QMrN%TB-GxFRYF<6!8oD%TdzfL zaXd{BE8{41zcKSvhM6+VHrq`d&S#hLy~o^fR?eAMy!BQsnU5pi=jsA9={$FkTI;9z z$#Hrpb8Sj=XlS_g#9ZH1%r-w01FT0{9wLR={3ndkR{z95op+qHJRMZH7hZDm0OIRTEzMKi2GwIGpckopc_#&UDo||IU34!rCHjD{0Ue)%^qul4!rI}lVXd%8n1(1nTli)eGn_+=WxW;8$=Hoy z>MEY=SE8>`zLMX@9A(F2-a!|SXbn9EBR7O={ED2RD3RF?&NtBggl#uOwhXG@%gp?K z$<=No11Ro$V0%XST)rnVcmpjny)<6HX~dRY9R>JyO->$tAYMApTxg%vGHeCT^{Ko{6VC*5L#$GWyW-PoO`e+ zYY%t72`zst-kanc)q02WafYbQzAI>QJ~7ATQug;1vK*h0e_!hXQD{!D0%Oa`pk9GA zjDA8qS9~F8Clu04QjTa=AU1x;_UkWl1(tR66kkJ6VFPwnpH-{i2fV-aR@l1DVAXCJ zR-^5p8h^D_9OP16R55iQrNAC!b)k4Ivq-{A32n_-Y;w6A{_psmXT$=>-+Kfo%}59A2GHgg*4j(TeOde z-q>n0_-9z-$=d6$hs3`ljPo+;v??S1Vzb8gT>&h~9>1G>w?Fb0)sq&*tGWa~(omS8 zUBxrERBWFI#fEc;PuZU7Wb)94_{7fYNNq1B@!sl3Ss=u*MZzH7s@_&ZS~K>>qe8pe zfGlrO$D*xVZRMB`vFUM;$AZFCF}%$8nDsM?Wp{FvKRNd$EYKriPd(QP#0{-?tX0&# zO135nWAuQsq0LwbL-W0%D!Z8KeLO21sqdMsgYF3a{gKOy4XB4a5BBAVm5hhL7(KHR zYkh*R+rvmD#lD_Uz42)=V#h;546V|teb19S=h7NfF0Ce-;5^vkrvs_jV({BzOJ{>1zS7FtQDS2vH(x`>|w0(OsznU)~FA{ z5*XS-3$Zqi<^K_?{9la4+{yJCYxqfY#Ui4#!r{m%bX(($%Bs5QoQg0WYTqjXQc_ZT zB?}mtbNHN1#JR>4U<~X7Wd|0L=Rb9Yh?e&G<9?GL>c8=y;%P#^1L+)$toZ<`1Qrw)F!h4#)2fj5~t zgj0#>)tLJVGP*U9<}a|UO{D#W$rg;uC;xw?|0$WdRI0x;4$*APMJ~M(!x{d&VMAxY zV~)bp$Hw}l_dAL2jiYi2IpP+)$#x>jo%~+HeXZsm=iy@pi5q4%BWHL;9|^hl2d?&4 z#`he@d4u?T4B6*-A1#a?CJhs!_4)Dn<-!JGu`nV`6lMqy_-~QMXU1ya?xNkR(Q0GN z_QRve(gVE21@uE+TU)$UoWr{gM=wuNmU27Ut*QtxftWBjG0weG!+g_E~Fj~Ty?xV(9n#Gk?}#7RwYPjF|s9P^bLpQ zf;_Kv1sPjcJZAYH?HL%JRXS$fx^b*C(O4l5@wv4^^f|^i zHekN*Pjp(?7eN|h`rB?5-t8Mj@5PX^Zy3EUWB`lZZI1E_vj3;M#&H*Nj!K-}x**F6 z8Lb?eK33Q{>yX;1MAdy|aoS=>J{P-N8m>RPGv0xJxXQ=eS!9q^6<&rDU6v!ftNy)L zhA;nL=zqS*57b{+Qdjmbwb@@%ErfF_0h|;R+gli($1D@!$I&wMSc%*~sVP_^W)T zwN^#G5Vyfc+D$e;lV1$SpA%sKi`5V;_EcpR)07+C#KB zU<*h4Lpyf2RHbHhY8i#_P*8JFka4%YjfX@Bh5%$Z@7AShyhl#xKrhH*lPJf&ie_4s zP)zR9;>0v!Y&C3J=dP(Dz`AiCYY*}!pL!qrc!^jxvCr-ck-?VanT4^7PGoo2g+8v& zNfxkhWb+=|(=h^Z|v=g%T6Gh6L5 zyxNRnm5HW`^>n=Rv9!@vx@<4ovdx^ru*xEoB}36K$NO2_b=61i*Zyn=VYGL`%Kl9B zWqsPcd5p#`bYteM*7BHE{|ue)O>uC4g{G%f-H@hQCVl7B+{mB2^3$JpW% zT*Xfuvpl1bNoeesRi78dix&6giDfkzDOJ&B zv1u``cRm?RAtdH5@w@k@i3cV#HhskUGEv;Wld<{Dv1Kzi{1xVB19qVmx^3)vR%KO3tP~A}lku(gT8kt5wocNR807-~zrR1| zKMC7}-F+2j*uhq7Z)h`3Ro7Q3sDf{?ovyLy`xN5OrCN=%>aux!ww=6wE4048_P$#q znH|I`K2D#u`jib?eY1@Dm@o*eF7|$4XvT)KxLTcs=KYemr`i=f#oT5Q3QTLtr0#?~0>fwr96)+C<=#+6t>b>;6M{aMB2WE~5}U~>YWXsh&c`4IxK4DIgG`_YSFlU#j~kG$JE~9G!8JPPwH9UU5N~lk z&xv4O1xd9|@FEDs>G?`K6?a}&IGm8pyQ*rT%Ym)G#lS`-)wNsx9T!=9jtwcqbsO_@ zUUAVIie3uwQC?#7b`$rH!us|V`hO?YSB++rXRCWF3K?VyoSez41wXS_Ns5H-X%5hOn)M9<8FwFlw{;i4s(CjFFjctfGzoJ zDp`_sFjxoGJbw1!?{4U0U11?t<+a=BYZ+qq1%AEXOCG<`uk%-YK`cP7uplvi;xHMx zK!LDr*qSV$F=txOShnZvwl-q;0R{05#;MvDyR(hF~gBI z`ZdB9w3WZvM4Q8qy}9Vr9KJC@=pA!}I`M# zUp$}pIpg12t=lfm-7RLUo55q@>tsPzyWo@Vq0X`VOJ}T9FI?awnAbA?3+(O?G}?AN zc5{T|(*FIb3Vj*G6hClGp*_1IlO ze-<%PRnf_Mywg<({=JB6+N+~^vHOE-9VL##>RJ~yZmT}p|BK0(^~M6M5{{9zGd|LozHVV&@eaG?K(d|`m71r{#(YmYZHPQTH)U)PQZEU>YJrropY+ui9%Svj}0(% z?LF9lJFk7>6Gg%1nJoiNr1h4JisuYB_5)$T*{;Apcqgj~uoylS*8USDHJ4U1tfSp* zzM+w%QnqGni7}mZ0lwfFp-MYrM4GDZ!W-h0x~aAF%beeFjQYr{`JQulpRH~sk6n2G zS1vAA;1Y9{$nBN=FbnleQT1*9GL5uIF`lmdnQT;Y{(Fer#88j47n_h_$1oeli)LL@SFo$5@u!j5mqPzbVy!p+aI5IK%7~rhFN@dT@$nfi=P$b1j9C-q3yYBQQ&`s{ zE;pZ8f@S`kjI{`!JqLM}^`j2NV_jja1M=0EF1}As{^hX_x%k94z6CK^Ub2f6*o53< z+(~_GpMh6$k$X6Qj5F24LY7nyQDr=<@dd^EKk2_=biI${S&j1BjJnle=ERc(>XD1j zIM#5(i5V}rH^=~9Dk2|FOfm>vvdFq7K6a`YpqgO=W@6tqsbY8(-oGloxCP$0z8Dbi zxCB_uenj49$o{AK<34LxGW-|P8I5(ahpw*@{;ob2YA{lMijjZnvM{n)eH))U z{49La=X8d*v|ZRii_rKsdKjWte|*bo`Tdou>YdHsbBR8?3TMiYsk)0LUG^gB^@2yLax)t7^mXwfT}BV%I74{|+!J+p?-RD9VN1Qu z?5#upqj{@fz2+_wojoH%yNW#>hHPCDI^P+NXPHMr?dTg*s6*NeH#81M+$n^q*9A@D4NbF?sE~*sV0G|4+yxqima1w^;U{ zQ^-Bn7`=7ap)EoLo-WUCXn%be|H-Phn5=$)wc4S%$MxEJL}AWg{IMxtWAIzHl0-HC znK(lNMI7n)%R0wmxF^COc*W?)o4iWm|)Cc59P<=@yb`)>p$z>_4UXWue$lFtF4H|tAoWXfsbBB#I%H{d=z6bhx}(T z|MllOKSV40k_T9AeJ z)*bV)Rv&Du>{eTIT)PI3umH9%+(5mcwm)c`a<-@X1EX35ulh1bEbOk-!bCIQZ(Vn3 zg?pJ^H6w}Dv7Ai%_}5=|j9X7aIwbWbn|t#BhecXsn4hRRR4F4NI>G*47EL zi_tlmutJRCB!hOi^5BI^OK;1dqdSDsX0=tu`eh#9SQSQd-f2VwbA+U@o^w159;%zd z_$+g2?If-$iL+^y?`_MEu?QK3a9kA2lv%aF0q0Aj*!L;-dR*A@hF6e?Pubr3Pg=uT z!I1aQpRZ#F()dUGwU-#8 zy5=_%_i0w`|EB%M5J-)Yr@v{8t9cJqb|BJ8VzxNINmsqiPeK~AVO}`d-OYDviS-E?}@+g z75Za1?I^GozMQaqz~u?|Vaduk{VwHfapne$5O{QTN|!TrZ2YkkgV z(y9hLxz^-U2raG>(a%Rny~Vf>R4X1&-Z{Nu>vP)Gjl*XaV9{fHz`!WRo18AL9F&rUUi77@F>!jML&cN-wZ+*76)C*zg zppW_Pabe6wsIJG@ZsQ2SF{)R5DJyu6|JOc6iR zGG4o;D#TNaUIvbuToqonCwf4gN%uHcQli(4NU5zr<(BqaO<)%70$7KI6P9c;ylFD6 z872^pelp<~mXg02EUw;NXzL8I2i-smllhcBu74)&-9`L4i}C8gcz%VQu8EY6#bT@@ zF39UgE2>D(D|vlWJkLcu{W3m1m6)~-p6eL7!e7pMQ3vtg9HP@pXwnTH$HedW7)x-Q znCup_6G?m)pbf@ebdQ zGJv>Y@vuWU1)Xmb4i4KB3H%cFA_k}%#tc{ak-j_DCiHh0<8d0Vp3KG%T%T2Ol+$`% zZ9IQxtjv5yv;zB$V zpU7k;lT2hL?(Rl#3-0djnvg(nhXi*Cjpp6^Q}z9>^{(}M|9O97t5#ce)vbG<`<(Nf z=bU}^&IAwM07Z0%U;k^z>%ifAe1y$WfJ z8im)xyJv-)zbexG3cmZXT2baHKEJ40xkU4O2^=Ed=pNmtmEXz=cW8BAs&Q-)wTk{u z=C+Pj`&YG|eG=7x<@TudSko0NF9^NXPt!3cQcE8yYyVwG_wk0x=HA<{SYW9>@q*^qZ-H6+|8MO-C$}j(f3p;oW2Gn`7A1dTZi2@03J>b6CTc}@ zo}xgsSXcC%JVp~mNoFzoK(lDJu3-?Irafiz^AzQLB;Pq!*DwK<`T~kHZ;hVNs(vy0 zT|4~rSdm!M*hjIgu{E(lv9Ynqu}QHBiUa->YaNSX=CiI56^u@3jLjZyO`(qzv%a9a zQeF4)asAa*e_L<9E7*eKYGH4fEuU)|3gU`_r@1+Rf6WRA*P<>PNdiU|T z6Kk5H{4sjQoyW$WIZJ*FoZ$DY_+H!H%kR0L7lp4z;QMN5-q+Dw$t1^e8Re&4bgsE? zw}$3u8}`Iz<*q|#{A0QU57Ir-KtA_Yoww&&W!T}fpqCScL~{5 zVR$&s$r=;+G3WErxXDBjCC{qp3GYUvyjeT>;4g7Q(@+@^QTAQO2pD5Ch>d>>Uo57yFEwBnUU zpB9xRTVXq0M{qT>k-Xt@&Upj<46}3xhAH+p=UH(g)O7mQg76SJz31qmXh;Wz(TPpS zjHZJ;Fe|Zp?y~f~BupUQL08a~7DgRlvwW9(O6;q0==zK1pY)s)3@;on-U+=5Ado+wkfh=OHyhKX$tyX9= zi*NiVSbt7#pmE8@C&t*3B{I1Yx?0w|E3Y&8MvoD?`mKs?y2<{n@Ad~>^{YC+sq{=v z)?E6S-Txvz^R-^RM!OrUQeO=7D{iP2-APNtDiykiT+A<^{d>bPxmM;rUsW6|1BpJytL)%@orNHSh2J;ho^N zD(RVgaPOB5tr(fZJBq^z=Kl9pup5k$=US#~Jqio%)4EeT6xF%A`=r*DARUDjaf__V zycic)f*vk^yOjNm`JF8@BitM7wo3-9jO|dOtf6i)3fazMyfn$ z6M3TEitoqBn$xv*F4j49$JU3*{>JINr^`w|(b*dLGhTkIzpiAD#^~3uuzcL5ux|9{ z=+)>;*?+}Yt=L1_>3^)~e_-s**gdhwW6#I_9P1dX5IYvlil#>2MbAVHWWSlwetp73 z+4ZaPt8eHY_-;I}Pn;wRenF%DxT1ieil#u&|EGh5(z0_c`B2|TL3P>Kt)fKi&b91^6@MQH*1fWt zaa#SXad23xaDLg8HRWq!FLkxDw1a86zC2o8t#h?x0i{9DHA8u>0-2nu`kp`hg;-@F z%4lZdH-kVWjb2Ys6q|LQT(cUfnLJ8&ucQ9wZqQW5=2!VQt5jZKKR*o?lCyfh`zlZA z>>bHe!0PNXil8QIE`Mh<4w47ipm!V(GWDvG%-KsYn>bgP2_C;1>JvqE1=qox(@IAy zPnBUGTBWPxYey(Xv&xP8VckV!bmeyXeZ6KM3tT@a$By6oBG)6lw|CXTI^f34ni0gP z){-dtR@Wz_f}y;mGqa}SF;LdIXa^mFo#}i~Ns-utnkUw>{uJhYXJX!x7x+SJ++o?H z^Ckcl<;ox@%!yKC`C?l%`(M{?w0e|3GM@gKsFdEH zr6~0tMFQvG(w(Rk>nBBF@5{D&$bu%y@(+dCiW}OYn0sy1MIPk-=%PN&eWFMIDeHeu zZX5=-LiprHD8w0I>IkhgRh`!IZv%CPlXTr)%};C2{2;sQBabj1R%4@=%?J33*6E>| zPwUVI`ZfG5tfRH~s_60P)d$I1Zmtt3*;PN+k$)olKSq&$uKY`*=pl`*Rq9{SNbXjw zP@Sy$36wOJvV)vYUT8JU73K;ks(Ic5w&|0)+Xpp^maxh@%QO^r`JvkJkENs6-Da+) z_f>>2QqPSeUpPaap`RiFBU0bjUcssZYjnpGOrA67z%@Vl5wh~mb5$faUq$oLyK!sc zB=A4K2WRLo+JS#EddP^Zaby(dQ4P!ww%7Bvl~yIA>+8|gSWWihj6gl?z6q=gX4*KY zSzKCct!>ox`J-A7YoZ_42%q6qvAulh1M;Q=+~t}qe7O_V>3ZBA<*utoo<_6~bPoSY{ zXk<#!L0?TrOb^}FUYuB?G&R`j@W>=kuW{{m){#*-jRyAx>K<9TM^@Xu4iE4Kb*5*) zx{Z@R_%56uZrA+ouN~As6yx75zhJb1TgWc@ay0d9z@MXA~q{2u0wD##AZgjHWL zL(S;6=;`QB(WB8V(Q!q-rL=qf=U9JEu6dXopOt_?wgcGtMzAp%5zrD0PanlQ)3i$L z)ZS;ie8B>umEMX2tPDI@U+*dc=!Rn87{x_1iG<2W4dt(1(c|5yZ!{x1AKegpA@*wQ z;n*Eo^`DM4jTMR=jy6X-qFd>F|OIQw}_^YbI!htK5` z%tT^D(u2{^XkIi;?|MXg{WXf1nrq&y0=eeiTKCY*lFg39VvX5xRKFGd?cK~p<5-UC z{+r`&F#K}8Pz3%Ycs95%c!(;WwdOtp+1s0nz$oH^DPV!W1taV(q2c;_3>cvWvX!5S z`!~|1ze+P9hL(JO&9}tf*YUAesmgTx8{ldXSJ+0q$kYQu?$yWPNM6<_xFg^Yd#`Eqvl%K zi$rG?MH~wA$pan#fn%ODpbMsLH>lHUI74x!{T5`QRPJ{XJ#peW^Q{tA94R zu)b(~Pn6yFN8j6;o(o|jbv|JeU3uOG9Dvul1RCy%uJ>}}086919>9ND7F?|n^;=`)FYXhF@h^DtYSA#Yw(Ug9A=?hNnJo%o~fNp1X1 zn#O03V)={kj(M+et#)-i6=SZIH~m>YyN7mDU9=wmfGVhQVCOV;#{#nym8MVpxX$lP zP!0rQCahhhQ298jceuN!h|aJ!deZi)<_r8;&sK#MppmSzHr+wadbn4>InJ6yn$Z;0Tzko`hPoE0Y0GC zKN!Z)$+Guv!!PAIM=KtftG{Mzbu1gL(D9s|yrA-kW;-P1gQ?^w;RK=o{I|EAj&8_21`Y0qx`sT1J1+b06w`k3`ogI_Rcr zzVJ`9{+!$`;8g0Qw@k(*+WRB>W!CLp- zwfGn{>Q}Wwf2g>?D9IMG;sS~Q?$P<*CSUfrEOvWzI%*WVH}*&E`Fq9s#_o&dDE40; zjnvA2M^szmb2*G@2ft5#GrxYG36E*@udXqut7xLV#>i}J_b3i}RdG|bXs$eORl1do z9W@iyMi`#H*Y{nZKCJ~?UsqCsnQHCOWpwo|ki91Kd91wCGx!oT*@rNBOhD&zY!Yey zp&nn#KlF!x#=QSssrh|QKG6JM?)zU1)BQy>ReshdI4bx>_Gmm#JG?D2Ka&Pl}!8+7LDP&Z$!t2h-z@M08%$FKx>ax3Zm9vDAUkxD^9U7tB_oY77v zm*B68^ySs(UUon|v_30e1DHlby{3`o`QwV;2C}ny6`hp(6hCBxl&`I?L-IzcI%-k) zhK|v{*No2eLLm2w=}|zon~ojVASNk_j%6DCs*c_Bf+@}9mASCB9t!e1)7@{7hfIS+anj9I2Ex~An?quf%@byUzu(W%we zE1^$TkzTqg`kYMm6_@B9&Q9v^y5`Uv_MJ?Q)PYV3`)ezsy$^5AlUiBIg)#OF2jn4F zQe`qzyfM5nGUz3BHJxFqEFkMBCoA(`?)|MnuGRg0r@=HH06!4P7i=aTTcI(z#FbP= zAH0dq{7PLxLc!9?mvwahZ9wapv3oDb>0_uIU4l2nxd(UkRw1g%B%fCv&H(2;3xRt| zlZPw{!aoBA;KE#S7Wv2GU|KUlTe#!E71+X{1&tqZKchRS5*3D&(3osr%lV)*yJ7R$ z-=!UZ@$Y@L8{VdfbS3;0G1+QrR4kgWD8tyyx^(cj&{>w&6;29EN2Q{RinCUQYqT;J zj7n-1KO8!WUZUNsIWA`Cu`awAo(?x^Z*5+EBkcdENP3Olw-sf9AN87^;WOclI_f{y z`g3x3%37S+T1}ocgX(eyBUTYF*-TgVK{y2^piEinpJatEYt2sRcg~^~KM91yHjPFp z(4{R<^tvy)S)SsV=!K{+%JczhRYlE^X>{K?*ES9gn8j$)%+tJGD_h)xs_qs= zqOM%8kUf1Z8@GZ@cUU8=);k!Uj~QT0W+<+oq+Nu$JLgdSvr@+#czs5~MalJq%Hrp z@CkZR%b?|1QJ-Plq3a+=gPmjoot3{xO=Po;2VH**Fj1Q97%5WqH@;Izm-;Ds^;b zd8wzK(HR|4ED^v8T0mFR2y}HiwV31jgmXIcG@VBceMU8QT;?P_qdibZ#kcRtKi;Q! z(~3NA$QI0hzcJiL|72dx`Ssyjx*PU`SL(P;^i@S8b(eO@Yr^&6LR9mHYoFCeU;Pw$ zeJQ`^EX=iv#O^{5@L5IBZQv_0cZM^V_lAF#-?@r9>#ef<=IjLj@49~ePY>(M?uA7m zuRb>$ec9H;V)a0;HPv~1sk2|MXl9FI^48I_TK#XAb+%K~epbHg2YD!WNSzML>)Ai( z>snY++Ue^W#XfcQ+kj|ev_4varb>xeW5og~u{^OO(KLCI$F<*iNjsry~O|cKDt4U{~qBUDW*D3fjh*^97otb7je2>T61}S8u+aoxn=|6Ii%a z)B&utJd+W%_)=D7f!n4T+^@|wi`r{cuLQGmrS4=E_NPYl)udYI{{I-U!veZz zF9w+)v2wwyI-8Z9#K@M!28|rZBkQTB|1={~%d6-!WSuSyKVK#lfgLFG1p1sSHQ&$Z z%r^&(HTT?0Wro_X!5DrJKCOG585&F9Lhs#zdbu@!7lPkS*O@jZ(yz^KyB&DO5^!o< zfJfSDUseD#k}pqK09;v)X6q?9%*-wA?16V7RbctOslc znfCDbT}zi&C-Qw6jE3`s&ZicIwKBntYd(^8aE?`Gyy_<_6;|KsLe8KL{;M?X3r4!6 z66v~rT8X?!Q~kHLj!;WuajouC7w%en`Y<~wW_n1^+Vj4^-hZ|t;%)K-&Y-+N5Adzp z%lt|H?Izjn75ZsLQL_RpQpE6);^cp5*X3Hm)pSAD(Fo+h;yeOYZD^q}t;bcJ4GNNx z$O%i3_b48Q)RD3^zW;3d&&jQ+xpNW(t8taZbiJM7Nv#XxbQSQLZFTPb6y;BsZ8p@( zf2(Y|v!e2=wKvaDq+U0wqy0>#b~TxiJ8jQ|7i7Wicg!PuE~Y5{i)eJTI6AELzj~}; ztZwXg#RRML?DJavYsu=J?cb(2r#F3upMmNbCV%;!M)z)getNhQFJR+zeYW}^=phwKOw+Tg!qp}rOWtMBDHk+5#;)m-!!$I>bN4Ik>c05#mVBUDuhUHQzl!qgnUY>66Cj)n=jE0SC6@{%V?48M??P$ zybt7F1J*y!p@!tqYm#wpNH<&=bTXZ3TMGhjJIJCv^z#{);yj$O{Ken(f^82l{u z_Kpr3(N*Z4w;FJ2n*sT-u74NW4#o6rLpao@$i-X|_@lw0c9my+PiJ{8Y`LCw zQ8*iBlpY$1WwPpg^zYTB`?L`}KDM$_?CkRq=U=4XxKNUVq%=CfwNU>$rO&fQ(0On} z+3*8ZV>gpSRWe7ftfaB9Qfv*ncuLS`=nhmz_}0F0wA5MAh7s$nb)N0?zFM#f$63j1 zk!P&TYg^EX*g@-R3r4uDtneZI)kQXW58b-A(TwbuR8aD5PgE7^B#T|}`TyMHeReGgXbMsrRL63Hp*6lg^-F;}Q;eJ>n&)^*3ZhC3AD^BqI zH#@{KRCFEl_ob3QT)X+l^>|IQd>C52qh-~-w8r<7rN17$r0;%hSMA0>)z0B#_<+XA zdd8xKJrG5&DRilBr)s~I9su(v`YslPEvF3{EsdG!S83kefexe@u}gzBtHoZS4mB*} zVXJ_LJFg@D#A6NGn?G^nbn>&c!02R=Ppks!r7Aw81@o;YnZGQU9QWb{kCF8c+50*J zc2x1o7WfD6)9Ajg`#CloFF!CQ8~_8(tvZVHDm``m-E@`H<%J5NRa1f7Mgb6WnfQs? zaP^d+{^s79wz8XRbXGyKGsr8mbrV;?$>BV+>xBWlY%SRTx25x>KA7kWs2&!eFYj_- zv{a0pjyZ)J%Cee(?5V}BDF>aJ`b4TX%bKnxa;~hgXd;WLplfIY({CBPq4C!Z8MWGY zk#=Zo-bqL8ZS*`v4> zMD5LWZY}gF<~ggc#}z2`)Pw8II2(KB-Ru;-Z)>EpGyicdooNZ(vvthb&1e-x^o6)T z(fzm=KzE=2C+GhD=iv-VA+0c}AY;!2_CRKwD}}~*I^CvK!JPk9G0kZ00*b*{QbBw5 zR@&=76nz#=k0wR$%Nyj^>c2T$E6dLf4=O(L4(L#5b*Yk3z395=sc4v1{uIUjA86gL zqQ^f~)|pyPZV6|J8%4jW|+t7H>if&0l;CupTV1bX8rd^_8~-tN!{ zS|Mt_ta>gnz_egIIsR|i(_1sjoD$yz?~?KFN>8czq`Gm`Z}rNr$rN-Y-}gBh--Bce z-?97uE?F}ig%0j)?JEuiuI8O4TV)TLS933s>oYc|E<1N;x9Zb*QbW(w#_zYG(o%^G zOIubW?|rk$LmL;Lt84m&K7RMJRi$618nNlsWb>N9aa)yLa7LKusJnzJxY>3u1+L3) zmtS;Vwv-wkx%Pt#~$2uiaWT-3E0 z4^)7iN&>l?pHD50H8fPZ%z-m*1UZw_` zTTMU(8MB$KzweMYs;vJvp?9KS7>Bd3Dm8%e;B@N4U}5&*L{=ct4P_qv%Ak=G+149% zRkl83sVb9`DWLZzDw6e4+;FGMqq5Swv?Fh=D|1hLMQTUhqonK6Q2wAHIIQNnPp*9) z(w)x0>sHV+9blRAnsv91@_hJrc)g8waK6@t8_{Xy6yp{5lBY70 znRnwqFk+6#%_iyE^8y%O|25X{Uf|yYtCPC7>WF4bOrw;pS)CsRN7t$ntci|5vo)@- zhaRW?WT)neb0)t(7{3JHpV7M$c->6Bew3bl7xv!wg13TK_4T>d{$a%b{n!bN zfp2CaI|D1twM_V9qN^tXY)2R<`Dj ztJb%}=3F0LjPfA-%aVV+Ec;m(>_oAy16i}{^}PlCf%P;Gv*AVaYpcO5QjA>IA^hM0 zdGI5|Mc<>~vlit|GvAsw_*WgX26&vO<#pYG)?f3r3+mF&eA|<)0{v4QoMKtjbMhwp zXlqhKsKIWzA!>UqG#|3Sj2|Qmx+TeivXffOc9aZ%Q553JVO8v*1l*rxK{mSf(UjP_ zGyM*(j8=!`zLTyfAN9rjvi*u0r5ugRMfk{yp&nk2cbjecO3(nV;5SX`?Yd{;Dp+of zRjj7xE5SkH)jh#QoC5>YIr^Mxp%+(^F3Re3xc@9NneR@34`L5X zx>s!3)Aj84XvwV5Z&PKzqsi?}fQQ$*w(j6F%bd|_1IXgwwI{pe%e zf!c0;M%X=y&FI2zi#A*%&9zo^hGZl&g3Z~ZH3nx@jw+|MgA?4Ojd@>3a`CNU-mA_? zWsucvMdrdfp3UjRZq5C5f5{25)XonrB{$`@%UZ-6b!T?#_j!s>tqw6)U#?@VX56fk zup1W6AKAUG(ik4$NZbB})}NDW{8UF>LnC6=@_518+>^?TN;TAm5?Jk4upT@v>o?Eo zgz$WLKlr6l(ah*O?dWfcDo2;XOW~<-r&jk7@)SKa(%=tCsT$I^z1JO*HqnP&Oa79*HTN*SefFmj z_n6|ULUhGcg6-l@iu}LTeSA#!)rv{k_>m%T6~@r;^6OfWsq4rZZO!^e7YSbFkM$xFxcv>*d;i+oyVqP`OF9jD^mt#x`DJXKy| z?<_dNs+03C3kISQ6~e3ZXs36#A$saUFLW1qsZP{dJCn7uH)%%}psoJr{DdnDSLodp zQK)DEQmTPG%SHKaul0?Y*>~%>Mh&;oEW8fy=lICXW;M_gjKVWop|i+_8fnyAcjY`? zv+jO!=5`%j%S+L5`$=Q4UiUK=9*{NfCwIG-T5SRO>5VWLoYL4Gge}rz7Nf3uN^|=_ zV9wG5D0BZS?Y}el$(F>ag>?VT*O-?&w&zzfxRe?*Z!3@$y&-%6ROJV<>0@C|^kno- z^l9{E^pEJ?s9n^aKK|p1?nlF|J^)VT{-7KBg>Q#1hHvTXsqi^Po^R?mqgIVce?WJ! zRZs|jARMEL#MJ(D_=U$Hp+2fT(OqH&f)t&hj=|m0bMK8xbwk)g8Z?c=8b(Het z_~VM@zn4E6OJuQ9*L5+7lYuKn2T(~mTI*p8wdmF^%5f^d0dhKtn^`MwW@RjEnIDs1 z$pw*IJBdZOQ6v6V_@(ZEwPn19wbl8=Vf=H=uNn1AGpJ{?;$8v!gL~-ANmx;L;#Ymb zI(*{xlL~k@8Mm!Z{!ZA>S_{AJj^{8Uz@R^mc zeEaAssPHCg3f|uv2UQPFrFO(`wRK1D*H{_pWZjLkx)!5N4$CeJktL7lobZaURaZU- z-G`Z4HN5j2jAGm{txC%@0+$1$IAYrETUUOg#%-crZw=K8L0NK^W^mXGhGGFb*xB@y zEYvvu_%F5poZM<;kxH|>DXiIOwwQ8MP;Np|qc&ZrjbK*1Mqcqc+3f9F%O{6R73Vhv z75GGSd(`kE6?~^aNUDp3t_$2w# zMAgx`Zm*?9srpug89N_!U#pbllkfBjV+O5@bgcTXTvF08d@<{k& z2T}F2p4ZUeYgj#Bk)^+`?@#IRynenfo44-#V7+^kY~I-4zSQ?u=zZo4S)=>5RlYet zESZjUcf(V2NPCnb#N>6rr!=4zS58-vSix$8`zsKhg+Jfx?{%y}w&1+sPFd-0Sj4@D zH*a@>$$uR?oR#`%X3lgnvX12QkeBxgSpxJ;K6vh(Vb2c|?>x~_f?v#g$&}Fj&UvY| zHDibSqV`^MboVCcEpQ7tGJK7@6xQVPd^WkEj z%x~tBcJIhI&7PfleOhRB*!}uz4V~mxnRb2Id4TnxS$`sPZKl<6nvwnf#nzvbYcy94 zDiICQVM}nd8V~FpPE+i^8S70m=4^f0uyOxAHHWO&>2Cl0Aoyx(Z=V(Y7A^`WYV{wb zIKQ{-{tZ@qt8-ZI&RmSni{C`f^lC8Lo#gLZg8{8bwz~m1lU97H_gG!fS*Z&)%Uvh# zJxd9l2{;!xc641lftow5Q8bQbu4d#M)ZyHpJ6P-dr||m>k$u0V#|Pki`z4V*pQGkA zl)L9j-@xEo{J?14fkm>-qq58?dhZb3E$3vsw*IVp?3}vlHO+N|To~E7skx%{-vj-O4_`4m;ZdboAM` z8A<32UrE-~0B!2Zpo~jWV>|$-&~DH_+mfn*tC9@-&I4FY;8*z14}ilyfwkvJa&E=p zIgaU0IyackJ-w(AEX0n#0?d77K@8U_1Q!So@qPp3lmXg!mEuXQI^&(gA zn}tft_xiaMbywGYzvrht!4jg``8w9W+WvEL-7(RS8FaJet8rA-VFq)a)98zqpqk8& za=YxdtsZ{eBU<67hChc}!j<8+@MP$2y|v*wt^SiyHG3y~4c@+c6@%TTz10)??tNcf z;;nY_2OU6xG|=Z+X{IVzE?1Pxu^+RCuH6+k{YpfLwBJbCN{8=sX z$X>6ldOH(L@z+EgBQ$H4>M9n2dN>TzZ2>H&9NMpyWhHsx(XU8s-VQavHsJkhXw`aH zpJ`_FyY;*ErM*I0o8VGV5{ynsYSm5jyV+zTkcPhp?iS7qDy9l~#QJ0>uFz3S(;J`Q z7d7K*aWME*$Vrr^YP_Ca>QS2Sv#7@G2@a6QG~aQq&i<5m5nQ$KG zxO|Q?1O*u}_c5C%Ee(cGR~yQ))>ok7Q9$vt`&RSNw^Nu3q8UDn5-v#9zr zVII_0@)^yjz?zNCSmWj(51cE>OGTpuy+sMUMnhuVraDS#nAcjvKK-n`fU~fF)Mz)u zdmPcaZXCIJ)5oI%vlDgnEyM&%m>UB$tE^LCzR8vH+Xe7-8{kMbm(&hD_M-CR+W$i4 z*Z*))e5RQ-Nway}zrp%*a?8^L+#YoyE0LCi7a)f@+mXIfb2L4I8pmJtmo;DSmN$4@ zyZFx)MGn*6exz3WZ^C!O=TYFfhjs6M-ea`XU&DVWwt7q>`FD-t{TkKQpe0+d<1zzY zJH5l}VR`C3#vNXxJJ1p3$f_W{s)B$`@LiUHuduN0cNKPKoAIR1=FQYR>ZDlXn6Y{Sn|@&FKGi(1X~27(0i>^!_eF-R66GS&R}kU(h)6 z3EO3xTZ!VV_K~79YE8w@OzF4ls}t*L6}rx|<>|U`z4n{ln`Y6;XY{YR!0l&@ys-lD z5S_!tB1;RaW ztSr=HCdlX?(Li?&(^=R(D3W@oa2|b9GykNMflsHtR|F-24E9Q~@C3V`3hXwkg9OZ= z>(G{7gxIg7&NhKJ&ZLT%pKi!HV3V69u@_A=4$bv$YZ104rmdJ%QY*mc7=hP-$f6@X z+E?kWG$K3F8s*@c$nxS&o5Z9|e!ZEM~Cx{!54$zR^ncwPx_Y!~Sz}OQDxs zi|R(A-zp3JxrD~y{U9XFJ9mXvvxjBjH`2>?Bb^cMS9nqu{!;j+?Ehui_d~F$KP78_ zPS3q1pYXCCiN9Y8|E70z(R(|Sxpg-9L8<@`h4+zdxeKO0Yx=e#B4|LqrYYIA9Jncq z(P3Uev)kRXyEV>BK}oFE>O2>mZXfy2PlK;u_xn(>y%nQB*UJ7n489-2@ME0oXL{8a zumBF$9au-#+D6pk4r%6YqMy)xEI;Y4tk7qZD>MZB?71kD_;(4 zR2!;tx1t7}LDnuGc2F3Go5Hg5U+IO~&Mv{M{3qZJFM+aPB^dHrfj}+8t0VG$j;4QR zJooDQ^T3WB=-D(_bF#>hnajg!-#1V(GS`l4mFuV*E=T+H1bOQaw*Pd+9b3r_I<|Gq z)|j?zaHaW@`Gx%Gn%U|?xTg!@y)wvel%(e2?&gx{gOp$eEkPY4p@8PBNOMqtM*lXY zPv{o92aGkkLaR?l;-uQ-Wot0<#`3y~SRed^`~0tBUKzK4rLOW?`P8QD)jR`havu4^ z6W}P!r@k&3HCkuc2$VesD(zYi&pik=vL{#zQ1a+3VJ2ub#=1p={)__WMj?W zb}#Y4!?NlR^>wG>gqLAb^@{%w_}%W(h`NXJX~hK(%C0+e4?2U9zFOAeSH8*rU(@5y zde8N&lTE;uxo_qM&@!HJ)}X7S8E*?UDs8_;bD~CbI+g#)aD7dZt#_v9-pCf{kUe8(7QN-wpB)$;IwzIftBsHgQ-2w`elrbJ975ICy*Od zpz7zQ z?^hHqtD~$RS#a0C{C3WM??<)o0yu)baODTQce`eldC87z^(;n>y9>(m zSL@w*LgQ4NcaO`Cf7Gn@?!zibKWO$H53HGE_N{y{c~%E`RE$bN5qwQSGLV;b^w}Ew zP1Lb}Lq*Q2n*~9-SBJl&3O#womhOj%DL>Wn%c!1IRTShsh-;#4P^UH`vK&6dzA2$< zUPxCHCj)mJb<$$sQ!6G>qt2o?z^^rACvh8DgBvwk_sg#9feB7=Mo0@$|B-q`U2VSfxGR%*Fn%LjC@q9?fBhGy9p9C+^S) znFXma^=4OCye{9T|6B`#`YDa6XW?D?`6sRKR^xk47JQ$cy9dO`ojO7n#=j-`0@qQm zkT*!^dS=75Vzu5sX-AOYJ$^BK1)V`NTHOVY&F%6i?xJ}_vB7P4?9z0_x&p8tw8UOU zY87ao8DIcbsNsjkpF8Ak)|D=({S@1Vc0X5Ftv7CjO9 z7DLT>1vPrF^2UUi$H>}alc?PNh?Yh+t5!BuPj}0-k}tef$Epz8!V19mT?RyuI}pr` zdyKR78hih>(uIA(@`A2s+E)UF@ zm8vm6l&tF;fAtGF{*_=?cazyZpwD*HWYyn%Xc^jb8dq2d#6lI&(Y0B1tFQvJOlBmT z!0VL**Qwcm-1nRh9?G(yC^C}#sm0kdoDPg-F!Cr3T$=Nh<;hbexIfA=YR%yPDvx(` zN5IvZPv*V9O0T?vJ5+_7Uu|NG@_K!1m;|rZ+;fj(Th^xb#B~X7g_EE?w}Lg9qJ3j` zu;bm~h+IUbZVuI&HQdj|dgZUoQS&>Ufgg2)?&)E$W5(KUW8c3B6xuk@YV$ysTV-;A z{#WE*()08G^+@o!w9uHCJ-LJSuVztePVUcmwg+U9e~~plu9f32`uz?nCb!B)UkbaU z+4DC&e;ZmNjwNoQU+b~(ZQ1k#@(B;={MoGxEy2OHL94`T!VZn~Y`CH)Bo$--u9f}^s(mBn1G?#%&osK;iT)tl z8pIBN0lb@DqfVk=ahx2@PB;QL@QfpYty=4?YE_5s(L(S<7oZ+pP^;Ks`FP{B4$GPn zi2MZqb}5*43WH~J_M`^gGlhw~i-K{nF2;HIKNrd;eF3}3r{EBVD?<55-pWzS3RzMN zUc8!cS#?GU>>7|aIWTG!gulHISU_{1TJ7r;N|^aL2dldN&Z@JX$lMyk=I=^J^QlO9 z5~ZLlR^|fXQT7YQO>AJdGoM)2+9v}wwqv#4b=O~W>9N|N5u8l)x z6_4n8Rzve^ZYF~LRX*bgx%pImQb#Z~kIAyUZ+uACATCvan8 ze&;W$!Px%?^8IB{46IIm)pym=e|2^bSvsFxXdLeak^4PZl0KSE1Nj=OyEjmgB*Ik|Uh z{BMN)ycN349YBiQE1SPt^X~@zw=;YM^+82;l1<*Bulr@WW=VTZp5X?%rmp~-)k3el zLSEGjfj6NH`~b}SjsR+~v#UYQycJvnm58CMqjlMZ+SvUZ`xY|i?wn}^+WS^|D~z-& zr4?bTM$rtNZ^+8~Yle0spZBe->03QMgSoS>zFfbbN^j6OS=l(e^bdIR6=d06tMY1j z5!}^p@cDQRGAm>oV#I7_k!|@mSZGh6^R-Uji_vG^hM8NAOqTN|mC06m<;|c&|Df(@ zE<7tG;pN;fpEMJOepigT1@8p!qAU1;&b>RGiAxlxoC>VTYP?WmjpohzoK|GTDiaIT zW~OG!f{W_-+mpx7K=;S%<5|tYA3-v2(v0%D{9BMlUrQ-)3IEgA=PrJ84{jn_U8Q%- zfFZG;eB}u8s9y#j(izcLWBsZx*%w^EI0?O`h5)fjmjz-^LF4WK!_e0AYiE(7~rLB=TpyO^uB zV5LTKXRwo)eH~e$?aZAOx`VTH{R7#v&Cv?J02HeCb4H|3CWkyLSPeJrFWeJ%v23El zbGhcwYIc}AVQRbp_R-jdavGC=ul48T-p1bE*bA#?+@jU|FX(XJL3XsE{@0k^%Nl5I zJt#}Oi`vt@tkuse{(nYx?mV}>$hEpd_35`t@U_%I>+yOW_eOHF87M+zg8ryQhNT>F zp#R?njC{*v#=%(6jym2ga6KB!X@1ADn)3+_?}^k{jg;}7a7S-9#R3C0@`)KbLcb5E z!*>R%oJOB~&&>Uqj$!W}cInQztKK;V&w+~IZtI}M+X{4j4hXr+=+$J?4O0L<%+loI zYb5uIC0So9C|QMH@_3V9$M2m|TcTS6{ko9xmY z&86U}D5$wwnrQZBP6r*%qdfZVpkSZcegm*~QNECp{O?A+#Z>$!D~0QR;pP zMKZ6`J5b$rFZD=rki&IOOEjOSXw~m0U*L}G?}9gj=j5e6(tfHp{gCs?YFQD*`RqjQ z@N!@-@rZG02x_1)Rgq?7Zpx8?v|2zy`6LZpfrQ>c3Gxe#;J!%FHCel}Ht3rK@3`v* zb@gmQLnOh5UIDJcOsd9BS<7z$U)B_VTpYd)^D)#$8LSES&^xCJa2Fc$UI#4mZ}5PJ z;V~@R`^wF--|xvRyAHPtHuD6EcPsVzIjr?oel_R6na_4&>x*Ukv-R7L`kD?m{Ak_P zueh(1!J1A-CE-VyXSSo5Zaxre6Nf|~1yLu=__y1CPHqdTR<|g^e~|d>cKRkd(V5?t z)!LmwwNPGZE<1b}MPS#U?o^C$1BmQ|vSUMPFl|7l*CuOZ{T|YTUhot`TI0$2Ed8xku~C$PYy;z7Kgn>vWBSm46E8 zw2^wnQr)H1V6YBoZSq=m47|4cRE}Y*6~X9VO@%JOgl42c0$rcri%ka?-++#u+UV@X zHFJ)#+m2w$a31X}^XGElsz3($^D@lZY-%d5#hpiO;#a)aSdazI2QL6==(uFN=Gt-e zeVunJ4Kn{+U`Cz8)XUF+8$Zat@*ugfedPPx1HBd=Gc%n{#@pG(F3QfAbM$jT8FG`> z=w73d`x#W@a*dGD&figa>_@+&*%B78QvIm2>xSm>Ft`?0z|y~fZ1!-y$5=J6 z6B#=zkPeciF49cutE*e2zrWD6&IL8H8otIpVEv5ynXYRvm)y_2kx|a<{QIpxC--48dbiNy)g1rZl9j&^ zJnJ>E)Q0HJIVQ_W)<)}s40DC337nS+rblB1n^UVY``eZL)lt5pBfdNyo`dJsj1p!} z%OT@#l?da%>Jo)ChULNe?rYddH>7u@D!blGWVGgLEPE*)?S-1>C#>@`HTGN3_v@}Z z)&sxbPM@u0Rh@gW=7!mh+}WHD)u_ruvzU1>I^bsmmzcWWzCACaFVNnMkxUolHjKI2t&M&F&`OxD(BSMbwInj^D}* z+Dr#XKKShlV@dWTY2Z$e;sMO;ca{w3_f$V-f+BSn#LOf|**yI|Nme_N^~jt^XM#fX zR-}cA?kOu5Z-+tEJB9u*p7xg~m<(%*ceF!5qkMy&&cm)Xp!d1bh^K1!e8nRQ1ee%nRu3LwwoSb1+Q?;t|`AFzi6bNRpWltYmM_Y#{Uo* z($#v-+2;9Z#o7xm1u3yW&n(s*j%l9MW~Z1+JtqSV=VQ9J{|Wog$u(}m=g}I*r|KZu zn$bg@Lnmu1(0b)iwA~HvJu&*#i0y9&;oA}EsEp zMO(mOR51%vzb+P9_xd6|wk4@dWx)7Sj$MIw+G*te9lw`{Bg`r`B~hX}M1}q^c-b8~ z*ZJ7lPIxq&4@xjs7AMlpLuTv{Du&;KOfu$dEph5BX4y}=FDLb`jo`|SB^szvSqoG8 zM!L#RB)f5rf#Uc2yEYjGtRY|c1Bmsng4dIX1b0VI(P$bAIhN|=EcpgU1nAbFo9>b`{u0jQ*1o6wIATN2IGVl|gpzfFn2VZ@Vc?rI`(xLBA1j5r=T@6_| zS`jmrpl;BK%4$ctNN%AAxDnV#?+N4dkJkhNT$(*Y6%ZrN*(55K2`uss+2#f+bX)0B za-MPxOb*`bPo-;YHJt3r~+dt|Jho1-~42K{HVMt`bRrw=Hy541D#NWG&OH&Q=m zCzW9xVVP;pjC9Ay>s<=W)trWIqS;F;vL7s+R4=TOWEA?(Sbt7#TRJS8!75!B1ZH(~ z5gN0XD+5c7H6P5clBv0PDM)CNyW&y-zgiEUnRg-}O&0w#<&u4Wj?*%z#kj|HI&0GGJ6`;@w5hq8I5JQ&>~oQpFi_lw@0sgKet6j}xzk6Z2XLo2tc0Yp^ZMV@edz{LU6-9mv z+|?4m1X_qWV{I>MK)X_JZ0HnNk5}mDNNOP7hwdaZmEaPdBn#Z4PgxHtY68rKKk51} z$v^C6C*)53UF80LVr}fq=YCOlpy}g8y=u1)*4}z=;Sd*z$#7FM0J;s*GA_v z^N`m}#gmx9(|uI8!J6wmsJK{*5GjGUQuz6YbX zRF9uP-z~<2Zb5}$7F}f4d;3uKJOP%Ol^WBo8Vkn+KWO%K)2Ixhi@Y~$&;YW5qcqA3 z(UY`?cD_GR-QUglTDkaAkROC`8Td|Ir)+}qmRXt)pm+A4vj3diMy&TWL3=etNx_{g z?q;nIa;qA7+1jkkb;)hJr*j2;&i1G$$ff5;v8ot79p333p_k z=c@WV@~l6~8eDxcbIb)gVKb?CyALHDOnPzl_3jd>4?|pKRt@7`j-zy)3I4q{%o|y- zNBLX}C)rzTvXjgUcFnP?_in|=t(Rd}Q4W@gvh?QHC!Q^&`MZaHnH6B-tfqBNbK+Oo z#)-hV_5?CEh90M*{5V;LQ_1?!Ce2dw7Jm=6bRPTAq3D>6B=Vn#Ug1Qr1T#=To65YL zhIbsOx$pJ=pw7T*h0av$W%b*oyZ0m6|FLKyT0eLaeH8uRNODi>NL0_h!NYzEa>{I} z?*?xw4)|PS|BjyRq1TO(9nICzTt`e)2z$tnOeM-#FQ2!G$Yl+9gp)yGv^i4XyxT!G z!#(I{lKGBJy6(cGSIV zE69zYs9N!NC%9ER!CYm|Q)g;#RFqyL3{ZZVgZH#z^9AbLx$KZHfEU?IE$AfqkS#=7 z&WLUdnuT-1rqR{WvG8O0f!o3-!xzK9g@1s9xE!dI-vdX?A>0tZ(|La~$@jMsW`5VH zx@vyDuDRDktIs4Z3?;WEv)kcL?NU~`q@E|4F z^B00Iq9*JQmAU4|^eERP50Iau)}fAEiOjycWop31Qx%kIZBS$tiGecEi7=}6Okl;? z(~Qjy+2BFcC(QkI1UAfc^gQCAkWOp9SQ+miIq4K6AcGErhgw1GJC~~C5AY^ASM9!@Pl7k}aDQY^ zVu){K=iP{g`|IfA^{M@2+kH@17_7&)L;?%Ry^hy>eoIH_h24$N5vGB~SRwmx7SZ*X zeV|{BmHAcQ4`>9;uav+OttX<{O&8}5@EJxXyC1@s;0vIXUDr3`$u>HX+6OrK4G7FSb$d?G`*8 zJQ~~-Gzba>09Qb$zXwzQllJdDKx5bt+MuL(dw5?`VeP^2iSX|5PW^p%_!rq~CtXQ( z*1z&ZE>^Mng}l~Qu;<2o?5FR^5kLZGvs5E&UcGNLkDm!2j;h7pi@g!c7kfS`7;Oxf zg+GK7!&l^0>g$+?HD=zKozfWXXPw$b&(tpX{v1~gLBsD0jq)e-&P;+;!5UO&f_xxj z%txD_s(W6n=`#7Rdc+iE$TerP18oGC#wA&VSM1`%Em`y_X2H}^k{v=_Sjnov$(i8y zs0N2`P4ZH$P)}?`mwG312if$Z<z8Y8RO2c_kBw5ue#u#Rx5L|%Ruq`SsZ_rg zaeUiZx8Q4fto!OLhUk5cPRx%n3CzO?SQdxC($HJ?uR9$uTc~4v4~OVMSPbkhcgq5& z{BL&SC(x1G(0uxyegfZ=$C8Fig(Z_&FH>-qoW=7~!4$uv? z5oRCP3lEYB&6Dg@%%qb#ojLcD#{JQteNZYmo;p9ZTk7loVe9v!4f-TE(fRX7@cl;c zJgo25J-rnyYaJ>pRmj9Tr{jIwDQeCM9;jcygE`jS0Sm>hB(K$Ujc#w<^~T}T(GRhY z;^X2U#%soh#G1u+MBhbEMwOzUhAYKb;ZwBKvi>m&2xJP9A5U-jx-6u2COF zrfDJ7{|$6g7$2Ge7mOniM~tV))>%0tKsP21mfRit&Q!VwrUYHD716FbMr}P4HUjI? zRUp!LCbALu@&s0?1-i){U`MJaPuYPSNp;jyI9C(~KYpr6R`&w}Z2H1pLu9sODPo#*hnYkiU>%ypy6N9h&w z;69wGv028N>%SIIZ}WXhC?I!d&VEVG)LHLQn#mKeX77Q`d_I+2f@6tqWzojF^^>oi z4{z;M{q{BQHD0JI_1A&2>^H#)_10f=lO1x4u;7X8*vuEQRMxmu?|VD=Q*dwa*Wd%a zx-T6Wi}jyXa4RgK-o6jJHN*2Z7*d=Uxu~mH0!O;nUw3ECM*ndWI0oCOHPuF<1+y3n zpDYWWN31^)bhWV!GqKV!pvA|K+nbCJ^}fmsu;asI`Jv7ljOnWk|NZR7~=ka#&1F^2L_OUJU0sF!~%Vx}9f^+nt|Av;NIjo9NPcxo3#>#wF z{^AVk9p>aNM(1;J_VN{|DOaNpsxthfHP~UcrzfcmO0;$8KdDJ(q)swdS{F21B^ZDT z!B%}G==5f&Wtkn{DB^T5DD}ZSR7K^%3{00nnVd#>BVDun7}x~Ywhm}kP9yX5Jzb8Y zHOpqOp4--~Og5kTmC+`j>G3USh;KF4&jX-6aJ}nI_g|l?W~ECKq-E#IQaG8MXmka*%8l^r3}+&bXQdTl&twxok1Vs;(Q*2;Zd67_(7m-xuNg?5U<|cH_ez`# z61~`^s6V#RJTOLTx8B_$IGZ{#_3hLrQtwY~m0B`&Z_0n#_7jhLG{c*+<8MkIq^o*e zsKYna{J$$SR=6V!wk<$cRHut7hdpk9{*2e^ZPb;g%U)fHA5KI%R5Rqwpkg>Z>KC7t zb|me)wBzxo;}69jiMNkm5w8+oDj)D|v`*Gx6s7h3*3((NlkT+Ha7-9sKA)V*bne(# zjrm&k2&*(pR+0nX0UwZexCL018=?VU6P4-WMA=qiI7bz#1f8fwWVxMSdnrR_T`^GS z9Z>UV3PVzTlyY3jZvaBT7+-S{Gyp$Z5e=Q%=xyW&fm)fIVNJY*6>u++`K|`PSy`%p z5s`jjDh+1KNJZ1C0-fsa;JE-V#kRSq$_(Lex@OM?ILg<1L1N13Vo8%Adpv(ZFiipUE{P&vtb2%Z!_t! z9jh^$3#Zd$xXC8zGl$7TIPQ10@-xlKK|20e7-Jm!yGrER=F;GVB9FQ3AB--w8vHo& z_|xbh8Ish2nT{75pevb)euOJ5W5EErzCDv@>{O6WrKk{9t$fsy;^98M^48#7>KCaG zq~4L*J~cZvZ|a7WLH{MzpOb4&uB++t?Vxq*21U0u!B%zF!;pZMW*H z9c*5WHJkU43!F&YHBEQKzW05+z`L4P{WRyshJT9HOFNjhG_7sglkw5939+K_>*IID zUyi>TFB$I=`%CnGcvK@efGBH@jx<=KYh=YzSbIi+mUWN+VAg_#tRS1nrXM5zFUKnE zeR|O_l`MZ@G$V8AO3fmMDNfvCWNvkkPC4ZHtAXvS$j^r0p6kLlP#<33@>B=&fd;S& zPl7G|MsTN1P~j;;S8QqWj`lRE;cx6uFM~03lu;Lc9q%;`!}w-2>}iy;GT2#_Au@4Z zI2E+Pujn3ZhE;AEI6-#_Po8lnVCfCy>uTwk;T5C zmH!o;!AKBSQ}y~0`mAMo-MjkFGqSh7tN`vN`bhJkk6yEeisJ<0XXi4}6IlRz!I>yA4Mn@zG4~8K9hc~OegcRrDw{E|26iXlWQEm z`!H?+Np%anogLvrzLuVyTf#r+aR=Ff1b=XXrKuo#l-ps2a9>X4eMNl`a z7R`;dk@a^=E0uP2{O;Jf=$_b#*n{z5@#)$N6ph!56_1*QtM$&_%z;le@^i_`4%XcM zTku%$Nbs~g%4C#%tO#cOsgY*+br!XF)Sxr8DC+U4@b+fF_t>2NFf&`1O``wGk&#Ic z6BgPOv}i?m<7=`faJ@dkHCPz#8h@3b7TQ?;uN7+ZP093E(QB*1H({P{bJM!RB+fCi zIj0)n3yLQ5e#PZ|y!!nX6sOy-SQ0bnyu)QMBpa!jneV{Z^jR9u9$IO-Yu=6^+FV3@ z^$``iu0*Ndfq)*znm3uA^pVuF#uH7=p&GS7Gkh1lI(uO6TS;fySnPZlQTaIX0ewMG zP9yrBj^1H^5Wmx~g&}yA?r0}`0h_X`hOUY`Ug%9ma6Dba^FfP!ufNQ~^jF=xPjtN1 z;1+wZhxmpXVmFi+dg#4fbtN;|m%GpQL&X+v>9}K<0b_`_$AHjVPPA^8mR+EFmXiTZ zsJYs6^q_ZXtNu4$GpVo6d?kubLt$8P)_yqr&i!D8>kU_ok^KXB&2Vxd^XRJhi9JDr zBhKUUjmE^7lf>?7fUfKVebyp8wfDhB_ti`CRu+c8&CGfi^_dR@7gKwuHctIHWn{|S zlpj;3rM#AMYf8ueBJ0n|Eelqw2`nA0;C;CR4x6SR0&jph@T{aa>ongIj9lJ@PGVNh(u{i~ygiy2yA*#p?XI-l@!Ih}#*Rm)qeo*U;*;a~)AFQ! z7hf3b9=#oIr;Be6T5=;nq;%D)@VcVRS9BjHP^liFPq3FhrmsA7%G60}6 zudJ4={wDf9Yr^GTm`?EqRP?IDKU;%tklI@78=zBL9^`o@edq4{GlnEDOn9Zymn#z{ z(0=*DLP<=3cR|^jHUGcNUPbOxbE&J(DJ+(j9(HGQfUl0L~9X4Qhi|7zCMt%+XG%F|!kPVnu`4yd0 zSFQ1H$Rc`?(_27=!aD%3v2&A58bfr4zaqZ=l+5{PV!OepmzWdvYgzCYV2lP(#TbG% z>oA@f16RppGHmle+qlnhKiuzw$x`-(QL&G%ZMCe_%7#N&x4mC72e&KqE2!EVz1U4( z{mG;Z51tGDLNql9G*fr*Prc!coB%i6IQ+}lq+ZNyx_-UNEhkEIopddV>ZOw^pM~jw zyrhWWg&;kcnR<6>@zi}OYqjbxO<9uCBjvi3^pul%{?j)9|9+f8MY1p%vkW?^>%fHW zejoSvnYp(G3T{^_61a-|S6vWsB~cGECi|!?*Zz4TG1F4IBMt_ShkuT`#|Fn6rKP2f zj_1V3#BPq&k9CQyjXfHlA3qn*oAy||PHcm$cMkaV5oB)1li7M*^TpNV1+aT8*BWL# zo3$#dvCA?RKhfiL0nCBfvx>8OFN3B;wyq`*DpaMx=ah$`yCu9c=00-8F9(jJM&#s; zI?7M?etvWZQuX?}U;vEjJqJ?dEH%bTXin55k5`mEeMS0#tHO9v6I5ztx?jq|Raq2$ zg%(M*@cQH(O3^Lj?tp_j^IWdYh{f%?+L5~IRa7w!$lgZL`TV);n8hsh3x$pFn|My+wEDlfe%j9 z;?_`=_>s1?bLHH3WUhcHJO-``IUSC|Lr_sRNi4>G4S z$Y{(*InAAqw)K)=TGx~3bbaD@P#`?0&+QT{N_`~tiqyiX2U1q0j7{m9@=eNfDb-TW zL6-|0sbN3yFW$|2)pN^1Ac(M$zxo2fn#bxF0 z9W|$Yv!uRDDJpW6=;p13Voy1qFHXFl0TW#*(BxI&pb7CG#-U}yJ5d((g#W=8=hbUV z!!&U{no<>E<#cv54*zvIz2{2!4s*!;xmU(`l?=MrtgK_Ux#Qs6j%f8i2y15nJ-=U; zFqazH4?I@EAa5*0SK|L(WdA=VHu#tdl=JXIiKJb7o6owvf(*@kRz_QvIqKGfg`Lj& zH<~PBw`9~kh+V-@a^%CweR+qwoIS&I_Py?*o=jb4nC|loussubehF4PNO#Zdi?8W; zPwVFg>{iUb_yM&vdx)=-D8jDf6`fIdN&g?B^EEnXJ6d|1sKqUS=Xna*!!S$X8@j2PF46 zWAwfcbjAxbhbPgwX(qWT$vi{Culj6`fqiWRpOK^gN~l$s5qYHctS3|NP5nJ(eae)S zp((>s`lq~;^4FAWQ{pL0{tK-?CwC)Owp(Mr7v}SFXmeBp^->9xTthnH6A1T^ig`Iy zp3GLCO#p3Z-<2BPB zO&cGt5gQurfQ$c2`b=DR{R*uAD%nH=A8K^`ZmiusaaPATj1G;Jvx|~R&tMG?=?p0b zj;9vgqP2+ov#{_?IIR<1I)!A7Mvb~l@OK^mlx#2t+m2W3R=Pr?5-TJ-&N7p%G2y*6#bP}#1B|M`?5Rt&eeP1{%9T=-Ljqzpjn#JpXt@(&_o-->k@H5 zqB^)hpRrHhy*`ghswR#hGcZV2@c|qqz0g+en`FNkOC7dU_3fBpb?uPwWgx%L=WpYb%J%NcckuB z#J@acx;()AlrbsqYTqBGjLFmUztaA5a+hjmIL6+H*5-0F4PAjXH{^Pa<~nTdWRPHP zY^Qy0UA%+yUvYLnIp7?=N5}9WS*-G5pYV>TLo6%4GTuBbD{X4LQ~W^em)ND)so23- z{`i;L7d)F*ENyM9Ra7T5+te^}L_J`gmpbKQD{0?g6sncIOT&k2X731#Etd2o#jxn2^a@s> zlIuvmSduxpG)SMOVE;;?N)tz$`%+MVjGucBJIZTjp}Cqzv*a?oT*W~flm{p5ZlEJD z2PII4b>K^i>Dl$@>h6KNa0{vgBjp)il_kBc_3Iy6SKpS^jL^e6htpY?Ci8PT3UhQ`e@%9>A1JB0>}&?mowES8#ZmgK$#~7L zS^I}D0*gUHOs9^qoL+x3LhsO6EK91HpP<^h4Sc3`Ned@?mW$~A)seNkYvVM^B*z2i zuwMyU1bb6IPVJm}F=d79er3v{l!+h{*W8XB!){^6sAB9~Y(TthT8Fgs zv=8DJV>4pQV(Vh-V};|r;E32KBWlU^A%9!J)`S$2fgzQdlmg|pf}JJk2%~A$LU6^z9VaVQ?s}?xD(g= zyt?&4k!uXS8A~+Z`_Qx7L!-9~OtH~)Yv_+&maK6tB0A{DUVkO_HW7uh#pE9nTtx}I z%uEnB6G3D3OImPu(1Ziv46;ocu{oBVb1%?AW3a0cWGQFS8*l3$m(*Dwr&kR}k$I5L zXeXX|GoL(1f7`=5mpL}sWj7M!;io$KRI(XU*wx#%e}DyH8mq=9Fsr>xm%ihbAxVXJ zBOMo_*x~qnGu6Z~Fdxi^M`||bw-+td^{_x60?&F0wvMxOxFwVwjd$OM284Ul&5Ywd z*ed$pPJLG2;L)INuru}Vsijjdq#Q|Eoia_2sVTElW~6+c(k3M>Wq+Opd3yZU+J8>& zV9;JY*;jgRH;p{p0Q}`bGVe#YH$Ur+{ifA2Nb+1&p<~az*v1GZ)NoJBLJNeqYX5&a zoDjVhyCMF2{I0Z{)Aq)1j310`iyewhkM-9MU|alAMF5r3D#pKzt_&x_!vFo7?Dr^|*%A5vykKp!(cdjeoj<`}Yz>_Jbk$iyB89x&QJt?fbs7+zC(wQN z64sn3$8XhO8odM;u<`g|GD1)6fwIU9RHhrKTv&i8z*s_ zXLsz(`Y8UMN#EZ9viUvn+-vcmD^cv+p|x!z9q@~&)h`8Avz=a=g>WXVVzpdIrF}g} zi_sj<)$uv9)8ocU~K19as~;toT0Gqdo^+v&h>-uKp8H>L(PSWe=3!R zuXR4IKpMd~2yfzQM54!NFMi=?cuQBKXtJ8zu`9=W0(T!ecjQ&&3_L0YQJ}e~`|M8l zQ1{PXpda)_pO1nkgId9q)az1zOIesQNmf5GWnfCTl($n}O!;$4YsLMu@_dn} zSDxYj#n$hKcR+7w_DqHWVE_oM-eB`avsMfMO*sp+(+)Ust?X6+RJ-{-O2YS&$flX? zt#o*0*gNbJHH<~^P4PdZJ)Kr2?Ya0b{||fb9bQ$L_W!QuSvv`ef&~FZQBmx@JEP7x zjyk>QbZ17#aqJD1CcTH2kVXB!c9qAZjsqVxPj34VeI)@H)wppK`p@NPP=PW}0Z0*;B zLocT0Zh5kSAZhC8ZmYw~Z6ZIvlFpSmF!-ha6yXa(FqE9ur*fZx3WME@ct zA1$Lh*g991Q#D+}RG(eiV<@{tl9Bynbf$yy8v)zGG?4J=bO#hm+D9;Pv7E|8BS^Yw zbi|Dz6K|CTtIt)@DQLd?bS&|EOjtGK^VV1#QvzPM0!~^}KsW9na~y&kIaBuiE&U&z zIA-iz)|1o;w&&B}G&Pi#qc7dCnxE*^HS)!N5w;3v_(%PxuG$T7Pq^Q^C*AYzZ|*7m ze%M{+;@rw0E$E?b_&>Sy-*mDCj8iTct&$keZZ6f;TrgQS1FwPp&MFYyhT8u?tM?*s z@#iB;Z9v=_FTB;_o{H2*Zi;&^ZfgAB6I`piTOCRGO~Tgre(_J~r!M~U_`4G_5`3#0 zTHV=dXF~7z^2h?ZS>|K=--0)DJGhv)@y1%guz8xS`1P@gai_tH+m`-ZlgKZ1|02w} zYXfrUYWjF@U^dS+bO6~z8q4ur6q}=ch}yzuFi_me+<~(|^mhg2bTM3VT|oq19I