1 line
14 KiB
Plaintext
1 line
14 KiB
Plaintext
{"version":3,"sources":["../src/index.ts","../src/base83.ts","../src/utils.ts","../src/error.ts","../src/decode.ts","../src/encode.ts"],"sourcesContent":["export { default as decode, isBlurhashValid } from \"./decode\";\nexport { default as encode } from \"./encode\";\nexport * from \"./error\";\n","const digitCharacters = [\n \"0\",\n \"1\",\n \"2\",\n \"3\",\n \"4\",\n \"5\",\n \"6\",\n \"7\",\n \"8\",\n \"9\",\n \"A\",\n \"B\",\n \"C\",\n \"D\",\n \"E\",\n \"F\",\n \"G\",\n \"H\",\n \"I\",\n \"J\",\n \"K\",\n \"L\",\n \"M\",\n \"N\",\n \"O\",\n \"P\",\n \"Q\",\n \"R\",\n \"S\",\n \"T\",\n \"U\",\n \"V\",\n \"W\",\n \"X\",\n \"Y\",\n \"Z\",\n \"a\",\n \"b\",\n \"c\",\n \"d\",\n \"e\",\n \"f\",\n \"g\",\n \"h\",\n \"i\",\n \"j\",\n \"k\",\n \"l\",\n \"m\",\n \"n\",\n \"o\",\n \"p\",\n \"q\",\n \"r\",\n \"s\",\n \"t\",\n \"u\",\n \"v\",\n \"w\",\n \"x\",\n \"y\",\n \"z\",\n \"#\",\n \"$\",\n \"%\",\n \"*\",\n \"+\",\n \",\",\n \"-\",\n \".\",\n \":\",\n \";\",\n \"=\",\n \"?\",\n \"@\",\n \"[\",\n \"]\",\n \"^\",\n \"_\",\n \"{\",\n \"|\",\n \"}\",\n \"~\",\n];\n\nexport const decode83 = (str: String) => {\n let value = 0;\n for (let i = 0; i < str.length; i++) {\n const c = str[i];\n const digit = digitCharacters.indexOf(c);\n value = value * 83 + digit;\n }\n return value;\n};\n\nexport const encode83 = (n: number, length: number): string => {\n var result = \"\";\n for (let i = 1; i <= length; i++) {\n let digit = (Math.floor(n) / Math.pow(83, length - i)) % 83;\n result += digitCharacters[Math.floor(digit)];\n }\n return result;\n};\n","export const sRGBToLinear = (value: number) => {\n let v = value / 255;\n if (v <= 0.04045) {\n return v / 12.92;\n } else {\n return Math.pow((v + 0.055) / 1.055, 2.4);\n }\n};\n\nexport const linearTosRGB = (value: number) => {\n let v = Math.max(0, Math.min(1, value));\n if (v <= 0.0031308) {\n return Math.trunc(v * 12.92 * 255 + 0.5);\n } else {\n return Math.trunc((1.055 * Math.pow(v, 1 / 2.4) - 0.055) * 255 + 0.5);\n }\n};\n\nexport const sign = (n: number) => (n < 0 ? -1 : 1);\n\nexport const signPow = (val: number, exp: number) =>\n sign(val) * Math.pow(Math.abs(val), exp);\n","export class ValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ValidationError\";\n this.message = message;\n }\n}\n","import { decode83 } from \"./base83\";\nimport { sRGBToLinear, signPow, linearTosRGB } from \"./utils\";\nimport { ValidationError } from \"./error\";\n\n/**\n * Returns an error message if invalid or undefined if valid\n * @param blurhash\n */\nconst validateBlurhash = (blurhash: string) => {\n if (!blurhash || blurhash.length < 6) {\n throw new ValidationError(\n \"The blurhash string must be at least 6 characters\"\n );\n }\n\n const sizeFlag = decode83(blurhash[0]);\n const numY = Math.floor(sizeFlag / 9) + 1;\n const numX = (sizeFlag % 9) + 1;\n\n if (blurhash.length !== 4 + 2 * numX * numY) {\n throw new ValidationError(\n `blurhash length mismatch: length is ${\n blurhash.length\n } but it should be ${4 + 2 * numX * numY}`\n );\n }\n};\n\nexport const isBlurhashValid = (\n blurhash: string\n): { result: boolean; errorReason?: string } => {\n try {\n validateBlurhash(blurhash);\n } catch (error) {\n return { result: false, errorReason: error.message };\n }\n\n return { result: true };\n};\n\nconst decodeDC = (value: number) => {\n const intR = value >> 16;\n const intG = (value >> 8) & 255;\n const intB = value & 255;\n return [sRGBToLinear(intR), sRGBToLinear(intG), sRGBToLinear(intB)];\n};\n\nconst decodeAC = (value: number, maximumValue: number) => {\n const quantR = Math.floor(value / (19 * 19));\n const quantG = Math.floor(value / 19) % 19;\n const quantB = value % 19;\n\n const rgb = [\n signPow((quantR - 9) / 9, 2.0) * maximumValue,\n signPow((quantG - 9) / 9, 2.0) * maximumValue,\n signPow((quantB - 9) / 9, 2.0) * maximumValue,\n ];\n\n return rgb;\n};\n\nconst decode = (\n blurhash: string,\n width: number,\n height: number,\n punch?: number\n) => {\n validateBlurhash(blurhash);\n\n punch = punch | 1;\n\n const sizeFlag = decode83(blurhash[0]);\n const numY = Math.floor(sizeFlag / 9) + 1;\n const numX = (sizeFlag % 9) + 1;\n\n const quantisedMaximumValue = decode83(blurhash[1]);\n const maximumValue = (quantisedMaximumValue + 1) / 166;\n\n const colors = new Array(numX * numY);\n\n for (let i = 0; i < colors.length; i++) {\n if (i === 0) {\n const value = decode83(blurhash.substring(2, 6));\n colors[i] = decodeDC(value);\n } else {\n const value = decode83(blurhash.substring(4 + i * 2, 6 + i * 2));\n colors[i] = decodeAC(value, maximumValue * punch);\n }\n }\n\n const bytesPerRow = width * 4;\n const pixels = new Uint8ClampedArray(bytesPerRow * height);\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n let r = 0;\n let g = 0;\n let b = 0;\n\n for (let j = 0; j < numY; j++) {\n for (let i = 0; i < numX; i++) {\n const basis =\n Math.cos((Math.PI * x * i) / width) *\n Math.cos((Math.PI * y * j) / height);\n let color = colors[i + j * numX];\n r += color[0] * basis;\n g += color[1] * basis;\n b += color[2] * basis;\n }\n }\n\n let intR = linearTosRGB(r);\n let intG = linearTosRGB(g);\n let intB = linearTosRGB(b);\n\n pixels[4 * x + 0 + y * bytesPerRow] = intR;\n pixels[4 * x + 1 + y * bytesPerRow] = intG;\n pixels[4 * x + 2 + y * bytesPerRow] = intB;\n pixels[4 * x + 3 + y * bytesPerRow] = 255; // alpha\n }\n }\n return pixels;\n};\n\nexport default decode;\n","import { encode83 } from \"./base83\";\nimport { sRGBToLinear, signPow, linearTosRGB } from \"./utils\";\nimport { ValidationError } from \"./error\";\n\ntype NumberTriplet = [number, number, number];\n\nconst bytesPerPixel = 4;\n\nconst multiplyBasisFunction = (\n pixels: Uint8ClampedArray,\n width: number,\n height: number,\n basisFunction: (i: number, j: number) => number\n): NumberTriplet => {\n let r = 0;\n let g = 0;\n let b = 0;\n const bytesPerRow = width * bytesPerPixel;\n\n for (let x = 0; x < width; x++) {\n const bytesPerPixelX = bytesPerPixel * x;\n\n for (let y = 0; y < height; y++) {\n const basePixelIndex = bytesPerPixelX + y * bytesPerRow;\n const basis = basisFunction(x, y);\n r +=\n basis * sRGBToLinear(pixels[basePixelIndex]);\n g +=\n basis * sRGBToLinear(pixels[basePixelIndex + 1]);\n b +=\n basis * sRGBToLinear(pixels[basePixelIndex + 2]);\n }\n }\n\n let scale = 1 / (width * height);\n\n return [r * scale, g * scale, b * scale];\n};\n\nconst encodeDC = (value: NumberTriplet): number => {\n const roundedR = linearTosRGB(value[0]);\n const roundedG = linearTosRGB(value[1]);\n const roundedB = linearTosRGB(value[2]);\n return (roundedR << 16) + (roundedG << 8) + roundedB;\n};\n\nconst encodeAC = (value: NumberTriplet, maximumValue: number): number => {\n let quantR = Math.floor(\n Math.max(\n 0,\n Math.min(18, Math.floor(signPow(value[0] / maximumValue, 0.5) * 9 + 9.5))\n )\n );\n let quantG = Math.floor(\n Math.max(\n 0,\n Math.min(18, Math.floor(signPow(value[1] / maximumValue, 0.5) * 9 + 9.5))\n )\n );\n let quantB = Math.floor(\n Math.max(\n 0,\n Math.min(18, Math.floor(signPow(value[2] / maximumValue, 0.5) * 9 + 9.5))\n )\n );\n\n return quantR * 19 * 19 + quantG * 19 + quantB;\n};\n\nconst encode = (\n pixels: Uint8ClampedArray,\n width: number,\n height: number,\n componentX: number,\n componentY: number\n): string => {\n if (componentX < 1 || componentX > 9 || componentY < 1 || componentY > 9) {\n throw new ValidationError(\"BlurHash must have between 1 and 9 components\");\n }\n if (width * height * 4 !== pixels.length) {\n throw new ValidationError(\"Width and height must match the pixels array\");\n }\n\n let factors: Array<[number, number, number]> = [];\n for (let y = 0; y < componentY; y++) {\n for (let x = 0; x < componentX; x++) {\n const normalisation = x == 0 && y == 0 ? 1 : 2;\n const factor = multiplyBasisFunction(\n pixels,\n width,\n height,\n (i: number, j: number) =>\n normalisation *\n Math.cos((Math.PI * x * i) / width) *\n Math.cos((Math.PI * y * j) / height)\n );\n factors.push(factor);\n }\n }\n\n const dc = factors[0];\n const ac = factors.slice(1);\n\n let hash = \"\";\n\n let sizeFlag = componentX - 1 + (componentY - 1) * 9;\n hash += encode83(sizeFlag, 1);\n\n let maximumValue: number;\n if (ac.length > 0) {\n let actualMaximumValue = Math.max(...ac.map((val) => Math.max(...val)));\n let quantisedMaximumValue = Math.floor(\n Math.max(0, Math.min(82, Math.floor(actualMaximumValue * 166 - 0.5)))\n );\n maximumValue = (quantisedMaximumValue + 1) / 166;\n hash += encode83(quantisedMaximumValue, 1);\n } else {\n maximumValue = 1;\n hash += encode83(0, 1);\n }\n\n hash += encode83(encodeDC(dc), 4);\n\n ac.forEach((factor) => {\n hash += encode83(encodeAC(factor, maximumValue), 2);\n });\n\n return hash;\n};\n\nexport default encode;\n"],"mappings":"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","names":[]} |