Skip to content

Commit

Permalink
feat: Use the blurhash in Files
Browse files Browse the repository at this point in the history
Signed-off-by: Louis Chemineau <[email protected]>
  • Loading branch information
artonge authored and susnux committed Aug 29, 2024
1 parent 19dd329 commit 56e4859
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 11 deletions.
64 changes: 54 additions & 10 deletions apps/files/src/components/FileEntry/FileEntryPreview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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 />

Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -107,6 +114,7 @@ export default Vue.extend({
data() {
return {
backgroundFailed: undefined as boolean | undefined,
backgroundLoaded: false,
}
},

Expand Down Expand Up @@ -206,24 +214,60 @@ export default Vue.extend({

return null
},

hasBlurhash() {
return this.source.attributes['metadata-blurhash'] !== undefined
},
},

mounted() {
if (this.hasBlurhash && this.$refs.canvas) {
this.drawBlurhash()
}
},

methods: {
// Called from FileEntry
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,
Expand Down
15 changes: 14 additions & 1 deletion apps/files/src/components/FilesListVirtual.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

This comment has been minimized.

Copy link
@susnux

susnux Sep 6, 2024

Contributor

Scoping this to the container breaks fall back icons


&-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;
Expand Down
1 change: 1 addition & 0 deletions apps/files/src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"@vueuse/integrations": "^11.0.1",
"backbone": "^1.4.1",
"blueimp-md5": "^2.19.0",
"blurhash": "^2.0.5",
"browserslist-useragent-regexp": "^4.1.1",
"camelcase": "^8.0.0",
"cancelable-promise": "^4.3.1",
Expand Down

0 comments on commit 56e4859

Please sign in to comment.