bitpacker.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. 'use strict';
  2. var constants = require('./constants');
  3. module.exports = function(dataIn, width, height, options) {
  4. var outHasAlpha = [constants.COLORTYPE_COLOR_ALPHA, constants.COLORTYPE_ALPHA].indexOf(options.colorType) !== -1;
  5. if (options.colorType === options.inputColorType) {
  6. var bigEndian = (function() {
  7. var buffer = new ArrayBuffer(2);
  8. new DataView(buffer).setInt16(0, 256, true /* littleEndian */);
  9. // Int16Array uses the platform's endianness.
  10. return new Int16Array(buffer)[0] !== 256;
  11. })();
  12. // If no need to convert to grayscale and alpha is present/absent in both, take a fast route
  13. if (options.bitDepth === 8 || (options.bitDepth === 16 && bigEndian)) {
  14. return dataIn;
  15. }
  16. }
  17. // map to a UInt16 array if data is 16bit, fix endianness below
  18. var data = options.bitDepth !== 16 ? dataIn : new Uint16Array(dataIn.buffer);
  19. var maxValue = 255;
  20. var inBpp = constants.COLORTYPE_TO_BPP_MAP[options.inputColorType];
  21. if (inBpp === 4 && !options.inputHasAlpha) {
  22. inBpp = 3;
  23. }
  24. var outBpp = constants.COLORTYPE_TO_BPP_MAP[options.colorType];
  25. if (options.bitDepth === 16) {
  26. maxValue = 65535;
  27. outBpp *= 2;
  28. }
  29. var outData = new Buffer(width * height * outBpp);
  30. var inIndex = 0;
  31. var outIndex = 0;
  32. var bgColor = options.bgColor || {};
  33. if (bgColor.red === undefined) {
  34. bgColor.red = maxValue;
  35. }
  36. if (bgColor.green === undefined) {
  37. bgColor.green = maxValue;
  38. }
  39. if (bgColor.blue === undefined) {
  40. bgColor.blue = maxValue;
  41. }
  42. function getRGBA() {
  43. var red;
  44. var green;
  45. var blue;
  46. var alpha = maxValue;
  47. switch (options.inputColorType) {
  48. case constants.COLORTYPE_COLOR_ALPHA:
  49. alpha = data[inIndex + 3];
  50. red = data[inIndex];
  51. green = data[inIndex + 1];
  52. blue = data[inIndex + 2];
  53. break;
  54. case constants.COLORTYPE_COLOR:
  55. red = data[inIndex];
  56. green = data[inIndex + 1];
  57. blue = data[inIndex + 2];
  58. break;
  59. case constants.COLORTYPE_ALPHA:
  60. alpha = data[inIndex + 1];
  61. red = data[inIndex];
  62. green = red;
  63. blue = red;
  64. break;
  65. case constants.COLORTYPE_GRAYSCALE:
  66. red = data[inIndex];
  67. green = red;
  68. blue = red;
  69. break;
  70. default:
  71. throw new Error('input color type:' + options.inputColorType + ' is not supported at present');
  72. }
  73. if (options.inputHasAlpha) {
  74. if (!outHasAlpha) {
  75. alpha /= maxValue;
  76. red = Math.min(Math.max(Math.round((1 - alpha) * bgColor.red + alpha * red), 0), maxValue);
  77. green = Math.min(Math.max(Math.round((1 - alpha) * bgColor.green + alpha * green), 0), maxValue);
  78. blue = Math.min(Math.max(Math.round((1 - alpha) * bgColor.blue + alpha * blue), 0), maxValue);
  79. }
  80. }
  81. return { red: red, green: green, blue: blue, alpha: alpha };
  82. }
  83. for (var y = 0; y < height; y++) {
  84. for (var x = 0; x < width; x++) {
  85. var rgba = getRGBA(data, inIndex);
  86. switch (options.colorType) {
  87. case constants.COLORTYPE_COLOR_ALPHA:
  88. case constants.COLORTYPE_COLOR:
  89. if (options.bitDepth === 8) {
  90. outData[outIndex] = rgba.red;
  91. outData[outIndex + 1] = rgba.green;
  92. outData[outIndex + 2] = rgba.blue;
  93. if (outHasAlpha) {
  94. outData[outIndex + 3] = rgba.alpha;
  95. }
  96. }
  97. else {
  98. outData.writeUInt16BE(rgba.red, outIndex);
  99. outData.writeUInt16BE(rgba.green, outIndex + 2);
  100. outData.writeUInt16BE(rgba.blue, outIndex + 4);
  101. if (outHasAlpha) {
  102. outData.writeUInt16BE(rgba.alpha, outIndex + 6);
  103. }
  104. }
  105. break;
  106. case constants.COLORTYPE_ALPHA:
  107. case constants.COLORTYPE_GRAYSCALE:
  108. // Convert to grayscale and alpha
  109. var grayscale = (rgba.red + rgba.green + rgba.blue) / 3;
  110. if (options.bitDepth === 8) {
  111. outData[outIndex] = grayscale;
  112. if (outHasAlpha) {
  113. outData[outIndex + 1] = rgba.alpha;
  114. }
  115. }
  116. else {
  117. outData.writeUInt16BE(grayscale, outIndex);
  118. if (outHasAlpha) {
  119. outData.writeUInt16BE(rgba.alpha, outIndex + 2);
  120. }
  121. }
  122. break;
  123. default:
  124. throw new Error('unrecognised color Type ' + options.colorType);
  125. }
  126. inIndex += inBpp;
  127. outIndex += outBpp;
  128. }
  129. }
  130. return outData;
  131. };