diff --git a/src/io/ReadImageDICOMArrayBufferSeriesOptions.ts b/src/io/ReadImageDICOMArrayBufferSeriesOptions.ts new file mode 100644 index 000000000..1f7401f9c --- /dev/null +++ b/src/io/ReadImageDICOMArrayBufferSeriesOptions.ts @@ -0,0 +1,8 @@ +import CastImageOptions from '../core/CastImageOptions.js' + +interface ReadImageDICOMArrayBufferSeriesOptions extends CastImageOptions { + singleSortedSeries?: boolean + fileNames?: string[] +} + +export default ReadImageDICOMArrayBufferSeriesOptions \ No newline at end of file diff --git a/src/io/browser/index.ts b/src/io/browser/index.ts index 11b5fd6c6..026a8f772 100644 --- a/src/io/browser/index.ts +++ b/src/io/browser/index.ts @@ -24,6 +24,7 @@ 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 ReadImageDICOMArrayBufferSeriesOptions } from './../ReadImageDICOMArrayBufferSeriesOptions.js' export { default as readImageDICOMArrayBufferSeries } from './../readImageDICOMArrayBufferSeries.js' export { default as writeImageArrayBuffer } from './../writeImageArrayBuffer.js' diff --git a/src/io/readImageDICOMArrayBufferSeries.ts b/src/io/readImageDICOMArrayBufferSeries.ts index 941343291..edfc2c12d 100644 --- a/src/io/readImageDICOMArrayBufferSeries.ts +++ b/src/io/readImageDICOMArrayBufferSeries.ts @@ -4,11 +4,13 @@ import stackImages from '../core/stackImages.js' import BinaryFile from '../core/BinaryFile.js' import InterfaceTypes from '../core/InterfaceTypes.js' import Image from '../core/Image.js' +import castImage from '../core/castImage.js' import config from '../itkConfig.js' import ReadImageResult from './ReadImageResult.js' import ReadImageFileSeriesResult from './ReadImageFileSeriesResult.js' +import ReadImageDICOMArrayBufferSeriesOptions from './ReadImageDICOMArrayBufferSeriesOptions.js' const workerFunction = async ( webWorker: Worker | null, @@ -78,11 +80,29 @@ const seriesBlockSize = 8 const readImageDICOMArrayBufferSeries = async ( arrayBuffers: ArrayBuffer[], - singleSortedSeries = false, - fileNames?: string[] + options?: ReadImageDICOMArrayBufferSeriesOptions | boolean, + fileNamesBackwardsCompatibility?: string[] ): Promise => { - const validFileNames = (fileNames != null) && fileNames.length === arrayBuffers.length + let singleSortedSeries = false + let fileNames: undefined | string[] = undefined + if (typeof options === 'boolean') { + // Backwards compatibility + singleSortedSeries = options + } + if (typeof fileNamesBackwardsCompatibility !== 'undefined') { + fileNames = fileNamesBackwardsCompatibility + } + if (typeof options === 'object') { + if (typeof options.singleSortedSeries !== 'undefined') { + singleSortedSeries = options.singleSortedSeries + } + if (typeof options.fileNames !== 'undefined') { + fileNames = options.fileNames + } + } + const validFileNames = (typeof fileNames !== 'undefined') && fileNames.length === arrayBuffers.length const fileDescriptions = arrayBuffers.map((ab, index) => { + // @ts-ignore: TS2532: Object is possibly 'undefined'. return { path: validFileNames ? fileNames[index] : `${index}.dcm`, data: new Uint8Array(ab) } }) if (singleSortedSeries) { @@ -93,12 +113,19 @@ const readImageDICOMArrayBufferSeries = async ( } const results = await workerPool.runTasks(taskArgsArray).promise const images = results.map((result) => result.image) - const stacked = stackImages(images) + let stacked = stackImages(images) + if (typeof options === 'object' && (typeof options.componentType !== 'undefined' || typeof options.pixelType !== 'undefined')) { + stacked = castImage(stacked, options) + } return { image: stacked, webWorkerPool: workerPool } } else { const taskArgsArray = [[fileDescriptions, singleSortedSeries]] const results = await workerPool.runTasks(taskArgsArray).promise - return { image: results[0].image, webWorkerPool: workerPool } + let image = results[0].image + if (typeof options === 'object' && (typeof options.componentType !== 'undefined' || typeof options.pixelType !== 'undefined')) { + image = castImage(image, options) + } + return { image, webWorkerPool: workerPool } } } diff --git a/test/browser/io/DICOMSeriesTest.js b/test/browser/io/DICOMSeriesTest.js index 6e9e8d370..c0bb8dc5c 100644 --- a/test/browser/io/DICOMSeriesTest.js +++ b/test/browser/io/DICOMSeriesTest.js @@ -6,10 +6,18 @@ import { IntTypes, PixelTypes, getMatrixElement, readImageDICOMFileSeries, readI const testSeriesDirectory = 'base/build-emscripten/ExternalData/test/Input/DicomImageOrientationTest/' const fileNames = ['ImageOrientation.1.dcm', 'ImageOrientation.2.dcm', 'ImageOrientation.3.dcm'] -function verifyImage (t, image) { +function verifyImage (t, image, expectedComponentType, expectedPixelType) { t.is(image.imageType.dimension, 3, 'dimension') - t.is(image.imageType.componentType, IntTypes.Int16, 'componentType') - t.is(image.imageType.pixelType, PixelTypes.Scalar, 'pixelType') + let componentType = IntTypes.Int16 + if (expectedComponentType) { + componentType = expectedComponentType + } + let pixelType = PixelTypes.Scalar + if (expectedPixelType) { + pixelType = expectedPixelType + } + t.is(image.imageType.componentType, componentType, 'componentType') + t.is(image.imageType.pixelType, pixelType, 'pixelType') t.is(image.imageType.components, 1, 'components') t.is(image.origin[0], -17.3551, 'origin[0]') t.is(image.origin[1], -133.9286, 'origin[1]') @@ -87,6 +95,21 @@ export default function () { verifyImage(t, image) }) + test('Test reading DICOM array buffer series given componentType, pixelType', async t => { + const fetchFiles = fileNames.map(async function (file) { + const path = testSeriesDirectory + file + const response = await axios.get(path, { responseType: 'arraybuffer' }) + return response.data + }) + + const arrayBuffers = await Promise.all(fetchFiles) + const componentType = IntTypes.Int32 + const pixelType = PixelTypes.Vector + const { image, webWorkerPool } = await readImageDICOMArrayBufferSeries(arrayBuffers, { pixelType, componentType }) + webWorkerPool.terminateWorkers() + verifyImage(t, image, componentType, pixelType) + }) + test('Test reading DICOM array buffer series, assume a single sorted series', async t => { const fetchFiles = fileNames.map(async function (file) { const path = testSeriesDirectory + file @@ -100,4 +123,20 @@ export default function () { webWorkerPool.terminateWorkers() verifyImage(t, image) }) + + test('Test reading DICOM array buffer series, assume a single sorted series, given componentType, pixelType', async t => { + const fetchFiles = fileNames.map(async function (file) { + const path = testSeriesDirectory + file + const response = await axios.get(path, { responseType: 'arraybuffer' }) + return response.data + }) + + const arrayBuffers = await Promise.all(fetchFiles) + const singleSortedSeries = true + const componentType = IntTypes.Int32 + const pixelType = PixelTypes.Vector + const { image, webWorkerPool } = await readImageDICOMArrayBufferSeries(arrayBuffers, { singleSortedSeries, componentType, pixelType }) + webWorkerPool.terminateWorkers() + verifyImage(t, image, componentType, pixelType) + }) }