diff --git a/doc/content/api/browser_io.md b/doc/content/api/browser_io.md index 6ea92a9ec..362e5fb2c 100644 --- a/doc/content/api/browser_io.md +++ b/doc/content/api/browser_io.md @@ -90,6 +90,19 @@ Returns: - tags: a [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) containing the mapping from tag to tag value. - webWorker: a webworker that can be re-used. +## readDICOMTagsArrayBuffer(webWorker: Worker | null, arrayBuffer: ArrayBuffer, tags: string[] | null = null): Promise<{ tags: Map, webWorker: Worker }> + +Read tags from a DICOM [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer). + +Tags should be of the form `"GGGG|EEEE"`, where `GGGG` is the group ID in hex and `EEEE` is the element ID in hex. As an example, "0010|0010" is the PatientID. +Hexadecimal strings are treated case-insensitively. +A web worker object can be optionally provided to re-use a previously created web worker. +Otherwise, leave this null. + +Returns: +- tags: a [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) containing the mapping from tag to tag value. +- webWorker: a webworker that can be re-used. + ## writeImageArrayBuffer(webWorker: Worker | null, useCompression: boolean, image: [Image](./Image.html), fileName: string, mimeType: string): Promise<{ webWorker: Worker, arrayBuffer: [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) }> Write an image to a an [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer). diff --git a/src/io/browser/index.ts b/src/io/browser/index.ts index 6c251da4f..4a8cc5383 100644 --- a/src/io/browser/index.ts +++ b/src/io/browser/index.ts @@ -17,6 +17,7 @@ export { default as readFile } from './../readFile.js' export { default as readImageHTTP } from './../readImageHTTP.js' export { default as readDICOMTags } from './../readDICOMTags.js' +export { default as readDICOMTagsArrayBuffer } from './../readDICOMTagsArrayBuffer.js' export { default as readImageDICOMFileSeries } from './../readImageDICOMFileSeries.js' export { default as readImageDICOMArrayBufferSeries } from './../readImageDICOMArrayBufferSeries.js' diff --git a/src/io/readDICOMTags.ts b/src/io/readDICOMTags.ts index 79568ebb0..4504cf5b2 100644 --- a/src/io/readDICOMTags.ts +++ b/src/io/readDICOMTags.ts @@ -1,59 +1,11 @@ -import createWebWorkerPromise from '../core/internal/createWebWorkerPromise.js' import { readAsArrayBuffer } from 'promise-file-reader' -import PipelineInput from '../pipeline/PipelineInput.js' -import TextStream from '../core/TextStream.js' - -import config from '../itkConfig.js' import ReadDICOMTagsResult from './ReadDICOMTagsResult.js' -import InterfaceTypes from '../core/InterfaceTypes.js' +import readDICOMTagsArrayBuffer from './readDICOMTagsArrayBuffer.js' async function readDICOMTags (webWorker: Worker, file: File, tags: string[] | null = null): Promise { - let worker = webWorker - const { webworkerPromise, worker: usedWorker } = await createWebWorkerPromise( - 'pipeline', - worker - ) - worker = usedWorker - const arrayBuffer = await readAsArrayBuffer(file) - const dataArray = new Uint8Array(arrayBuffer) - - const path = `./${file.name}` - const args = [path, '0', '--memory-io'] - const inputs = [ - { type: InterfaceTypes.BinaryFile, data: { data: dataArray, path } } - ] as PipelineInput[] - if (tags != null) { - args.push('--tags-to-read') - args.push('1') - inputs.push({ type: InterfaceTypes.TextStream, data: { data: JSON.stringify({ tags: tags }) } }) - } - const outputs = [ - { type: InterfaceTypes.TextStream } - ] - - interface PipelineResult { - stdout: string - stderr: string - outputs: any[] - } - - const result: PipelineResult = await webworkerPromise.postMessage( - { - operation: 'readDICOMTags', - config: config, - pipelinePath: 'ReadDICOMTags', // placeholder - args, - outputs, - inputs - }, - [arrayBuffer] - ) - const tagsJSON = (result.outputs[0].data as TextStream).data - const tagsResult = JSON.parse(tagsJSON) - const tagsMap: Map = new Map(tagsResult.tags) - return { tags: tagsMap, webWorker: worker } + return await readDICOMTagsArrayBuffer(webWorker, arrayBuffer, tags) } export default readDICOMTags diff --git a/src/io/readDICOMTagsArrayBuffer.ts b/src/io/readDICOMTagsArrayBuffer.ts new file mode 100644 index 000000000..c0170c9ce --- /dev/null +++ b/src/io/readDICOMTagsArrayBuffer.ts @@ -0,0 +1,57 @@ +import createWebWorkerPromise from '../core/internal/createWebWorkerPromise.js' +import PipelineInput from '../pipeline/PipelineInput.js' +import TextStream from '../core/TextStream.js' + +import config from '../itkConfig.js' + +import ReadDICOMTagsResult from './ReadDICOMTagsResult.js' +import InterfaceTypes from '../core/InterfaceTypes.js' + +async function readDICOMTagsArrayBuffer (webWorker: Worker, arrayBuffer: ArrayBuffer, tags: string[] | null = null): Promise { + let worker = webWorker + const { webworkerPromise, worker: usedWorker } = await createWebWorkerPromise( + 'pipeline', + worker + ) + worker = usedWorker + + const dataArray = new Uint8Array(arrayBuffer) + + const path = './file.dcm' + const args = [path, '0', '--memory-io'] + const inputs = [ + { type: InterfaceTypes.BinaryFile, data: { data: dataArray, path } } + ] as PipelineInput[] + if (tags != null) { + args.push('--tags-to-read') + args.push('1') + inputs.push({ type: InterfaceTypes.TextStream, data: { data: JSON.stringify({ tags: tags }) } }) + } + const outputs = [ + { type: InterfaceTypes.TextStream } + ] + + interface PipelineResult { + stdout: string + stderr: string + outputs: any[] + } + + const result: PipelineResult = await webworkerPromise.postMessage( + { + operation: 'readDICOMTags', + config: config, + pipelinePath: 'ReadDICOMTags', // placeholder + args, + outputs, + inputs + }, + [arrayBuffer] + ) + const tagsJSON = (result.outputs[0].data as TextStream).data + const tagsResult = JSON.parse(tagsJSON) + const tagsMap: Map = new Map(tagsResult.tags) + return { tags: tagsMap, webWorker: worker } +} + +export default readDICOMTagsArrayBuffer diff --git a/test/browser/io/DICOMTest.js b/test/browser/io/DICOMTest.js index 7a1671cde..e1271b7a4 100644 --- a/test/browser/io/DICOMTest.js +++ b/test/browser/io/DICOMTest.js @@ -1,7 +1,7 @@ import test from 'tape' import axios from 'axios' -import { IntTypes, PixelTypes, getMatrixElement, readImageFile, readDICOMTags } from 'browser/index.js' +import { IntTypes, PixelTypes, getMatrixElement, readImageFile, readDICOMTags, readDICOMTagsArrayBuffer } from 'browser/index.js' export default function () { test('Test reading a DICOM file', t => { @@ -65,6 +65,27 @@ export default function () { t.end() }) + test('Test reading DICOM tags ArrayBuffer', async t => { + const expected = { + '0010|0020': 'NOID', + '0020|0032': '-3.295510e+01\\-1.339286e+02\\1.167857e+02', + '0020|0037': '0.00000e+00\\ 1.00000e+00\\-0.00000e+00\\-0.00000e+00\\ 0.00000e+00\\-1.00000e+00', + // case sensitivity test + '0008|103e': 'SAG/RF-FAST/VOL/FLIP 30 ', + '0008|103E': 'SAG/RF-FAST/VOL/FLIP 30 ' + } + const fileName = '1.3.6.1.4.1.5962.99.1.3814087073.479799962.1489872804257.100.0.dcm' + const testFilePath = 'base/build/ExternalData/test/Input/' + fileName + const response = await axios.get(testFilePath, { responseType: 'arraybuffer' }) + const arrayBuffer = response.data + const { tags: result, webWorker } = await readDICOMTagsArrayBuffer(null, arrayBuffer, Object.keys(expected)) + webWorker.terminate() + t.true(result instanceof Map) + Object.keys(expected).forEach((tag) => { + t.is(result.get(tag), expected[tag], tag) + }) + t.end() + }) test('Test reading all DICOM tags', async t => { const expected = { '0010|0020': 'NOID',