Repository: InsightSoftwareConsortium/ITK-Wasm (language: python)

Issue:
Core package



Discussion / hints:
Closes #662 

Fix patch:
diff --git a/packages/image-io/typescript/package.json b/packages/image-io/typescript/package.json
index b00f446bd..0278a3dda 100644
--- a/packages/image-io/typescript/package.json
+++ b/packages/image-io/typescript/package.json
@@ -60,7 +60,7 @@
     "esbuild": "^0.19.8",
     "shx": "^0.3.4",
     "start-server-and-test": "^2.0.1",
-    "typescript": "^5.0.4",
+    "typescript": "^5.3.3",
     "vite": "^4.5.0",
     "vite-plugin-static-copy": "^0.17.0"
   },
@@ -74,4 +74,4 @@
       "!test/node/common.js"
     ]
   }
-}
\ No newline at end of file
+}
diff --git a/packages/image-io/typescript/src/read-image-file-series.ts b/packages/image-io/typescript/src/read-image-file-series.ts
index 43a3c3905..9860677fb 100644
--- a/packages/image-io/typescript/src/read-image-file-series.ts
+++ b/packages/image-io/typescript/src/read-image-file-series.ts
@@ -1,4 +1,4 @@
-import { stackImages, WorkerPool, castImage } from 'itk-wasm'
+import { stackImages, WorkerPool, castImage, BinaryFile } from 'itk-wasm'
 
 import readImage from './read-image.js'
 
@@ -9,7 +9,7 @@ const numberOfWorkers = typeof globalThis.navigator?.hardwareConcurrency === 'nu
 const workerPool = new WorkerPool(numberOfWorkers, readImage)
 
 async function readImageFileSeries (
-  fileList: File[] | FileList,
+  fileList: File[] | FileList | BinaryFile[],
   options?: ReadImageFileSeriesOptions,
 ): Promise<ReadImageFileSeriesResult> {
   let zSpacing = 1.0
@@ -26,26 +26,25 @@ async function readImageFileSeries (
       sortedSeries = options.sortedSeries
     }
   }
