Skip to content

Instantly share code, notes, and snippets.

@lassoan
Last active Jul 14, 2021
Embed
What would you like to do?
Launch 3D Slicer from web browser to view 3D image file
# This 3D Slicer module allows launching 3D Slicer from the web browser and load an image file, for example from NRRD format.
# It uses a custom URL, which launches 3D Slicer and contains the download URL as query parameter (with percent encoding).
# See discussion at https://discourse.slicer.org/t/how-to-load-nifti-file-from-web-browser-link/18664/5
#
# Setup:
# - save this file as "LoadRemoteFile.py" in an empty folder.
# - add the folder to additional module paths in Slicer
#
# To test, open a terminal and execute this command:
#
# start slicer://viewer/?download=https%3A%2F%2Fgithub.com%2Frbumm%2FSlicerLungCTAnalyzer%2Freleases%2Fdownload%2FSampleData%2FLungCTAnalyzerChestCT.nrrd
#
import os
import unittest
import logging
import vtk, qt, ctk, slicer
from slicer.ScriptedLoadableModule import *
from slicer.util import VTKObservationMixin
#
# LoadRemoteFile
#
class LoadRemoteFile(ScriptedLoadableModule):
"""Uses ScriptedLoadableModule base class, available at:
https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
"""
def __init__(self, parent):
ScriptedLoadableModule.__init__(self, parent)
self.parent.title = "Load Remote File"
self.parent.categories = ["Utilities"]
self.parent.dependencies = []
self.parent.contributors = ["ASH", "Andras Lasso (PerkLab)"]
self.parent.helpText = """
This module loads NRRD files from custom URLs such as:
slicer://viewer/?download=https%3A%2F%2Fgithub.com%2Frbumm%2FSlicerLungCTAnalyzer%2Freleases%2Fdownload%2FSampleData%2FLungCTAnalyzerChestCT.nrrd
See more information <a href="https://discourse.slicer.org/t/how-to-load-nifti-file-from-web-browser-link/18664/5">here</a>.
"""
self.parent.acknowledgementText = """
This file was originally developed by Andras Lasso, PerkLab and ASH.
"""
# Initilize self.sampleDataLogic. At this point, Slicer modules are not initialized yet, so we cannot instantiate the logic yet.
self.sampleDataLogic = None
slicer.app.connect("urlReceived(QString)", self.onURLReceived)
def reportProgress(self, message):
# Print progress in the console
print(f"Loading... {self.sampleDataLogic.downloadPercent}%")
# Abort download if cancel is clicked in progress bar
if self.progressWindow.wasCanceled:
raise Exception("download aborted")
# Update progress window
self.progressWindow.show()
self.progressWindow.activateWindow()
self.progressWindow.setValue(int(self.sampleDataLogic.downloadPercent))
self.progressWindow.setLabelText("Downloading...")
# Process events to allow screen to refresh
slicer.app.processEvents()
def onURLReceived(self, urlString):
"""Process DICOM view requests. Example:
urlString="slicer://viewer/?download=https%3A%2F%2Fgithub.com%2Frbumm%2FSlicerLungCTAnalyzer%2Freleases%2Fdownload%2FSampleData%2FLungCTAnalyzerChestCT.nrrd"
"""
logging.info(f"URL received: {urlString}")
# Check if we understand this URL
url = qt.QUrl(urlString)
if url.authority().lower() != "viewer":
return
query = qt.QUrlQuery(url)
queryMap = {}
for key, value in query.queryItems(qt.QUrl.FullyDecoded):
queryMap[key] = qt.QUrl.fromPercentEncoding(value)
if not "download" in queryMap:
return
# Get the download link and node name from URL
downloadUrl = qt.QUrl(queryMap["download"])
nodeName, ext = os.path.splitext(os.path.basename(downloadUrl.path()))
logging.info(f"Download URL detected - get the file from {downloadUrl} and load it now")
# Generate random filename to avoid reusing/overwriting older downloaded files that may have the same name
import uuid
filename = f"{nodeName}-{uuid.uuid4().hex}{ext}"
# Ensure sampleData logic is created
if not self.sampleDataLogic:
import SampleData
self.sampleDataLogic = SampleData.SampleDataLogic()
try:
self.progressWindow = slicer.util.createProgressDialog()
self.sampleDataLogic.logMessage = self.reportProgress
loadedNodes = self.sampleDataLogic.downloadFromURL(nodeNames=nodeName, fileNames=filename, uris=downloadUrl.toString())
finally:
self.progressWindow.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment