Skip to content

Commit e1e8c7a

Browse files
committed
examples/deepzoom: Show scale bar when MPP is known
<meta charset="utf-8"> ensures the "micro" symbol renders correctly in viewers written by deepzoom_tile.py.
1 parent 9cfc90b commit e1e8c7a

File tree

5 files changed

+62
-10
lines changed

5 files changed

+62
-10
lines changed

examples/deepzoom/deepzoom_multiserver.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# deepzoom_multiserver - Example web application for viewing multiple slides
44
#
5-
# Copyright (c) 2010-2014 Carnegie Mellon University
5+
# Copyright (c) 2010-2015 Carnegie Mellon University
66
#
77
# This library is free software; you can redistribute it and/or modify it
88
# under the terms of version 2.1 of the GNU Lesser General Public License
@@ -21,6 +21,7 @@
2121
from collections import OrderedDict
2222
from flask import Flask, abort, make_response, render_template, url_for
2323
from io import BytesIO
24+
import openslide
2425
from openslide import OpenSlide, OpenSlideError
2526
from openslide.deepzoom import DeepZoomGenerator
2627
import os
@@ -60,7 +61,16 @@ def get(self, path):
6061
slide = self._cache.pop(path)
6162
self._cache[path] = slide
6263
return slide
63-
slide = DeepZoomGenerator(OpenSlide(path), **self.dz_opts)
64+
65+
osr = OpenSlide(path)
66+
slide = DeepZoomGenerator(osr, **self.dz_opts)
67+
try:
68+
mpp_x = osr.properties[openslide.PROPERTY_NAME_MPP_X]
69+
mpp_y = osr.properties[openslide.PROPERTY_NAME_MPP_Y]
70+
slide.mpp = (float(mpp_x) + float(mpp_y)) / 2
71+
except (KeyError, ValueError):
72+
slide.mpp = 0
73+
6474
with self._lock:
6575
if path not in self._cache:
6676
if len(self._cache) == self.cache_size:
@@ -127,7 +137,7 @@ def slide(path):
127137
slide = _get_slide(path)
128138
slide_url = url_for('dzi', path=path)
129139
return render_template('slide-fullpage.html', slide_url=slide_url,
130-
slide_filename=slide.filename)
140+
slide_filename=slide.filename, slide_mpp=slide.mpp)
131141

132142

133143
@app.route('/<path:path>.dzi')

examples/deepzoom/deepzoom_server.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# deepzoom_server - Example web application for serving whole-slide images
44
#
5-
# Copyright (c) 2010-2014 Carnegie Mellon University
5+
# Copyright (c) 2010-2015 Carnegie Mellon University
66
#
77
# This library is free software; you can redistribute it and/or modify it
88
# under the terms of version 2.1 of the GNU Lesser General Public License
@@ -20,6 +20,7 @@
2020

2121
from flask import Flask, abort, make_response, render_template, url_for
2222
from io import BytesIO
23+
import openslide
2324
from openslide import ImageSlide, open_slide
2425
from openslide.deepzoom import DeepZoomGenerator
2526
from optparse import OptionParser
@@ -66,6 +67,12 @@ def load_slide():
6667
app.associated_images.append(name)
6768
slug = slugify(name)
6869
app.slides[slug] = DeepZoomGenerator(ImageSlide(image), **opts)
70+
try:
71+
mpp_x = slide.properties[openslide.PROPERTY_NAME_MPP_X]
72+
mpp_y = slide.properties[openslide.PROPERTY_NAME_MPP_Y]
73+
app.slide_mpp = (float(mpp_x) + float(mpp_y)) / 2
74+
except (KeyError, ValueError):
75+
app.slide_mpp = 0
6976

7077

7178
@app.route('/')
@@ -74,7 +81,8 @@ def index():
7481
associated_urls = dict((name, url_for('dzi', slug=slugify(name)))
7582
for name in app.associated_images)
7683
return render_template('slide-multipane.html', slide_url=slide_url,
77-
associated=associated_urls, properties=app.slide_properties)
84+
associated=associated_urls, properties=app.slide_properties,
85+
slide_mpp=app.slide_mpp)
7886

7987

8088
@app.route('/<slug>.dzi')

