@unlazy/core
Version:
Universal lazy loading library for placeholder images leveraging native browser APIs
114 lines (113 loc) • 4.1 kB
JavaScript
const require_utils = require("./utils-DQumiM1Z.cjs");
//#region ../../node_modules/.pnpm/fast-blurhash@1.1.4/node_modules/fast-blurhash/index.js
const digitLookup = new Uint8Array(128);
for (let i = 0; i < 83; i++) digitLookup["0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~".charCodeAt(i)] = i;
const decode83 = (str, start, end) => {
let value = 0;
while (start < end) {
value *= 83;
value += digitLookup[str.charCodeAt(start++)];
}
return value;
};
const pow = Math.pow;
const PI = Math.PI;
const PI2 = PI * 2;
const d = 3294.6;
const e = 269.025;
const sRGBToLinear = (value) => value > 10.31475 ? pow(value / e + .052132, 2.4) : value / d;
const linearTosRGB = (v) => ~~(v > 1227e-8 ? e * pow(v, .416666) - 13.025 : v * d + 1);
const signSqr = (x) => (x < 0 ? -1 : 1) * x * x;
/**
* Fast approximate cosine implementation
* Based on FTrig https://github.com/netcell/FTrig
*/
const fastCos = (x) => {
x += PI / 2;
while (x > PI) x -= PI2;
const cos = 1.27323954 * x - .405284735 * signSqr(x);
return .225 * (signSqr(cos) - cos) + cos;
};
/**
* Extracts average color from BlurHash image
* @param {string} blurHash BlurHash image string
* @returns {[number, number, number]}
*/
function getBlurHashAverageColor(blurHash) {
const val = decode83(blurHash, 2, 6);
return [
val >> 16,
val >> 8 & 255,
val & 255
];
}
/**
* Decodes BlurHash image
* @param {string} blurHash BlurHash image string
* @param {number} width Output image width
* @param {number} height Output image height
* @param {?number} punch
* @returns {Uint8ClampedArray}
*/
function decodeBlurHash(blurHash, width, height, punch) {
const sizeFlag = decode83(blurHash, 0, 1);
const numX = sizeFlag % 9 + 1;
const numY = ~~(sizeFlag / 9) + 1;
const size = numX * numY;
let i = 0, j = 0, x = 0, y = 0, r = 0, g = 0, b = 0, basis = 0, basisY = 0, colorIndex = 0, pixelIndex = 0, value = 0;
const maximumValue = (decode83(blurHash, 1, 2) + 1) / 13446 * (punch | 1);
const colors = new Float64Array(size * 3);
const averageColor = getBlurHashAverageColor(blurHash);
for (i = 0; i < 3; i++) colors[i] = sRGBToLinear(averageColor[i]);
for (i = 1; i < size; i++) {
value = decode83(blurHash, 4 + i * 2, 6 + i * 2);
colors[i * 3] = signSqr(~~(value / 361) - 9) * maximumValue;
colors[i * 3 + 1] = signSqr(~~(value / 19) % 19 - 9) * maximumValue;
colors[i * 3 + 2] = signSqr(value % 19 - 9) * maximumValue;
}
const cosinesY = new Float64Array(numY * height);
const cosinesX = new Float64Array(numX * width);
for (j = 0; j < numY; j++) for (y = 0; y < height; y++) cosinesY[j * height + y] = fastCos(PI * y * j / height);
for (i = 0; i < numX; i++) for (x = 0; x < width; x++) cosinesX[i * width + x] = fastCos(PI * x * i / width);
const bytesPerRow = width * 4;
const pixels = new Uint8ClampedArray(bytesPerRow * height);
for (y = 0; y < height; y++) for (x = 0; x < width; x++) {
r = g = b = 0;
for (j = 0; j < numY; j++) {
basisY = cosinesY[j * height + y];
for (i = 0; i < numX; i++) {
basis = cosinesX[i * width + x] * basisY;
colorIndex = (i + j * numX) * 3;
r += colors[colorIndex] * basis;
g += colors[colorIndex + 1] * basis;
b += colors[colorIndex + 2] * basis;
}
}
pixelIndex = 4 * x + y * bytesPerRow;
pixels[pixelIndex] = linearTosRGB(r);
pixels[pixelIndex + 1] = linearTosRGB(g);
pixels[pixelIndex + 2] = linearTosRGB(b);
pixels[pixelIndex + 3] = 255;
}
return pixels;
}
//#endregion
//#region src/blurhash.ts
function createPngDataUri(hash, { ratio = 1, size = 32 } = {}) {
const { width, height } = getAspectRatioDimensions(ratio, size);
return require_utils.rgbaToDataUri(width, height, decodeBlurHash(hash, width, height));
}
function getAspectRatioDimensions(ratio, size) {
const isLandscapeOrSquare = ratio >= 1;
return {
width: isLandscapeOrSquare ? size : Math.round(size * ratio),
height: isLandscapeOrSquare ? Math.round(size / ratio) : size
};
}
//#endregion
Object.defineProperty(exports, "createPngDataUri", {
enumerable: true,
get: function() {
return createPngDataUri;
}
});