feat: Blurhash integration

Resolve #6559
This commit is contained in:
syuilo
2020-07-19 00:24:07 +09:00
parent 705d40ab37
commit 3f71b14637
22 changed files with 249 additions and 214 deletions

View File

@ -6,6 +6,7 @@ import * as fileType from 'file-type';
import isSvg from 'is-svg';
import * as probeImageSize from 'probe-image-size';
import * as sharp from 'sharp';
import { encode } from 'blurhash';
const pipeline = util.promisify(stream.pipeline);
@ -18,7 +19,7 @@ export type FileInfo = {
};
width?: number;
height?: number;
avgColor?: number[];
blurhash?: string;
warnings: string[];
};
@ -71,12 +72,11 @@ export async function getFileInfo(path: string): Promise<FileInfo> {
}
}
// average color
let avgColor: number[] | undefined;
let blurhash: string | undefined;
if (['image/jpeg', 'image/gif', 'image/png', 'image/apng', 'image/webp', 'image/svg+xml'].includes(type.mime)) {
avgColor = await calcAvgColor(path).catch(e => {
warnings.push(`calcAvgColor failed: ${e}`);
blurhash = await getBlurhash(path).catch(e => {
warnings.push(`getBlurhash failed: ${e}`);
return undefined;
});
}
@ -87,7 +87,7 @@ export async function getFileInfo(path: string): Promise<FileInfo> {
type,
width,
height,
avgColor,
blurhash,
warnings,
};
}
@ -173,18 +173,15 @@ async function detectImageSize(path: string): Promise<{
/**
* Calculate average color of image
*/
async function calcAvgColor(path: string): Promise<number[]> {
const img = sharp(path);
const info = await (img as any).stats();
if (info.isOpaque) {
const r = Math.round(info.channels[0].mean);
const g = Math.round(info.channels[1].mean);
const b = Math.round(info.channels[2].mean);
return [r, g, b];
} else {
return [255, 255, 255];
}
function getBlurhash(path: string): Promise<string> {
return new Promise((resolve, reject) => {
sharp(path)
.raw()
.ensureAlpha()
.resize(64, 64, { fit: 'inside' })
.toBuffer((err, buffer, { width, height }) => {
if (err) return reject(err);
resolve(encode(new Uint8ClampedArray(buffer), width, height, 7, 7));
});
});
}