examples/deepzoom/deepzoom_tile.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# deepzoom_tile - Convert whole-slide images to Deep Zoom format
44
#
5-
# Copyright (c) 2010-2014 Carnegie Mellon University
5+
# Copyright (c) 2010-2015 Carnegie Mellon University
66
#
77
# This library is free software; you can redistribute it and/or modify it
88
# under the terms of version 2.1 of the GNU Lesser General Public License
@@ -23,6 +23,7 @@
2323
from __future__ import print_function
2424
import json
2525
from multiprocessing import Process, JoinableQueue
26+
import openslide
2627
from openslide import open_slide, ImageSlide
2728
from openslide.deepzoom import DeepZoomGenerator
2829
from optparse import OptionParser
@@ -186,10 +187,17 @@ def _write_html(self):
186187
template = env.get_template('slide-multipane.html')
187188
associated_urls = dict((n, self._url_for(n))
188189
for n in self._slide.associated_images)
190+
try:
191+
mpp_x = self._slide.properties[openslide.PROPERTY_NAME_MPP_X]
192+
mpp_y = self._slide.properties[openslide.PROPERTY_NAME_MPP_Y]
193+
mpp = (float(mpp_x) + float(mpp_y)) / 2
194+
except (KeyError, ValueError):
195+
mpp = 0
189196
# Embed the dzi metadata in the HTML to work around Chrome's
190197
# refusal to allow XmlHttpRequest from file:///, even when
191198
# the originating page is also a file:///
192199
data = template.render(slide_url=self._url_for(None),
200+
slide_mpp=mpp,
193201
associated=associated_urls,
194202
properties=self._slide.properties,
195203
dzi_data=json.dumps(self._dzi_data))

examples/deepzoom/templates/slide-fullpage.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<!doctype html>
2+
<meta charset="utf-8">
23
<title>{{ slide_filename }}</title>
34

45
<style type="text/css">
@@ -23,6 +24,7 @@
2324

2425
<script type="text/javascript" src="{{ url_for('static', filename='jquery.js') }}"></script>
2526
<script type="text/javascript" src="{{ url_for('static', filename='openseadragon.js') }}"></script>
27+
<script type="text/javascript" src="{{ url_for('static', filename='openseadragon-scalebar.js') }}"></script>
2628
<script type="text/javascript">
2729
$(document).ready(function() {
2830
var viewer = new OpenSeadragon({
@@ -47,5 +49,16 @@
4749
// from DZI XML.
4850
viewer.source.minLevel = 8;
4951
});
52+
53+
var mpp = parseFloat("{{ slide_mpp }}");
54+
viewer.scalebar({
55+
pixelsPerMeter: mpp ? (1e6 / mpp) : 0,
56+
xOffset: 10,
57+
yOffset: 10,
58+
barThickness: 3,
59+
color: '#555555',
60+
fontColor: '#333333',
61+
backgroundColor: 'rgba(255, 255, 255, 0.5)',
62+
});
5063
});
5164
</script>

examples/deepzoom/templates/slide-multipane.html

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<!doctype html>
2+
<meta charset="utf-8">
23
<title>Slide Viewer</title>
34

45
<style type="text/css">
@@ -74,7 +75,8 @@
7475
<div id="images">
7576
<h1>View</h1>
7677
<div class="current-slide">
77-
<a class="load-slide" href="#" data-url="{{ slide_url }}">Slide</a>
78+
<a class="load-slide" href="#" data-url="{{ slide_url }}"
79+
data-mpp="{{ slide_mpp }}">Slide</a>
7880
</div>
7981
<h2>Associated images</h2>
8082
{% if associated %}
@@ -109,6 +111,7 @@ <h1>Slide properties</h1>
109111

110112
<script type="text/javascript" src="static/jquery.js"></script>
111113
<script type="text/javascript" src="static/openseadragon.js"></script>
114+
<script type="text/javascript" src="static/openseadragon-scalebar.js"></script>
112115
<script type="text/javascript">
113116
$(document).ready(function() {
114117
var dzi_data = {{ dzi_data|default('{}')|safe }};
@@ -132,7 +135,7 @@ <h1>Slide properties</h1>
132135
viewer.source.minLevel = 8;
133136
});
134137

135-
function open_slide(url) {
138+
function open_slide(url, mpp) {
136139
var tile_source;
137140
if (dzi_data[url]) {
138141
// DZI XML provided as template argument (deepzoom_tile.py)
@@ -144,13 +147,23 @@ <h1>Slide properties</h1>
144147
tile_source = url;
145148
}
146149
viewer.open(tile_source);
150+
viewer.scalebar({
151+
pixelsPerMeter: mpp ? (1e6 / mpp) : 0,
152+
xOffset: 10,
153+
yOffset: 10,
154+
barThickness: 3,
155+
color: '#555555',
156+
fontColor: '#333333',
157+
backgroundColor: 'rgba(255, 255, 255, 0.5)',
158+
});
147159
}
148160

149-
open_slide("{{ slide_url }}");
161+
open_slide("{{ slide_url }}", parseFloat('{{ slide_mpp }}'));
150162
$(".load-slide").click(function(ev) {
151163
$(".current-slide").removeClass("current-slide");
152164
$(this).parent().addClass("current-slide");
153-
open_slide($(this).attr('data-url'));
165+
open_slide($(this).attr('data-url'),
166+
parseFloat($(this).attr('data-mpp')));
154167
ev.preventDefault();
155168
});
156169
});

0 commit comments

Comments
 (0)