Skip to content

Commit

Permalink
Show warning if user exceeds Z-projection limit
Browse files Browse the repository at this point in the history
  • Loading branch information
will-moore committed May 2, 2024
1 parent 0aa5e25 commit 11c0079
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 18 deletions.
5 changes: 5 additions & 0 deletions omero_figure/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
re_path(r'^imgData/(?P<image_id>[0-9]+)/$', views.img_data_json,
name='figure_imgData'),

re_path(r'^max_projection_range_exceeded/'
r'(?P<iid>[0-9]+)/(?:(?P<z>[0-9]+)/)?(?:(?P<t>[0-9]+)/)?$',
views.max_projection_range_exceeded,
name='max_projection_range_exceeded'),

# Send json to OMERO to create pdf using scripting service
re_path(r'^make_web_figure/', views.make_web_figure,
name='make_web_figure'),
Expand Down
49 changes: 49 additions & 0 deletions omero_figure/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ def index(request, file_id=None, conn=None, **kwargs):
max_w, max_h = conn.getMaxPlaneSize()
max_plane_size = max_w * max_h
length_units = get_length_units()
cfg = conn.getConfigService()
max_bytes = cfg.getConfigValue('omero.pixeldata.max_projection_bytes')
is_public_user = "false"
if (hasattr(settings, 'PUBLIC_USER')
and settings.PUBLIC_USER == user.getOmeName()):
Expand All @@ -117,6 +119,9 @@ def index(request, file_id=None, conn=None, **kwargs):
'const MAX_PLANE_SIZE = %s;' % max_plane_size)
html = html.replace('const LENGTH_UNITS = LENGTHUNITS;',
'const LENGTH_UNITS = %s;' % json.dumps(length_units))
if max_bytes:
html = html.replace('const MAX_PROJECTION_BYTES = 1024 * 1024 * 256;',
'const MAX_PROJECTION_BYTES = %s;' % max_bytes)
if export_enabled:
html = html.replace('const EXPORT_ENABLED = false;',
'const EXPORT_ENABLED = true;')
Expand All @@ -136,6 +141,50 @@ def index(request, file_id=None, conn=None, **kwargs):
return HttpResponse(html)


@login_required()
def max_projection_range_exceeded(request, iid, z=None, t=None,
conn=None, **kwargs):
"""
The app will use this URL instead of `render_image/` if the
requested Z-projection range exceeds the maximum projected
bytes (given the number of active channels)
This returns a placeholder image with suitable message
"""

from PIL import Image, ImageDraw, ImageFont

font14 = ImageFont.load_default(14)
font20 = ImageFont.load_default(20)
msg = "Max Z projection exceeded"
msg_size = font20.getbbox(msg)
txt_w = msg_size[2]
txt_h = msg_size[3]
advice = "Try to turn off channels or reduce Z-range"
advice_size = font14.getbbox(advice)
adv_w = advice_size[2]
adv_h = advice_size[3]

image_size = max(txt_w, adv_w) + 10
line_space = 10
total_h = txt_h + adv_h + line_space

im = Image.new("RGB", (image_size, image_size), (5, 0, 0))
draw = ImageDraw.Draw(im)
text_y = im.size[1]/2 - total_h/2
draw.text((im.size[0]/2 - txt_w/2, text_y), msg,
font=font20,
fill=(256, 256, 256))
text_y += txt_h + line_space
draw.text((im.size[0]/2 - adv_w/2, text_y), advice,
font=font14,
fill=(200, 200, 200))

rv = BytesIO()
im.save(rv, "jpeg", quality=90)
return HttpResponse(rv.getvalue(), content_type="image/jpeg")


@login_required()
def img_data_json(request, image_id, conn=None, **kwargs):

Expand Down
5 changes: 0 additions & 5 deletions src/css/figure.css
Original file line number Diff line number Diff line change
Expand Up @@ -646,11 +646,6 @@
.z-projection {
padding: 1px 5px 5px;
}
.z-projection span{
background-image: url("../images/projection20.png");
width: 20px;
height: 20px;
}
.crop-btn span{
background-image: url("../images/crop20.png");
width: 20px;
Expand Down
1 change: 1 addition & 0 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
const IS_PUBLIC_USER = false;
// Images larger than this are 'big' tiled images
const MAX_PLANE_SIZE = 10188864;
const MAX_PROJECTION_BYTES = 1024 * 1024 * 256;

const LOCAL_STORAGE_RECOVERED_FIGURE = "recoveredFigure" + USER_ID;

Expand Down
30 changes: 24 additions & 6 deletions src/js/models/panel_model.js
Original file line number Diff line number Diff line change
Expand Up @@ -560,18 +560,16 @@
}
},

