Skip to content

Commit

Permalink
Merge pull request #1004 from biigle/screenshot-videos
Browse files Browse the repository at this point in the history
Add screenshot button to video annotator
  • Loading branch information
mzur authored Jan 28, 2025
2 parents 6999c17 + f2f18bc commit dfa70da
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 17 deletions.
2 changes: 2 additions & 0 deletions resources/assets/js/annotations/annotatorContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export default {
userUpdatedVolareResolution: false,
userId: null,
crossOriginError: false,
imageFilenames: {}
};
},
computed: {
Expand Down Expand Up @@ -682,6 +683,7 @@ export default {
this.volumeId = biigle.$require('annotations.volumeId');
this.isEditor = biigle.$require('annotations.isEditor');
this.userId = biigle.$require('annotations.userId');
this.imageFilenames = biigle.$require('annotations.imagesFilenames');
this.annotationFilters = [
new LabelFilter(),
new UserFilter(),
Expand Down
36 changes: 21 additions & 15 deletions resources/assets/js/annotations/components/screenshotButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,29 @@ import Keyboard from '../../core/keyboard';
* @type {Object}
*/
export default {
props: {
filenames: {
type: Array,
default: () => [],
},
currentId: {
type: Number,
default: -1,
},
ids: {
type: Array,
default: () => []
}
},
data() {
return {
filenames: {},
currentId: null,
};
filesObj: {}
}
},
computed: {
filename() {
if (this.currentId) {
let name = this.filenames[this.currentId].split('.');
let name = this.filesObj[this.currentId].split('.');
if (name.length > 1) {
name[name.length - 1] = 'png';
}
Expand Down Expand Up @@ -145,21 +158,14 @@ export default {
setMap(map) {
this.map = map;
},
updateCurrentId(id) {
this.currentId = id;
},
},
created() {
let ids = biigle.$require('annotations.imagesIds');
let filenames = {};
biigle.$require('annotations.imagesFilenames').forEach((filename, index) => {
filenames[ids[index]] = filename;
this.filenames.forEach((filename, index) => {
this.filesObj[this.ids[index]] = filename;
});
this.filenames = filenames;
this.currentId = biigle.$require('annotations.imageId');
Events.$on('images.change', this.updateCurrentId);
Events.$on('annotations.map.init', this.setMap);
Keyboard.on('p', this.capture);
Events.$on(['annotations.map.init', 'videos.map.init'], this.setMap);
},
};
</script>
12 changes: 12 additions & 0 deletions resources/assets/js/annotations/components/settingsTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ export default {
type: Object,
default: null,
},
imageFilenames: {
type: Array,
default: () => [],
},
currentId: {
type: Number,
default: -1,
},
ids: {
type: Array,
default: () => []
}
},
data() {
return {
Expand Down
22 changes: 22 additions & 0 deletions resources/assets/js/videos/components/settingsTab.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
<script>
import PowerToggle from '../../core/components/powerToggle';
import Settings from '../stores/settings';
import ScreenshotButton from '../../annotations/components/screenshotButton.vue';
import Keyboard from '../../core/keyboard';
export default {
components: {
powerToggle: PowerToggle,
screenshotButton: ScreenshotButton
},
props: {
supportsJumpByFrame: {
type: Boolean,
default: false,
},
crossOriginError: {
type: Boolean,
default: false,
},
videoFilenames: {
type: Array,
default: () => []
},
currentId: {
type: Number,
default: -1,
},
map: {
type: Object,
default: null,
},
ids: {
type: Array,
default: () => []
}
},
data() {
return {
Expand Down
16 changes: 16 additions & 0 deletions resources/assets/js/videos/videoContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ export default {
swappingLabel: false,
disableJobTracking: false,
supportsJumpByFrame: false,
hasCrossOriginError: false,
videoFilenames: null,
focusInputFindlabel: false,
};
},
Expand Down Expand Up @@ -563,6 +565,7 @@ export default {
let videoPromise = new Vue.Promise((resolve) => {
this.video.addEventListener('canplay', resolve);
});
videoPromise.then(this.checkCORSProperty);
let annotationPromise = VideoAnnotationApi.query({id: video.id});
let promise = Vue.Promise.all([annotationPromise, videoPromise])
.then(this.setAnnotations)
Expand Down Expand Up @@ -592,6 +595,16 @@ export default {
return promise;
},
checkCORSProperty() {
let testCanvas = document.createElement('canvas');
let ctx = testCanvas.getContext('2d');
ctx.drawImage(this.video, 0, 0);
try {
ctx.getImageData(0, 0, 1, 1);
} catch (e) {
this.hasCrossOriginError = true;
}
},
showPreviousVideo() {
this.reset();
let length = this.videoIds.length;
Expand Down Expand Up @@ -729,6 +742,7 @@ export default {
this.labelTrees = biigle.$require('videos.labelTrees');
this.errors = biigle.$require('videos.errors');
this.user = biigle.$require('videos.user');
this.videoFilenames = biigle.$require('videos.videoFilenames');
this.initAnnotationFilters();
this.restoreUrlParams();
Expand Down Expand Up @@ -775,6 +789,8 @@ export default {
if(navigator.userAgent.toLowerCase().indexOf('firefox') > -1){
Messages.danger('Current versions of the Firefox browser may not show the correct video frame for a given time. Annotations may be placed incorrectly. Please consider using Chrome until the issue is fixed in Firefox. Learn more on https://github.com/biigle/core/issues/391.');
}
Events.$emit('videos.map.init', this.$refs.videoScreen.map);
},
};
</script>
17 changes: 15 additions & 2 deletions resources/views/annotations/show/tabs/settings.blade.php
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
<sidebar-tab name="settings" icon="cog" title="Settings" :highlight="highlightSettingsTab">
<settings-tab v-cloak :image="image" v-on:change="handleSettingsChange" inline-template>
<settings-tab
v-cloak
:image="image"
:current-id="imageId"
:image-filenames="imageFilenames"
:ids="allImagesIds"
v-on:change="handleSettingsChange"
inline-template>
<div class="annotator-tab">
<div class="sidebar-tab__section">
<button v-if="crossOrigin" class="btn btn-default" title="Screenshots are not available for remote images without cross-origin resource sharing" disabled="disabled" ><span class="fa fa-camera" aria-hidden="true"></span> Capture screenshot</button>
<screenshot-button v-else inline-template>
<screenshot-button
v-else
inline-template
:current-id="currentId"
:filenames="imageFilenames"
:ids="ids"
>
<button class="btn btn-default" title="Get a screenshot of the visible area 𝗣" v-on:click="capture"><span class="fa fa-camera" aria-hidden="true"></span> Capture screenshot</button>
</screenshot-button>
</div>
Expand Down
3 changes: 3 additions & 0 deletions resources/views/manual/tutorials/videos/shortcuts.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@
<td><kbd>c</kbd></td>
<td>Select last created annotation</td>
</tr>
<tr>
<td><kbd>p</kbd></td>
<td>Capture a screenshot</td>
<tr>
<td><kbd>Ctrl</kbd>+<kbd>k</kbd></td>
<td>Open label trees sidebar and focus the find label input field</td>
Expand Down
16 changes: 16 additions & 0 deletions resources/views/videos/show/sidebar-settings.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,24 @@
<settings-tab inline-template
v-on:update="handleUpdatedSettings"
:supports-jump-by-frame="supportsJumpByFrame"
:cross-origin-error="hasCrossOriginError"
:current-id="videoId"
:video-filenames="videoFilenames"
:ids="videoIds"
>
<div class="annotator-tab settings-tab">
<div class="sidebar-tab__section">
<button v-if="crossOriginError" class="btn btn-default" title="Screenshots are not available for remote videos without cross-origin resource sharing" disabled="disabled" ><span class="fa fa-camera" aria-hidden="true"></span> Capture screenshot</button>
<screenshot-button
v-else
inline-template
:current-id="currentId"
:filenames="videoFilenames"
:ids="ids"
>
<button class="btn btn-default" title="Get a screenshot of the visible area 𝗣" v-on:click="capture"><span class="fa fa-camera" aria-hidden="true"></span> Capture screenshot</button>
</screenshot-button>
</div>

<div class="sidebar-tab__section">
<h5 title="Set the opacity of annotations">Annotation Opacity (<span v-text="annotationOpacity"></span>)</h5>
Expand Down

0 comments on commit dfa70da

Please sign in to comment.