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

Dynamic generation of the LUTs png #581

Merged
merged 20 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
e5553bf
view to load LUTs binaries
Tom-TBT Sep 10, 2024
613e552
lut png generated and cached in views
Tom-TBT Sep 16, 2024
1d24809
put back gradient in generate lut image
Tom-TBT Sep 17, 2024
d770a16
changed luts_png docstring
Tom-TBT Sep 17, 2024
6312fb1
linear LUT gradient on 2/3rd of the array
Tom-TBT Sep 17, 2024
53b966a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 17, 2024
2ebbf99
add version param to lutsJson
Tom-TBT Sep 17, 2024
d4aac5a
Merge branch 'lut_view' of https://github.com/Tom-TBT/omero-web into …
Tom-TBT Sep 19, 2024
33d95fe
request for v2 of listLuts_json view
Tom-TBT Sep 30, 2024
c7c5734
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 30, 2024
b03bae5
Merge branch 'master' of https://github.com/ome/omero-web into lut_view
Tom-TBT Sep 30, 2024
07998fa
Merge branch 'lut_view' of https://github.com/Tom-TBT/omero-web into …
Tom-TBT Sep 30, 2024
f3bbb0e
restore accidentally deleted css for lut
Tom-TBT Oct 8, 2024
5bcffda
listLuts_json version replaced by returning old and new values together
Tom-TBT Oct 8, 2024
353f99b
Doc update for listLuts_json and luts_png
Tom-TBT Oct 8, 2024
dea938a
flake8 fix
Tom-TBT Oct 8, 2024
3483e04
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 8, 2024
84b14b3
Set LUT cache timeout to None (no timeout)
Tom-TBT Oct 22, 2024
c592bfb
change png_lut path to relative
Tom-TBT Nov 16, 2024
eb48769
Merge branch 'lut_view' of https://github.com/Tom-TBT/omero-web into …
Tom-TBT Nov 16, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@
// Load the Lookup Tables straight off - need them ASAP
if (!OME.LUTS) {
$.getJSON("{% url 'webgateway_listLuts_json' %}", function(data){
// Since 5.28.0, LUTs list and image is generated dynamically
OME.LUTS = data.luts;
OME.PNG_LUTS = data.png_luts;
OME.PNG_LUTS = data.png_luts_new;
});
}

Expand Down Expand Up @@ -390,7 +391,7 @@

<!-- VIEWER "Preview"-->
<div class="right_tab_inner">

<!-- open-image link -->

<div>
Expand All @@ -399,7 +400,7 @@
class="btn silver btn_text" alt="View"
title="Open full viewer" rel="{% content_identifier 'preview' manager.image.id %}"> <!-- rel is used by robot framework, do not remove it! -->
<span>
{% trans "Full viewer" %}
{% trans "Full viewer" %}
</span>
</a>
</div>
Expand Down Expand Up @@ -447,7 +448,7 @@
<img src="{% static "webclient/image/icon_redo16.png" %}" /><br>
Redo
</button></li>

<li class="seperator"></li>

<li><button id="rdef-copy-btn" class="button" title="Copy Rendering Settings">
Expand Down
27 changes: 13 additions & 14 deletions omeroweb/webgateway/static/webgateway/css/ome.viewport.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/**
* weblitz_viewport - style definitions
*
*
* Copyright (c) 2007, 2008, 2009 Glencoe Software, Inc. All rights reserved.
*
*
* This software is distributed under the terms described by the LICENCE file
* you can find at the root of the distribution bundle, which states you are
* free to use it only for non commercial purposes.
Expand All @@ -26,8 +26,8 @@ div.weblitz-viewport-tiles img {
padding: 0;
position: absolute;
}*/


