Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add screenshot button to video annotator #1004

Merged
merged 26 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from 17 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
5 changes: 5 additions & 0 deletions resources/assets/js/annotations/annotatorContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ export default {
userUpdatedVolareResolution: false,
userId: null,
crossOriginError: false,
map: null,
imagesObj: {}
};
},
computed: {
Expand Down Expand Up @@ -676,6 +678,7 @@ export default {
this.volumeId = biigle.$require('annotations.volumeId');
this.isEditor = biigle.$require('annotations.isEditor');
this.userId = biigle.$require('annotations.userId');
this.imagesObj = biigle.$require('annotations.imagesObj');
this.annotationFilters = [
new LabelFilter(),
new UserFilter(),
Expand Down Expand Up @@ -751,7 +754,9 @@ export default {
Keyboard.on('C', this.selectLastAnnotation, 0, this.listenerSet);
},
mounted() {
// Event is used in laserpointer module
Events.$emit('annotations.map.init', this.$refs.canvas.map);
this.map = this.$refs.canvas.map;
mzur marked this conversation as resolved.
Show resolved Hide resolved
},
};
</script>
36 changes: 14 additions & 22 deletions resources/assets/js/annotations/components/screenshotButton.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<script>
import Events from '../../core/events';
import Messages from '../../core/messages/store';
import Keyboard from '../../core/keyboard';

Expand All @@ -9,16 +8,24 @@ import Keyboard from '../../core/keyboard';
* @type {Object}
*/
export default {
data() {
return {
filenames: {},
currentId: null,
};
props: {
filesObj: {
type: Object,
default: () => {}
},
mzur marked this conversation as resolved.
Show resolved Hide resolved
currentId: {
type: Number,
default: -1,
},
map: {
type: Object,
default: null,
}
},
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 @@ -142,23 +149,8 @@ export default {
handleError(message) {
Messages.danger(message);
},
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 = 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);
},
};
Expand Down
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 @@ -28,6 +28,18 @@ export default {
type: Object,
default: null,
},
imagesObj: {
type: Object,
default: () => {},
},
currentId: {
type: Number,
default: -1,
},
map: {
type: Object,
default: null,
}
},
data() {
return {
Expand Down
18 changes: 18 additions & 0 deletions resources/assets/js/videos/components/settingsTab.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,34 @@
<script>
import PowerToggle from '../../core/components/powerToggle';
import Settings from '../stores/settings';
import ScreenshotButton from '../../annotations/components/screenshotButton.vue';

export default {
components: {
powerToggle: PowerToggle,
screenshotButton: ScreenshotButton
},
props: {
supportsJumpByFrame: {
type: Boolean,
default: false,
},
crossOriginError: {
type: Boolean,
default: false,
},
videosObj: {
type: Object,
default: () => {}
},
currentId: {
type: Number,
default: -1,
},
map: {
type: Object,
default: null,
}
},
data() {
return {
Expand Down
21 changes: 20 additions & 1 deletion resources/assets/js/videos/videoContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ export default {
swappingLabel: false,
disableJobTracking: false,
supportsJumpByFrame: false,
hasCrossOriginError: false,
map: null,
videosObj: null,
};
},
computed: {
Expand Down Expand Up @@ -551,7 +554,10 @@ export default {
},
fetchVideoContent(video) {
let videoPromise = new Vue.Promise((resolve) => {
this.video.addEventListener('canplay', resolve);
this.video.addEventListener('canplay', () => {
this.checkCORSProperty();
resolve();
});
});
mzur marked this conversation as resolved.
Show resolved Hide resolved
let annotationPromise = VideoAnnotationApi.query({id: video.id});
let promise = Vue.Promise.all([annotationPromise, videoPromise])
Expand Down Expand Up @@ -582,6 +588,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 @@ -709,6 +725,7 @@ export default {
this.labelTrees = biigle.$require('videos.labelTrees');
this.errors = biigle.$require('videos.errors');
this.user = biigle.$require('videos.user');
this.videosObj = biigle.$require('videos.videosObj');

this.initAnnotationFilters();
this.restoreUrlParams();
Expand Down Expand Up @@ -752,6 +769,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.');
}

this.map = this.$refs.videoScreen.map;
},
};
</script>
1 change: 1 addition & 0 deletions resources/views/annotations/show.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
biigle.$declare('annotations.shapes', {!! $shapes !!});
biigle.$declare('annotations.imagesIds', {!! $images->keys() !!});
biigle.$declare('annotations.imagesFilenames', {!! $images->values() !!});
biigle.$declare('annotations.imagesObj', {!! $images !!});
mzur marked this conversation as resolved.
Show resolved Hide resolved
biigle.$declare('annotations.imageFileUri', '{!! url('api/v1/images/:id/file') !!}');
biigle.$declare('annotations.tilesUri', '{{ $tilesUriTemplate }}');
biigle.$declare('annotations.sessions', {!!$annotationSessions!!});
Expand Down
16 changes: 14 additions & 2 deletions resources/views/annotations/show/tabs/settings.blade.php
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
<sidebar-tab name="settings" icon="cog" title="Settings">
<settings-tab v-cloak :image="image" v-on:change="handleSettingsChange" inline-template>
<settings-tab
v-cloak
:image="image"
:current-id="imageId"
:images-obj="imagesObj"
:map="map"
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"
:files-obj="imagesObj"
:map="map">
<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
4 changes: 4 additions & 0 deletions resources/views/manual/tutorials/videos/shortcuts.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@
<td><kbd>c</kbd></td>
<td>Select last created annotation</td>
</tr>
<tr>
<td><kbd>p</kbd></td>
<td>Capture a screenshot</td>
</tr>
</tbody>
</table>

Expand Down
1 change: 1 addition & 0 deletions resources/views/videos/show.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class="sidebar-container__content"
biigle.$declare('videos.isEditor', @can('add-annotation', $video) true @else false @endcan);
biigle.$declare('videos.videoIds', {!! $videos->keys() !!});
biigle.$declare('videos.videoFilenames', {!! $videos->values() !!});
biigle.$declare('videos.videosObj', {!! $videos !!});
mzur marked this conversation as resolved.
Show resolved Hide resolved
biigle.$declare('videos.user', {!! $user !!});
biigle.$declare('videos.isAdmin', @can('update', $volume) true @else false @endcan);
biigle.$declare('videos.fileUuids', {!! $fileIds !!});
Expand Down
15 changes: 15 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,23 @@
<settings-tab inline-template
v-on:update="handleUpdatedSettings"
:supports-jump-by-frame="supportsJumpByFrame"
:cross-origin-error="hasCrossOriginError"
:current-id="videoId"
:videos-obj="videosObj"
:map="map"
>
<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"
:files-obj="videosObj"
:map="map">
<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