Commit 83fde84d2afb6e93b76213340269d7fa91c5b63c

Improvements in the image annotation from OCD results

  - Now client side is more intelligent in loading image from OCD search
    results for annotation. Also, an endpoint in the server is available to
check the resource type of a URL. The loadURL function can be told explicitly
what type of resource it has to load for annotation. If it is not told, it
tries to find out by various means.
  • Diff rendering mode:
  • inline
  • side by side

swtr/server.py

85# takes in `query`, `size`, and `from` parameters in query string85# takes in `query`, `size`, and `from` parameters in query string
86# returns a JSON response86# returns a JSON response
87@app.route('/search/ocd', methods=['GET'])87@app.route('/search/ocd', methods=['GET'])
88def search_ocd():
88def searchOCD():
89 query = flask.request.args.get('query')89 query = flask.request.args.get('query')
90 #collection = flask.request.args.get('collection')90 #collection = flask.request.args.get('collection')
91 size = flask.request.args.get('size') or 1091 size = flask.request.args.get('size') or 10
117117
118118
119# resolve OCD Media URLs: http://docs.opencultuurdata.nl/user/api.html#resolver119# resolve OCD Media URLs: http://docs.opencultuurdata.nl/user/api.html#resolver
120@app.route('/resolve-ocd-media/<media_hash>', methods=['GET'])
121def resolve_ocd_media_urls(media_hash):
120@app.route('/resolve-ocd-media', methods=['GET'])
121def resolveOCDMediaURLs():
122122
123 media_hash = flask.request.args.get('hash') or None
124
125 if not media_hash:
126 flask.abort(400)
127
123 resp = requests.get('http://api.opencultuurdata.nl/v0/resolve/' +128 resp = requests.get('http://api.opencultuurdata.nl/v0/resolve/' +
124 media_hash)129 media_hash)
125130
126 response = flask.make_response()
127 response.data = resp.url
128 return response
131 return flask.jsonify(url=resp.url)
129132
130133
134@app.route('/media-type', methods=['GET'])
135def getMediaType():
136
137 where = flask.request.args.get('where') or None
138
139 if not where:
140 flask.abort(400)
141
142 resp = requests.get(where)
143 content = resp.text
144
145 if imghdr.what('ignore', content) is None:
146 return flask.jsonify({'type': 'html'})
147 else:
148 return flask.jsonify({'type': 'image'})
149
150
131@app.route('/annotate', methods=['GET'])151@app.route('/annotate', methods=['GET'])
132def annotate():152def annotate():
133 # img = urllib2.urlopen(flask.request.args['where']).read()153 # img = urllib2.urlopen(flask.request.args['where']).read()
239 style.set("rel", "stylesheet")239 style.set("rel", "stylesheet")
240 style.set("type", "text/css")240 style.set("type", "text/css")
241241
242
243@app.route('/getMediaType')
244def getMediaType():
245 request = requests.get(flask.request.args['where'])
246 content = request.text
247 if imghdr.what('ignore', content) is None:
248 return flask.jsonify({'type': 'html'})
249 else:
250 return flask.jsonify({'type': 'image'})
251242
252# if the app is run directly from command-line243# if the app is run directly from command-line
253# assume its being run locally in a dev environment244# assume its being run locally in a dev environment

swtr/static/js/swtmaker.js

