next-blurhash-previews 0.0.3-beta51 → 0.0.3-beta52
Sign up to get free protection for your applications and to get access to all the features.
- package/.vscode/settings.json +10 -0
- package/components/ImageWithPreview.tsx +15 -6
- package/components/imagePreviewBootstrap.tsx +13 -4
- package/components/workerScript.ts +20 -0
- package/imagePreviewBootstrap.js +13 -4
- package/package.json +2 -2
- package/util/setBootstrap.js +19 -20
- package/{vite.config.ts → vite.wc.config.ts} +3 -6
- package/vite.worker.config.ts +18 -0
- package/vite.b.config.ts +0 -40
@@ -2,6 +2,9 @@ import { decode } from "blurhash/dist/esm";
|
|
2
2
|
|
3
3
|
type blurhash = { w: number; h: number; blurhash: string };
|
4
4
|
|
5
|
+
declare function __blurhashDecode(blurhash: string, width: number, height: any);
|
6
|
+
(window as any).__blurhashDecode = decode;
|
7
|
+
|
5
8
|
class ImageWithPreview extends HTMLElement {
|
6
9
|
sd: ShadowRoot;
|
7
10
|
mo?: MutationObserver;
|
@@ -81,12 +84,18 @@ function updateBlurHashPreview(canvasEl: HTMLCanvasElement, preview: blurhash) {
|
|
81
84
|
canvasEl.width = width;
|
82
85
|
canvasEl.height = height;
|
83
86
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
87
|
+
if (true) {
|
88
|
+
const workerBlob = new Blob(
|
89
|
+
[document.querySelector("#next-blurhash-worker-script")!.textContent!],
|
90
|
+
{ type: "text/javascript" }
|
91
|
+
);
|
92
|
+
|
93
|
+
const worker = new Worker(window.URL.createObjectURL(workerBlob));
|
94
|
+
const offscreen = (canvasEl as any).transferControlToOffscreen();
|
95
|
+
worker.postMessage({ canvas: offscreen, width, height, blurhash }, [
|
96
|
+
offscreen,
|
97
|
+
]);
|
98
|
+
}
|
90
99
|
|
91
100
|
return;
|
92
101
|
const pixels = decode(blurhash, width, height);
|
@@ -1,5 +1,14 @@
|
|
1
|
-
import { createElement } from "react";
|
1
|
+
import { createElement, Fragment } from "react";
|
2
2
|
|
3
|
-
export const imagePreviewBootstrap = createElement(
|
4
|
-
|
5
|
-
}
|
3
|
+
export const imagePreviewBootstrap = createElement(
|
4
|
+
Fragment,
|
5
|
+
{},
|
6
|
+
createElement("script", {
|
7
|
+
dangerouslySetInnerHTML: { __html: `(() => { /*WC*/ })();` },
|
8
|
+
}),
|
9
|
+
createElement("script", {
|
10
|
+
id: "next-blurhash-worker-script",
|
11
|
+
type: "javascript/worker",
|
12
|
+
dangerouslySetInnerHTML: { __html: `(() => { /*WORKER*/ })();` },
|
13
|
+
})
|
14
|
+
);
|
@@ -0,0 +1,20 @@
|
|
1
|
+
declare function __blurhashDecode(blurhash: string, width: number, height: any);
|
2
|
+
|
3
|
+
addEventListener("message", evt => {
|
4
|
+
console.log(evt);
|
5
|
+
|
6
|
+
const { canvas, width, height, blurhash } = evt.data;
|
7
|
+
|
8
|
+
const p = new Promise(res => setTimeout(res, 5000));
|
9
|
+
Promise.resolve(p).then(() => {
|
10
|
+
console.log("Encoding", blurhash);
|
11
|
+
const start = +new Date();
|
12
|
+
const pixels = __blurhashDecode(blurhash, width, height);
|
13
|
+
const ctx = canvas.getContext("2d");
|
14
|
+
const imageData = ctx.createImageData(width, height);
|
15
|
+
imageData.data.set(pixels);
|
16
|
+
ctx.putImageData(imageData, 0, 0);
|
17
|
+
const end = +new Date();
|
18
|
+
console.log("Done Encoding", blurhash, end - start);
|
19
|
+
});
|
20
|
+
});
|
package/imagePreviewBootstrap.js
CHANGED
@@ -1,5 +1,14 @@
|
|
1
|
-
import { createElement } from "react";
|
1
|
+
import { createElement, Fragment } from "react";
|
2
2
|
|
3
|
-
export const imagePreviewBootstrap = createElement(
|
4
|
-
|
5
|
-
}
|
3
|
+
export const imagePreviewBootstrap = createElement(
|
4
|
+
Fragment,
|
5
|
+
{},
|
6
|
+
createElement("script", {
|
7
|
+
dangerouslySetInnerHTML: { __html: `(() => { "use strict";const k=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","#","$","%","*","+",",","-",".",":",";","=","?","@","[","]","^","_","{","|","}","~"],u=t=>{let e=0;for(let s=0;s<t.length;s++){const n=t[s],i=k.indexOf(n);e=e*83+i}return e},M=t=>{let e=t/255;return e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4)},p=t=>{let e=Math.max(0,Math.min(1,t));return e<=.0031308?Math.round(e*12.92*255+.5):Math.round((1.055*Math.pow(e,.4166666666666667)-.055)*255+.5)},E=t=>t<0?-1:1,v=(t,e)=>E(t)*Math.pow(Math.abs(t),e);class C extends Error{constructor(e){super(e),this.name="ValidationError",this.message=e}}const P=t=>{if(!t||t.length<6)throw new C("The blurhash string must be at least 6 characters");const e=u(t[0]),s=Math.floor(e/9)+1,n=e%9+1;if(t.length!==4+2*n*s)throw new C(\`blurhash length mismatch: length is \${t.length} but it should be \${4+2*n*s}\`)},A=t=>{const e=t>>16,s=t>>8&255,n=t&255;return[M(e),M(s),M(n)]},O=(t,e)=>{const s=Math.floor(t/361),n=Math.floor(t/19)%19,i=t%19;return[v((s-9)/9,2)*e,v((n-9)/9,2)*e,v((i-9)/9,2)*e]},G=(t,e,s,n)=>{P(t),n=n|1;const i=u(t[0]),c=Math.floor(i/9)+1,a=i%9+1,L=(u(t[1])+1)/166,d=new Array(a*c);for(let o=0;o<d.length;o++)if(o===0){const r=u(t.substring(2,6));d[o]=A(r)}else{const r=u(t.substring(4+o*2,6+o*2));d[o]=O(r,L*n)}const l=e*4,h=new Uint8ClampedArray(l*s);for(let o=0;o<s;o++)for(let r=0;r<e;r++){let x=0,y=0,B=0;for(let m=0;m<c;m++)for(let g=0;g<a;g++){const f=Math.cos(Math.PI*r*g/e)*Math.cos(Math.PI*o*m/s);let b=d[g+m*a];x+=b[0]*f,y+=b[1]*f,B+=b[2]*f}let R=p(x),q=p(y),T=p(B);h[4*r+0+o*l]=R,h[4*r+1+o*l]=q,h[4*r+2+o*l]=T,h[4*r+3+o*l]=255}return h};var S=G;window.__blurhashDecode=S;class j extends HTMLElement{sd;mo;static observedAttributes=["preview"];#s=!1;get#t(){return this.querySelector("img")}get#e(){return this.querySelector("canvas")}constructor(){super(),this.sd=this.attachShadow({mode:"open"}),this.sd.innerHTML='<slot name="preview"></slot>'}#n=()=>{if(this.#t&&this.#e)return this.mo?.disconnect(),this.#t.complete?this.#o():(this.#r(),this.#t.addEventListener("load",this.#o)),!0};connectedCallback(){this.#s=!0,this.#n()||(this.mo=new MutationObserver(this.#n),this.mo.observe(this,{subtree:!0,childList:!0,attributes:!1}))}#o=()=>{setTimeout(()=>{this.sd.innerHTML='<slot name="image"></slot>'},19e3)};attributeChangedCallback(e){this.#e&&e==="preview"&&this.#r()}#r(){if(!this.#s||!this.getAttribute("preview"))return;const e=JSON.parse(this.getAttribute("preview"));H(this.#e,e)}}customElements.get("blurhash-image")||customElements.define("blurhash-image",j);function H(t,e){const{w:s,h:n,blurhash:i}=e;t.width=s,t.height=n;{const c=new Blob([document.querySelector("#next-blurhash-worker-script").textContent],{type:"text/javascript"}),a=new Worker(window.URL.createObjectURL(c)),w=t.transferControlToOffscreen();a.postMessage({canvas:w,width:s,height:n,blurhash:i},[w])}} })();` },
|
8
|
+
}),
|
9
|
+
createElement("script", {
|
10
|
+
id: "next-blurhash-worker-script",
|
11
|
+
type: "javascript/worker",
|
12
|
+
dangerouslySetInnerHTML: { __html: `(() => { "use strict";addEventListener("message",o=>{console.log(o);const{canvas:g,width:s,height:n,blurhash:e}=o.data,i=new Promise(t=>setTimeout(t,5e3));Promise.resolve(i).then(()=>{console.log("Encoding",e);const t=+new Date,d=__blurhashDecode(e,s,n),a=g.getContext("2d"),c=a.createImageData(s,n);c.data.set(d),a.putImageData(c,0,0);const l=+new Date;console.log("Done Encoding",e,l-t)})}); })();` },
|
13
|
+
})
|
14
|
+
);
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "next-blurhash-previews",
|
3
|
-
"version": "0.0.3-
|
3
|
+
"version": "0.0.3-beta52",
|
4
4
|
"description": "",
|
5
5
|
"main": "index.js",
|
6
6
|
"module": "index.js",
|
@@ -9,7 +9,7 @@
|
|
9
9
|
},
|
10
10
|
"scripts": {
|
11
11
|
"test": "echo \"Error: no test specified\" && exit 1",
|
12
|
-
"build": "vite build",
|
12
|
+
"build": "rm -rf build && vite build --config vite.wc.config.ts && vite build --config vite.worker.config.ts && node util/setBootstrap.js",
|
13
13
|
"build-watch": "vite build -w",
|
14
14
|
"prepare": "npm run build"
|
15
15
|
},
|
package/util/setBootstrap.js
CHANGED
@@ -1,22 +1,21 @@
|
|
1
1
|
import fs from "fs";
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
}
|
3
|
+
let BootstrapModule = fs.readFileSync(
|
4
|
+
"./components/imagePreviewBootstrap.tsx",
|
5
|
+
"utf8"
|
6
|
+
);
|
7
|
+
|
8
|
+
const wcScript = fs.readFileSync("./build/imageWithPreview.js", "utf8");
|
9
|
+
const workerScript = fs.readFileSync("./build/workerScript.js", "utf8");
|
10
|
+
|
11
|
+
BootstrapModule = BootstrapModule.replace(
|
12
|
+
"/*WC*/",
|
13
|
+
wcScript.replace(/[\r\n]\s*$/, "").replace(/`/g, "\\`")
|
14
|
+
)
|
15
|
+
.replace(
|
16
|
+
"/*WORKER*/",
|
17
|
+
workerScript.replace(/[\r\n]\s*$/, "").replace(/`/g, "\\`")
|
18
|
+
)
|
19
|
+
.replace(/\${/g, "\\${");
|
20
|
+
|
21
|
+
fs.writeFileSync("./imagePreviewBootstrap.js", BootstrapModule);
|
@@ -1,21 +1,18 @@
|
|
1
1
|
import { defineConfig } from "vite";
|
2
2
|
import react from "@vitejs/plugin-react";
|
3
|
-
import writeBootstrapPlugin from "./util/setBootstrap";
|
4
3
|
|
5
4
|
export default defineConfig({
|
6
5
|
build: {
|
7
6
|
target: "es2022",
|
8
7
|
outDir: "./build",
|
8
|
+
emptyOutDir: false,
|
9
9
|
lib: {
|
10
|
-
entry: "components/
|
10
|
+
entry: "components/ImageWithPreview.tsx",
|
11
11
|
formats: ["cjs"],
|
12
12
|
fileName: () => "imageWithPreview.js",
|
13
13
|
name: "imageWithPreview",
|
14
14
|
},
|
15
15
|
//minify: false,
|
16
|
-
rollupOptions: {
|
17
|
-
external: ["react", "react-dom", "next", "next/script"],
|
18
|
-
},
|
19
16
|
},
|
20
|
-
plugins: [react()
|
17
|
+
plugins: [react()],
|
21
18
|
});
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { defineConfig } from "vite";
|
2
|
+
import react from "@vitejs/plugin-react";
|
3
|
+
|
4
|
+
export default defineConfig({
|
5
|
+
build: {
|
6
|
+
target: "es2022",
|
7
|
+
outDir: "./build",
|
8
|
+
emptyOutDir: false,
|
9
|
+
lib: {
|
10
|
+
entry: "components/workerScript.ts",
|
11
|
+
formats: ["cjs"],
|
12
|
+
fileName: () => "workerScript.js",
|
13
|
+
name: "workerScript",
|
14
|
+
},
|
15
|
+
//minify: false,
|
16
|
+
},
|
17
|
+
plugins: [react()],
|
18
|
+
});
|
package/vite.b.config.ts
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
import { defineConfig } from "vite";
|
2
|
-
// @ts-ignore
|
3
|
-
import path from "path";
|
4
|
-
import react from "@vitejs/plugin-react";
|
5
|
-
import writeBootstrapPlugin from "./util/setBootstrap";
|
6
|
-
|
7
|
-
export default defineConfig({
|
8
|
-
build: {
|
9
|
-
target: "es2022",
|
10
|
-
outDir: "./build",
|
11
|
-
|
12
|
-
// lib: {
|
13
|
-
// entry: "components/imageWithPreview.tsx",
|
14
|
-
// formats: ["cjs"],
|
15
|
-
// fileName: (a, b, c) => {
|
16
|
-
// console.log("mm", a, b, c);
|
17
|
-
// return "imageWithPreview.js";
|
18
|
-
// },
|
19
|
-
// name: "imageWithPreview",
|
20
|
-
// },
|
21
|
-
minify: false,
|
22
|
-
rollupOptions: {
|
23
|
-
input: {
|
24
|
-
imageWithPreview: path.resolve(
|
25
|
-
// @ts-ignore
|
26
|
-
__dirname,
|
27
|
-
"components/imageWithPreview.tsx"
|
28
|
-
),
|
29
|
-
},
|
30
|
-
output: {
|
31
|
-
dir: "./build/",
|
32
|
-
|
33
|
-
//file: "imageWithPreview.js",
|
34
|
-
// file: (a, b, c) => { console.log(a, b, c); return "imageWithPreview.js"; }
|
35
|
-
},
|
36
|
-
external: ["react", "react-dom", "next", "next/script"],
|
37
|
-
},
|
38
|
-
},
|
39
|
-
plugins: [react(), writeBootstrapPlugin()],
|
40
|
-
});
|