InsightSoftwareConsortium / ITK-Wasm

High performance spatial analysis in a web browser and across programming languages and hardware architectures
https://wasm.itk.org
Apache License 2.0
195 stars 48 forks source link

readImageFile never resolves #432

Closed dsillman2000 closed 3 years ago

dsillman2000 commented 3 years ago

Hi,

I'm creating an application using VTK.js to render planes displaying NIFTI DICOM slices. I'm trying to read a locally-stored .nii.gz file as an Image object in ITK.js in order to use it as a texture in VTK.js. My existing code loads a directory of files via a directory input form. A specifically-named .nii.gz file is read in as a File object, which is subsequently handled in the following method:

export default async function loadInputImage(file) {
    const out = await readImageFile(null, file);
    out.webWorker.terminate();
    console.log(out.image);
    return out;
}

However, the out.image object is never printed to the console. Any time I await the output of readImageFile, I never can reach any code that follows it, which I can only assume means that the Promise returned by readImageFile never resolves.

Moreover, I've tried essentially equivalent approaches using readImageBlob and readImageArrayBuffer, resulting in the same stalling behavior.

How can I work around this?

Thanks, David

EDIT: It may be worth mentioning that I believe that the readImageFile function or its subfunctions are halting somehow because, according to the Chrome inspection pane, a thread is started in the name of "ImageIO.worker.js" that simply stays open without ever terminating (I imagine this is the webworker that never resolves).

thewtex commented 3 years ago

Hi @dsillman2000 how is loadInputImage being used?, i.e. are we sure this is not an issue with top level async / await?

dsillman2000 commented 3 years ago

Hi @dsillman2000 how is loadInputImage being used?, i.e. are we sure this is not an issue with top level async / await?

Hi @thewtex, thanks for your response! Below is the code that calls the aforementioned function. It's called in a callback that loads other files in the input directory, where the specific image file is handled as so:

if (files.inputImageNii !== null) {
     console.log("RECOGNIZED INPUT IMAGE: " + files.inputImageNii.name);
     let result = loadInputImage(files.inputImageNii);
     result.then((out) => {
              console.log(out);
     }).catch((err) => {
              console.error(err);
     })
}

I have lots of other methods in my code that use asynchronous loading with promises (namely, parsing XML files) which I handle in a similar way that don't have any such halting problem. Please let me know if you need any other information! It might also be worthwhile to note that the environment I am developing in is a React.js framework being tested on localhost in Google Chrome. If any of those details raise a red flag, please let me know.

David

dsillman2000 commented 3 years ago

@thewtex Oh WOW. I don't know if this error always came up, but I found it buried in a couple of my print statements, referring to Line 1 of ImageIO.worker.js:

Uncaught SyntaxError: Unexpected token '<' :3005/itk/WebWorkers/ImageIO.worker.js:1 

Does this give you any more info?

David

thewtex commented 3 years ago

:3005/itk/WebWorkers/ImageIO.worker.js

@dsillman2000 is ImageIO.worker.js correctly being served at that location?

dsillman2000 commented 3 years ago

:3005/itk/WebWorkers/ImageIO.worker.js

@dsillman2000 is ImageIO.worker.js correctly being served at that location?

Not sure what you mean. I would expect a localhost to precede the colon (considering I'm testing on https://localhost:3005), but I'm not sure how I would remedy that issue. How do I verify that it's "correctly being served?"

Thanks again, David

dsillman2000 commented 3 years ago

Hey, I think it's possible that it's not being served correctly. I was able to navigate to what the browser console believes was "ImageIO.worker.js" and it certainly was NOT the correct file, but rather the homepage for my app:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="/favicon.jpg" />
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css" rel="stylesheet">
    <script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="/manifest.json" />
    <!--
      Notice the use of  in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>Ion PlanPoint Web Viewer</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  <script src="/static/js/bundle.js"></script><script src="/static/js/vendors~main.chunk.js"></script><script src="/static/js/main.chunk.js"></script></body>
</html>

How can I ensure that the file is being served correctly, and not redirecting to this source? Sorry if these are stupid questions, I've never used react for this sort of application before and any guidance you can give me would be greatly appreciated.

Thanks, David

dsillman2000 commented 3 years ago

Hey,

So I solved the problem. I didn't have the ITK scripts copied into my "public" folder in my project, so it wasn't being served properly. After copying them over, the print statements I was expecting are finally printing. Thanks for all of your help! To anyone who has the same issue, just copy the following folders to your public folder:

node_modules/itk/WebWorkers
node_modules/itk/ImageIOs
node_modules/itk/PolydataIOs
node_modules/itk/MeshIOs

David

thewtex commented 2 years ago

Thanks for the follow-up @dsillman2000 .

As another follow-up, the itk-wasm refactor now hosts these required workers, wasm modules on JsDelivr by default so it is easier to get started.