bitmapper.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. 'use strict';
  2. var interlaceUtils = require('./interlace');
  3. var pixelBppMapper = [
  4. // 0 - dummy entry
  5. function() {},
  6. // 1 - L
  7. // 0: 0, 1: 0, 2: 0, 3: 0xff
  8. function(pxData, data, pxPos, rawPos) {
  9. if (rawPos === data.length) {
  10. throw new Error('Ran out of data');
  11. }
  12. var pixel = data[rawPos];
  13. pxData[pxPos] = pixel;
  14. pxData[pxPos + 1] = pixel;
  15. pxData[pxPos + 2] = pixel;
  16. pxData[pxPos + 3] = 0xff;
  17. },
  18. // 2 - LA
  19. // 0: 0, 1: 0, 2: 0, 3: 1
  20. function(pxData, data, pxPos, rawPos) {
  21. if (rawPos + 1 >= data.length) {
  22. throw new Error('Ran out of data');
  23. }
  24. var pixel = data[rawPos];
  25. pxData[pxPos] = pixel;
  26. pxData[pxPos + 1] = pixel;
  27. pxData[pxPos + 2] = pixel;
  28. pxData[pxPos + 3] = data[rawPos + 1];
  29. },
  30. // 3 - RGB
  31. // 0: 0, 1: 1, 2: 2, 3: 0xff
  32. function(pxData, data, pxPos, rawPos) {
  33. if (rawPos + 2 >= data.length) {
  34. throw new Error('Ran out of data');
  35. }
  36. pxData[pxPos] = data[rawPos];
  37. pxData[pxPos + 1] = data[rawPos + 1];
  38. pxData[pxPos + 2] = data[rawPos + 2];
  39. pxData[pxPos + 3] = 0xff;
  40. },
  41. // 4 - RGBA
  42. // 0: 0, 1: 1, 2: 2, 3: 3
  43. function(pxData, data, pxPos, rawPos) {
  44. if (rawPos + 3 >= data.length) {
  45. throw new Error('Ran out of data');
  46. }
  47. pxData[pxPos] = data[rawPos];
  48. pxData[pxPos + 1] = data[rawPos + 1];
  49. pxData[pxPos + 2] = data[rawPos + 2];
  50. pxData[pxPos + 3] = data[rawPos + 3];
  51. }
  52. ];
  53. var pixelBppCustomMapper = [
  54. // 0 - dummy entry
  55. function() {},
  56. // 1 - L
  57. // 0: 0, 1: 0, 2: 0, 3: 0xff
  58. function(pxData, pixelData, pxPos, maxBit) {
  59. var pixel = pixelData[0];
  60. pxData[pxPos] = pixel;
  61. pxData[pxPos + 1] = pixel;
  62. pxData[pxPos + 2] = pixel;
  63. pxData[pxPos + 3] = maxBit;
  64. },
  65. // 2 - LA
  66. // 0: 0, 1: 0, 2: 0, 3: 1
  67. function(pxData, pixelData, pxPos) {
  68. var pixel = pixelData[0];
  69. pxData[pxPos] = pixel;
  70. pxData[pxPos + 1] = pixel;
  71. pxData[pxPos + 2] = pixel;
  72. pxData[pxPos + 3] = pixelData[1];
  73. },
  74. // 3 - RGB
  75. // 0: 0, 1: 1, 2: 2, 3: 0xff
  76. function(pxData, pixelData, pxPos, maxBit) {
  77. pxData[pxPos] = pixelData[0];
  78. pxData[pxPos + 1] = pixelData[1];
  79. pxData[pxPos + 2] = pixelData[2];
  80. pxData[pxPos + 3] = maxBit;
  81. },
  82. // 4 - RGBA
  83. // 0: 0, 1: 1, 2: 2, 3: 3
  84. function(pxData, pixelData, pxPos) {
  85. pxData[pxPos] = pixelData[0];
  86. pxData[pxPos + 1] = pixelData[1];
  87. pxData[pxPos + 2] = pixelData[2];
  88. pxData[pxPos + 3] = pixelData[3];
  89. }
  90. ];
  91. function bitRetriever(data, depth) {
  92. var leftOver = [];
  93. var i = 0;
  94. function split() {
  95. if (i === data.length) {
  96. throw new Error('Ran out of data');
  97. }
  98. var byte = data[i];
  99. i++;
  100. var byte8, byte7, byte6, byte5, byte4, byte3, byte2, byte1;
  101. switch (depth) {
  102. default:
  103. throw new Error('unrecognised depth');
  104. case 16:
  105. byte2 = data[i];
  106. i++;
  107. leftOver.push(((byte << 8) + byte2));
  108. break;
  109. case 4:
  110. byte2 = byte & 0x0f;
  111. byte1 = byte >> 4;
  112. leftOver.push(byte1, byte2);
  113. break;
  114. case 2:
  115. byte4 = byte & 3;
  116. byte3 = byte >> 2 & 3;
  117. byte2 = byte >> 4 & 3;
  118. byte1 = byte >> 6 & 3;
  119. leftOver.push(byte1, byte2, byte3, byte4);
  120. break;
  121. case 1:
  122. byte8 = byte & 1;
  123. byte7 = byte >> 1 & 1;
  124. byte6 = byte >> 2 & 1;
  125. byte5 = byte >> 3 & 1;
  126. byte4 = byte >> 4 & 1;
  127. byte3 = byte >> 5 & 1;
  128. byte2 = byte >> 6 & 1;
  129. byte1 = byte >> 7 & 1;
  130. leftOver.push(byte1, byte2, byte3, byte4, byte5, byte6, byte7, byte8);
  131. break;
  132. }
  133. }
  134. return {
  135. get: function(count) {
  136. while (leftOver.length < count) {
  137. split();
  138. }
  139. var returner = leftOver.slice(0, count);
  140. leftOver = leftOver.slice(count);
  141. return returner;
  142. },
  143. resetAfterLine: function() {
  144. leftOver.length = 0;
  145. },
  146. end: function() {
  147. if (i !== data.length) {
  148. throw new Error('extra data found');
  149. }
  150. }
  151. };
  152. }
  153. function mapImage8Bit(image, pxData, getPxPos, bpp, data, rawPos) { // eslint-disable-line max-params
  154. var imageWidth = image.width;
  155. var imageHeight = image.height;
  156. var imagePass = image.index;
  157. for (var y = 0; y < imageHeight; y++) {
  158. for (var x = 0; x < imageWidth; x++) {
  159. var pxPos = getPxPos(x, y, imagePass);
  160. pixelBppMapper[bpp](pxData, data, pxPos, rawPos);
  161. rawPos += bpp; //eslint-disable-line no-param-reassign
  162. }
  163. }
  164. return rawPos;
  165. }
  166. function mapImageCustomBit(image, pxData, getPxPos, bpp, bits, maxBit) { // eslint-disable-line max-params
  167. var imageWidth = image.width;
  168. var imageHeight = image.height;
  169. var imagePass = image.index;
  170. for (var y = 0; y < imageHeight; y++) {
  171. for (var x = 0; x < imageWidth; x++) {
  172. var pixelData = bits.get(bpp);
  173. var pxPos = getPxPos(x, y, imagePass);
  174. pixelBppCustomMapper[bpp](pxData, pixelData, pxPos, maxBit);
  175. }
  176. bits.resetAfterLine();
  177. }
  178. }
  179. exports.dataToBitMap = function(data, bitmapInfo) {
  180. var width = bitmapInfo.width;
  181. var height = bitmapInfo.height;
  182. var depth = bitmapInfo.depth;
  183. var bpp = bitmapInfo.bpp;
  184. var interlace = bitmapInfo.interlace;
  185. if (depth !== 8) {
  186. var bits = bitRetriever(data, depth);
  187. }
  188. var pxData;
  189. if (depth <= 8) {
  190. pxData = new Buffer(width * height * 4);
  191. }
  192. else {
  193. pxData = new Uint16Array(width * height * 4);
  194. }
  195. var maxBit = Math.pow(2, depth) - 1;
  196. var rawPos = 0;
  197. var images;
  198. var getPxPos;
  199. if (interlace) {
  200. images = interlaceUtils.getImagePasses(width, height);
  201. getPxPos = interlaceUtils.getInterlaceIterator(width, height);
  202. }
  203. else {
  204. var nonInterlacedPxPos = 0;
  205. getPxPos = function() {
  206. var returner = nonInterlacedPxPos;
  207. nonInterlacedPxPos += 4;
  208. return returner;
  209. };
  210. images = [{ width: width, height: height }];
  211. }
  212. for (var imageIndex = 0; imageIndex < images.length; imageIndex++) {
  213. if (depth === 8) {
  214. rawPos = mapImage8Bit(images[imageIndex], pxData, getPxPos, bpp, data, rawPos);
  215. }
  216. else {
  217. mapImageCustomBit(images[imageIndex], pxData, getPxPos, bpp, bits, maxBit);
  218. }
  219. }
  220. if (depth === 8) {
  221. if (rawPos !== data.length) {
  222. throw new Error('extra data found');
  223. }
  224. }
  225. else {
  226. bits.end();
  227. }
  228. return pxData;
  229. };