mirror of
https://github.com/KevinMidboe/immich.git
synced 2025-12-08 20:29:05 +00:00
feat(web,server): add thumbhash support (#2649)
* add thumbhash: server generation and web impl * move logic to infra & use byta in db * remove unnecesary logs * update generated API and simplify thumbhash gen * fix check errors * removed unnecessary library and css tag * style edits * syntax mistake * update server test, change thumbhash job name * fix tests * Update server/src/domain/asset/response-dto/asset-response.dto.ts Co-authored-by: Thomas <9749173+uhthomas@users.noreply.github.com> * add unit test, change migration date * change to official thumbhash impl * update call method to not use eval * "generate missing" looks for thumbhash * improve queue & improve syntax * update syntax again * update tests * fix thumbhash generation * consolidate queueing to avoid duplication * cover all types of incorrect thumbnail cases * split out jest tasks * put back thumbnail duration loading for images without thumbhash * Remove stray package.json --------- Co-authored-by: Luke McCarthy <mail@lukehmcc.com> Co-authored-by: Thomas <9749173+uhthomas@users.noreply.github.com> Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
61
web/package-lock.json
generated
61
web/package-lock.json
generated
@@ -20,7 +20,8 @@
|
||||
"rxjs": "^7.8.0",
|
||||
"socket.io-client": "^4.6.1",
|
||||
"svelte-local-storage-store": "^0.5.0",
|
||||
"svelte-material-icons": "^3.0.4"
|
||||
"svelte-material-icons": "^3.0.4",
|
||||
"unlazy": "^0.8.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
@@ -4134,6 +4135,15 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@unlazy/core": {
|
||||
"version": "0.8.9",
|
||||
"resolved": "https://registry.npmjs.org/@unlazy/core/-/core-0.8.9.tgz",
|
||||
"integrity": "sha512-DQ4WB/cuEWTknU/59uRwpSipvMAJzBDmRyaHDUc1RcXi0Z7/Vcl0EE7BpROxEynqd1EI+2oMWQaDLyXffUdUiA==",
|
||||
"dependencies": {
|
||||
"fast-blurhash": "^1.1.2",
|
||||
"thumbhash": "^0.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@zoom-image/core": {
|
||||
"version": "0.18.2",
|
||||
"resolved": "https://registry.npmjs.org/@zoom-image/core/-/core-0.18.2.tgz",
|
||||
@@ -5945,6 +5955,11 @@
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-blurhash": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-blurhash/-/fast-blurhash-1.1.2.tgz",
|
||||
"integrity": "sha512-lJVOgYSlahqkRhrKumNx/SGB2F/qS0D1z7xjGYjb5EZJRtlzySGMniZjkQ9h9Rv8sPmM/V9orEgRiMwazDNH6A=="
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
@@ -11217,6 +11232,11 @@
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/thumbhash": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/thumbhash/-/thumbhash-0.1.1.tgz",
|
||||
"integrity": "sha512-kH5pKeIIBPQXAOni2AiY/Cu/NKdkFREdpH+TLdM0g6WA7RriCv0kPLgP731ady67MhTAqrVG/4mnEeibVuCJcg=="
|
||||
},
|
||||
"node_modules/tiny-glob": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
|
||||
@@ -11441,6 +11461,18 @@
|
||||
"node": ">= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unlazy": {
|
||||
"version": "0.8.9",
|
||||
"resolved": "https://registry.npmjs.org/unlazy/-/unlazy-0.8.9.tgz",
|
||||
"integrity": "sha512-lRCuXN20N1esqSQqtSVBLAw9GJz0lcBuOBs3UGGw7cFWHQlWJVZZ3OviwOl42f1CnVHjAON1rs2hIdJWgMAUyg==",
|
||||
"dependencies": {
|
||||
"@unlazy/core": "0.8.9"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"fast-blurhash": "^1.1.2",
|
||||
"thumbhash": "^0.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/update-browserslist-db": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
|
||||
@@ -14739,6 +14771,15 @@
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"@unlazy/core": {
|
||||
"version": "0.8.9",
|
||||
"resolved": "https://registry.npmjs.org/@unlazy/core/-/core-0.8.9.tgz",
|
||||
"integrity": "sha512-DQ4WB/cuEWTknU/59uRwpSipvMAJzBDmRyaHDUc1RcXi0Z7/Vcl0EE7BpROxEynqd1EI+2oMWQaDLyXffUdUiA==",
|
||||
"requires": {
|
||||
"fast-blurhash": "^1.1.2",
|
||||
"thumbhash": "^0.1.1"
|
||||
}
|
||||
},
|
||||
"@zoom-image/core": {
|
||||
"version": "0.18.2",
|
||||
"resolved": "https://registry.npmjs.org/@zoom-image/core/-/core-0.18.2.tgz",
|
||||
@@ -16053,6 +16094,11 @@
|
||||
"source-map-support": "^0.5.21"
|
||||
}
|
||||
},
|
||||
"fast-blurhash": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-blurhash/-/fast-blurhash-1.1.2.tgz",
|
||||
"integrity": "sha512-lJVOgYSlahqkRhrKumNx/SGB2F/qS0D1z7xjGYjb5EZJRtlzySGMniZjkQ9h9Rv8sPmM/V9orEgRiMwazDNH6A=="
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
@@ -19861,6 +19907,11 @@
|
||||
"thenify": ">= 3.1.0 < 4"
|
||||
}
|
||||
},
|
||||
"thumbhash": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/thumbhash/-/thumbhash-0.1.1.tgz",
|
||||
"integrity": "sha512-kH5pKeIIBPQXAOni2AiY/Cu/NKdkFREdpH+TLdM0g6WA7RriCv0kPLgP731ady67MhTAqrVG/4mnEeibVuCJcg=="
|
||||
},
|
||||
"tiny-glob": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
|
||||
@@ -20023,6 +20074,14 @@
|
||||
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
|
||||
"dev": true
|
||||
},
|
||||
"unlazy": {
|
||||
"version": "0.8.9",
|
||||
"resolved": "https://registry.npmjs.org/unlazy/-/unlazy-0.8.9.tgz",
|
||||
"integrity": "sha512-lRCuXN20N1esqSQqtSVBLAw9GJz0lcBuOBs3UGGw7cFWHQlWJVZZ3OviwOl42f1CnVHjAON1rs2hIdJWgMAUyg==",
|
||||
"requires": {
|
||||
"@unlazy/core": "0.8.9"
|
||||
}
|
||||
},
|
||||
"update-browserslist-db": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"rxjs": "^7.8.0",
|
||||
"socket.io-client": "^4.6.1",
|
||||
"svelte-local-storage-store": "^0.5.0",
|
||||
"svelte-material-icons": "^3.0.4"
|
||||
"svelte-material-icons": "^3.0.4",
|
||||
"unlazy": "^0.8.9"
|
||||
}
|
||||
}
|
||||
|
||||
6
web/src/api/open-api/api.ts
generated
6
web/src/api/open-api/api.ts
generated
@@ -637,6 +637,12 @@ export interface AssetResponseDto {
|
||||
* @memberof AssetResponseDto
|
||||
*/
|
||||
'resized': boolean;
|
||||
/**
|
||||
* base64 encoded thumbhash
|
||||
* @type {string}
|
||||
* @memberof AssetResponseDto
|
||||
*/
|
||||
'thumbhash': string | null;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
altText={person.name}
|
||||
widthStyle="90px"
|
||||
heightStyle="90px"
|
||||
thumbhash={null}
|
||||
/>
|
||||
<p class="font-medium mt-1 truncate">{person.name}</p>
|
||||
</a>
|
||||
|
||||
@@ -1,27 +1,58 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { lazyLoad } from 'unlazy';
|
||||
import { imageLoad } from '$lib/utils/image-load';
|
||||
|
||||
export let url: string;
|
||||
export let altText: string;
|
||||
export let heightStyle: string | undefined = undefined;
|
||||
export let widthStyle: string;
|
||||
export let thumbhash: string | null = null;
|
||||
export let curve = false;
|
||||
export let shadow = false;
|
||||
export let circle = false;
|
||||
let loading = true;
|
||||
|
||||
let imageElement: HTMLImageElement;
|
||||
|
||||
onMount(() => {
|
||||
if (thumbhash) {
|
||||
lazyLoad(imageElement, {
|
||||
hash: thumbhash,
|
||||
hashType: 'thumbhash'
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<img
|
||||
style:width={widthStyle}
|
||||
style:height={heightStyle}
|
||||
src={url}
|
||||
alt={altText}
|
||||
class="object-cover transition-opacity duration-300"
|
||||
class:rounded-lg={curve}
|
||||
class:shadow-lg={shadow}
|
||||
class:rounded-full={circle}
|
||||
class:opacity-0={loading}
|
||||
draggable="false"
|
||||
use:imageLoad
|
||||
on:image-load|once={() => (loading = false)}
|
||||
/>
|
||||
{#if thumbhash}
|
||||
<img
|
||||
style:width={widthStyle}
|
||||
style:height={heightStyle}
|
||||
data-src={url}
|
||||
alt={altText}
|
||||
class="object-cover"
|
||||
class:rounded-lg={curve}
|
||||
class:shadow-lg={shadow}
|
||||
class:rounded-full={circle}
|
||||
draggable="false"
|
||||
bind:this={imageElement}
|
||||
/>
|
||||
|
||||
<!-- not everthing yet has thumbhash support so the old method is kept -->
|
||||
{:else}
|
||||
<img
|
||||
style:width={widthStyle}
|
||||
style:height={heightStyle}
|
||||
src={url}
|
||||
alt={altText}
|
||||
class="object-cover transition-opacity duration-300"
|
||||
class:rounded-lg={curve}
|
||||
class:shadow-lg={shadow}
|
||||
class:rounded-full={circle}
|
||||
class:opacity-0={loading}
|
||||
draggable="false"
|
||||
use:imageLoad
|
||||
on:image-load|once={() => (loading = false)}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -129,6 +129,7 @@
|
||||
altText={asset.originalFileName}
|
||||
widthStyle="{width}px"
|
||||
heightStyle="{height}px"
|
||||
thumbhash={asset.thumbhash}
|
||||
/>
|
||||
{:else}
|
||||
<div class="w-full h-full p-4 flex items-center justify-center">
|
||||
|
||||
Reference in New Issue
Block a user