1
2
3
4
5
6
7
8
9
10
11
12
13
14 import omero
15 import omero.clients
16 from django.http import HttpResponse, HttpResponseServerError, HttpResponseRedirect, Http404
17 from django.utils import simplejson
18 from django.utils.http import urlquote
19 from django.core import template_loader
20 from django.core.urlresolvers import reverse
21 from django.template import RequestContext as Context
22
23 try:
24 from hashlib import md5
25 except:
26 from md5 import md5
27
28 from cStringIO import StringIO
29
30 from omero import client_wrapper, ApiUsageException
31 from omero.gateway import timeit, TimeIt
32
33 import Ice
34
35
36
37 from webgateway_cache import webgateway_cache, CacheBase, webgateway_tempfile
38
39 cache = CacheBase()
40
41 connectors = {}
42 CONNECTOR_POOL_SIZE = 70
43 CONNECTOR_POOL_KEEP = 0.75
44
45 import logging, os, traceback, time, zipfile, shutil
46
47
48
49 logger = logging.getLogger('webgateway')
50
51 logger.debug("INIT")
54 """
55 Remove reference to old sUuid key and old blitz connection.
56
57 @param request: http request
58 @param server_id: used to generate session_key
59 @param force_key: If specified, use this as session_key
60 """
61
62 if force_key:
63 session_key = force_key
64 else:
65 browsersession_connection_key = 'cuuid#%s'%server_id
66 session_key = 'S:' + request.session.get(browsersession_connection_key,'') + '#' + str(server_id)
67 if request.session.has_key(browsersession_connection_key):
68 logger.debug('logout: removing "%s"' % (request.session[browsersession_connection_key]))
69 del request.session[browsersession_connection_key]
70 for k in ('username', 'password', 'server', 'host', 'port', 'ssl'):
71 if request.session.has_key(k):
72 del request.session[k]
73 if connectors.has_key(session_key):
74 logger.debug('logout: killing connection "%s"' % (session_key))
75 if connectors[session_key]:
76 logger.info('logout request for "%s"' % connectors[session_key].getUser().omeName)
77 connectors[session_key] and connectors[session_key].seppuku()
78 del connectors[session_key]
79
81 """
82 Represents the current user of the connection, with methods delegating to the connection itself.
83 """
84
86 """
87 Initialises the User proxy with the L{omero.gateway.BlitzGateway} connection
88
89 @param blitzcon: connection
90 @type blitzcon: L{omero.gateway.BlitzGateway}
91 """
92
93 self._blitzcon = blitzcon
94 self.loggedIn = False
95
97 """ Sets the loggedIn Flag to True """
98
99 self.loggedIn = True
100
102 """
103 True if the current user is an admin
104
105 @return: True if the current user is an admin
106 @rtype: Boolean
107 """
108
109 return self._blitzcon.isAdmin()
110
112 """
113 True if the current user can be admin
114
115 @return: True if the current user can be admin
116 @rtype: Boolean
117 """
118
119 return self._blitzcon.canBeAdmin()
120
122 """
123 Returns the ID of the current user
124
125 @return: User ID
126 @rtype: Long
127 """
128
129 return self._blitzcon._user.id
130
132 """
133 Returns the Name of the current user
134
135 @return: User Name
136 @rtype: String
137 """
138
139 return self._blitzcon._user.omeName
140
142 """
143 Returns the first name of the current user
144
145 @return: First Name
146 @rtype: String
147 """
148
149 return self._blitzcon._user.firstName or self.getName()
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 -def _createConnection (server_id, sUuid=None, username=None, passwd=None, host=None, port=None, retry=True, group=None, try_super=False, secure=False, anonymous=False, useragent=None):
172 """
173 Attempts to create a L{omero.gateway.BlitzGateway} connection.
174 Tries to join an existing session for the specified user, using sUuid.
175
176 @param server_id: Way of referencing the server, used in connection dict keys. Int or String
177 @param sUuid: Session ID - used for attempts to join sessions etc without password
178 @param username: User name to log on with
179 @param passwd: Password
180 @param host: Host name
181 @param port: Port number
182 @param retry: Boolean
183 @param group: String? TODO: parameter is ignored.
184 @param try_super: If True, try to log on as super user, 'system' group
185 @param secure: If True, use an encrypted connection
186 @param anonymous: Boolean
187 @param useragent: Log which python clients use this connection. E.g. 'OMERO.webadmin'
188 @return: The connection
189 @rtype: L{omero.gateway.BlitzGateway}
190 """
191 try:
192 blitzcon = client_wrapper(username, passwd, host=host, port=port, group=None, try_super=try_super, secure=secure, anonymous=anonymous, useragent=useragent)
193 blitzcon.connect(sUuid=sUuid)
194 blitzcon.server_id = server_id
195 blitzcon.user = UserProxy(blitzcon)
196 if blitzcon._anonymous and hasattr(blitzcon.c, 'onEventLogs'):
197 logger.debug('Connecting weblitz_cache to eventslog')
198 def eventlistener (e):
199 return webgateway_cache.eventListener(server_id, e)
200 blitzcon.c.onEventLogs(eventlistener)
201 return blitzcon
202 except:
203 logger.debug(traceback.format_exc())
204 if not retry:
205 return None
206 logger.error("Critical error during connect, retrying after _purge")
207 logger.debug(traceback.format_exc())
208 _purge(force=True)
209 return _createConnection(server_id, sUuid, username, passwd, retry=False, host=host, port=port, group=None, try_super=try_super, anonymous=anonymous, useragent=useragent)
210
222
223 -def getBlitzConnection (request, server_id=None, with_session=False, retry=True, force_key=None, group=None, try_super=False, useragent=None):
224 """
225 Grab a connection to the Ice server, trying hard to reuse connections as possible.
226 A per-process dictionary of StoredConnection based connections (key = "C:$base") is kept.
227 A per-process dictionary of session created connections (key = "S:$session_id") is kept.
228 Another set of connections (key = "C:$server_id") is also kept, for creating 'guest' connections
229 using with_session=False.
230 Server id, if not passed in as function argument, is retrieved from session['server'].
231 To allow multiple worker processes to access the session created connections (which will need to be
232 recreated on each process) the blitz session key will be kept in the django session data, and joining that
233 session is attempted, thus avoiding having to keep user/pass around.
234
235 @param request: http request. Used to get these values, either from request.session or
236 from request.REQUEST if not in session:
237 - username
238 - password
239 - host
240 - port
241 - secure (optional, False by default)
242 @param server_id: Way of referencing the server, used in connection dict keys. Int or String
243 @param with_session: If true, try to use existing session
244 @param retry: If true, make an extra attempt to connect
245 @param group: String?
246 @param try_super: If True, try to log on as super user, 'system' group
247 @param useragent: Log which python clients use this connection. E.g. 'OMERO.webadmin'
248 @return: The connection
249 @rtype: L{omero.gateway.BlitzGateway}
250 """
251
252 r = request.REQUEST
253 if server_id is None:
254
255
256 with_session = True
257 server_id = request.session.get('server',None)
258 if server_id is None:
259 return None
260
261 browsersession_connection_key = 'cuuid#%s'%server_id
262 browsersession_key = request.session.session_key
263 blitz_session = None
264
265 username = request.session.get('username', r.get('username', None))
266 passwd = request.session.get('password', r.get('password', None))
267 host = request.session.get('host', r.get('host', None))
268 port = request.session.get('port', r.get('port', None))
269 secure = request.session.get('ssl', r.get('ssl', False))
270 logger.debug(':: (session) %s %s %s' % (str(request.session.get('username', None)),
271 str(request.session.get('host', None)),
272 str(request.session.get('port', None))))
273 logger.debug(':: (request) %s %s %s' % (str(r.get('username', None)),
274 str(r.get('host', None)),
275 str(r.get('port', None))))
276
277
278
279
280 if r.has_key('bsession'):
281 blitz_session = r['bsession']
282 request.session[browsersession_connection_key] = blitz_session
283
284 if force_key:
285 ckey = force_key
286 else:
287
288
289 if not with_session and not request.session.has_key(browsersession_connection_key) and \
290 not username and not blitz_session:
291 ckey = 'C:' + str(server_id)
292
293 elif browsersession_key is None:
294 ckey = 'C:' + str(server_id)
295 else:
296
297
298 if browsersession_key is not None and request.session.get(browsersession_connection_key, False):
299 ckey = 'S:' + request.session[browsersession_connection_key] + '#' + str(server_id)
300
301 else:
302 ckey = 'S:'
303
304 if r.get('username', None):
305 logger.info('getBlitzConnection(host=%s, port=%s, ssl=%s, username=%s)' %
306 (str(host), str(port), str(secure), str(username)))
307 logger.debug('k=%s' % str(browsersession_connection_key))
308 blitzcon = None
309 else:
310
311 logger.debug('trying stored connection with userAgent: %s ckey: %s' % (useragent, ckey))
312 logger.debug(connectors.items())
313 blitzcon = connectors.get(ckey, None)
314 if not force_key and blitzcon and request.session.get(browsersession_connection_key, blitzcon._sessionUuid) != blitzcon._sessionUuid:
315 logger.debug('stale connection found: %s != %s' % (str(request.session.get(browsersession_connection_key, None)), str(blitzcon._sessionUuid)))
316 blitzcon.seppuku()
317 blitzcon = None
318
319 if blitzcon is None:
320
321
322 if ckey.startswith('S:') and not force_key:
323 ckey = 'S:'
324 if force_key or r.get('username', None):
325 sUuid = None
326 else:
327 sUuid = request.session.get(browsersession_connection_key, None)
328 logger.debug('creating new connection with ckey "%s", sUuid "%s" (%s)' % (ckey, sUuid, try_super))
329
330 blitzcon = _createConnection(server_id, sUuid=sUuid,
331 username=username, passwd=passwd,
332 host=host, port=port, group=group, try_super=try_super, secure=secure,
333 anonymous=ckey.startswith('C:'), useragent=useragent)
334 if blitzcon is None:
335 if not retry or username:
336 logger.debug('connection failed with provided login information, bail out')
337 return None
338 return getBlitzConnection(request, server_id, with_session, retry=False, group=group, try_super=try_super, useragent=useragent)
339 else:
340 logger.debug('created new connection %s' % str(blitzcon))
341
342 if not blitzcon.isConnected():
343
344
345 if username:
346 logger.debug('connection failed with provided login information, bail out')
347 return None
348 logger.debug('Failed connection, logging out')
349 _session_logout(request, server_id)
350
351 return None
352
353 else:
354
355
356 if ckey == 'S:':
357 ckey = 'S:' + blitzcon._sessionUuid + '#' + str(server_id)
358 _purge()
359 connectors[ckey] = blitzcon
360 logger.debug(str(connectors.items()))
361 if username or blitz_session:
362
363
364 if not force_key:
365 request.session[browsersession_connection_key] = blitzcon._sessionUuid
366 logger.debug('blitz session key: ' + blitzcon._sessionUuid)
367 logger.debug('stored as session.' + ckey)
368 blitzcon.user.logIn()
369 elif request.session.get(browsersession_connection_key, None):
370 blitzcon.user.logIn()
371
372 if blitzcon and not blitzcon.keepAlive() and not ckey.startswith('C:'):
373
374
375 logger.info("Failed keepalive for connection %s" % ckey)
376
377 del connectors[ckey]
378
379
380 return getBlitzConnection(request, server_id, with_session, retry=False, group=group, try_super=try_super, useragent=useragent)
381 if blitzcon and ckey.startswith('C:') and not blitzcon.isConnected():
382 logger.info("Something killed the base connection, recreating")
383 del connectors[ckey]
384 return None
385
386 if r.has_key('logout') and not ckey.startswith('C:'):
387 logger.debug('logout required by HTTP GET or POST : killing current connection')
388 _session_logout(request, server_id)
389 return None
390
391
392
393
394
395
396 return blitzcon
397
399 """
400 Splits the request query channel information for images into a sequence of channels, window ranges
401 and channel colors.
402
403 @param rchannels: The request string with channel info. E.g 1|100:505$0000FF,-2,3|620:3879$FF0000
404 @type rchannels: String
405 @return: E.g. [1, -2, 3] [[100.0, 505.0], (None, None), [620.0, 3879.0]] [u'0000FF', None, u'FF0000']
406 @rtype: tuple of 3 lists
407 """
408
409 channels = []
410 windows = []
411 colors = []
412 for chan in rchannels.split(','):
413 chan = chan.split('|')
414 t = chan[0].strip()
415 color = None
416 if t.find('$')>=0:
417 t,color = t.split('$')
418 try:
419 channels.append(int(t))
420 ch_window = (None, None)
421 if len(chan) > 1:
422 t = chan[1].strip()
423 if t.find('$')>=0:
424 t, color = t.split('$')
425 t = t.split(':')
426 if len(t) == 2:
427 try:
428 ch_window = [float(x) for x in t]
429 except ValueError:
430 pass
431 windows.append(ch_window)
432 colors.append(color)
433 except ValueError:
434 pass
435 logger.debug(str(channels)+","+str(windows)+","+str(colors))
436 return channels, windows, colors
437
439 """ Break the GET information from the request object into details on how to render the image.
440 The following keys are recognized:
441 z - Z axis position
442 t - T axis position
443 q - Quality set (0,0..1,0)
444 m - Model (g for greyscale, c for color)
445 p - Projection (see blitz_gateway.ImageWrapper.PROJECTIONS for keys)
446 x - X position (for now based on top/left offset on the browser window)
447 y - Y position (same as above)
448 c - a comma separated list of channels to be rendered (start index 1)
449 - format for each entry [-]ID[|wndst:wndend][#HEXCOLOR][,...]
450 zm - the zoom setting (as a percentual value)
451
452 @param request: http request with keys above
453 @param as_string: If True, return a string representation of the rendering details
454 @return: A dict or String representation of rendering details above.
455 @rtype: Dict or String
456 """
457
458 r = request.REQUEST
459 rv = {}
460 for k in ('z', 't', 'q', 'm', 'zm', 'x', 'y', 'p'):
461 if r.has_key(k):
462 rv[k] = r[k]
463 if r.has_key('c'):
464 rv['c'] = []
465 ci = _split_channel_info(r['c'])
466 logger.debug(ci)
467 for i in range(len(ci[0])):
468
469 rv['c'].append({'a':abs(ci[0][i]), 'i':ci[0][i], 's':ci[1][i][0], 'e':ci[1][i][1], 'c':ci[2][i]})
470 if as_string:
471 return "&".join(["%s=%s" % (x[0], x[1]) for x in rv.items()])
472 return rv
473
475 def handler (request, *args, **kwargs):
476 if not kwargs.has_key('server_id'):
477 kwargs['server_id'] = request.session.get('server', None)
478 return func(request, *args, **kwargs)
479 return handler
480
481 @serverid
482 -def render_birds_eye_view (request, iid, server_id=None, size=None,
483 _conn=None, **kwargs):
484 """
485 Returns an HttpResponse wrapped jpeg with the rendered bird's eye view
486 for image 'iid'. Rendering settings can be specified in the request
487 parameters as in L{render_image} and L{render_image_region}; see
488 L{getImgDetailsFromReq} for a complete list.
489
490 @param request: http request
491 @param iid: Image ID
492 @param size: Maximum size of the longest side of the resulting bird's eye view.
493 @param server_id: Optional, used for getting connection if needed etc
494 @return: http response containing jpeg
495 """
496 if _conn is None:
497 blitzcon = getBlitzConnection(request, server_id, useragent="OMERO.webgateway")
498 else:
499 blitzcon = _conn
500 if blitzcon is None or not blitzcon.isConnected():
501 logger.debug("failed connect, HTTP404")
502 raise Http404
503 USE_SESSION = False
504 img = _get_prepared_image(request, iid, server_id=server_id, _conn=_conn,
505 with_session=USE_SESSION)
506 if img is None:
507 logger.debug("(b)Image %s not found..." % (str(iid)))
508 raise Http404
509 img, compress_quality = img
510 return HttpResponse(img.renderBirdsEyeView(size), mimetype='image/jpeg')
511
512 @serverid
513 -def render_thumbnail (request, iid, server_id=None, w=None, h=None, _conn=None, _defcb=None, **kwargs):
514 """
515 Returns an HttpResponse wrapped jpeg with the rendered thumbnail for image 'iid'
516
517 @param request: http request
518 @param iid: Image ID
519 @param server_id: Optional, used for getting connection if needed etc
520 @param w: Thumbnail max width. 64 by default
521 @param h: Thumbnail max height
522 @return: http response containing jpeg
523 """
524 if w is None:
525 size = (64,)
526 else:
527 if h is None:
528 size = (int(w),)
529 else:
530 size = (int(w), int(h))
531 if _conn is None:
532 blitzcon = getBlitzConnection(request, server_id, useragent="OMERO.webgateway")
533 else:
534 blitzcon = _conn
535 if blitzcon is None or not blitzcon.isConnected():
536 logger.debug("failed connect, HTTP404")
537 raise Http404
538 user_id = blitzcon.getEventContext().userId
539 jpeg_data = webgateway_cache.getThumb(request, server_id, user_id, iid, size)
540 if jpeg_data is None:
541 prevent_cache = False
542 img = blitzcon.getObject("Image", iid)
543 if img is None:
544 logger.debug("(b)Image %s not found..." % (str(iid)))
545 if _defcb:
546 jpeg_data = _defcb(size=size)
547 prevent_cache = True
548 else:
549 raise Http404
550 else:
551 jpeg_data = img.getThumbnail(size=size)
552 if jpeg_data is None:
553 logger.debug("(c)Image %s not found..." % (str(iid)))
554 if _defcb:
555 jpeg_data = _defcb(size=size)
556 prevent_cache = True
557 else:
558 return HttpResponseServerError('Failed to render thumbnail')
559 if not prevent_cache:
560 webgateway_cache.setThumb(request, server_id, user_id, iid, jpeg_data, size)
561 else:
562 pass
563 rsp = HttpResponse(jpeg_data, mimetype='image/jpeg')
564 return rsp
565
567 """
568 returns a string that identifies this image, along with the settings passed on the request.
569 Useful for using as img identifier key, for prepared image.
570
571 @param request: http request
572 @return: String
573 """
574
575 r = request.REQUEST
576 rv = r.get('m','_') + r.get('p','_')+r.get('c','_')+r.get('q', '_')
577 return rv
578
579 @serverid
580 -def _get_prepared_image (request, iid, server_id=None, _conn=None, with_session=True, saveDefs=False, retry=True):
581 """
582 Fetches the Image object for image 'iid' and prepares it according to the request query, setting the channels,
583 rendering model and projection arguments. The compression level is parsed and returned too.
584 For parameters in request, see L{getImgDetailsFromReq}
585
586 @param request: http request
587 @param iid: Image ID
588 @param server_id:
589 @param _conn: L{omero.gateway.BlitzGateway} connection
590 @param with_session: If true, attempt to use existing session
591 @param saveDefs: Try to save the rendering settings, default z and t.
592 @param retry: Try an extra attempt at this method
593 @return: Tuple (L{omero.gateway.ImageWrapper} image, quality)
594 """
595 r = request.REQUEST
596 logger.debug('Preparing Image:%r with_session=%r saveDefs=%r ' \
597 'retry=%r request=%r' % (iid, with_session, saveDefs, retry,
598 r))
599 if _conn is None:
600 _conn = getBlitzConnection(request, server_id=server_id, with_session=with_session, useragent="OMERO.webgateway")
601 if _conn is None or not _conn.isConnected():
602 return HttpResponseServerError('""', mimetype='application/javascript')
603 img = _conn.getObject("Image", iid)
604 if r.has_key('c'):
605 logger.debug("c="+r['c'])
606 channels, windows, colors = _split_channel_info(r['c'])
607 if not img.setActiveChannels(channels, windows, colors):
608 logger.debug("Something bad happened while setting the active channels...")
609 if r.get('m', None) == 'g':
610 img.setGreyscaleRenderingModel()
611 elif r.get('m', None) == 'c':
612 img.setColorRenderingModel()
613 img.setProjection(r.get('p', None))
614 img.setInvertedAxis(bool(r.get('ia', "0") == "1"))
615 compress_quality = r.get('q', None)
616 if saveDefs:
617 r.has_key('z') and img._re.setDefaultZ(long(r['z'])-1)
618 r.has_key('t') and img._re.setDefaultT(long(r['t'])-1)
619 try:
620 img.saveDefaults()
621 except Ice.Exception, x:
622 if x.serverExceptionClass == 'ome.conditions.InternalException':
623
624
625
626
627 if x.message.find('Session is dirty') >= 0:
628 if retry:
629
630 return _get_prepared_image(request, iid=iid, server_id=server_id, _conn=_conn, with_session=with_session, saveDefs=saveDefs, retry=False)
631 logger.debug("Session is dirty, bailing out")
632 raise
633 else:
634 raise
635 return (img, compress_quality)
636
637 @serverid
638 -def render_image_region(request, iid, z, t, server_id=None, _conn=None, **kwargs):
639 """
640 Returns a jpeg of the OMERO image, rendering only a region specified in query string as
641 region=x,y,width,height. E.g. region=0,512,256,256
642 Rendering settings can be specified in the request parameters.
643
644 @param request: http request
645 @param iid: image ID
646 @param z: Z index
647 @param t: T index
648 @param server_id:
649 @param _conn: L{omero.gateway.BlitzGateway} connection
650 @return: http response wrapping jpeg
651 """
652
653
654
655
656
657
658 USE_SESSION = False
659 pi = _get_prepared_image(request, iid, server_id=server_id, _conn=_conn, with_session=USE_SESSION)
660
661 if pi is None:
662 raise Http404
663 img, compress_quality = pi
664
665 tile = request.REQUEST.get('tile', None)
666 region = request.REQUEST.get('region', None)
667 level = None
668
669 if tile:
670 try:
671 img._prepareRenderingEngine()
672 tiles = img._re.requiresPixelsPyramid()
673 w, h = img._re.getTileSize()
674 levels = img._re.getResolutionLevels()-1
675
676 zxyt = tile.split(",")
677
678
679
680 level = levels-int(zxyt[0])
681
682 x = int(zxyt[1])*w
683 y = int(zxyt[2])*h
684 except:
685 logger.debug("render_image_region: tile=%s" % tile)
686 logger.debug(traceback.format_exc())
687
688 elif region:
689 try:
690 xywh = region.split(",")
691
692 x = int(xywh[0])
693 y = int(xywh[1])
694 w = int(xywh[2])
695 h = int(xywh[3])
696 except:
697 logger.debug("render_image_region: region=%s" % region)
698 logger.debug(traceback.format_exc())
699
700
701 jpeg_data = webgateway_cache.getImage(request, server_id, img, z, t)
702 if jpeg_data is None:
703 jpeg_data = img.renderJpegRegion(z,t,x,y,w,h,level=level, compression=compress_quality)
704 if jpeg_data is None:
705 raise Http404
706 webgateway_cache.setImage(request, server_id, img, z, t, jpeg_data)
707 rsp = HttpResponse(jpeg_data, mimetype='image/jpeg')
708 return rsp
709
710 @serverid
711 -def render_image (request, iid, z, t, server_id=None, _conn=None, **kwargs):
712 """
713 Renders the image with id {{iid}} at {{z}} and {{t}} as jpeg.
714 Many options are available from the request dict. See L{getImgDetailsFromReq} for list.
715 I am assuming a single Pixels object on image with image-Id='iid'. May be wrong
716
717 @param request: http request
718 @param iid: image ID
719 @param z: Z index
720 @param t: T index
721 @param server_id:
722 @param _conn: L{omero.gateway.BlitzGateway} connection
723 @return: http response wrapping jpeg
724 """
725
726 USE_SESSION = False
727 pi = _get_prepared_image(request, iid, server_id=server_id, _conn=_conn, with_session=USE_SESSION)
728 if pi is None:
729 raise Http404
730 img, compress_quality = pi
731 jpeg_data = webgateway_cache.getImage(request, server_id, img, z, t)
732 if jpeg_data is None:
733 jpeg_data = img.renderJpeg(z,t, compression=compress_quality)
734 if jpeg_data is None:
735 raise Http404
736 webgateway_cache.setImage(request, server_id, img, z, t, jpeg_data)
737
738 try:
739 from PIL import Image, ImageDraw
740 except ImportError:
741 try:
742 import Image, ImageDraw
743 except:
744 logger.error("You need to install the Python Imaging Library. Get it at http://www.pythonware.com/products/pil/")
745 logger.error(traceback.format_exc())
746
747 rsp = HttpResponse(jpeg_data, mimetype='image/jpeg')
748 return rsp
749
750 @serverid
751 -def render_ome_tiff (request, ctx, cid, server_id=None, _conn=None, **kwargs):
752 """
753 Renders the OME-TIFF representation of the image(s) with id cid in ctx (i)mage,
754 (d)ataset, or (p)roject.
755
756 @param request: http request
757 @param ctx: 'p' or 'd' or 'i'
758 @param cid: Project, Dataset or Image ID
759 @param server_id:
760 @param _conn: L{omero.gateway.BlitzGateway} connection
761 @return: http response wrapping the tiff (or zip for multiple files), or redirect to temp file/zip
762 """
763 USE_SESSION = False
764 if _conn is None:
765 _conn = getBlitzConnection(request, server_id=server_id, with_session=USE_SESSION, useragent="OMERO.webgateway")
766 if _conn is None or not _conn.isConnected():
767 return HttpResponseServerError('""', mimetype='application/javascript')
768 imgs = []
769 if ctx == 'p':
770 obj = _conn.getObject("Project", cid)
771 if obj is None:
772 raise Http404
773 for d in obj.listChildren():
774 imgs.extend(list(d.listChildren()))
775 name = obj.getName()
776 elif ctx == 'd':
777 obj = _conn.getObject("Dataset", cid)
778 if obj is None:
779 raise Http404
780 imgs.extend(list(obj.listChildren()))
781 selection = filter(None, request.REQUEST.get('selection', '').split(','))
782 if len(selection):
783 logger.debug(selection)
784 logger.debug(imgs)
785 imgs = filter(lambda x: str(x.getId()) in selection, imgs)
786 logger.debug(imgs)
787 if len(imgs) == 0:
788 raise Http404
789 name = '%s-%s' % (obj.getParent().getName(), obj.getName())
790 else:
791 obj = _conn.getObject("Image", cid)
792 if obj is None:
793 raise Http404
794 imgs.append(obj)
795
796 if len(imgs) == 1:
797 obj = imgs[0]
798 key = '_'.join((str(x.getId()) for x in obj.getAncestry())) + '_' + str(obj.getId()) + '_ome_tiff'
799 fpath, rpath, fobj = webgateway_tempfile.new(str(obj.getId()) + '-'+obj.getName() + '.ome.tiff', key=key)
800 if fobj is True:
801
802 return HttpResponseRedirect('/appmedia/tfiles/' + rpath)
803 tiff_data = webgateway_cache.getOmeTiffImage(request, server_id, imgs[0])
804 if tiff_data is None:
805 tiff_data = imgs[0].exportOmeTiff()
806 if tiff_data is None:
807 raise Http404
808 webgateway_cache.setOmeTiffImage(request, server_id, imgs[0], tiff_data)
809 if fobj is None:
810 rsp = HttpResponse(tiff_data, mimetype='application/x-ome-tiff')
811 rsp['Content-Disposition'] = 'attachment; filename="%s.ome.tiff"' % (str(obj.getId()) + '-'+obj.getName())
812 rsp['Content-Length'] = len(tiff_data)
813 return rsp
814 else:
815 fobj.write(tiff_data)
816 fobj.close()
817 return HttpResponseRedirect('/appmedia/tfiles/' + rpath)
818 else:
819 try:
820 img_ids = '+'.join((str(x.getId()) for x in imgs))
821 key = '_'.join((str(x.getId()) for x in imgs[0].getAncestry())) + '_' + md5(img_ids).hexdigest() + '_ome_tiff_zip'
822 fpath, rpath, fobj = webgateway_tempfile.new(name + '.zip', key=key)
823 if fobj is True:
824 return HttpResponseRedirect('/appmedia/tfiles/' + rpath)
825 logger.debug(fpath)
826 if fobj is None:
827 fobj = StringIO()
828 zobj = zipfile.ZipFile(fobj, 'w', zipfile.ZIP_STORED)
829 for obj in imgs:
830 tiff_data = webgateway_cache.getOmeTiffImage(request, server_id, obj)
831 if tiff_data is None:
832 tiff_data = obj.exportOmeTiff()
833 if tiff_data is None:
834 continue
835 webgateway_cache.setOmeTiffImage(request, server_id, obj, tiff_data)
836 zobj.writestr(str(obj.getId()) + '-'+obj.getName() + '.ome.tiff', tiff_data)
837 zobj.close()
838 if fpath is None:
839 zip_data = fobj.getvalue()
840 rsp = HttpResponse(zip_data, mimetype='application/zip')
841 rsp['Content-Disposition'] = 'attachment; filename="%s.zip"' % name
842 rsp['Content-Length'] = len(zip_data)
843 return rsp
844 except:
845 logger.debug(traceback.format_exc())
846 raise
847 return HttpResponseRedirect('/appmedia/tfiles/' + rpath)
848
849 @serverid
850 -def render_movie (request, iid, axis, pos, server_id=None, _conn=None, **kwargs):
851 """
852 Renders a movie from the image with id iid
853
854 @param request: http request
855 @param iid: Image ID
856 @param axis: Movie frames are along 'z' or 't' dimension. String
857 @param pos: The T index (for z axis) or Z index (for t axis)
858 @param server_id:
859 @param _conn: L{omero.gateway.BlitzGateway} connection
860 @return: http response wrapping the file, or redirect to temp file
861 """
862
863 try:
864
865 opts = {}
866 opts['format'] = 'video/' + request.REQUEST.get('format', 'quicktime')
867 opts['fps'] = int(request.REQUEST.get('fps', 4))
868 opts['minsize'] = (512,512, '#222222')
869 ext = opts['format']== 'video/quicktime' and '.mov' or '.avi'
870 key = "%s-%s-%s-%d-%s-%s" % (iid, axis, pos, opts['fps'], _get_signature_from_request(request),
871 request.REQUEST.get('format', 'quicktime'))
872
873 USE_SESSION = False
874 pos = int(pos)
875 pi = _get_prepared_image(request, iid, server_id=server_id, _conn=_conn, with_session=USE_SESSION)
876 if pi is None:
877 raise Http404
878 img, compress_quality = pi
879
880 fpath, rpath, fobj = webgateway_tempfile.new(img.getName() + ext, key=key)
881 logger.debug(fpath, rpath, fobj)
882 if fobj is True:
883 return HttpResponseRedirect('/appmedia/tfiles/' + rpath)
884
885 if kwargs.has_key('optsCB'):
886 opts.update(kwargs['optsCB'](img))
887 opts.update(kwargs.get('opts', {}))
888 logger.debug('rendering movie for img %s with axis %s, pos %i and opts %s' % (iid, axis, pos, opts))
889
890 if fpath is None:
891 import tempfile
892 fo, fn = tempfile.mkstemp()
893 else:
894 fn = fpath
895 if axis.lower() == 'z':
896 dext, mimetype = img.createMovie(fn, 0, img.getSizeZ()-1, pos-1, pos-1, opts)
897 else:
898 dext, mimetype = img.createMovie(fn, pos-1, pos-1, 0, img.getSizeT()-1, opts)
899 if dext is None and mimetype is None:
900
901
902 raise Http404
903 if fpath is None:
904 movie = open(fn).read()
905 os.close(fo)
906 rsp = HttpResponse(movie, mimetype=mimetype)
907 rsp['Content-Disposition'] = 'attachment; filename="%s"' % (img.getName()+ext)
908 rsp['Content-Length'] = len(movie)
909 return rsp
910 else:
911 fobj.close()
912
913 return HttpResponseRedirect('/appmedia/tfiles/' + rpath)
914 except:
915 logger.debug(traceback.format_exc())
916 raise
917
920 """
921 Renders a split channel view of the image with id {{iid}} at {{z}} and {{t}} as jpeg.
922 Many options are available from the request dict.
923 Requires PIL to be installed on the server.
924
925 @param request: http request
926 @param iid: Image ID
927 @param z: Z index
928 @param t: T index
929 @param server_id:
930 @param _conn: L{omero.gateway.BlitzGateway} connection
931 @return: http response wrapping a jpeg
932 """
933
934 USE_SESSION = False
935 pi = _get_prepared_image(request, iid, server_id=server_id, _conn=_conn, with_session=USE_SESSION)
936 if pi is None:
937 raise Http404
938 img, compress_quality = pi
939 compress_quality = compress_quality and float(compress_quality) or 0.9
940 jpeg_data = webgateway_cache.getSplitChannelImage(request, server_id, img, z, t)
941 if jpeg_data is None:
942 jpeg_data = img.renderSplitChannel(z,t, compression=compress_quality)
943 if jpeg_data is None:
944 raise Http404
945 webgateway_cache.setSplitChannelImage(request, server_id, img, z, t, jpeg_data)
946 rsp = HttpResponse(jpeg_data, mimetype='image/jpeg')
947 return rsp
948
950 """
951 Decorator for adding debugging functionality to methods.
952
953 @param f: The function to wrap
954 @return: The wrapped function
955 """
956
957 def wrap (request, *args, **kwargs):
958 debug = request.REQUEST.getlist('debug')
959 if 'slow' in debug:
960 time.sleep(5)
961 if 'fail' in debug:
962 raise Http404
963 if 'error' in debug:
964 raise AttributeError('Debug requested error')
965 return f(request, *args, **kwargs)
966 wrap.func_name = f.func_name
967 return wrap
968
970 """
971 Decorator for adding connection debugging and returning function result as json, depending on
972 values in kwargs
973
974 @param f: The function to wrap
975 @return: The wrapped function, which will return json
976 """
977
978 def wrap (request, *args, **kwargs):
979 logger.debug('jsonp')
980 try:
981 server_id = kwargs.get('server_id', None)
982 if server_id is None:
983 server_id = request.session.get('server', None)
984 kwargs['server_id'] = server_id
985 _conn = kwargs.get('_conn', None)
986 if _conn is None:
987 blitzcon = getBlitzConnection(request, server_id, useragent="OMERO.webgateway")
988 kwargs['_conn'] = blitzcon
989 if kwargs['_conn'] is None or not kwargs['_conn'].isConnected():
990 return HttpResponseServerError('"failed connection"', mimetype='application/javascript')
991 rv = f(request, *args, **kwargs)
992 if _conn is not None and kwargs.get('_internal', False):
993 return rv
994 if isinstance(rv, HttpResponseServerError):
995 return rv
996 rv = simplejson.dumps(rv)
997 c = request.REQUEST.get('callback', None)
998 if c is not None and not kwargs.get('_internal', False):
999 rv = '%s(%s)' % (c, rv)
1000 if _conn is not None or kwargs.get('_internal', False):
1001 return rv
1002 return HttpResponse(rv, mimetype='application/javascript')
1003 except omero.ServerError:
1004 if kwargs.get('_internal', False):
1005 raise
1006 return HttpResponseServerError('("error in call","%s")' % traceback.format_exc(), mimetype='application/javascript')
1007 except:
1008 logger.debug(traceback.format_exc())
1009 if kwargs.get('_internal', False):
1010 raise
1011 return HttpResponseServerError('("error in call","%s")' % traceback.format_exc(), mimetype='application/javascript')
1012 wrap.func_name = f.func_name
1013 return wrap
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023 @debug
1024 @serverid
1025 -def render_row_plot (request, iid, z, t, y, server_id=None, _conn=None, w=1, **kwargs):
1026 """
1027 Renders the line plot for the image with id {{iid}} at {{z}} and {{t}} as gif with transparent background.
1028 Many options are available from the request dict.
1029 I am assuming a single Pixels object on image with Image ID='iid'. May be wrong
1030 TODO: cache
1031
1032 @param request: http request
1033 @param iid: Image ID
1034 @param z: Z index
1035 @param t: T index
1036 @param y: Y position of row to measure
1037 @param server_id:
1038 @param _conn: L{omero.gateway.BlitzGateway} connection
1039 @param w: Line width
1040 @return: http response wrapping a gif
1041 """
1042
1043 if not w:
1044 w = 1
1045 pi = _get_prepared_image(request, iid, server_id=server_id, _conn=_conn)
1046 if pi is None:
1047 raise Http404
1048 img, compress_quality = pi
1049 gif_data = img.renderRowLinePlotGif(int(z),int(t),int(y), int(w))
1050 if gif_data is None:
1051 raise Http404
1052 rsp = HttpResponse(gif_data, mimetype='image/gif')
1053 return rsp
1054
1055 @debug
1056 @serverid
1057 -def render_col_plot (request, iid, z, t, x, w=1, server_id=None, _conn=None, **kwargs):
1058 """
1059 Renders the line plot for the image with id {{iid}} at {{z}} and {{t}} as gif with transparent background.
1060 Many options are available from the request dict.
1061 I am assuming a single Pixels object on image with id='iid'. May be wrong
1062 TODO: cache
1063
1064 @param request: http request
1065 @param iid: Image ID
1066 @param z: Z index
1067 @param t: T index
1068 @param x: X position of column to measure
1069 @param server_id:
1070 @param _conn: L{omero.gateway.BlitzGateway} connection
1071 @param w: Line width
1072 @return: http response wrapping a gif
1073 """
1074
1075 if not w:
1076 w = 1
1077 pi = _get_prepared_image(request, iid, server_id=server_id, _conn=_conn)
1078 if pi is None:
1079 raise Http404
1080 img, compress_quality = pi
1081 gif_data = img.renderColLinePlotGif(int(z),int(t),int(x), int(w))
1082 if gif_data is None:
1083 raise Http404
1084 rsp = HttpResponse(gif_data, mimetype='image/gif')
1085 return rsp
1086
1088 """
1089 return a dict with all there is to know about a channel
1090
1091 @param channel: L{omero.gateway.ChannelWrapper}
1092 @return: Dict
1093 """
1094
1095 return {'emissionWave': channel.getEmissionWave(),
1096 'label': channel.getLabel(),
1097 'color': channel.getColor().getHtml(),
1098 'window': {'min': channel.getWindowMin(),
1099 'max': channel.getWindowMax(),
1100 'start': channel.getWindowStart(),
1101 'end': channel.getWindowEnd(),},
1102 'active': channel.isActive()}
1103
1105 """
1106 return a dict with pretty much everything we know and care about an image,
1107 all wrapped in a pretty structure.
1108
1109 @param image: L{omero.gateway.ImageWrapper}
1110 @param key: key of specific attributes to select
1111 @return: Dict
1112 """
1113
1114 image.loadRenderOptions()
1115 pr = image.getProject()
1116 ds = None
1117 try:
1118
1119
1120
1121 parents = image.listParents()
1122 if parents is not None and len(parents) == 1 \
1123 and parents[0].OMERO_CLASS == 'Dataset':
1124 ds = parents[0]
1125 except omero.SecurityViolation, e:
1126
1127
1128 logger.warn('Security violation while retrieving Dataset when ' \
1129 'marshaling image metadata: %s' % e.message)
1130
1131 try:
1132 reOK = image._prepareRenderingEngine()
1133 if not reOK:
1134 logger.debug("Failed to prepare Rendering Engine for imageMarshal")
1135 return None
1136 except omero.ConcurrencyException, ce:
1137 backOff = ce.backOff
1138 rv = {
1139 'ConcurrencyException': {
1140 'backOff': backOff
1141 }
1142 }
1143 return rv
1144
1145
1146 tiles = image._re.requiresPixelsPyramid()
1147 width, height = image._re.getTileSize()
1148 levels = image._re.getResolutionLevels()-1
1149 init_zoom = image._re.getResolutionLevel()
1150
1151 try:
1152 rv = {
1153 'tiles': tiles,
1154 'tile_size': {'width': width,
1155 'height': height},
1156 'init_zoom': init_zoom,
1157 'levels': levels,
1158 'id': image.id,
1159 'size': {'width': image.getSizeX(),
1160 'height': image.getSizeY(),
1161 'z': image.getSizeZ(),
1162 't': image.getSizeT(),
1163 'c': image.getSizeC(),},
1164 'pixel_size': {'x': image.getPixelSizeX(),
1165 'y': image.getPixelSizeY(),
1166 'z': image.getPixelSizeZ(),},
1167 'meta': {'imageName': image.name or '',
1168 'imageDescription': image.description or '',
1169 'imageAuthor': image.getAuthor(),
1170 'projectName': pr and pr.name or 'Multiple',
1171 'projectId': pr and pr.id or None,
1172 'projectDescription':pr and pr.description or '',
1173 'datasetName': ds and ds.name or 'Multiple',
1174 'datasetId': ds and ds.id or '',
1175 'datasetDescription': ds and ds.description or '',
1176 'imageTimestamp': time.mktime(image.getDate().timetuple()),
1177 'imageId': image.id,},
1178 }
1179 try:
1180 rv['pixel_range'] = image.getPixelRange()
1181 rv['channels'] = map(lambda x: channelMarshal(x), image.getChannels())
1182 rv['split_channel'] = image.splitChannelDims()
1183 rv['rdefs'] = {'model': image.isGreyscaleRenderingModel() and 'greyscale' or 'color',
1184 'projection': image.getProjection(),
1185 'defaultZ': image._re.getDefaultZ(),
1186 'defaultT': image._re.getDefaultT(),
1187 'invertAxis': image.isInvertedAxis()}
1188 except TypeError:
1189
1190 rv['pixel_range'] = (0, 0)
1191 rv['channels'] = ()
1192 rv['split_channel'] = ()
1193 rv['rdefs'] = {'model': 'color', 'projection': image.getProjection(), 'invertAxis': image.isInvertedAxis()}
1194 except AttributeError:
1195 rv = None
1196 raise
1197 if key is not None and rv is not None:
1198 for k in key.split('.'):
1199 rv = rv.get(k, {})
1200 if rv == {}:
1201 rv = None
1202 return rv
1203
1204 @jsonp
1205 -def imageData_json (request, server_id=None, _conn=None, _internal=False, **kwargs):
1206 """
1207 Get a dict with image information
1208 TODO: cache
1209
1210 @param request: http request
1211 @param server_id:
1212 @param _conn: L{omero.gateway.BlitzGateway}
1213 @param _internal: TODO: ?
1214 @return: Dict
1215 """
1216
1217 iid = kwargs['iid']
1218 key = kwargs.get('key', None)
1219 blitzcon = _conn
1220 image = blitzcon.getObject("Image", iid)
1221 if image is None:
1222 return HttpResponseServerError('""', mimetype='application/javascript')
1223 rv = imageMarshal(image, key)
1224 return rv
1225
1226 @jsonp
1227 -def wellData_json (request, server_id=None, _conn=None, _internal=False, **kwargs):
1228 """
1229 Get a dict with image information
1230 TODO: cache
1231
1232 @param request: http request
1233 @param server_id:
1234 @param _conn: L{omero.gateway.BlitzGateway}
1235 @param _internal: TODO: ?
1236 @return: Dict
1237 """
1238
1239 wid = kwargs['wid']
1240 blitzcon = _conn
1241 well = blitzcon.getObject("Well", wid)
1242 if well is None:
1243 return HttpResponseServerError('""', mimetype='application/javascript')
1244 prefix = kwargs.get('thumbprefix', 'webgateway.views.render_thumbnail')
1245 def urlprefix(iid):
1246 return reverse(prefix, args=(iid,))
1247 xtra = {'thumbUrlPrefix': urlprefix}
1248 rv = well.simpleMarshal(xtra=xtra)
1249 return rv
1250
1251 @jsonp
1252 -def plateGrid_json (request, pid, field=0, server_id=None, _conn=None, **kwargs):
1253 """
1254 """
1255 plate = _conn.getObject('plate', long(pid))
1256 try:
1257 field = long(field or 0)
1258 except ValueError:
1259 field = 0
1260 if plate is None:
1261 return HttpResponseServerError('""', mimetype='application/javascript')
1262 grid = []
1263 prefix = kwargs.get('thumbprefix', 'webgateway.views.render_thumbnail')
1264 def urlprefix(iid):
1265 return reverse(prefix, args=(iid,64))
1266 xtra = {'thumbUrlPrefix': urlprefix}
1267 plate.setGridSizeConstraints(8,12)
1268 for row in plate.getWellGrid(field):
1269 tr = []
1270 for e in row:
1271 if e:
1272 i = e.getImage()
1273 if i:
1274 t = i.simpleMarshal(xtra=xtra)
1275 t['wellId'] = e.getId()
1276 t['field'] = field
1277 tr.append(t)
1278 continue
1279 tr.append(None)
1280 grid.append(tr)
1281
1282 return {'grid': grid,
1283 'collabels': plate.getColumnLabels(),
1284 'rowlabels': plate.getRowLabels()}
1285
1286 @jsonp
1287 -def listImages_json (request, did, server_id=None, _conn=None, **kwargs):
1288 """
1289 lists all Images in a Dataset, as json
1290 TODO: cache
1291
1292 @param request: http request
1293 @param did: Dataset ID
1294 @param server_id:
1295 @param _conn: L{omero.gateway.BlitzGateway}
1296 @return: list of image json.
1297 """
1298
1299 blitzcon = _conn
1300 dataset = blitzcon.getObject("Dataset", did)
1301 if dataset is None:
1302 return HttpResponseServerError('""', mimetype='application/javascript')
1303 prefix = kwargs.get('thumbprefix', 'webgateway.views.render_thumbnail')
1304 def urlprefix(iid):
1305 return reverse(prefix, args=(iid,))
1306 xtra = {'thumbUrlPrefix': urlprefix}
1307 return map(lambda x: x.simpleMarshal(xtra=xtra), dataset.listChildren())
1308
1311 """
1312 lists all Images in a Well, as json
1313 TODO: cache
1314
1315 @param request: http request
1316 @param did: Well ID
1317 @param server_id:
1318 @param _conn: L{omero.gateway.BlitzGateway}
1319 @return: list of image json.
1320 """
1321
1322 blitzcon = _conn
1323 well = blitzcon.getObject("Well", did)
1324 if well is None:
1325 return HttpResponseServerError('""', mimetype='application/javascript')
1326 prefix = kwargs.get('thumbprefix', 'webgateway.views.render_thumbnail')
1327 def urlprefix(iid):
1328 return reverse(prefix, args=(iid,))
1329 xtra = {'thumbUrlPrefix': urlprefix}
1330 return map(lambda x: x.getImage() and x.getImage().simpleMarshal(xtra=xtra), well.listChildren())
1331
1332 @jsonp
1333 -def listDatasets_json (request, pid, server_id=None, _conn=None, **kwargs):
1334 """
1335 lists all Datasets in a Project, as json
1336 TODO: cache
1337
1338 @param request: http request
1339 @param pid: Project ID
1340 @param server_id:
1341 @param _conn: L{omero.gateway.BlitzGateway}
1342 @return: list of dataset json.
1343 """
1344
1345 blitzcon = _conn
1346 project = blitzcon.getObject("Project", pid)
1347 rv = []
1348 if project is None:
1349 return HttpResponse('[]', mimetype='application/javascript')
1350 return [x.simpleMarshal(xtra={'childCount':0}) for x in project.listChildren()]
1351
1354 """
1355 return json encoded details for a dataset
1356 TODO: cache
1357 """
1358 blitzcon = _conn
1359 ds = blitzcon.getObject("Dataset", did)
1360 return ds.simpleMarshal()
1361
1364 """
1365 lists all Projects, as json
1366 TODO: cache
1367
1368 @param request: http request
1369 @param server_id:
1370 @param _conn: L{omero.gateway.BlitzGateway}
1371 @return: list of project json.
1372 """
1373
1374 blitzcon = _conn
1375 rv = []
1376 for pr in blitzcon.listProjects():
1377 rv.append( {'id': pr.id, 'name': pr.name, 'description': pr.description or ''} )
1378 return rv
1379
1382 """
1383 grab details from one specific project
1384 TODO: cache
1385
1386 @param request: http request
1387 @param pid: Project ID
1388 @param server_id:
1389 @param _conn: L{omero.gateway.BlitzGateway}
1390 @return: project details as dict.
1391 """
1392
1393 blitzcon = _conn
1394 pr = blitzcon.getObject("Project", pid)
1395 rv = pr.simpleMarshal()
1396 return rv
1397
1399 """
1400 Returns a dict of options for searching, based on
1401 parameters in the http request
1402 Request keys include:
1403 - ctx: (http request) 'imgs' to search only images
1404 - text: (http request) the actual text phrase
1405 - start: starting index (0 based) for result
1406 - limit: nr of results to retuen (0 == unlimited)
1407 - author:
1408 - grabData:
1409 - parents:
1410
1411 @param request: http request
1412 @return: Dict of options
1413 """
1414
1415 try:
1416 r = request.REQUEST
1417 opts = {
1418 'search': unicode(r.get('text', '')).encode('utf8'),
1419 'ctx': r.get('ctx', ''),
1420 'grabData': not not r.get('grabData', False),
1421 'parents': not not bool(r.get('parents', False)),
1422 'start': int(r.get('start', 0)),
1423 'limit': int(r.get('limit', 0)),
1424 'key': r.get('key', None)
1425 }
1426 author = r.get('author', '')
1427 if author:
1428 opts['search'] += ' author:'+author
1429 return opts
1430 except:
1431 logger.error(traceback.format_exc())
1432 return {}
1433
1434 @TimeIt(logging.INFO)
1435 @jsonp
1436 -def search_json (request, server_id=None, _conn=None, **kwargs):
1437 """
1438 Search for objects in blitz.
1439 Returns json encoded list of marshalled objects found by the search query
1440 Request keys include:
1441 - text: The text to search for
1442 - ctx: (http request) 'imgs' to search only images
1443 - text: (http request) the actual text phrase
1444 - start: starting index (0 based) for result
1445 - limit: nr of results to retuen (0 == unlimited)
1446 - author:
1447 - grabData:
1448 - parents:
1449
1450 @param request: http request
1451 @param server_id:
1452 @param _conn: L{omero.gateway.BlitzGateway}
1453 @return: json search results
1454 TODO: cache
1455 """
1456 opts = searchOptFromRequest(request)
1457 rv = []
1458 logger.debug("searchObjects(%s)" % (opts['search']))
1459
1460 def urlprefix(iid):
1461 return reverse('webgateway.views.render_thumbnail', args=(iid,))
1462 xtra = {'thumbUrlPrefix': urlprefix}
1463 pks = None
1464 try:
1465 if opts['ctx'] == 'imgs':
1466 sr = _conn.searchObjects(["image"], opts['search'])
1467 else:
1468 sr = _conn.searchObjects(None, opts['search'])
1469 except ApiUsageException:
1470 return HttpResponseServerError('"parse exception"', mimetype='application/javascript')
1471 def marshal ():
1472 rv = []
1473 if (opts['grabData'] and opts['ctx'] == 'imgs'):
1474 bottom = min(opts['start'], len(sr)-1)
1475 if opts['limit'] == 0:
1476 top = len(sr)
1477 else:
1478 top = min(len(sr), bottom + opts['limit'])
1479 for i in range(bottom, top):
1480 e = sr[i]
1481
1482 try:
1483 rv.append(imageData_json(request, server_id, iid=e.id, key=opts['key'], _conn=_conn, _internal=True))
1484 except AttributeError, x:
1485 logger.debug('(iid %i) ignoring Attribute Error: %s' % (e.id, str(x)))
1486 pass
1487 except omero.ServerError, x:
1488 logger.debug('(iid %i) ignoring Server Error: %s' % (e.id, str(x)))
1489 return rv
1490 else:
1491 return map(lambda x: x.simpleMarshal(xtra=xtra, parents=opts['parents']), sr)
1492 rv = timeit(marshal)()
1493 logger.debug(rv)
1494 return rv
1495
1498 """
1499 Requests that the rendering defs passed in the request be set as the default for this image.
1500 Rendering defs in request listed at L{getImgDetailsFromReq}
1501 TODO: jsonp
1502
1503 @param request: http request
1504 @param iid: Image ID
1505 @param server_id:
1506 @return: http response 'true' or 'false'
1507 """
1508
1509 r = request.REQUEST
1510 pi = _get_prepared_image(request, iid, server_id=server_id, with_session=True, saveDefs=True)
1511 if pi is None:
1512 json_data = 'false'
1513 else:
1514 user_id = pi[0]._conn.getEventContext().userId
1515 webgateway_cache.invalidateObject(server_id, user_id, pi[0])
1516 pi[0].getThumbnail()
1517 json_data = 'true'
1518 if r.get('callback', None):
1519 json_data = '%s(%s)' % (r['callback'], json_data)
1520 return HttpResponse(json_data, mimetype='application/javascript')
1521
1524 """
1525 Lists the images on the same project that would be viable targets for copying rendering settings.
1526 TODO: change method to:
1527 list_compatible_imgs_json (request, iid, server_id=None, _conn=None, **kwargs):
1528
1529 @param request: http request
1530 @param server_id:
1531 @param iid: Image ID
1532 @param _conn: L{omero.gateway.BlitzGateway}
1533 @return: json list of image IDs
1534 """
1535
1536 json_data = 'false'
1537 r = request.REQUEST
1538 if _conn is None:
1539 blitzcon = getBlitzConnection(request, server_id, with_session=True, useragent="OMERO.webgateway")
1540 else:
1541 blitzcon = _conn
1542 if blitzcon is None or not blitzcon.isConnected():
1543 img = None
1544 else:
1545 img = blitzcon.getObject("Image", iid)
1546
1547 if img is not None:
1548
1549 imgs = []
1550 for ds in img.getProject().listChildren():
1551 imgs.extend(ds.listChildren())
1552
1553 img_ptype = img.getPrimaryPixels().getPixelsType().getValue()
1554 img_ccount = img.getSizeC()
1555 img_ew = [x.getLabel() for x in img.getChannels()]
1556 img_ew.sort()
1557 def compat (i):
1558 if long(i.getId()) == long(iid):
1559 return False
1560 pp = i.getPrimaryPixels()
1561 if pp is None or \
1562 i.getPrimaryPixels().getPixelsType().getValue() != img_ptype or \
1563 i.getSizeC() != img_ccount:
1564 return False
1565 ew = [x.getLabel() for x in i.getChannels()]
1566 ew.sort()
1567 if ew != img_ew:
1568 return False
1569 return True
1570 imgs = filter(compat, imgs)
1571 json_data = simplejson.dumps([x.getId() for x in imgs])
1572
1573 if r.get('callback', None):
1574 json_data = '%s(%s)' % (r['callback'], json_data)
1575 return HttpResponse(json_data, mimetype='application/javascript')
1576
1577 @jsonp
1578 @serverid
1579 -def copy_image_rdef_json (request, server_id=None, _conn=None, _internal=False, **kwargs):
1580 """
1581 Copy the rendering settings from one image to a list of images.
1582 Images are specified in request by 'fromid' and list of 'toids'
1583 Returns json dict of Boolean:[Image-IDs] for images that have successfully
1584 had the rendering settings applied, or not.
1585
1586 @param request: http request
1587 @param server_id:
1588 @param _conn: L{omero.gateway.BlitzGateway}
1589 @return: json dict of Boolean:[Image-IDs]
1590 """
1591
1592 json_data = False
1593 r = request.REQUEST
1594 try:
1595 fromid = long(r.get('fromid', None))
1596 toids = map(lambda x: long(x), r.getlist('toids'))
1597 except TypeError:
1598 fromid = None
1599 except ValueError:
1600 fromid = None
1601 if fromid is not None and len(toids) > 0:
1602
1603
1604
1605 blitzcon = _conn
1606
1607 fromimg = blitzcon.getObject("Image", fromid)
1608 details = fromimg.getDetails()
1609 frompid = fromimg.getPixelsId()
1610 newConn = None
1611 if blitzcon.isAdmin():
1612 p = omero.sys.Principal()
1613 p.name = details.getOwner().omeName
1614 p.group = details.getGroup().name
1615 p.eventType = "User"
1616
1617 newConnId = blitzcon.getSessionService().createSessionWithTimeout(p, 1200000)
1618 newConn = blitzcon.clone()
1619 newConn.connect(sUuid=newConnId.getUuid().val)
1620 elif fromimg.isEditable():
1621 newConn = blitzcon
1622 newConn.setGroupForSession(details.getGroup().getId())
1623
1624 if newConn is not None and newConn.isConnected():
1625 frompid = newConn.getObject("Image", fromid).getPixelsId()
1626 rsettings = newConn.getRenderingSettingsService()
1627 json_data = rsettings.applySettingsToImages(frompid, list(toids))
1628 if fromid in json_data[True]:
1629 del json_data[True][json_data[True].index(fromid)]
1630 for iid in json_data[True]:
1631 img = newConn.getObject("Image", iid)
1632 user_id = newConn.getEventContext().userId
1633 img is not None and webgateway_cache.invalidateObject(server_id, user_id, img)
1634 return json_data
1635
1636
1637
1638
1639
1640
1641
1642 @serverid
1643 @jsonp
1644 -def reset_image_rdef_json (request, iid, server_id=None, _conn=None, **kwargs):
1645 """
1646 Try to remove all rendering defs the logged in user has for this image.
1647
1648 @param request: http request
1649 @param iid: Image ID
1650 @param server_id:
1651 @param _conn: L{omero.gateway.BlitzGateway}
1652 @return: json 'true', or 'false' if failed
1653 """
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663 img = _conn.getObject("Image", iid)
1664
1665 if img is not None and img.resetRDefs():
1666 user_id = _conn.getEventContext().userId
1667 webgateway_cache.invalidateObject(server_id, user_id, img)
1668 return True
1669 json_data = 'true'
1670 else:
1671 json_data = 'false'
1672 return False
1673
1680 """
1681 For debugging, return connectors dict as plain text
1682 """
1683 rv = connectors.items()
1684 return HttpResponse(rv, mimetype='text/plain')
1685
1686 @serverid
1687 -def full_viewer (request, iid, server_id=None, _conn=None, **kwargs):
1688 """
1689 This view is responsible for showing the omero_image template
1690 Image rendering options in request are used in the display page. See L{getImgDetailsFromReq}.
1691
1692 @param request: http request.
1693 @param iid: Image ID
1694 @param server_id:
1695 @param _conn: L{omero.gateway.BlitzGateway}
1696 @param **kwargs: Can be used to specify the html 'template' for rendering
1697 @return: html page of image and metadata
1698 """
1699
1700 rid = getImgDetailsFromReq(request)
1701 try:
1702 if _conn is None:
1703 _conn = getBlitzConnection(request, server_id=server_id, useragent="OMERO.webgateway")
1704 if _conn is None or not _conn.isConnected():
1705 raise Http404
1706 image = _conn.getObject("Image", iid)
1707 if image is None:
1708 logger.debug("(a)Image %s not found..." % (str(iid)))
1709 raise Http404
1710 d = {'blitzcon': _conn,
1711 'image': image,
1712 'opts': rid,
1713 'viewport_server': kwargs.get('viewport_server', '/webgateway'),
1714 'object': 'image:%i' % int(iid)}
1715
1716 template = kwargs.get('template', "webgateway/omero_image.html")
1717 t = template_loader.get_template(template)
1718 c = Context(request,d)
1719 rsp = t.render(c)
1720 except omero.SecurityViolation:
1721 raise Http404
1722 return HttpResponse(rsp)
1723
1724 @serverid
1725 -def get_rois_json(request, imageId, server_id=None):
1726 """
1727 Returns json data of the ROIs in the specified image.
1728 """
1729 _conn = getBlitzConnection(request, server_id=server_id, with_session=False, useragent="OMERO.webgateway")
1730 if _conn is None or not _conn.isConnected():
1731 raise Http404
1732
1733 def stringToSvg(string):
1734 """
1735 Method for converting the string returned from omero.model.ShapeI.getPoints()
1736 into an SVG for display on web.
1737 E.g: "points[309,427, 366,503, 190,491] points1[309,427, 366,503, 190,491] points2[309,427, 366,503, 190,491]"
1738 To: M 309 427 L 366 503 L 190 491 z
1739 """
1740 pointLists = string.strip().split("points")
1741 if len(pointLists) < 2:
1742 logger.error("Unrecognised ROI shape 'points' string: %s" % string)
1743 return ""
1744 firstList = pointLists[1]
1745 nums = firstList.strip("[]").replace(", ", " L").replace(",", " ")
1746 return "M" + nums
1747
1748 def rgb_int2css(rgbint):
1749 """
1750 converts a bin int number into css colour, E.g. -1006567680 to '#00ff00'
1751 """
1752 r,g,b = (rgbint // 256 // 256 % 256, rgbint // 256 % 256, rgbint % 256)
1753 return "#%02x%02x%02x" % (r,g,b)
1754
1755 rois = []
1756 roiService = _conn.getRoiService()
1757
1758 result = roiService.findByImage(long(imageId), None)
1759
1760 for r in result.rois:
1761 roi = {}
1762 roi['id'] = r.getId().getValue()
1763
1764 shapes = []
1765 for s in r.copyShapes():
1766 shape = {}
1767 if s is None:
1768 continue
1769 shape['id'] = s.getId().getValue()
1770 shape['theT'] = s.getTheT().getValue()
1771 shape['theZ'] = s.getTheZ().getValue()
1772 if type(s) == omero.model.RectI:
1773 shape['type'] = 'Rectangle'
1774 shape['x'] = s.getX().getValue()
1775 shape['y'] = s.getY().getValue()
1776 shape['width'] = s.getWidth().getValue()
1777 shape['height'] = s.getHeight().getValue()
1778 elif type(s) == omero.model.MaskI:
1779 shape['type'] = 'Mask'
1780 shape['x'] = s.getX().getValue()
1781 shape['y'] = s.getY().getValue()
1782 shape['width'] = s.getWidth().getValue()
1783 shape['height'] = s.getHeight().getValue()
1784
1785 elif type(s) == omero.model.EllipseI:
1786 shape['type'] = 'Ellipse'
1787 shape['cx'] = s.getCx().getValue()
1788 shape['cy'] = s.getCy().getValue()
1789 shape['rx'] = s.getRx().getValue()
1790 shape['ry'] = s.getRy().getValue()
1791 elif type(s) == omero.model.PolylineI:
1792 shape['type'] = 'PolyLine'
1793 shape['points'] = stringToSvg(s.getPoints().getValue())
1794 elif type(s) == omero.model.LineI:
1795 shape['type'] = 'Line'
1796 shape['x1'] = s.getX1().getValue()
1797 shape['x2'] = s.getX2().getValue()
1798 shape['y1'] = s.getY1().getValue()
1799 shape['y2'] = s.getY2().getValue()
1800 elif type(s) == omero.model.PointI:
1801 shape['type'] = 'Point'
1802 shape['cx'] = s.getCx().getValue()
1803 shape['cy'] = s.getCy().getValue()
1804 elif type(s) == omero.model.PolygonI:
1805 shape['type'] = 'Polygon'
1806 shape['points'] = stringToSvg(s.getPoints().getValue()) + "z"
1807 elif type(s) == omero.model.LabelI:
1808 shape['type'] = 'Label'
1809 shape['x'] = s.getX().getValue()
1810 shape['y'] = s.getY().getValue()
1811 else:
1812 logger.debug("Shape type not supported: %s" % str(type(s)))
1813 try:
1814 if s.getTextValue() and s.getTextValue().getValue():
1815 shape['textValue'] = s.getTextValue().getValue()
1816
1817 if s.getFontSize() and s.getFontSize().getValue():
1818 shape['fontSize'] = s.getFontSize().getValue()
1819 if s.getFontStyle() and s.getFontStyle().getValue():
1820 shape['fontStyle'] = s.getFontStyle().getValue()
1821 if s.getFontFamily() and s.getFontFamily().getValue():
1822 shape['fontFamily'] = s.getFontFamily().getValue()
1823 except AttributeError: pass
1824 if s.getTransform():
1825 t = s.getTransform().getValue()
1826 if t and t != 'none':
1827 shape['transform'] = t
1828 if s.getFillColor() and s.getFillColor().getValue():
1829 shape['fillColor'] = rgb_int2css(s.getFillColor().getValue())
1830 if s.getStrokeColor() and s.getStrokeColor().getValue():
1831 shape['strokeColor'] = rgb_int2css(s.getStrokeColor().getValue())
1832 if s.getStrokeWidth() and s.getStrokeWidth().getValue():
1833 shape['strokeWidth'] = s.getStrokeWidth().getValue()
1834 shapes.append(shape)
1835
1836 shapes.sort(key=lambda x: "%03d%03d"% (x['theZ'],x['theT']) );
1837 roi['shapes'] = shapes
1838 rois.append(roi)
1839
1840 rois.sort(key=lambda x: x['id'])
1841
1842 return HttpResponse(simplejson.dumps(rois), mimetype='application/javascript')
1843
1844
1845 -def test (request):
1846 """
1847 Tests the L{full_viewer} with no args passed to the template.
1848
1849 @param request: http request.
1850 @return: blank page template
1851 """
1852
1853 context = {}
1854
1855 t = template_loader.get_template('webgateway/omero_image.html')
1856 c = Context(request,context)
1857 return HttpResponse(t.render(c))
1858
1859 @jsonp
1860 -def su (request, user, server_id=None, _conn=None, **kwargs):
1861 """
1862 If current user is admin, switch the session to a new connection owned by 'user'
1863 (puts the new session ID in the request.session)
1864 Return False if not possible
1865
1866 @param request: http request.
1867 @param user: Username of new connection owner
1868 @param server_id:
1869 @param _conn: L{omero.gateway.BlitzGateway}
1870 @param **kwargs: Can be used to specify the html 'template' for rendering
1871 @return: Boolean
1872 """
1873 if not _conn.canBeAdmin():
1874 return False
1875 _conn.setGroupNameForSession('system')
1876 if server_id is None:
1877
1878
1879 try:
1880 server_id = request.session['server']
1881 except KeyError:
1882 return None
1883 browsersession_connection_key = 'cuuid#%s'%server_id
1884 c = _conn.suConn(user,
1885 ttl=_conn.getSessionService().getSession(_conn._sessionUuid).getTimeToIdle().val)
1886 _conn.revertGroupForSession()
1887 _conn.seppuku()
1888 logger.debug(browsersession_connection_key)
1889 request.session[browsersession_connection_key] = c._sessionUuid
1890 return True
1891