-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgenerate-blurred-images.ts
87 lines (72 loc) · 2.37 KB
/
generate-blurred-images.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// Code taken from https://github.com/nikolovlazar/nikolovlazar.com/blob/main/src/utils/plugins/image-metadata.ts
import imageSize from 'image-size';
import { ISizeCalculationResult } from 'image-size/dist/types/interface';
import path from 'path';
import { getPlaiceholder } from 'plaiceholder';
import { Node } from 'unist';
import { visit } from 'unist-util-visit';
import { promisify } from 'util';
const sizeOf = promisify(imageSize);
interface ImageNode {
type: 'element';
tagName: 'img';
properties: {
src: string;
height?: number;
width?: number;
blurDataURL?: string;
placeholder?: 'blur' | 'empty';
};
}
const isImageNode = (node: Node): node is ImageNode => {
const img = node as ImageNode;
return img.type === 'element' && img.tagName === 'img' && !!img.properties;
};
interface BlurResult {
size: { width: number; height: number };
blur64?: string;
}
export const getBlurData = async (imageSrc?: string): Promise<BlurResult | null> => {
if (!imageSrc) return null;
let res: ISizeCalculationResult | undefined;
let blur64: string;
const isExternal = imageSrc.startsWith('http');
if (!isExternal) {
res = await sizeOf(path.join(process.cwd(), 'public', imageSrc));
blur64 = (await getPlaiceholder(imageSrc)).base64;
} else {
const imageRes = await fetch(imageSrc);
const arrayBuffer = await imageRes.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
res = await imageSize(buffer);
blur64 = (await getPlaiceholder(buffer)).base64;
}
if (!res) throw Error(`Invalid image with src "${imageSrc}"`);
return {
size: { width: res.width || 0, height: res.height || 0 },
blur64,
};
};
const addProps = async (node: ImageNode): Promise<void> => {
const res = await getBlurData(node.properties.src).catch(() => null);
if (!res) return;
node.properties.width = res.size.width;
node.properties.height = res.size.height;
node.properties.blurDataURL = res.blur64;
node.properties.placeholder = 'blur';
};
const blurredImageDataRehypePlugin = () => {
return async function transformer(tree: Node): Promise<Node> {
const images: ImageNode[] = [];
visit(tree, 'element', (node) => {
if (isImageNode(node)) {
images.push(node);
}
});
for (const image of images) {
await addProps(image);
}
return tree;
};
};
export default blurredImageDataRehypePlugin;