// The max number of Planes we can do Z-projection, based on
// sizeXY, pixelType and the number of currently active Channels
getMaxZprojPlanes: function() {
const MAX_BYTES = 1024 * 1024 * 256;
let bytes_per_pixel = 4;
if (this.get("pixel_range")) {
bytes_per_pixel = Math.ceil(Math.log2(this.get("pixel_range")[1]) / 8.0);
}
console.log('pixel_range', this.get("pixel_range"), 'bytes_per_pixel', bytes_per_pixel);
let active_channels = this.get("channels").reduce((prev, channel) => channel.active ? prev + 1 : prev, 0);
console.log('active_channels', active_channels);
let max_planes = MAX_BYTES / bytes_per_pixel / (this.get('orig_width') * this.get('orig_height'));
let max_planes = MAX_PROJECTION_BYTES / bytes_per_pixel / (this.get('orig_width') * this.get('orig_height'));
max_planes = Math.floor(max_planes / active_channels);
console.log("max_planes", max_planes);
return max_planes;
},

Expand Down Expand Up @@ -717,6 +715,17 @@
return this.get('orig_width') * this.get('orig_height') > MAX_PLANE_SIZE;
},

is_max_projection_exceeded: function() {
if (this.get('z_projection')) {
let maxProjPlanes = this.getMaxZprojPlanes();
let zRange = parseInt(this.get('z_end')) - parseInt(this.get('z_start'));
if (zRange > maxProjPlanes) {
return true;
}
}
return false;
},

get_img_src: function(force_no_padding) {
var chs = this.get('channels');
var cStrings = chs.map(function(c, i){
Expand All @@ -740,7 +749,11 @@

// If BIG image, render scaled region
var region = "";
if (this.is_big_image()) {
if (this.is_max_projection_exceeded()) {
// if we're trying to do Z-projection with too many planes,
// this figure URL renders a suitable error message
baseUrl = BASE_WEBFIGURE_URL + 'max_projection_range_exceeded/'
} else if (this.is_big_image()) {
baseUrl = BASE_WEBFIGURE_URL + 'render_scaled_region/';
var rect = this.getViewportAsRect();
// Render a region that is 1.5 x larger
Expand Down Expand Up @@ -785,6 +798,11 @@
// offset of the img within it's frame
get_vp_img_css: function(zoom, frame_w, frame_h, x, y) {

if (this.is_max_projection_exceeded()) {
// We want the warning placeholder image shown full width, mid-height
return {'left':0, 'top':(frame_h - frame_w)/2, 'width':frame_w, 'height': frame_w}
}

// For non-big images, we have the full plane in hand
// css just shows the viewport region
if (!this.is_big_image()) {
Expand Down
5 changes: 5 additions & 0 deletions src/js/views/right_panel_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -1124,8 +1124,13 @@
// Don't currently support Z_projection on Big images.
const z_projection_disabled = ((sum_sizeZ === this.models.length) || anyBig);

let sizeZ = this.models.getIfEqual('sizeZ');
let show_max_Zrange = sizeZ && z_projection && max_z_proj_planes < sizeZ;

html = this.template({
max_projection_bytes: MAX_PROJECTION_BYTES,
zrange_max: max_z_proj_planes,
show_max_Zrange: show_max_Zrange,
projectionIconUrl,
'z_projection_disabled': z_projection_disabled,
'rotation': rotation,
Expand Down
3 changes: 2 additions & 1 deletion src/js/views/scalebar_form_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,9 @@ var ScalebarFormView = Backbone.View.extend({
} else {
let pix_sze = m.get('pixel_size_x');
// account for floating point imprecision when comparing
pix_sze = pix_sze ? pix_sze.toFixed(10) : pix_sze;
if (json.pixel_size_x != '-' &&
json.pixel_size_x.toFixed(10) != pix_sze.toFixed(10)) {
json.pixel_size_x.toFixed(10) != pix_sze) {
json.pixel_size_x = '-';
}
if (json.pixel_size_symbol != m.get('pixel_size_x_symbol')) {
Expand Down
15 changes: 9 additions & 6 deletions src/templates/image_display_options.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@
<% if(z_projection) { %>zp-btn-down<% } else if (typeof z_projection == 'boolean') { %><% } else { %>ch-btn-flat<% }%>"
<% if (z_projection_disabled) { %>disabled="disabled"<% } %>
>
<img src="<%= projectionIconUrl %>" />
</button>
</div>

<div style="font-size: 80%; line-height: 1.3;">
<button class="btn btn-sm btn-link" style="padding: 0; margin: 0; font-size: 0.8rem; text-align: left;;">
Z-range max: <%= zrange_max %>
<% if(show_max_Zrange) { %>
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger"
title="Max Z-projection range with current channels active. MAX_PROJECTION_BYTES = <%= max_projection_bytes %>">
Max <%= zrange_max %>
<span class="visually-hidden">Maximum Z-projection range</span>
</span>
<% } %>

<img src="<%= projectionIconUrl %>" />
</button>
</div>

0 comments on commit 11c0079

Please sign in to comment.