Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vizarr for s3 ngff #16

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Install with::
$ pip install -e .

Configuration
-------------

::

Expand Down Expand Up @@ -67,6 +68,28 @@ In the webclient UI you can use the context menu to `Open With > Vizarr`, or use

[omero-server]/zarr/vizarr/?source=[omero-server]/zarr/v0.4/image/[ID].zarr

Viewing s3 data
---------------

If you have imported OME-Zarr images into OMERO and the data is publicly accessible, e.g. hosted
on s3, then you can use this app to view that s3 data directly (instead of using the OMERO server).
This relies on the public data source being set as the `clientPath` location (shown in the webclient
as "Imported From"). At least 1 `clientPath` for an Image or Plate should be in the form:
`http....zarr/.zattrs`.
For data that matches this criteria, we can replace the image-viewer with `vizarr`` (images that do not
have such a clientPath will default to using iviewer):

::

$ omero config set omero.web.viewer.view omero_web_zarr.views.vizarr_or_iviewer

If you want to remove the Preview panel

::

$ omero config set omero.web.ui.right_plugins '[["Acquisition", "webclient/data/includes/right_plugin.acquisition.js.html", "metadata_tab"]]'


Testing
-------

Expand All @@ -84,5 +107,5 @@ The application is released under the AGPL.
Copyright
---------

2022-2023, The Open Microscopy Environment
2022-2024, The Open Microscopy Environment

21 changes: 21 additions & 0 deletions omero_web_zarr/static/omero_web_zarr/vizarr/blosc-5eba38ca.js

Large diffs are not rendered by default.

Binary file not shown.
2 changes: 2 additions & 0 deletions omero_web_zarr/static/omero_web_zarr/vizarr/index-99be1c79.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions omero_web_zarr/static/omero_web_zarr/vizarr/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link
rel="icon"
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🔬</text></svg>"
/>
<link rel="alternate icon" href="./favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="A minimal, purely client-side program for viewing Zarr-based images." />
<title>vizarr</title>
<script type="module" crossorigin src="./index-99be1c79.js"></script>
<link rel="modulepreload" crossorigin href="./vizarr-09ae863b.js">
</head>
<body>
<div id="root"></div>
<noscript>You need to enable JavaScript to run this app.</noscript>

<style>
html {
background-color: black;
}
</style>
</body>
</html>
3,888 changes: 3,888 additions & 0 deletions omero_web_zarr/static/omero_web_zarr/vizarr/vizarr-09ae863b.js

Large diffs are not rendered by default.

56 changes: 56 additions & 0 deletions omero_web_zarr/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#

from django.http import Http404
from omero.sys import ParametersI
from omero.rtypes import rstring


def marshal_pixel_sizes(image):
Expand Down Expand Up @@ -96,3 +98,57 @@ def generate_coordinate_transformations(shapes):
transformations.append([{"type": "scale", "scale": scale}])

return transformations


def get_clientpath_by_endswith(conn, image_id, pathending):
query_service = conn.getQueryService()
params = ParametersI()
params.addId(image_id)
params.add("zarr", rstring("%%%s" % pathending))
query = """ select u.clientPath from Fileset fs
join fs.usedFiles u
left outer join fs.images as image
where image.id=:id
and u.clientPath like :zarr"""
result = query_service.projection(query, params, conn.SERVICE_OPTS)
if len(result) == 0:
return None
return result[0][0].val


def get_zarr_s3_path(conn, image_id):
"""
Check Fileset clientPaths for path ending zarr/.zattrs

If Image is in a Plate/Well, add eg. /A/1/0/ to path.
"""
client_path = get_clientpath_by_endswith(conn, image_id, "zarr/.zattrs")
if client_path is None:
return None

# We also need clientPath to be a publicly-accessible URL
zarr_path = client_path.replace("/.zattrs", "")

# Check if Image is in a Well - need to add /row/col/field/ e.g. /A/1/0
query_service = conn.getQueryService()
wsparams = ParametersI()
wsparams.addId(image_id)
wsquery = """select well.plate.id, well.row, well.column, index(ws) from Well well
join well.wellSamples ws where ws.image.id=:id"""
ws = query_service.projection(wsquery, wsparams, conn.SERVICE_OPTS)
if len(ws) > 0:
plate_id = ws[0][0].val
plate = conn.getObject("Plate", plate_id)
row = plate.getRowLabels()[ws[0][1].val]
column = plate.getColumnLabels()[ws[0][2].val]
ws_index = ws[0][3].val
row_col_field = f"/{row}/{column}/{ws_index}/"
zarr_path += row_col_field
else:
# Check whether this is a bioformats2raw image
metadata_path = get_clientpath_by_endswith(conn, image_id,
"OME/METADATA.ome.xml")
if metadata_path is not None:
zarr_path += "/0/"

return zarr_path
25 changes: 24 additions & 1 deletion omero_web_zarr/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
from django.http import HttpResponse, JsonResponse
from django.urls import reverse
from django.shortcuts import redirect
from django.templatetags.static import static

from .utils import marshal_axes, marshal_axes_v3
from .utils import marshal_axes, marshal_axes_v3, get_zarr_s3_path
from .utils import generate_coordinate_transformations

from omero.model.enums import PixelsTypeint8, PixelsTypeuint8, PixelsTypeint16
Expand Down Expand Up @@ -312,3 +313,25 @@ def apps(request, app, url):
rsp['content-type'] = "application/javascript"

return rsp


@login_required()
def vizarr_or_iviewer(request, iid=None, conn=None, **kwargs):

s3_url = get_zarr_s3_path(conn, iid)

local_vizarr_url = static("omero_web_zarr/vizarr/index.html")

if s3_url is not None:
url = f"{local_vizarr_url}?source={s3_url}"
return redirect(url)

else:
try:
# Default to iviewer (if installed)...
from omero_iviewer.views import index as iviewer_index
return iviewer_index(request, iid, **kwargs)
except ImportError:
# ...otherwise revert to original image viewer
from omeroweb.webclient.views import image_viewer
return image_viewer(request, iid, **kwargs)
Loading