+  // @ts-ignore  error TS2769: No overload matches this call.
   const fetchFileDescriptions = Array.from(fileList, async function (file) {
-    return await file.arrayBuffer().then(function (
-      arrayBuffer
-    ) {
-      const fileDescription = {
-        name: file.name,
-        type: file.type,
-        data: arrayBuffer
+    if (file instanceof File) {
+      const arrayBuffer = await file.arrayBuffer()
+      return {
+        path: file.name,
+        data: new Uint8Array(arrayBuffer)
       }
-      return fileDescription
-    })
+    }
+    return file as BinaryFile
   })
 
-  const fileDescriptions = await Promise.all(fetchFileDescriptions)
+  const fileDescriptions = await Promise.all(fetchFileDescriptions) as BinaryFile[]
   if (!sortedSeries) {
     fileDescriptions.sort((a, b) => {
-      if (a.name < b.name) {
+      if (a.path < b.path) {
         return -1
       }
-      if (a.name > b.name) {
+      if (a.path > b.path) {
         return 1
       }
       return 0
@@ -53,7 +52,7 @@ async function readImageFileSeries (
   }
   const taskArgsArray = []
   for (let index = 0; index < fileDescriptions.length; index++) {
-    taskArgsArray.push([fileDescriptions[index].data, fileDescriptions[index].name])
+    taskArgsArray.push([fileDescriptions[index],])
   }
   const results = await workerPool.runTasks(taskArgsArray).promise
   const images = results.map((result) => {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c30e343d2..6a64cf1e3 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -305,8 +305,8 @@ importers:
         specifier: ^2.0.1
         version: 2.0.3
       typescript:
-        specifier: ^5.0.4
-        version: 5.3.2
+        specifier: ^5.3.3
+        version: 5.3.3
       vite:
         specifier: ^4.5.0
         version: 4.5.1(@types/node@20.10.3)
@@ -5791,6 +5791,12 @@ packages:
     hasBin: true
     dev: true
 
+  /typescript@5.3.3:
+    resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==}
+    engines: {node: '>=14.17'}
+    hasBin: true
+    dev: true
+
   /uint8arraylist@2.4.7:
     resolution: {integrity: sha512-ohRElqR6C5dd60vRFLq40MCiSnUe1AzkpHvbCEMCGGP6zMoFYECsjdhL6bR1kTK37ONNRDuHQ3RIpScRYcYYIg==}
     dependencies:


Test patch:
diff --git a/packages/image-io/typescript/cypress/e2e/read-image-file-series.cy.ts b/packages/image-io/typescript/cypress/e2e/read-image-file-series.cy.ts
new file mode 100644
index 000000000..ca15b6387
--- /dev/null
+++ b/packages/image-io/typescript/cypress/e2e/read-image-file-series.cy.ts
@@ -0,0 +1,103 @@
+import { demoServer } from './common.ts'
+
+function verifyImage (image) {
+  cy.expect(image.imageType.dimension).to.equal(3)
+  cy.expect(image.imageType.componentType).to.equal('uint16')
+  cy.expect(image.imageType.pixelType).to.equal('Scalar')
+  cy.expect(image.imageType.components).to.equal(1)
+  cy.expect(image.origin[0]).to.equal(0.0)
+  cy.expect(image.origin[1]).to.equal(0.0)
+  cy.expect(image.origin[2]).to.equal(2.0)
+  cy.expect(image.spacing[0]).to.equal(0.85935)
+  cy.expect(image.spacing[1]).to.equal(0.85935)
+  cy.expect(image.spacing[2]).to.equal(3.0)
+  cy.expect(image.size[0]).to.equal(256)
+  cy.expect(image.size[1]).to.equal(256)
+  cy.expect(image.size[2]).to.equal(3)
+  cy.expect(image.data.length).to.equal(3 * 65536)
+  cy.expect(image.data[1000]).to.equal(0)
+}
+
+const zSpacing = 3.0
+const zOrigin = 2.0
+const testImageFiles = [
+  'mri3D_01.png',
+  'mri3D_02.png',
+  'mri3D_03.png',
+]
+
+describe('meta-image', () => {
+  beforeEach(function() {
+    cy.visit(demoServer)
+
+    const testPathPrefix = '../test/data/input/PNGSeries/'
+
+    cy.window().then((win) => {
+      win.testImageFiles = {}
+    })
+    testImageFiles.forEach((fileName) => {
+      cy.readFile(`${testPathPrefix}${fileName}`, null).as(fileName)
+      cy.window().then((win) => {
+        win.testImageFiles[fileName] = this[fileName]
+      })
+    })
+  })
+
+  it('Reads a sorted PNG file series', function () {
+    cy.window().then(async (win) => {
+      const files = testImageFiles.map((fileName) => {
+        return { data: new Uint8Array(win.testImageFiles[fileName]), path: fileName }
+      })
+      const sortedSeries = true
+
+      const { image, webWorkerPool } = await win.imageIo.readImageFileSeries(files, { zSpacing, zOrigin, sortedSeries })
+      webWorkerPool.terminateWorkers()
+      verifyImage(image)
+    })
+  })
+
+  it('Reads sorted PNG file series, specify componentType, pixelType', function () {
+    cy.window().then(async (win) => {
+      const files = testImageFiles.map((fileName) => {
+        return { data: new Uint8Array(win.testImageFiles[fileName]), path: fileName }
+      })
+      const sortedSeries = true
+      const componentType = win.itk.IntTypes.Int32
+      const pixelType = win.itk.PixelTypes.Vector
+
+      const { image, webWorkerPool } = await win.imageIo.readImageFileSeries(files, { zSpacing, zOrigin, sortedSeries, componentType, pixelType })
+      webWorkerPool.terminateWorkers()
+      cy.expect(image.imageType.componentType).to.equal('int32')
+      cy.expect(image.imageType.pixelType).to.equal('Vector')
+    })
+  })
+
+  it('Reads an unsorted PNG file series', function () {
+    cy.window().then(async (win) => {
+      const files = testImageFiles.map((fileName) => {
+        return { data: new Uint8Array(win.testImageFiles[fileName]), path: fileName }
+      })
+      files.reverse()
+
+      const { image, webWorkerPool } = await win.imageIo.readImageFileSeries(files, { zSpacing, zOrigin })
+      webWorkerPool.terminateWorkers()
+      verifyImage(image)
+    })
+  })
+
+  it('Reads an unsorted PNG file series, specifying componentType, pixelType', function () {
+    cy.window().then(async (win) => {
+      const files = testImageFiles.map((fileName) => {
+        return { data: new Uint8Array(win.testImageFiles[fileName]), path: fileName }
+      })
+      files.reverse()
+      const componentType = win.itk.IntTypes.Int32
+      const pixelType = win.itk.PixelTypes.Vector
+
+      const { image, webWorkerPool } = await win.imageIo.readImageFileSeries(files, { zSpacing, zOrigin, componentType, pixelType })
+      webWorkerPool.terminateWorkers()
+      cy.expect(image.imageType.componentType).to.equal('int32')
+      cy.expect(image.imageType.pixelType).to.equal('Vector')
+    })
+  })
+})
\ No newline at end of file
diff --git a/test/browser/io/readImageFileSeriesTest.js b/test/browser/io/readImageFileSeriesTest.js
deleted file mode 100644
index d7a4ef0c8..000000000
--- a/test/browser/io/readImageFileSeriesTest.js
+++ /dev/null
@@ -1,105 +0,0 @@
-import test from 'tape'
-import axios from 'axios'
-
-import { IntTypes, PixelTypes, getMatrixElement, readImageFileSeries } from 'browser/index.js'
-
-export default function () {
-  function verifyImage (t, image, expectedComponentType, expectedPixelType) {
-    let componentType = IntTypes.UInt16
-    if (expectedComponentType) {
-      componentType = expectedComponentType
-    }
-    let pixelType = PixelTypes.Scalar
-    if (expectedPixelType) {
-      pixelType = expectedPixelType
-    }
-    t.is(image.imageType.dimension, 3, 'dimension')
-    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], 0.0, 'origin[0]')
-    t.is(image.origin[1], 0.0, 'origin[1]')
-    t.is(image.origin[2], 2.0, 'origin[2]')
-    t.is(image.spacing[0], 0.85935, 'spacing[0]')
-    t.is(image.spacing[1], 0.85935, 'spacing[1]')
-    t.is(image.spacing[2], 3.0, 'spacing[2]')
-    t.is(getMatrixElement(image.direction, 3, 0, 0), 1.0, 'direction (0, 0)')
-    t.is(getMatrixElement(image.direction, 3, 0, 1), 0.0, 'direction (0, 1)')
-    t.is(getMatrixElement(image.direction, 3, 0, 2), 0.0, 'direction (0, 2)')
-    t.is(getMatrixElement(image.direction, 3, 1, 0), 0.0, 'direction (1, 0)')
-    t.is(getMatrixElement(image.direction, 3, 1, 1), 1.0, 'direction (1, 1)')
-    t.is(getMatrixElement(image.direction, 3, 1, 2), 0.0, 'direction (1, 2)')
-    t.is(getMatrixElement(image.direction, 3, 2, 0), 0.0, 'direction (2, 0)')
-    t.is(getMatrixElement(image.direction, 3, 2, 1), 0.0, 'direction (2, 1)')
-    t.is(getMatrixElement(image.direction, 3, 2, 2), 1.0, 'direction (2, 2)')
-    t.is(image.size[0], 256, 'size[0]')
-    t.is(image.size[1], 256, 'size[1]')
-    t.is(image.size[2], 3, 'size[2]')
-    t.is(image.data.length, 3 * 65536, 'data.length')
-    t.is(image.data[1000], 0, 'data[1000]')
-  }
-
-  const zSpacing = 3.0
-  const zOrigin = 2.0
-  function fetchTestFiles (fileNames) {
-    const testSeriesDirectory = 'base/build-emscripten/ExternalData/test/Input/PNGSeries/'
-    const fetchFiles = fileNames.map(function (file) {
-      const path = testSeriesDirectory + file
-      return axios.get(path, { responseType: 'blob' }).then(function (response) {
-        const jsFile = new window.File([response.data], file)
-        return jsFile
-      })
-    })
-    return fetchFiles
-  }
-
-  test('Test reading sorted PNG file series', async t => {
-    const fileNames = ['mri3D_01.png', 'mri3D_02.png', 'mri3D_03.png']
-    const fetchFiles = fetchTestFiles(fileNames)
-    const sortedSeries = true
-
-    const files = await Promise.all(fetchFiles)
-    const { image, webWorkerPool } = await readImageFileSeries(files, zSpacing, zOrigin, sortedSeries)
-    webWorkerPool.terminateWorkers()
-    verifyImage(t, image)
-    t.end()
-  })
-
-  test('Test reading sorted PNG file series, specify componentType, pixelType', async t => {
-    const fileNames = ['mri3D_01.png', 'mri3D_02.png', 'mri3D_03.png']
-    const fetchFiles = fetchTestFiles(fileNames)
-    const sortedSeries = true
-
-    const files = await Promise.all(fetchFiles)
-    const componentType = IntTypes.Int32
-    const pixelType = PixelTypes.Vector
-    const { image, webWorkerPool } = await readImageFileSeries(files, { zSpacing, zOrigin, sortedSeries, componentType, pixelType })
-    webWorkerPool.terminateWorkers()
-    verifyImage(t, image, componentType, pixelType)
-    t.end()
-  })
-
-  test('Test reading unsorted PNG file series', async t => {
-    const fileNames = ['mri3D_02.png', 'mri3D_01.png', 'mri3D_03.png']
-    const fetchFiles = fetchTestFiles(fileNames)
-
-    const files = await Promise.all(fetchFiles)
-    const { image, webWorkerPool } = await readImageFileSeries(files, zSpacing, zOrigin)
-    webWorkerPool.terminateWorkers()
-    verifyImage(t, image)
-    t.end()
-  })
-
-  test('Test reading unsorted PNG file series, specify componentType, pixelType', async t => {
-    const fileNames = ['mri3D_02.png', 'mri3D_01.png', 'mri3D_03.png']
-    const fetchFiles = fetchTestFiles(fileNames)
-
-    const files = await Promise.all(fetchFiles)
-    const componentType = IntTypes.Int32
-    const pixelType = PixelTypes.Vector
-    const { image, webWorkerPool } = await readImageFileSeries(files, { zSpacing, zOrigin, componentType, pixelType })
-    webWorkerPool.terminateWorkers()
-    verifyImage(t, image, componentType, pixelType)
-    t.end()
-  })
-}