306 this.loadURL(input);306 this.loadURL(input);
307 }307 }
308 },308 },
309 loadURL: function(url) {
310 $('#ocd-results').hide();
309 loadURL: function(url, type) {
310 console.log('loadURL()');
311 if(this.source !== 'ocd') {
312 $('#ocd-results').hide();
313 }
311 $('#img-annotation-wrapper').show();314 $('#img-annotation-wrapper').show();
312 if(!url) {315 if(!url) {
313 return false;316 return false;
314 }317 }
315 // if image url then load the image annotation
318 // if type is given explicitly; we load it as such.
319 if(type === 'image') {
320 this.setImage(url);
321 return false;
322 }
323 // else try to find what resource is the URL..
324 // if url has an image extension then load the image annotation
316 if(url.match(/.jpg|.jpeg|.png|.gif|.bmp|.svg/)) {325 if(url.match(/.jpg|.jpeg|.png|.gif|.bmp|.svg/)) {
317
318 this.imgURL = url;
319
320 if(this.$img.attr('src') === this.imgURL) {
321 return;
322 }
323 anno.reset();
324 var self = this;
325 this.$overlay.show();
326 this.helpview.step(7);
327 this.$img.attr('src', this.imgURL);
326 this.setImage(url);
328 return false;327 return false;
329 }328 }
330 // else load text annotation
329 // else check with our /media-type endpoint to see what type of resource
330 // it is
331 else {331 else {
332 window.location.href = '/annotate?where=' + url;
332 this.helpview.step(12);
333 this.$overlay.show();
334 var self = this;
335 $.get('/media-type', {where: url}, function(response) {
336 //console.log(response);
337 self.$overlay.hide();
338 if(response.type === 'image') {
339 self.setImage(url);
340 }
341 else {
342 window.location.href = '/annotate?where=' + url;
343 }
344 });
333 }345 }
334 },346 },
347 setImage: function(url) {
348 this.imgURL = url;
349
350 if(this.$img.attr('src') === this.imgURL) {
351 return;
352 }
353 anno.reset();
354 var self = this;
355 this.$overlay.show();
356 this.helpview.step(7);
357 this.$img.attr('src', this.imgURL);
358 },
335 imageLoaded: function(event) {359 imageLoaded: function(event) {
336 var self = event.data;360 var self = event.data;
337 console.log('image loaded');361 console.log('image loaded');
635 var $row_el;635 var $row_el;
636 this.$el.html('');636 this.$el.html('');
637 _.each(this.model, function(item, idx) {637 _.each(this.model, function(item, idx) {
638 // put every 3 items in a row
638 if(idx % 3 === 0) {639 if(idx % 3 === 0) {
639 $row_el = $('<div class="row"></div>');640 $row_el = $('<div class="row"></div>');
640 this.$el.append($row_el);641 this.$el.append($row_el);
646 authors: item._source.authors646 authors: item._source.authors
647 }));647 }));
648 }, this);648 }, this);
649 this.resolve();
649 this.resolveOCDURLs();
650 },650 },
651 // resolve the OCD media URLs651 // resolve the OCD media URLs
652 resolve: function() {
652 resolveOCDURLs: function() {
653 var self = this;653 var self = this;
654 $('.ocd-item').each(function(idx, elem) {654 $('.ocd-item').each(function(idx, elem) {
655 var temp_arr = self.model[idx]._source.media_urls[0].url.split('/');655 var temp_arr = self.model[idx]._source.media_urls[0].url.split('/');
656 var media_hash = temp_arr[temp_arr.length - 1];656 var media_hash = temp_arr[temp_arr.length - 1];
657 $.get('/resolve-ocd-media/'+ media_hash, function(resp) {
658 $(elem).find('img').attr('src', resp);
657 $.get('/resolve-ocd-media', {hash: media_hash}, function(resp) {
658 $(elem).find('img').attr('src', resp.url);
659 });659 });
660 });660 });
661 },661 },
663 event.preventDefault();663 event.preventDefault();
664 // TODO: init the image anno664 // TODO: init the image anno
665 var url = $(event.currentTarget).find('img').attr('src');665 var url = $(event.currentTarget).find('img').attr('src');
666 swtr.appView.loadURL(url);
666 swtr.appView.loadURL(url, 'image');
667 return false;667 return false;
668 }668 }
669 });669 });
682 var text = '';682 var text = '';
683 switch (n) {683 switch (n) {
684 case 0 : text = 'Getting annotations..';684 case 0 : text = 'Getting annotations..';
685 break;
685 break;
686 case 1: text = 'Enter the URL of an image or web page below, and start annotating!';686 case 1: text = 'Enter the URL of an image or web page below, and start annotating!';
687 break;
687 break;
688 case 2: text = 'Annotate the image, or see other annotations';688 case 2: text = 'Annotate the image, or see other annotations';
689 break;
689 break;
690 case 3: text = 'Now you can sweet this annotation, or add more annotations';690 case 3: text = 'Now you can sweet this annotation, or add more annotations';
691 break;
691 break;
692 case 4: text = 'Click Sweet button to publish these annotations to the Sweet Store';692 case 4: text = 'Click Sweet button to publish these annotations to the Sweet Store';
693 break;
693 break;
694 case 5: text = 'Publishing your sweets';694 case 5: text = 'Publishing your sweets';
695 break;
695 break;
696 case 6: text = 'Sweets successfully posted';696 case 6: text = 'Sweets successfully posted';
697 break;
697 break;
698 case 7: text = 'Fetching your image..';698 case 7: text = 'Fetching your image..';
699 break;
699 break;
700 case 8: text = 'Oops! Seems like the image URL is wrong! Or we couldn\'t fetch the image.';700 case 8: text = 'Oops! Seems like the image URL is wrong! Or we couldn\'t fetch the image.';
701 break;
701 break;
702 case 9: text = 'You have to be <i>signed in</i> to sweet store to post sweets';702 case 9: text = 'You have to be <i>signed in</i> to sweet store to post sweets';
703 break;
703 break;
704 case 10: text = 'Oops! Something went wrong. We couldn\'t publish the sweets. Try again.'704 case 10: text = 'Oops! Something went wrong. We couldn\'t publish the sweets. Try again.'
705 break;
705 break;
706 case 11: text = 'Search in <a href="http://www.opencultuurdata.nl/">Open Cuultur Data API</a>';706 case 11: text = 'Search in <a href="http://www.opencultuurdata.nl/">Open Cuultur Data API</a>';
707 break;
707 break;
708 case 12: text = 'Analyzing the resource type..';
709 break;
708 }710 }
709 $(this.el).html(text);711 $(this.el).html(text);
710 $(window).scrollTop(0, 0);712 $(window).scrollTop(0, 0);

swtr/templates/index.html

71 <div class="row">71 <div class="row">
72 <div id="img-annotation-wrapper" class="col-md-12 col-xs-12 col-lg-12 col-sm-12 well">72 <div id="img-annotation-wrapper" class="col-md-12 col-xs-12 col-lg-12 col-sm-12 well">
73 {% if url %}73 {% if url %}
74 <img src="{{ url }}" id="annotatable-img" class="img-responsive">
74 <img src="{{ url }}" id="annotatable-img" class="img-responsive" alt="Annotation Workbench">
75 {% else %}75 {% else %}
76 <img src="" id="annotatable-img" class="img-responsive">
76 <img src="" id="annotatable-img" class="img-responsive" alt="Annotation Workbench">
77 {% endif %}77 {% endif %}
78 </div>78 </div>
79 <div id="ocd-results"></div>79 <div id="ocd-results"></div>