diff options
author | Louis Chemineau <louis@chmn.me> | 2024-08-29 14:27:59 +0200 |
---|---|---|
committer | Ferdinand Thiessen <opensource@fthiessen.de> | 2024-08-29 23:08:11 +0200 |
commit | 56e4859201d80d3ea444bc88647d96ad71b59f88 (patch) | |
tree | b307b795be9ad14a471a90fd6794a264ef181faa /apps/files/src | |
parent | 19dd32962de7a73ecc934f8e7a5340d09fd24317 (diff) | |
download | nextcloud-server-56e4859201d80d3ea444bc88647d96ad71b59f88.tar.gz nextcloud-server-56e4859201d80d3ea444bc88647d96ad71b59f88.zip |
feat: Use the blurhash in Files
Signed-off-by: Louis Chemineau <louis@chmn.me>
Diffstat (limited to 'apps/files/src')
-rw-r--r-- | apps/files/src/components/FileEntry/FileEntryPreview.vue | 64 | ||||
-rw-r--r-- | apps/files/src/components/FilesListVirtual.vue | 15 | ||||
-rw-r--r-- | apps/files/src/init.ts | 1 |
3 files changed, 69 insertions, 11 deletions
diff --git a/apps/files/src/components/FileEntry/FileEntryPreview.vue b/apps/files/src/components/FileEntry/FileEntryPreview.vue index 2e43338cf05..6fe7a13a968 100644 --- a/apps/files/src/components/FileEntry/FileEntryPreview.vue +++ b/apps/files/src/components/FileEntry/FileEntryPreview.vue @@ -14,16 +14,22 @@ </template> </template> - <!-- Decorative image, should not be aria documented --> - <img v-else-if="previewUrl && backgroundFailed !== true" - ref="previewImg" - alt="" - class="files-list__row-icon-preview" - :class="{'files-list__row-icon-preview--loaded': backgroundFailed === false}" - loading="lazy" - :src="previewUrl" - @error="onBackgroundError" - @load="backgroundFailed = false"> + <!-- Decorative images, should not be aria documented --> + <span v-else-if="previewUrl" class="files-list__row-icon-preview-container"> + <canvas v-if="hasBlurhash && (backgroundFailed === true || !backgroundLoaded)" + ref="canvas" + class="files-list__row-icon-blurhash" + aria-hidden="true" /> + <img v-if="backgroundFailed !== true" + ref="previewImg" + alt="" + class="files-list__row-icon-preview" + :class="{'files-list__row-icon-preview--loaded': backgroundFailed === false}" + loading="lazy" + :src="previewUrl" + @error="onBackgroundError" + @load="onBackgroundLoad"> + </span> <FileIcon v-else v-once /> @@ -58,6 +64,7 @@ import LinkIcon from 'vue-material-design-icons/Link.vue' import NetworkIcon from 'vue-material-design-icons/Network.vue' import TagIcon from 'vue-material-design-icons/Tag.vue' import PlayCircleIcon from 'vue-material-design-icons/PlayCircle.vue' +import { decode } from 'blurhash' import CollectivesIcon from './CollectivesIcon.vue' import FavoriteIcon from './FavoriteIcon.vue' @@ -107,6 +114,7 @@ export default Vue.extend({ data() { return { backgroundFailed: undefined as boolean | undefined, + backgroundLoaded: false, } }, @@ -206,6 +214,16 @@ export default Vue.extend({ return null }, + + hasBlurhash() { + return this.source.attributes['metadata-blurhash'] !== undefined + }, + }, + + mounted() { + if (this.hasBlurhash && this.$refs.canvas) { + this.drawBlurhash() + } }, methods: { @@ -213,17 +231,43 @@ export default Vue.extend({ reset() { // Reset background state to cancel any ongoing requests this.backgroundFailed = undefined + this.backgroundLoaded = false if (this.$refs.previewImg) { this.$refs.previewImg.src = '' } }, + onBackgroundLoad() { + this.backgroundFailed = false + this.backgroundLoaded = true + }, + onBackgroundError(event) { // Do not fail if we just reset the background if (event.target?.src === '') { return } this.backgroundFailed = true + this.backgroundLoaded = false + }, + + drawBlurhash() { + const canvas = this.$refs.canvas as HTMLCanvasElement + + const width = canvas.width + const height = canvas.height + + const pixels = decode(this.source.attributes['metadata-blurhash'], width, height) + + const ctx = canvas.getContext('2d') + if (ctx === null) { + logger.error('Cannot create context for blurhash canvas') + return + } + + const imageData = ctx.createImageData(width, height) + imageData.data.set(pixels) + ctx.putImageData(imageData, 0, 0) }, t, diff --git a/apps/files/src/components/FilesListVirtual.vue b/apps/files/src/components/FilesListVirtual.vue index 14c846bc727..a791abdb3eb 100644 --- a/apps/files/src/components/FilesListVirtual.vue +++ b/apps/files/src/components/FilesListVirtual.vue @@ -556,11 +556,24 @@ export default defineComponent({ } } - &-preview { + &-preview-container { + position: relative; // Needed for the blurshash to be positioned correctly overflow: hidden; width: var(--icon-preview-size); height: var(--icon-preview-size); border-radius: var(--border-radius); + } + + &-blurhash { + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + object-fit: cover; + } + + &-preview { // Center and contain the preview object-fit: contain; object-position: center; diff --git a/apps/files/src/init.ts b/apps/files/src/init.ts index db4aec7fa06..0f4ef70b1b2 100644 --- a/apps/files/src/init.ts +++ b/apps/files/src/init.ts @@ -66,5 +66,6 @@ registerPreviewServiceWorker() registerDavProperty('nc:hidden', { nc: 'http://nextcloud.org/ns' }) registerDavProperty('nc:is-mount-root', { nc: 'http://nextcloud.org/ns' }) +registerDavProperty('nc:metadata-blurhash', { nc: 'http://nextcloud.org/ns' }) initLivePhotos() |