UNPKG

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