blurhash.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. (function($) {
  2. var digitCharacters = [
  3. "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
  4. "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
  5. "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
  6. "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d",
  7. "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
  8. "o", "p", "q", "r", "s", "t", "u", "v", "w", "x",
  9. "y", "z", "#", "$", "%", "*", "+", ",", "-", ".",
  10. ":", ";", "=", "?", "@", "[", "]", "^", "_", "{",
  11. "|", "}", "~",
  12. ];
  13. function decode83(str) {
  14. var value = 0;
  15. for (var i = 0; i < str.length; i++) {
  16. var c = str[i];
  17. var digit = digitCharacters.indexOf(c);
  18. value = value * 83 + digit;
  19. }
  20. return value;
  21. }
  22. function sRGBToLinear(value) {
  23. var v = value / 255;
  24. if (v <= 0.04045) {
  25. return v / 12.92;
  26. }
  27. else {
  28. return Math.pow((v + 0.055) / 1.055, 2.4);
  29. }
  30. }
  31. function linearTosRGB(value) {
  32. var v = Math.max(0, Math.min(1, value));
  33. if (v <= 0.0031308) {
  34. return Math.round(v * 12.92 * 255 + 0.5);
  35. }
  36. else {
  37. return Math.round((1.055 * Math.pow(v, 1 / 2.4) - 0.055) * 255 + 0.5);
  38. }
  39. }
  40. function sign(n) {
  41. return (n < 0 ? -1 : 1);
  42. }
  43. function signPow(val, exp) {
  44. return sign(val) * Math.pow(Math.abs(val), exp);
  45. }
  46. function decodeDC(value) {
  47. var intR = value >> 16;
  48. var intG = (value >> 8) & 255;
  49. var intB = value & 255;
  50. return [sRGBToLinear(intR), sRGBToLinear(intG), sRGBToLinear(intB)];
  51. }
  52. function decodeAC(value, maximumValue) {
  53. var quantR = Math.floor(value / (19 * 19));
  54. var quantG = Math.floor(value / 19) % 19;
  55. var quantB = value % 19;
  56. var rgb = [
  57. signPow((quantR - 9) / 9, 2.0) * maximumValue,
  58. signPow((quantG - 9) / 9, 2.0) * maximumValue,
  59. signPow((quantB - 9) / 9, 2.0) * maximumValue,
  60. ];
  61. return rgb;
  62. }
  63. $.decode = function(blurhash,width,height,punch) {
  64. punch = punch | 1;
  65. if (blurhash.length < 6) {
  66. console.error('too short blurhash');
  67. return null;
  68. }
  69. var sizeFlag = decode83(blurhash[0]);
  70. var numY = Math.floor(sizeFlag / 9) + 1;
  71. var numX = (sizeFlag % 9) + 1;
  72. var quantisedMaximumValue = decode83(blurhash[1]);
  73. var maximumValue = (quantisedMaximumValue + 1) / 166;
  74. if (blurhash.length !== 4 + 2 * numX * numY) {
  75. console.error('blurhash length mismatch', blurhash.length, 4 + 2 * numX * numY);
  76. return null;
  77. }
  78. var colors = new Array(numX * numY);
  79. for (var i = 0; i < colors.length; i++) {
  80. if (i === 0) {
  81. var value = decode83(blurhash.substring(2, 6));
  82. colors[i] = decodeDC(value);
  83. }
  84. else {
  85. var value = decode83(blurhash.substring(4 + i * 2, 6 + i * 2));
  86. colors[i] = decodeAC(value, maximumValue * punch);
  87. }
  88. }
  89. var bytesPerRow = width * 4;
  90. var pixels = new Uint8ClampedArray(bytesPerRow * height);
  91. for (var y = 0; y < height; y++) {
  92. for (var x = 0; x < width; x++) {
  93. var r = 0;
  94. var g = 0;
  95. var b = 0;
  96. for (var j = 0; j < numY; j++) {
  97. for (var i = 0; i < numX; i++) {
  98. var basis = Math.cos(Math.PI * x * i / width) * Math.cos(Math.PI * y * j / height);
  99. var color = colors[i + j * numX];
  100. r += color[0] * basis;
  101. g += color[1] * basis;
  102. b += color[2] * basis;
  103. }
  104. }
  105. var intR = linearTosRGB(r);
  106. var intG = linearTosRGB(g);
  107. var intB = linearTosRGB(b);
  108. pixels[4 * x + 0 + y * bytesPerRow] = intR;
  109. pixels[4 * x + 1 + y * bytesPerRow] = intG;
  110. pixels[4 * x + 2 + y * bytesPerRow] = intB;
  111. pixels[4 * x + 3 + y * bytesPerRow] = 255;
  112. }
  113. }
  114. return pixels;
  115. }
  116. })(jQuery);
  117. function getBlurImage(hash) {
  118. const pixels = $.decode(hash,32,32);
  119. if(pixels) {
  120. const canvas = document.createElement("canvas");
  121. canvas.height = 32;
  122. canvas.width = 32;
  123. const ctx = canvas.getContext('2d');
  124. const imagedata = new ImageData(pixels,32,32);
  125. ctx.putImageData(imagedata,0,0);
  126. return canvas.toDataURL();
  127. }
  128. else return false;
  129. }