diff --git a/src/openflexure_microscope_server/server/serve_static_files.py b/src/openflexure_microscope_server/server/serve_static_files.py index d87e5dec..4f5ad96c 100644 --- a/src/openflexure_microscope_server/server/serve_static_files.py +++ b/src/openflexure_microscope_server/server/serve_static_files.py @@ -44,3 +44,10 @@ def add_static_files(app: FastAPI) -> None: StaticFiles(directory=fpath), name=f"static_{fname}", ) + + # Mount the scan directory to .../scans/, to allow dzi viewing + app.mount( + "/scans/", + StaticFiles(directory="/var/openflexure/scans/"), + name="scans", + ) diff --git a/src/openflexure_microscope_server/things/smart_scan.py b/src/openflexure_microscope_server/things/smart_scan.py index a83a598b..7d819bb3 100644 --- a/src/openflexure_microscope_server/things/smart_scan.py +++ b/src/openflexure_microscope_server/things/smart_scan.py @@ -77,6 +77,7 @@ class ScanInfo(BaseModel): modified: datetime number_of_images: int stitch_available: bool + dzi: Optional[str] DOWNLOADABLE_SCAN_FILES = ( @@ -819,6 +820,11 @@ class SmartScanThing(Thing): ] number_of_images = len(scan_images) stitch_available = len(stitches) > 0 + dzi = [i for i in folder_contents if i.endswith("dzi")] + if len(dzi) > 0: + dzi = str(dzi[0]) + else: + dzi = None else: number_of_images = 0 stitch_available = False @@ -831,6 +837,7 @@ class SmartScanThing(Thing): modified=modified, number_of_images=number_of_images, stitch_available=stitch_available, + dzi=dzi, ) ) return scans @@ -925,7 +932,7 @@ class SmartScanThing(Thing): raise FileNotFoundError("No latest scan found") images_dir = self.images_dir_for_scan(self.latest_scan_name) - stitch_path = os.path.join(images_dir, "stitched_from_stage.jpg") + stitch_path = os.path.join(images_dir, "preview.jpg") if not os.path.isfile(stitch_path): raise FileNotFoundError("Latest scan has no preview stitch") return stitch_path @@ -980,7 +987,7 @@ class SmartScanThing(Thing): [ STITCHING_CMD, "--stitching_mode", - "only_stage_stitch", + "preview_stitch", "--minimum_overlap", f"{min_overlap}", self._ongoing_scan_images_dir, @@ -1096,6 +1103,7 @@ class SmartScanThing(Thing): "--stitching_mode", "all", f"{tiff_arg}", + "--stitch_dzi", "--minimum_overlap", f"{round(overlap * 0.9, 2)}", images_folder, @@ -1158,6 +1166,7 @@ class SmartScanThing(Thing): "stitched_from", "stitched.om", "stitching_correlations", + "preview.jp", ] with zipfile.ZipFile(zip_fname, mode="a") as scan_zip: diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 3c8a67ec..38a12b77 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -13,6 +13,7 @@ "material-design-icons": "^3.0", "material-symbols": "^0.14.3", "mousetrap": "^1.6.5", + "openseadragon": "^5.0.0", "vue-observe-visibility": "^0.4" }, "devDependencies": { @@ -10539,6 +10540,14 @@ "opener": "bin/opener-bin.js" } }, + "node_modules/openseadragon": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/openseadragon/-/openseadragon-5.0.1.tgz", + "integrity": "sha512-a/hjouW9i3UfWxRADVYN2MyRhXMGnE7x9VVL7/4jXCcDLFyO4UM5o4RStYtqa5BfaHw/wMNAaD2WbxQF8f1pJg==", + "funding": { + "url": "https://opencollective.com/openseadragon" + } + }, "node_modules/opn": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", diff --git a/webapp/package.json b/webapp/package.json index 014bfbcc..10550b76 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -17,6 +17,7 @@ "material-design-icons": "^3.0", "material-symbols": "^0.14.3", "mousetrap": "^1.6.5", + "openseadragon": "^5.0.0", "vue-observe-visibility": "^0.4" }, "devDependencies": { diff --git a/webapp/src/components/tabContentComponents/scanListComponents/openSeadragonViewer.vue b/webapp/src/components/tabContentComponents/scanListComponents/openSeadragonViewer.vue new file mode 100644 index 00000000..6f0be39c --- /dev/null +++ b/webapp/src/components/tabContentComponents/scanListComponents/openSeadragonViewer.vue @@ -0,0 +1,96 @@ + + + + + + + + + \ No newline at end of file diff --git a/webapp/src/components/tabContentComponents/scanListContent.vue b/webapp/src/components/tabContentComponents/scanListContent.vue index 20f4d461..293b9d0c 100644 --- a/webapp/src/components/tabContentComponents/scanListContent.vue +++ b/webapp/src/components/tabContentComponents/scanListContent.vue @@ -1,8 +1,7 @@ + class="galleryDisplay uk-padding uk-padding-remove-top"> + + + + + {{ selectedScan.name }} + close + + fullscreen + + + + + + + + {{ item.name }} - + + + Show Stitched Scan + + + {{ item.number_of_images }} images created: {{ formatDate(item.created) }} modified: {{ formatDate(item.modified) }} - Not enough images to stitch - Scan not stitched - + Not enough images to stitch + Interactive preview not available + High quality stitch not available + + @@ -285,6 +342,20 @@ export default { margin-bottom: 20px; } +#openseadragon { + width: 100%; + height: 100%; +} +#info-panel { + position: absolute; + top: 10px; + left: 10px; + background-color: rgba(255, 255, 255, 0.7); + padding: 5px; + border-radius: 1px; + z-index: 1000; +} + /deep/ .capture-card { width: 300px; height: 100%; // Used to have all cards in a row match their heights @@ -296,5 +367,18 @@ ul { display: inline-block; text-align: center; list-style-type:none; + margin: 5px 0px 10px 0px; +} + +.warning-msg { + color: red; + text-align: center; + font-weight: bold; +} + +.alert-msg{ + color: orange; + text-align: center; + font-weight: bold; } \ No newline at end of file