Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class EXACTViewer {
this.filterImage = new OpenseadragonFilteringViewer(this.viewer);
this.pluginHandler = new PluginHandler(this.imageId, gHeaders, this.viewer);
this.screeningTool = new ScreeningTool(imageInformation, user_id, gHeaders, this.viewer);
this.imageProperties = new ShowImageProperties(this.viewer, this.imageId);

console.log(`${this.constructor.name} loaded for id ${this.imageId}`);

Expand Down Expand Up @@ -841,7 +842,7 @@ class EXACTViewerLocalAnnotations extends EXACTViewer {
this.asthmaAnalysis = new AsthmaAnalysis(this.imageId, this.viewer, this.exact_sync);

this.showAnnotationProperties = new ShowAnnotationProperties(this.viewer, this.exact_sync);

let team_id = parseInt($('#team_id').html());
this.teamTool = new TeamTool(this.viewer, team_id);
this.processingTool = new ProcessingTool(this.viewer, this.imageId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
function include_server_subdir(url) {
sub_dir = window.location.pathname.split("/annotations/")[0]
if (sub_dir === "") { return url } else { return sub_dir + url }
}



class ShowImageProperties{
constructor(viewer, imageId) {

this.viewer = viewer;
this.imageId = imageId;

this.updateImageInfo(viewer, imageId);
}

updateImageInfo(viewer, imageId) {
// get current environment
let gCsrfToken = $('[name="csrfmiddlewaretoken"]').first().val();

let gHeaders = {
"Content-Type": 'application/json',
"X-CSRFTOKEN": gCsrfToken
};

let url = include_server_subdir('/images/api/image/metadata/'+imageId+'/');
$.ajax(url, {
type: 'GET', headers: gHeaders, dataType: 'json',
success: function (data) {

let table = ""
for (let [key,value] of Object.entries(data.meta_data)) {
table += "<tr><td>"+data.meta_data_dict[key]+"</td><td>"+value+'</td></tr>'
}
$("#image_info_table").html(table)
// window.dispatchEvent(new CustomEvent("sync_ProcessingJobListLoaded", {"detail": context}));
},
error: function (request, status, error) {
if (request.responseText !== undefined) {
$.notify(request.responseText, { position: "bottom center", className: "error" });
} else {
$.notify(`Server ERR_CONNECTION_TIMED_OUT`, { position: "bottom center", className: "error" });
}
}
});


}
}
17 changes: 17 additions & 0 deletions exact/exact/annotations/templates/annotations/annotate.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
<script type="text/javascript" src="{% static 'annotations/js/statistics-viewer.js' %}"></script>
<script type="text/javascript" src="{% static 'annotations/js/plugin-handler.js' %}"></script>
<script type="text/javascript" src="{% static 'annotations/js/show-annotation-properties.js' %}"></script>
<script type="text/javascript" src="{% static 'annotations/js/show-image-properties.js' %}"></script>
<script type="text/javascript" src="{% static 'annotations/js/exact-browser-sync.js' %}"></script>
<script type="text/javascript" src="{% static 'annotations/js/exact-quad-tree.js' %}"></script>
<script type="text/javascript" src="{% static 'annotations/js/exact-overlay-opacity.js' %}"></script>
Expand Down Expand Up @@ -176,6 +177,10 @@ <h5 id="active_image_name">{{ selected_image.name }}</h5>
role="tab" aria-controls="home">Annotation</a>
</li>

<li class="nav-item">
<a class="nav-link" id="default_info_tab" data-toggle="tab" href="#nav-item_info"
role="tab" aria-controls="home">Info</a>
</li>
{% if HasMediaFiles %}

<li class="nav-item">
Expand Down Expand Up @@ -299,7 +304,19 @@ <h5 id="active_image_name">{{ selected_image.name }}</h5>
</div>

{% endif %}
<div class="tab-pane fade" id="nav-item_info">
<div id="ImageInformation">
<table style="width: 100%; margin-top: 10px; text-align: center" id="image_info_table">
<tr>
<th></th>
<th></th>
<th>Remark</th>
</tr>
</table>
</div>


</div>
<div class="tab-pane fade" id="nav-item_anno">

<div id="AnnotationInformation">
Expand Down
22 changes: 22 additions & 0 deletions exact/exact/annotations/templates/annotations/annotate_v2.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
<script type="text/javascript" src="{% static 'annotations/js/statistics-viewer.js' %}"></script>
<script type="text/javascript" src="{% static 'annotations/js/plugin-handler.js' %}"></script>
<script type="text/javascript" src="{% static 'annotations/js/show-annotation-properties.js' %}"></script>
<script type="text/javascript" src="{% static 'annotations/js/show-image-properties.js' %}"></script>

<script type="text/javascript" src="{% static 'annotations/js/exact-browser-sync.js' %}"></script>
<script type="text/javascript" src="{% static 'annotations/js/exact-quad-tree.js' %}"></script>
<script type="text/javascript" src="{% static 'annotations/js/annotations.js' %}"></script>
Expand Down Expand Up @@ -178,6 +180,12 @@ <h5 id="active_image_name">{{ selected_image.name }}</h5>
role="tab" aria-controls="home">Annotation</a>
</li>

<li class="nav-item">
<a class="nav-link" id="default_info_tab" data-toggle="tab" href="#nav-item_info"
role="tab" aria-controls="home">Info</a>
</li>


{% if HasMediaFiles %}

<li class="nav-item">
Expand Down Expand Up @@ -302,6 +310,20 @@ <h5 id="active_image_name">{{ selected_image.name }}</h5>

{% endif %}

<div class="tab-pane fade" id="nav-item_info">
<div id="ImageInformation">
<table style="width: 100%; margin-top: 10px; text-align: center" id="image_info_table">
<tr>
<th></th>
<th></th>
<th>Remark</th>
</tr>
</table>
</div>


</div>

<div class="tab-pane fade" id="nav-item_anno">

<div id="AnnotationInformation">
Expand Down
1 change: 1 addition & 0 deletions exact/exact/images/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
re_path(r'^image/(\d+)/(\d+)/(\d+)/tile_files/(\d+)/(\d+_\d+.(?:png|jpeg))$', views.view_image_tile, name='view_image_tile'),
re_path(r'^api/image/verify/$', views.api_verify_image, name='verify_image'),

re_path(r'^api/image/metadata/(\d+)/$', views.image_metadata, name='metadata'),
re_path(r'^api/image/plugins/$', views.image_plugins, name='plugins'),
re_path(r'^image/centered_snapshot/(\d+)/(\d+)/(\d+)/(\d+)/(\d+)/', views.image_snapshots, name='centered_image_snapshot'),

Expand Down
47 changes: 47 additions & 0 deletions exact/exact/images/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,53 @@ def view_image(request, image_id, z_dimension:int=1, frame:int=1):
cache.set(cache_key, value, None)
return HttpResponse(value, content_type='application/xml')

@login_required
@api_view(['GET'])
def image_metadata(request, image_id) -> Response:
image = get_object_or_404(Image, pk=image_id)
if not image.image_set.has_perm('read', request.user):
return Response({
'detail': 'permission for reading this image set missing.',
}, status=HTTP_403_FORBIDDEN)

meta_data = {}
# descriptions in plain english
meta_data_dict = {'level_count': 'Image levels',
'image_size': 'Image size',
'numberOfFrames': 'Number of frames',
'frame_type': 'Frame type',
'mpp_x': 'x Resolution (microns/px)',
'mpp_y': 'y Resolution (microns/px)',
}

try:
slideobj = image_cache.get(image.path())

meta_data['level_count'] = slideobj.level_count
meta_data['image_size'] = ' x '.join([str(x) for x in slideobj.dimensions])
meta_data['numberOfFrames'] = slideobj.nFrames
meta_data['mpp_x'] = slideobj.mpp_x
meta_data['mpp_y'] = slideobj.mpp_y

if (slideobj.nFrames>1):
meta_data['frame_type'] = slideobj.frame_type

meta_data.update(slideobj.meta_data)
meta_data_dict.update(slideobj.meta_data_dict)

except Exception as e:
logger.error(str(e))

return Response({
'detail': 'Unable to retrieve basic metadata.',
}, status=HTTP_403_FORBIDDEN)

return Response({
'meta_data': meta_data,
'meta_data_dict': meta_data_dict,
}, status=HTTP_200_OK)


@login_required
@api_view(['GET'])
def image_plugins(request) -> Response:
Expand Down
41 changes: 41 additions & 0 deletions exact/util/slide_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,44 @@ def get_tile(self, level, address, frame=0):
tile.info['icc_profile'] = profile

return tile

@property
def dimensions(self):
if hasattr(self._osr,'dimensions'):
return self._osr.dimensions
else:
return [0]

@property
def meta_data(self):
if hasattr(self._osr,'meta_data'):
return self._osr.meta_data
else:
return {}

@property
def meta_data_dict(self):
if hasattr(self._osr,'meta_data_dict'):
return self._osr.meta_data_dict
else:
return {}

@property
def nFrames(self):
if hasattr(self._osr,'nFrames'):
return self._osr.nFrames
else:
return None

@property
def frame_type(self):
if hasattr(self._osr,'frame_type'):
return self._osr.frame_type
else:
return None



class OpenSlideWrapper(openslide.OpenSlide):
"""
Wraps an openslide.OpenSlide object. The rationale here is that OpenSlide.read_region does not support z Stacks / frames as arguments, hence we have to encapsulate it
Expand Down Expand Up @@ -523,8 +560,12 @@ def get(self, path):
mpp_x = osr.properties[openslide.PROPERTY_NAME_MPP_X]
mpp_y = osr.properties[openslide.PROPERTY_NAME_MPP_Y]
slide.mpp = (float(mpp_x) + float(mpp_y)) / 2
slide.mpp_x = mpp_x
slide.mpp_y = mpp_y
except (KeyError, ValueError):
slide.mpp = 0
slide.mpp_x = 0
slide.mpp_y = 0

with self._lock:
if path not in self._cache:
Expand Down