.weblitz-viewport-vp {
position: absolute;
display: block;
Expand All @@ -42,12 +42,12 @@ div.weblitz-viewport-tiles img {
left: 15px;
}

.weblitz-viewport-top {
.weblitz-viewport-top {
position: relative;
height: 100%;
}

.weblitz-viewport-bot {
.weblitz-viewport-bot {
position: relative;
left: 15px;
height: 15px;
Expand Down Expand Up @@ -86,11 +86,11 @@ div.weblitz-viewport-tiles img {

/* Customizing the jquery-plugin-viewportImage classes */

.image-viewer {
.image-viewer {
position: relative;
}

.vslider {
.vslider {
position: absolute;
width: 13px;
height: 100%;
Expand All @@ -99,24 +99,24 @@ div.weblitz-viewport-tiles img {
left: 1px;
}

.hslider {
.hslider {
position: relative;
height: 13px;
/*bottom: -3px;*/
display: block;
font-size: 0.1em;
}

.slider-line {
.slider-line {
/* width: 100%; */
background: #FFF;
font-size: 0.1em;
}

.slider-handle {
.slider-handle {
background: #184A89;
font-size: 0.1em;
left: -1px;
left: -1px;
top: -1px;
}

Expand Down Expand Up @@ -185,11 +185,10 @@ div.weblitz-viewport-tiles img {
}

.lutBackground {
background-image: url('../img/luts_10.png');
background-image: url('../../../webgateway/luts_png/');
background-repeat: no-repeat;
image-rendering: pixelated;
}
button>.lutBackground {
opacity: 0.3;
}

4 changes: 2 additions & 2 deletions omeroweb/webgateway/static/webgateway/js/ome.colorbtn.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* Author: C. Neves <[email protected]>
*
* Copyright (c) 2007, 2008 Glencoe Software, Inc. All rights reserved.
*
*
* This software is distributed under the terms described by the LICENCE file
* you can find at the root of the distribution bundle, which states you are
* free to use it only for non commercial purposes.
Expand Down Expand Up @@ -104,7 +104,7 @@ $.fn.colorbtn = function(cfg) {
if (OME && OME.LUTS) {
for (var l=0; l<OME.LUTS.length; l++) {
if (OME.LUTS[l].name === lutName) {
return OME.LUTS[l].png_index;
return OME.LUTS[l].png_index_new;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion omeroweb/webgateway/static/webgateway/js/omero_image.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@
if (OME && OME.LUTS) {
for (var l=0; l<OME.LUTS.length; l++) {
if (OME.LUTS[l].name === lutName) {
return OME.LUTS[l].png_index;
return OME.LUTS[l].png_index_new;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
<script type="text/javascript" src="{% static "3rdparty/jquery.selectboxes-2.2.6.js" %}"></script>
<script type="text/javascript" src="{% static "3rdparty/farbtastic-1.2/farbtastic.js" %}"></script>
<script type="text/javascript" src="{% static "webgateway/js/ome.gs_utils.js"|add:url_suffix %}"></script>

<script type="text/javascript" src="{% static "webgateway/js/ome.scalebardisplay.js"|add:url_suffix %}"></script>
<!-- for display of ROIs over the image -->
<script type="text/javascript" src="{% static "webgateway/js/ome.roidisplay.js"|add:url_suffix %}"></script>
Expand Down Expand Up @@ -116,7 +116,7 @@

<!-- hammer.js for tablet gestures -->
<script type="text/javascript" src="{% static "3rdparty/hammer-2.0.8/hammer.min.js" %}"></script>

{% endblock %}


Expand Down Expand Up @@ -346,16 +346,16 @@
}
viewport.viewportimg.scalebar_display(options);
}

viewport.viewportimg.get(0).setScalebarZoom(viewport.getZoom()/100 );
viewport.viewportimg.get(0).show_scalebar();
{% endif %}
}

var hide_scalebar = function () {
viewport.viewportimg.get(0).hide_scalebar();
}

/**
* ROI load & table methods
*/
Expand Down Expand Up @@ -1038,7 +1038,7 @@ <h1>ROI Count: {{ roiCount }}</h1>
// Load Lookup Tables - need them ASAP
$.getJSON("{% url 'webgateway_listLuts_json' %}", function(data){
OME.LUTS = data.luts;
OME.PNG_LUTS = data.png_luts;
OME.PNG_LUTS = data.png_luts_new;
});

/* Prepare the viewport */
Expand Down Expand Up @@ -1499,11 +1499,11 @@ <h1>ROI Count: {{ roiCount }}</h1>
nextPrevImage(1);
});
}

// we can bind events to viewportimg for roi_display-plugin to trigger (plugin not created yet)
viewport.viewportimg.on("shape_click", handle_shape_selection);
viewport.viewportimg.on("rois_loaded", handle_rois_loaded);

// 'Scalebar' checkbox to left of image
$("#wblitz-scalebar").on('change', function() {
if(this.checked) {
Expand All @@ -1512,7 +1512,7 @@ <h1>ROI Count: {{ roiCount }}</h1>
hide_scalebar();
}
});

// set up handlers for 'Save' button
$("#rdef-setdef-btn").on('click', function(){
setImageDefaults(viewport, this, function() {
Expand Down
6 changes: 6 additions & 0 deletions omeroweb/webgateway/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,11 @@
E.g. list of {path: "/luts/", size: 800, id: 37, name: "cool.lut"},
"""

luts_png = re_path(r"^luts_png/$", views.luts_png, name="webgateway_luts_png")
"""
returning a png of all LUTs on server sorted by name
"""

list_compatible_imgs_json = re_path(
r"^compatImgRDef/(?P<iid>[0-9]+)/$",
views.list_compatible_imgs_json,
Expand Down Expand Up @@ -666,6 +671,7 @@
get_image_rdef_json,
get_image_rdefs_json,
listLuts_json,
luts_png,
list_compatible_imgs_json,
copy_image_rdef_json,
reset_rdef_json,
Expand Down
104 changes: 96 additions & 8 deletions omeroweb/webgateway/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
HttpResponseNotFound,
)

from django.core.cache import cache
from django.views.decorators.http import require_POST
from django.views.decorators.debug import sensitive_post_parameters
from django.utils.decorators import method_decorator
Expand Down Expand Up @@ -2072,29 +2073,116 @@ def save_image_rdef_json(request, iid, conn=None, **kwargs):
@jsonp
def listLuts_json(request, conn=None, **kwargs):
"""
Lists lookup tables 'LUTs' availble for rendering
Lists lookup tables 'LUTs' availble for rendering.

This list is dynamic and will change if users add LUTs to their server.
We include 'png_index' which is the index of each LUT within the
static/webgateway/img/luts_10.png or -1 if LUT is not found.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to update this docstring and mention version etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docstring updated with mention to v5.28.0


Since 5.28.0, the list of LUTs is also generated dynamically.
The new LUT indexes and LUT list were added to
the response with the suffix '_new' (png_index_new and png_luts_new)
The png matching the new indexes and list of LUT is obtained from
this url: /webgateway/luts_png/ (views.luts_png)
"""
scriptService = conn.getScriptService()
luts = scriptService.getScriptsByMimetype("text/x-lut")
rv = []
for lut in luts:
luts.sort(key=lambda x: x.name.val.lower())
rv, all_luts = [], []
for i, lut in enumerate(luts):
lutsrc = lut.path.val + lut.name.val
png_index = LUTS_IN_PNG.index(lutsrc) if lutsrc in LUTS_IN_PNG else -1
all_luts.append(lutsrc)
idx = LUTS_IN_PNG.index(lutsrc) if lutsrc in LUTS_IN_PNG else -1
rv.append(
{
"id": lut.id.val,
"path": lut.path.val,
"name": lut.name.val,
"size": unwrap(lut.size),
"png_index": png_index,
"png_index": idx,
"png_index_new": i,
}
)
rv.sort(key=lambda x: x["name"].lower())
return {"luts": rv, "png_luts": LUTS_IN_PNG}
all_luts.append("gradient.png")

return {"luts": rv, "png_luts": LUTS_IN_PNG, "png_luts_new": all_luts}


@login_required()
def luts_png(request, conn=None, **kwargs):
"""
Generates the LUT png used for preview and selection of LUT. The png is
256px wide, and each LUT is 10px in height. The last portion of the png
is the channel sliders transparent gradient.

LUTs are listed in alphabetical order (lut name only from filename).

LUT files on the server are read with the script service, and
file content is parsed with a custom implementation.

This uses caching to prevent generating the png each time a LUT
menu is opened. The cache key is a hash of all LUTs path.
Change in the LUT name or path will force the generation of a new
png.
"""
scriptService = conn.getScriptService()
luts = scriptService.getScriptsByMimetype("text/x-lut")
luts.sort(key=lambda x: x.name.val)
luts_path = []
for lut in luts:
luts_path.append(lut.path.val + lut.name.val)
luts_hash = hash("\n".join(luts_path))
cache_key = f"lut_hash_{luts_hash}"

cached_image = cache.get(cache_key)
if cached_image:
return HttpResponse(cached_image, content_type="image/png")

# Generate the LUT, fourth png channel set to 255
new_img = numpy.zeros((10 * (len(luts) + 1), 256, 4), dtype="uint8") + 255
for i, lut in enumerate(luts):
orig_file = conn.getObject("OriginalFile", lut.getId()._val)
lut_data = bytearray()
# Collect the LUT data in byte form
for chunk in orig_file.getFileInChunks():
lut_data.extend(chunk)

if len(lut_data) in [768, 800]:
lut_arr = numpy.array(lut_data, dtype="uint8")[-768:]
new_img[(i * 10) : (i + 1) * 10, :, :3] = lut_arr.reshape(3, 256).T
else:
lut_data = lut_data.decode()
r, g, b = [], [], []

lines = lut_data.split("\n")
sep = None
if "\t" in lines[0]:
sep = "\t"
for line in lines:
val = line.split(sep)
if len(val) < 3 or not val[-1].isnumeric():
continue
r.append(int(val[-3]))
g.append(int(val[-2]))
b.append(int(val[-1]))
new_img[(i * 10) : (i + 1) * 10, :, 0] = numpy.array(r)
new_img[(i * 10) : (i + 1) * 10, :, 1] = numpy.array(g)
new_img[(i * 10) : (i + 1) * 10, :, 2] = numpy.array(b)

# Set the last row for the channel sliders transparent gradient
new_img[-10:] = 0
new_img[-10:, :180, 3] = numpy.linspace(255, 0, 180, dtype="uint8")

image = Image.fromarray(new_img)
# Save the image to a BytesIO stream
buffer = BytesIO()
image.save(buffer, format="PNG")
buffer.seek(0)

# Cache the image using the version-based key
# Cache timeout set to None (no timeout)
cache.set(cache_key, buffer.getvalue(), None)

return HttpResponse(buffer.getvalue(), content_type="image/png")


@login_required()
Expand Down
Loading