Source code for slideatlas.views.tile

# coding=utf-8

from flask import Blueprint, Response, current_app, request, redirect

from slideatlas import models
from slideatlas.common_utils import jsonify

import base64
from bson import ObjectId

################################################################################
mod = Blueprint('tile', __name__)


################################################################################
@mod.route('/tile/<ObjectId:image_store_id>/<ObjectId:image_id>/<string:tile_name>')
# @security.login_required
[docs]def tile(image_store_id, image_id, tile_name): """ Return a tile image. Note that the 'image_store' and 'image_id' URL parameters are accepted as an ObjectIds, to prevent unnecessary database queries if HTTP caching causes a 304 (Not Modified) response to be returned. """ response = Response(content_type='image/jpeg') # tiles could change, especially if PTIFFs are rebuilt, so mark the ETag as # weak # TODO: could we ensure that tiles are immutable? response.set_etag('%s-%s-v2' % (image_id, tile_name), weak=True) response.cache_control.public = True # since Last Modified is not used, and the ETag is weak, setting a max-age # is important, so clients don't cache tiles too long response.cache_control.max_age = current_app.get_send_file_max_age(None) # Last Modified is not strictly required, per RFC 2616 14.29, and setting # it accurately would require a database query; by leaving it unset, # user agents will use only If-None-Match with ETags for cache validation response.make_conditional(request) if response.status_code != 304: # Not Modified image_store = models.ImageStore.objects.get_or_404(id=image_store_id) try: tile_data = image_store.get_tile(image_id, tile_name) except models.DoesNotExist as e: # TODO: more specific exception current_app.logger.warning('Tile not loaded: %s' % e.message) return Response('{"error": "Tile loading error: %s"}' % e.message, status=404) response.set_data(tile_data) return response
@mod.route('/tile') # @security.login_required
[docs]def tile_query(): image_store_id = request.args.get('db') image_id = request.args.get('img') tile_name = request.args.get('name') return tile(image_store_id, image_id, tile_name) ################################################################################
@mod.route('/thumb/<ImageStore:image_store>/<Image:image>') # @security.login_required
[docs]def thumb(image_store, image): """ Return a thumbnail image """ # TODO: support Not Modified) responses, but only after thumbnails are # moved out of ImageStores; thumbnails are mutable, so 2 database lookups # will currently always have to be made try: tile_data = image_store.get_thumb(image) return Response(tile_data, mimetype='image/jpeg') except models.DoesNotExist as e: current_app.logger.warning('Thumb not available: %s' % e.message) return Response('{"error": "Thumb loading error: %s"}' % e.message, status=404) ################################################################################
@mod.route('/thumb') # @security.login_required
[docs]def thumb_query(): image_id = request.args.get('img') image_store_id = request.args.get('db') image_store = models.ImageStore.objects.get_or_404(id=image_store_id) with image_store: image = models.Image.objects.get_or_404(id=image_id) return thumb(image_store, image) ################################################################################
@mod.route('/viewthumb')
[docs]def thumb_from_view(): """ Gets a thumbnail from view directly, Chains the request to view objects helper method """ # Get parameters viewid = ObjectId(request.args.get("viewid", None)) # which = ObjectId(request.args.get("which","macro")) which = "macro" force = bool(request.args.get("force", False)) # Implementation without View viewcol = models.View._get_collection() viewobj = viewcol.find_one({"_id": viewid}) if "thumbs" not in viewobj: viewobj["thumbs"] = {} # Make thumbnail if force or which not in viewobj["thumbs"]: # Refresh the thumbnail if which not in ["macro"]: # Only know how to make macro image # Todo: add support for label supported raise Exception("%s thumbnail creation not supported" % which) # Make the thumb # Get the image store and image id and off load the request istore = models.ImageStore.objects.get(id=viewobj["ViewerRecords"][0]["Database"]) with istore: thumbimgdata = istore.make_thumb( models.Image.objects.get(id=viewobj["ViewerRecords"][0]["Image"])) viewcol.update({"_id": viewid}, {"$set": {"thumbs." + which: base64.b64encode(thumbimgdata)}}) viewobj = viewcol.find_one({"_id": viewid}) imagestr = viewobj["thumbs"][which] # current_app.logger.warning("Imagestr: " + imagestr) if int(request.args.get("binary", 0)): return Response(base64.b64decode(imagestr), mimetype="image/jpeg") else: return jsonify({which: imagestr})
@mod.route('/view')
[docs]def view_from_viewid(): """ redirects to the glviewer endpoint """ # Get parameters viewid = ObjectId(request.args.get("viewid", None)) # Implementation without View viewcol = models.View._get_collection() viewobj = viewcol.find_one({"_id": viewid}) return redirect("/webgl-viewer?db=%s&view=%s" % (viewobj["ViewerRecords"][0]["Database"], viewid), code=302)