mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Decode Blurhash pixels in a WebWorker
This commit is contained in:
parent
302094523e
commit
a47dd1b35c
2 changed files with 46 additions and 14 deletions
25
src/components/images/blurhash.worker.ts
Normal file
25
src/components/images/blurhash.worker.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { decode } from 'blurhash';
|
||||||
|
import { expose } from 'comlink';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes blurhash outside the main thread, in a web worker
|
||||||
|
*
|
||||||
|
* @param {string} hash - Hash to decode.
|
||||||
|
* @param {number} width - Width of the decoded pixel array
|
||||||
|
* @param {number} height - Height of the decoded pixel array.
|
||||||
|
* @param {number} punch - Contrast of the decoded pixels
|
||||||
|
* @returns {Uint8ClampedArray} - Returns the decoded pixels in the proxied response by Comlink
|
||||||
|
*/
|
||||||
|
function getPixels({
|
||||||
|
hash,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}): Uint8ClampedArray {
|
||||||
|
try {
|
||||||
|
return decode(hash, width, height);
|
||||||
|
} catch {
|
||||||
|
throw new TypeError(`Blurhash ${hash} is not valid`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expose(getPixels);
|
|
@ -1,6 +1,12 @@
|
||||||
import * as lazyLoader from '../lazyLoader/lazyLoaderIntersectionObserver';
|
import * as lazyLoader from '../lazyLoader/lazyLoaderIntersectionObserver';
|
||||||
import * as userSettings from '../../scripts/settings/userSettings';
|
import * as userSettings from '../../scripts/settings/userSettings';
|
||||||
import { decode, isBlurhashValid } from 'blurhash';
|
import { wrap } from 'comlink';
|
||||||
|
const getPixels = wrap(
|
||||||
|
new Worker(
|
||||||
|
// eslint-disable-next-line compat/compat
|
||||||
|
new URL('./blurhash.worker.ts', import.meta.url)
|
||||||
|
)
|
||||||
|
);
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
/* eslint-disable indent */
|
/* eslint-disable indent */
|
||||||
|
|
||||||
|
@ -12,21 +18,18 @@ import './style.scss';
|
||||||
fillImageElement(elem, source);
|
fillImageElement(elem, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
function itemBlurhashing(target, blurhashstr) {
|
async function itemBlurhashing(target, hash) {
|
||||||
if (isBlurhashValid(blurhashstr)) {
|
try {
|
||||||
// Although the default values recommended by Blurhash developers is 32x32, a size of 18x18 seems to be the sweet spot for us,
|
// Although the default values recommended by Blurhash developers is 32x32, a size of 18x18 seems to be the sweet spot for us,
|
||||||
// improving the performance and reducing the memory usage, while retaining almost full blur quality.
|
// improving the performance and reducing the memory usage, while retaining almost full blur quality.
|
||||||
// Lower values had more visible pixelation
|
// Lower values had more visible pixelation
|
||||||
const width = 18;
|
const width = 32;
|
||||||
const height = 18;
|
const height = 32;
|
||||||
let pixels;
|
const pixels = await getPixels({
|
||||||
try {
|
hash,
|
||||||
pixels = decode(blurhashstr, width, height);
|
width,
|
||||||
} catch (err) {
|
height
|
||||||
console.error('Blurhash decode error: ', err);
|
});
|
||||||
target.classList.add('non-blurhashable');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
canvas.width = width;
|
canvas.width = width;
|
||||||
canvas.height = height;
|
canvas.height = height;
|
||||||
|
@ -48,6 +51,10 @@ import './style.scss';
|
||||||
target.classList.add('blurhashed');
|
target.classList.add('blurhashed');
|
||||||
target.removeAttribute('data-blurhash');
|
target.removeAttribute('data-blurhash');
|
||||||
});
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
target.classList.add('non-blurhashable');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +149,7 @@ import './style.scss';
|
||||||
for (const lazyElem of elem.querySelectorAll('.lazy')) {
|
for (const lazyElem of elem.querySelectorAll('.lazy')) {
|
||||||
const blurhashstr = lazyElem.getAttribute('data-blurhash');
|
const blurhashstr = lazyElem.getAttribute('data-blurhash');
|
||||||
if (!lazyElem.classList.contains('blurhashed', 'non-blurhashable') && blurhashstr) {
|
if (!lazyElem.classList.contains('blurhashed', 'non-blurhashable') && blurhashstr) {
|
||||||
itemBlurhashing(lazyElem, blurhashstr);
|
Promise.resolve(itemBlurhashing(lazyElem, blurhashstr));
|
||||||
} else if (!blurhashstr && !lazyElem.classList.contains('blurhashed')) {
|
} else if (!blurhashstr && !lazyElem.classList.contains('blurhashed')) {
|
||||||
lazyElem.classList.add('non-blurhashable');
|
lazyElem.classList.add('non-blurhashable');
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue