Merge pull request #50 from DarkKirb/fix-pleroma-fe-jxl-polyfill

Fix the pleroma-fe jxl polyfill patch
This commit is contained in:
Charlotte 🦝 Delenk 2022-12-02 09:51:42 +01:00 committed by GitHub
commit 55703ca8f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -92,21 +92,105 @@ index 19a7e186..54a9c4af 100644
"engines": {
"node": ">= 16.0.0",
diff --git a/src/App.js b/src/App.js
index d4b3b41a..ee75815b 100644
index d4b3b41a..ef67a6a4 100644
--- a/src/App.js
+++ b/src/App.js
@@ -53,6 +53,11 @@ export default {
@@ -53,6 +53,9 @@ export default {
unmounted () {
window.removeEventListener('resize', this.updateMobileState)
},
+ mounted() {
+ let jxlPolyfill = document.createElement("script");
+ jxlPolyfill.setAttribute("src", "/node_modules/jxl.js/jxl.js");
+ document.head.appendChild(jxlPolyfill);
+ import("./lib/jxl.js").then(jxl => jxl.startPolyfill());
+ },
computed: {
classes () {
return [
diff --git a/src/lib/jxl.js b/src/lib/jxl.js
new file mode 100644
index 00000000..568b5293
--- /dev/null
+++ b/src/lib/jxl.js
@@ -0,0 +1,80 @@
+const config = {
+ useCache: true
+};
+
+let cache, workers = {};
+
+function imgDataToDataURL(img, imgData, isCSS) {
+ const jxlSrc = img.dataset.jxlSrc;
+ if (imgData instanceof Blob) {
+ const dataURL = URL.createObjectURL(imgData);
+ if (isCSS)
+ img.style.backgroundImage = 'url("' + dataURL + '")';
+ else
+ img.src = dataURL;
+ } else if ('OffscreenCanvas' in window) {
+ const canvas = new OffscreenCanvas(imgData.width, imgData.height);
+ workers[jxlSrc].postMessage({ canvas, imgData }, [canvas]);
+ workers[jxlSrc].addEventListener('message', m => {
+ if (m.data.url && m.data.blob) {
+ if (isCSS)
+ img.style.backgroundImage = 'url("' + m.data.url + '")';
+ else
+ img.src = m.data.url;
+ config.useCache && cache && cache.put(jxlSrc, new Response(m.data.blob));
+ }
+ });
+ } else {
+ const canvas = document.createElement('canvas');
+ canvas.width = imgData.width;
+ canvas.height = imgData.height;
+ canvas.getContext('2d').putImageData(imgData, 0, 0);
+ canvas.toBlob(blob => {
+ const dataURL = URL.createObjectURL(blob);
+ if (isCSS)
+ img.style.backgroundImage = 'url("' + dataURL + '")';
+ else
+ img.src = dataURL;
+ config.useCache && cache && cache.put(jxlSrc, new Response(blob));
+ }, 'image/jpeg');
+ }
+}
+
+
+async function decode(img, isCSS) {
+ const jxlSrc = img.dataset.jxlSrc = isCSS ? getComputedStyle(img).backgroundImage.slice(5, -2) : img.currentSrc;
+ img.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='; // blank 1x1 image
+ if (config.useCache) {
+ try {
+ cache = cache || await caches.open('jxl');
+ } catch (e) { }
+ const cachedImg = cache && await cache.match(jxlSrc);
+ if (cachedImg) {
+ const cachedImgData = await cachedImg.blob();
+ requestAnimationFrame(() => imgDataToDataURL(img, cachedImgData, isCSS));
+ return;
+ }
+ }
+ const res = await fetch(jxlSrc);
+ const image = await res.arrayBuffer();
+ workers[jxlSrc] = new Worker('/node_modules/jxl.js/jxl_dec.js');
+ workers[jxlSrc].postMessage({ jxlSrc, image });
+ workers[jxlSrc].addEventListener('message', m => m.data.imgData && requestAnimationFrame(() => imgDataToDataURL(img, m.data.imgData, isCSS)));
+}
+
+function handleElement(el) {
+ if (el instanceof HTMLImageElement && el.src.endsWith('.jxl')) {
+ decode(el, false);
+ return;
+ } else if (el instanceof Element && getComputedStyle(el).backgroundImage.endsWith('.jxl)'))
+ decode(el, true);
+ el.childNodes.forEach(handleElement);
+}
+
+
+export function startPolyfill() {
+ new MutationObserver(mutations => mutations.forEach(mutation => {
+ mutation.addedNodes.forEach(handleElement);
+ })).observe(document.documentElement, { subtree: true, childList: true });
+ handleElement(document.documentElement); // Run the polyfill once on the full DOM
+}
diff --git a/yarn.lock b/yarn.lock
index bbceba0b..92cfd7cd 100644
--- a/yarn.lock