@shqld/canvas 3.2.2-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Readme.md +654 -0
- package/binding.gyp +229 -0
- package/browser.js +31 -0
- package/index.d.ts +507 -0
- package/index.js +94 -0
- package/lib/DOMMatrix.js +678 -0
- package/lib/bindings.js +113 -0
- package/lib/canvas.js +113 -0
- package/lib/context2d.js +11 -0
- package/lib/image.js +97 -0
- package/lib/jpegstream.js +41 -0
- package/lib/pattern.js +15 -0
- package/lib/pdfstream.js +35 -0
- package/lib/pngstream.js +42 -0
- package/package.json +77 -0
- package/scripts/install.js +19 -0
- package/src/Backends.h +9 -0
- package/src/Canvas.cc +1026 -0
- package/src/Canvas.h +128 -0
- package/src/CanvasError.h +37 -0
- package/src/CanvasGradient.cc +113 -0
- package/src/CanvasGradient.h +20 -0
- package/src/CanvasPattern.cc +129 -0
- package/src/CanvasPattern.h +33 -0
- package/src/CanvasRenderingContext2d.cc +3527 -0
- package/src/CanvasRenderingContext2d.h +238 -0
- package/src/CharData.h +233 -0
- package/src/FontParser.cc +605 -0
- package/src/FontParser.h +115 -0
- package/src/Image.cc +1719 -0
- package/src/Image.h +146 -0
- package/src/ImageData.cc +138 -0
- package/src/ImageData.h +26 -0
- package/src/InstanceData.h +12 -0
- package/src/JPEGStream.h +157 -0
- package/src/PNG.h +292 -0
- package/src/Point.h +11 -0
- package/src/Util.h +9 -0
- package/src/bmp/BMPParser.cc +459 -0
- package/src/bmp/BMPParser.h +60 -0
- package/src/bmp/LICENSE.md +24 -0
- package/src/closure.cc +52 -0
- package/src/closure.h +98 -0
- package/src/color.cc +796 -0
- package/src/color.h +30 -0
- package/src/dll_visibility.h +20 -0
- package/src/init.cc +114 -0
- package/src/register_font.cc +352 -0
- package/src/register_font.h +7 -0
- package/util/has_lib.js +119 -0
- package/util/win_jpeg_lookup.js +21 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
#include "BMPParser.h"
|
|
2
|
+
|
|
3
|
+
#include <cassert>
|
|
4
|
+
#include <cstring>
|
|
5
|
+
|
|
6
|
+
using namespace std;
|
|
7
|
+
using namespace BMPParser;
|
|
8
|
+
|
|
9
|
+
#define MAX_IMG_SIZE 10000
|
|
10
|
+
|
|
11
|
+
#define E(cond, msg) if(cond) return setErr(msg)
|
|
12
|
+
#define EU(cond, msg) if(cond) return setErrUnsupported(msg)
|
|
13
|
+
#define EX(cond, msg) if(cond) return setErrUnknown(msg)
|
|
14
|
+
|
|
15
|
+
#define I1() get<char>()
|
|
16
|
+
#define U1() get<uint8_t>()
|
|
17
|
+
#define I2() get<int16_t>()
|
|
18
|
+
#define U2() get<uint16_t>()
|
|
19
|
+
#define I4() get<int32_t>()
|
|
20
|
+
#define U4() get<uint32_t>()
|
|
21
|
+
|
|
22
|
+
#define I1UC() get<char, false>()
|
|
23
|
+
#define U1UC() get<uint8_t, false>()
|
|
24
|
+
#define I2UC() get<int16_t, false>()
|
|
25
|
+
#define U2UC() get<uint16_t, false>()
|
|
26
|
+
#define I4UC() get<int32_t, false>()
|
|
27
|
+
#define U4UC() get<uint32_t, false>()
|
|
28
|
+
|
|
29
|
+
#define CHECK_OVERRUN(ptr, size, type) \
|
|
30
|
+
if((ptr) + (size) - data > len){ \
|
|
31
|
+
setErr("unexpected end of file"); \
|
|
32
|
+
return type(); \
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
Parser::~Parser(){
|
|
36
|
+
data = nullptr;
|
|
37
|
+
ptr = nullptr;
|
|
38
|
+
|
|
39
|
+
if(imgd){
|
|
40
|
+
delete[] imgd;
|
|
41
|
+
imgd = nullptr;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
void Parser::parse(uint8_t *buf, int bufSize, uint8_t *format){
|
|
46
|
+
assert(status == Status::EMPTY);
|
|
47
|
+
|
|
48
|
+
data = ptr = buf;
|
|
49
|
+
len = bufSize;
|
|
50
|
+
|
|
51
|
+
// Start parsing file header
|
|
52
|
+
setOp("file header");
|
|
53
|
+
|
|
54
|
+
// File header signature
|
|
55
|
+
string fhSig = getStr(2);
|
|
56
|
+
string temp = "file header signature";
|
|
57
|
+
EU(fhSig == "BA", temp + " \"BA\"");
|
|
58
|
+
EU(fhSig == "CI", temp + " \"CI\"");
|
|
59
|
+
EU(fhSig == "CP", temp + " \"CP\"");
|
|
60
|
+
EU(fhSig == "IC", temp + " \"IC\"");
|
|
61
|
+
EU(fhSig == "PT", temp + " \"PT\"");
|
|
62
|
+
EX(fhSig != "BM", temp); // BM
|
|
63
|
+
|
|
64
|
+
// Length of the file should not be larger than `len`
|
|
65
|
+
E(U4() > static_cast<uint32_t>(len), "inconsistent file size");
|
|
66
|
+
|
|
67
|
+
// Skip unused values
|
|
68
|
+
skip(4);
|
|
69
|
+
|
|
70
|
+
// Offset where the pixel array (bitmap data) can be found
|
|
71
|
+
auto imgdOffset = U4();
|
|
72
|
+
|
|
73
|
+
// Start parsing DIB header
|
|
74
|
+
setOp("DIB header");
|
|
75
|
+
|
|
76
|
+
// Prepare some variables in case they are needed
|
|
77
|
+
uint32_t compr = 0;
|
|
78
|
+
uint32_t redShift = 0, greenShift = 0, blueShift = 0, alphaShift = 0;
|
|
79
|
+
uint32_t redMask = 0, greenMask = 0, blueMask = 0, alphaMask = 0;
|
|
80
|
+
double redMultp = 0, greenMultp = 0, blueMultp = 0, alphaMultp = 0;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Type of the DIB (device-independent bitmap) header
|
|
84
|
+
* is determined by its size. Most BMP files use BITMAPINFOHEADER.
|
|
85
|
+
*/
|
|
86
|
+
auto dibSize = U4();
|
|
87
|
+
temp = "DIB header";
|
|
88
|
+
EU(dibSize == 64, temp + " \"OS22XBITMAPHEADER\"");
|
|
89
|
+
EU(dibSize == 16, temp + " \"OS22XBITMAPHEADER\"");
|
|
90
|
+
|
|
91
|
+
uint32_t infoHeader = dibSize == 40 ? 1 :
|
|
92
|
+
dibSize == 52 ? 2 :
|
|
93
|
+
dibSize == 56 ? 3 :
|
|
94
|
+
dibSize == 108 ? 4 :
|
|
95
|
+
dibSize == 124 ? 5 : 0;
|
|
96
|
+
|
|
97
|
+
// BITMAPCOREHEADER, BITMAP*INFOHEADER, BITMAP*HEADER
|
|
98
|
+
auto isDibValid = dibSize == 12 || infoHeader;
|
|
99
|
+
EX(!isDibValid, temp);
|
|
100
|
+
|
|
101
|
+
// Image width
|
|
102
|
+
w = dibSize == 12 ? U2() : I4();
|
|
103
|
+
E(!w, "image width is 0");
|
|
104
|
+
E(w < 0, "negative image width");
|
|
105
|
+
E(w > MAX_IMG_SIZE, "too large image width");
|
|
106
|
+
|
|
107
|
+
// Image height (specification allows negative values)
|
|
108
|
+
h = dibSize == 12 ? U2() : I4();
|
|
109
|
+
E(!h, "image height is 0");
|
|
110
|
+
E(h > MAX_IMG_SIZE, "too large image height");
|
|
111
|
+
|
|
112
|
+
bool isHeightNegative = h < 0;
|
|
113
|
+
if(isHeightNegative) h = -h;
|
|
114
|
+
|
|
115
|
+
// Number of color planes (must be 1)
|
|
116
|
+
E(U2() != 1, "number of color planes must be 1");
|
|
117
|
+
|
|
118
|
+
// Bits per pixel (color depth)
|
|
119
|
+
auto bpp = U2();
|
|
120
|
+
auto isBppValid = bpp == 1 || bpp == 4 || bpp == 8 || bpp == 16 || bpp == 24 || bpp == 32;
|
|
121
|
+
EU(!isBppValid, "color depth");
|
|
122
|
+
|
|
123
|
+
// Calculate image data size and padding
|
|
124
|
+
uint32_t expectedImgdSize = (((w * bpp + 31) >> 5) << 2) * h;
|
|
125
|
+
uint32_t rowPadding = (-w * bpp & 31) >> 3;
|
|
126
|
+
uint32_t imgdSize = 0;
|
|
127
|
+
|
|
128
|
+
// Color palette data
|
|
129
|
+
uint8_t* paletteStart = nullptr;
|
|
130
|
+
uint32_t palColNum = 0;
|
|
131
|
+
|
|
132
|
+
if(infoHeader){
|
|
133
|
+
// Compression type
|
|
134
|
+
compr = U4();
|
|
135
|
+
temp = "compression type";
|
|
136
|
+
EU(compr == 1, temp + " \"BI_RLE8\"");
|
|
137
|
+
EU(compr == 2, temp + " \"BI_RLE4\"");
|
|
138
|
+
EU(compr == 4, temp + " \"BI_JPEG\"");
|
|
139
|
+
EU(compr == 5, temp + " \"BI_PNG\"");
|
|
140
|
+
EU(compr == 6, temp + " \"BI_ALPHABITFIELDS\"");
|
|
141
|
+
EU(compr == 11, temp + " \"BI_CMYK\"");
|
|
142
|
+
EU(compr == 12, temp + " \"BI_CMYKRLE8\"");
|
|
143
|
+
EU(compr == 13, temp + " \"BI_CMYKRLE4\"");
|
|
144
|
+
|
|
145
|
+
// BI_RGB and BI_BITFIELDS
|
|
146
|
+
auto isComprValid = compr == 0 || compr == 3;
|
|
147
|
+
EX(!isComprValid, temp);
|
|
148
|
+
|
|
149
|
+
// Ensure that BI_BITFIELDS appears only with 16-bit or 32-bit color
|
|
150
|
+
E(compr == 3 && !(bpp == 16 || bpp == 32), "compression BI_BITFIELDS can be used only with 16-bit and 32-bit color depth");
|
|
151
|
+
|
|
152
|
+
// Size of the image data
|
|
153
|
+
imgdSize = U4();
|
|
154
|
+
|
|
155
|
+
// Horizontal and vertical resolution (ignored)
|
|
156
|
+
skip(8);
|
|
157
|
+
|
|
158
|
+
// Number of colors in the palette or 0 if no palette is present
|
|
159
|
+
palColNum = U4();
|
|
160
|
+
EU(palColNum && bpp > 8, "color palette and bit depth combination");
|
|
161
|
+
if(palColNum) paletteStart = data + dibSize + 14;
|
|
162
|
+
|
|
163
|
+
// Number of important colors used or 0 if all colors are important (generally ignored)
|
|
164
|
+
skip(4);
|
|
165
|
+
|
|
166
|
+
if(infoHeader >= 2){
|
|
167
|
+
// If BI_BITFIELDS are used, calculate masks, otherwise ignore them
|
|
168
|
+
if(compr == 3){
|
|
169
|
+
calcMaskShift(redShift, redMask, redMultp);
|
|
170
|
+
calcMaskShift(greenShift, greenMask, greenMultp);
|
|
171
|
+
calcMaskShift(blueShift, blueMask, blueMultp);
|
|
172
|
+
if(infoHeader >= 3) calcMaskShift(alphaShift, alphaMask, alphaMultp);
|
|
173
|
+
if(status == Status::ERROR) return;
|
|
174
|
+
}else{
|
|
175
|
+
skip(16);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Ensure that the color space is LCS_WINDOWS_COLOR_SPACE or sRGB
|
|
179
|
+
if(infoHeader >= 4 && !palColNum){
|
|
180
|
+
string colSpace = getStr(4, 1);
|
|
181
|
+
EU(colSpace != "Win " && colSpace != "sRGB", "color space \"" + colSpace + "\"");
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Skip to the image data (there may be other chunks between, but they are optional)
|
|
187
|
+
E(ptr - data > imgdOffset, "image data overlaps with another structure");
|
|
188
|
+
ptr = data + imgdOffset;
|
|
189
|
+
|
|
190
|
+
// Start parsing image data
|
|
191
|
+
setOp("image data");
|
|
192
|
+
|
|
193
|
+
if(!imgdSize){
|
|
194
|
+
// Value 0 is allowed only for BI_RGB compression type
|
|
195
|
+
E(compr != 0, "missing image data size");
|
|
196
|
+
imgdSize = expectedImgdSize;
|
|
197
|
+
}else{
|
|
198
|
+
E(imgdSize < expectedImgdSize, "invalid image data size");
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Ensure that all image data is present
|
|
202
|
+
E(ptr - data + imgdSize > len, "not enough image data");
|
|
203
|
+
|
|
204
|
+
// Direction of reading rows
|
|
205
|
+
int yStart = h - 1;
|
|
206
|
+
int yEnd = -1;
|
|
207
|
+
int dy = isHeightNegative ? 1 : -1;
|
|
208
|
+
|
|
209
|
+
// In case of negative height, read rows backward
|
|
210
|
+
if(isHeightNegative){
|
|
211
|
+
yStart = 0;
|
|
212
|
+
yEnd = h;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Allocate output image data array
|
|
216
|
+
int buffLen = w * h << 2;
|
|
217
|
+
imgd = new (nothrow) uint8_t[buffLen];
|
|
218
|
+
E(!imgd, "unable to allocate memory");
|
|
219
|
+
|
|
220
|
+
// Prepare color values
|
|
221
|
+
uint8_t color[4] = {0};
|
|
222
|
+
uint8_t &red = color[0];
|
|
223
|
+
uint8_t &green = color[1];
|
|
224
|
+
uint8_t &blue = color[2];
|
|
225
|
+
uint8_t &alpha = color[3];
|
|
226
|
+
|
|
227
|
+
// Check if pre-multiplied alpha is used
|
|
228
|
+
bool premul = format ? format[4] : 0;
|
|
229
|
+
|
|
230
|
+
// Main loop
|
|
231
|
+
for(int y = yStart; y != yEnd; y += dy){
|
|
232
|
+
// Use in-byte offset for bpp < 8
|
|
233
|
+
uint8_t colOffset = 0;
|
|
234
|
+
uint8_t cval = 0;
|
|
235
|
+
uint32_t val = 0;
|
|
236
|
+
|
|
237
|
+
for(int x = 0; x != w; x++){
|
|
238
|
+
// Index in the output image data
|
|
239
|
+
int i = (x + y * w) << 2;
|
|
240
|
+
|
|
241
|
+
switch(compr){
|
|
242
|
+
case 0: // BI_RGB
|
|
243
|
+
switch(bpp){
|
|
244
|
+
case 1:
|
|
245
|
+
if(colOffset) ptr--;
|
|
246
|
+
cval = (U1UC() >> (7 - colOffset)) & 1;
|
|
247
|
+
|
|
248
|
+
if(palColNum){
|
|
249
|
+
uint8_t* entry = paletteStart + (cval << 2);
|
|
250
|
+
blue = get<uint8_t>(entry);
|
|
251
|
+
green = get<uint8_t>(entry + 1);
|
|
252
|
+
red = get<uint8_t>(entry + 2);
|
|
253
|
+
if(status == Status::ERROR) return;
|
|
254
|
+
}else{
|
|
255
|
+
red = green = blue = cval ? 255 : 0;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
alpha = 255;
|
|
259
|
+
colOffset = (colOffset + 1) & 7;
|
|
260
|
+
break;
|
|
261
|
+
|
|
262
|
+
case 4:
|
|
263
|
+
if(colOffset) ptr--;
|
|
264
|
+
cval = (U1UC() >> (4 - colOffset)) & 15;
|
|
265
|
+
|
|
266
|
+
if(palColNum){
|
|
267
|
+
uint8_t* entry = paletteStart + (cval << 2);
|
|
268
|
+
blue = get<uint8_t>(entry);
|
|
269
|
+
green = get<uint8_t>(entry + 1);
|
|
270
|
+
red = get<uint8_t>(entry + 2);
|
|
271
|
+
if(status == Status::ERROR) return;
|
|
272
|
+
}else{
|
|
273
|
+
red = green = blue = cval << 4;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
alpha = 255;
|
|
277
|
+
colOffset = (colOffset + 4) & 7;
|
|
278
|
+
break;
|
|
279
|
+
|
|
280
|
+
case 8:
|
|
281
|
+
cval = U1UC();
|
|
282
|
+
|
|
283
|
+
if(palColNum){
|
|
284
|
+
uint8_t* entry = paletteStart + (cval << 2);
|
|
285
|
+
blue = get<uint8_t>(entry);
|
|
286
|
+
green = get<uint8_t>(entry + 1);
|
|
287
|
+
red = get<uint8_t>(entry + 2);
|
|
288
|
+
if(status == Status::ERROR) return;
|
|
289
|
+
}else{
|
|
290
|
+
red = green = blue = cval;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
alpha = 255;
|
|
294
|
+
break;
|
|
295
|
+
|
|
296
|
+
case 16:
|
|
297
|
+
// RGB555
|
|
298
|
+
val = U1UC();
|
|
299
|
+
val |= U1UC() << 8;
|
|
300
|
+
red = (val >> 10) << 3;
|
|
301
|
+
green = (val >> 5) << 3;
|
|
302
|
+
blue = val << 3;
|
|
303
|
+
alpha = 255;
|
|
304
|
+
break;
|
|
305
|
+
|
|
306
|
+
case 24:
|
|
307
|
+
blue = U1UC();
|
|
308
|
+
green = U1UC();
|
|
309
|
+
red = U1UC();
|
|
310
|
+
alpha = 255;
|
|
311
|
+
break;
|
|
312
|
+
|
|
313
|
+
case 32:
|
|
314
|
+
blue = U1UC();
|
|
315
|
+
green = U1UC();
|
|
316
|
+
red = U1UC();
|
|
317
|
+
|
|
318
|
+
if(infoHeader >= 3){
|
|
319
|
+
alpha = U1UC();
|
|
320
|
+
}else{
|
|
321
|
+
alpha = 255;
|
|
322
|
+
skip(1);
|
|
323
|
+
}
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
break;
|
|
327
|
+
|
|
328
|
+
case 3: // BI_BITFIELDS
|
|
329
|
+
uint32_t col = bpp == 16 ? U2UC() : U4UC();
|
|
330
|
+
red = ((col >> redShift) & redMask) * redMultp + .5;
|
|
331
|
+
green = ((col >> greenShift) & greenMask) * greenMultp + .5;
|
|
332
|
+
blue = ((col >> blueShift) & blueMask) * blueMultp + .5;
|
|
333
|
+
alpha = alphaMask ? ((col >> alphaShift) & alphaMask) * alphaMultp + .5 : 255;
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Pixel format:
|
|
339
|
+
* red,
|
|
340
|
+
* green,
|
|
341
|
+
* blue,
|
|
342
|
+
* alpha,
|
|
343
|
+
* is alpha pre-multiplied
|
|
344
|
+
* Default is [0, 1, 2, 3, 0]
|
|
345
|
+
*/
|
|
346
|
+
|
|
347
|
+
if(premul && alpha != 255){
|
|
348
|
+
double a = alpha / 255.;
|
|
349
|
+
red = static_cast<uint8_t>(red * a + .5);
|
|
350
|
+
green = static_cast<uint8_t>(green * a + .5);
|
|
351
|
+
blue = static_cast<uint8_t>(blue * a + .5);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if(format){
|
|
355
|
+
imgd[i] = color[format[0]];
|
|
356
|
+
imgd[i + 1] = color[format[1]];
|
|
357
|
+
imgd[i + 2] = color[format[2]];
|
|
358
|
+
imgd[i + 3] = color[format[3]];
|
|
359
|
+
}else{
|
|
360
|
+
imgd[i] = red;
|
|
361
|
+
imgd[i + 1] = green;
|
|
362
|
+
imgd[i + 2] = blue;
|
|
363
|
+
imgd[i + 3] = alpha;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Skip unused bytes in the current row
|
|
368
|
+
skip(rowPadding);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if(status == Status::ERROR) return;
|
|
372
|
+
status = Status::OK;
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
void Parser::clearImgd(){ imgd = nullptr; }
|
|
376
|
+
int32_t Parser::getWidth() const{ return w; }
|
|
377
|
+
int32_t Parser::getHeight() const{ return h; }
|
|
378
|
+
uint8_t *Parser::getImgd() const{ return imgd; }
|
|
379
|
+
Status Parser::getStatus() const{ return status; }
|
|
380
|
+
|
|
381
|
+
string Parser::getErrMsg() const{
|
|
382
|
+
return "Error while processing " + getOp() + " - " + err;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
template <typename T, bool check> inline T Parser::get(){
|
|
386
|
+
if(check)
|
|
387
|
+
CHECK_OVERRUN(ptr, sizeof(T), T);
|
|
388
|
+
T val;
|
|
389
|
+
std::memcpy(&val, ptr, sizeof(T));
|
|
390
|
+
ptr += sizeof(T);
|
|
391
|
+
return val;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
template <typename T, bool check> inline T Parser::get(uint8_t* pointer){
|
|
395
|
+
if(check)
|
|
396
|
+
CHECK_OVERRUN(pointer, sizeof(T), T);
|
|
397
|
+
T val = *(T*)pointer;
|
|
398
|
+
return val;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
string Parser::getStr(int size, bool reverse){
|
|
402
|
+
CHECK_OVERRUN(ptr, size, string);
|
|
403
|
+
string val = "";
|
|
404
|
+
|
|
405
|
+
while(size--){
|
|
406
|
+
if(reverse) val = string(1, static_cast<char>(*ptr++)) + val;
|
|
407
|
+
else val += static_cast<char>(*ptr++);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return val;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
inline void Parser::skip(int size){
|
|
414
|
+
CHECK_OVERRUN(ptr, size, void);
|
|
415
|
+
ptr += size;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
void Parser::calcMaskShift(uint32_t& shift, uint32_t& mask, double& multp){
|
|
419
|
+
mask = U4();
|
|
420
|
+
shift = 0;
|
|
421
|
+
|
|
422
|
+
if(mask == 0) return;
|
|
423
|
+
|
|
424
|
+
while(~mask & 1){
|
|
425
|
+
mask >>= 1;
|
|
426
|
+
shift++;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
E(mask & (mask + 1), "invalid color mask");
|
|
430
|
+
|
|
431
|
+
multp = 255. / mask;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
void Parser::setOp(string val){
|
|
435
|
+
if(status != Status::EMPTY) return;
|
|
436
|
+
op = val;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
string Parser::getOp() const{
|
|
440
|
+
return op;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
void Parser::setErrUnsupported(string msg){
|
|
444
|
+
setErr("unsupported " + msg);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
void Parser::setErrUnknown(string msg){
|
|
448
|
+
setErr("unknown " + msg);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
void Parser::setErr(string msg){
|
|
452
|
+
if(status != Status::EMPTY) return;
|
|
453
|
+
err = msg;
|
|
454
|
+
status = Status::ERROR;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
string Parser::getErr() const{
|
|
458
|
+
return err;
|
|
459
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#ifdef ERROR
|
|
4
|
+
#define ERROR_ ERROR
|
|
5
|
+
#undef ERROR
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
#include <stdint.h> // node < 7 uses libstdc++ on macOS which lacks complete c++11
|
|
9
|
+
#include <string>
|
|
10
|
+
|
|
11
|
+
namespace BMPParser{
|
|
12
|
+
enum Status{
|
|
13
|
+
EMPTY,
|
|
14
|
+
OK,
|
|
15
|
+
ERROR,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
class Parser{
|
|
19
|
+
public:
|
|
20
|
+
Parser()=default;
|
|
21
|
+
~Parser();
|
|
22
|
+
void parse(uint8_t *buf, int bufSize, uint8_t *format=nullptr);
|
|
23
|
+
void clearImgd();
|
|
24
|
+
int32_t getWidth() const;
|
|
25
|
+
int32_t getHeight() const;
|
|
26
|
+
uint8_t *getImgd() const;
|
|
27
|
+
Status getStatus() const;
|
|
28
|
+
std::string getErrMsg() const;
|
|
29
|
+
|
|
30
|
+
private:
|
|
31
|
+
Status status = Status::EMPTY;
|
|
32
|
+
uint8_t *data = nullptr;
|
|
33
|
+
uint8_t *ptr = nullptr;
|
|
34
|
+
int len = 0;
|
|
35
|
+
int32_t w = 0;
|
|
36
|
+
int32_t h = 0;
|
|
37
|
+
uint8_t *imgd = nullptr;
|
|
38
|
+
std::string err = "";
|
|
39
|
+
std::string op = "";
|
|
40
|
+
|
|
41
|
+
template <typename T, bool check=true> inline T get();
|
|
42
|
+
template <typename T, bool check=true> inline T get(uint8_t* pointer);
|
|
43
|
+
std::string getStr(int len, bool reverse=false);
|
|
44
|
+
inline void skip(int len);
|
|
45
|
+
void calcMaskShift(uint32_t& shift, uint32_t& mask, double& multp);
|
|
46
|
+
|
|
47
|
+
void setOp(std::string val);
|
|
48
|
+
std::string getOp() const;
|
|
49
|
+
|
|
50
|
+
void setErrUnsupported(std::string msg);
|
|
51
|
+
void setErrUnknown(std::string msg);
|
|
52
|
+
void setErr(std::string msg);
|
|
53
|
+
std::string getErr() const;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
#ifdef ERROR_
|
|
58
|
+
#define ERROR ERROR_
|
|
59
|
+
#undef ERROR_
|
|
60
|
+
#endif
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
|
2
|
+
|
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
4
|
+
distribute this software, either in source code form or as a compiled
|
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
|
6
|
+
means.
|
|
7
|
+
|
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
|
9
|
+
of this software dedicate any and all copyright interest in the
|
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
|
11
|
+
of the public at large and to the detriment of our heirs and
|
|
12
|
+
successors. We intend this dedication to be an overt act of
|
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
|
14
|
+
software under copyright law.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
+
|
|
24
|
+
For more information, please refer to <http://unlicense.org>
|
package/src/closure.cc
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#include "closure.h"
|
|
2
|
+
#include "Canvas.h"
|
|
3
|
+
|
|
4
|
+
#ifdef HAVE_JPEG
|
|
5
|
+
void JpegClosure::init_destination(j_compress_ptr cinfo) {
|
|
6
|
+
JpegClosure* closure = (JpegClosure*)cinfo->client_data;
|
|
7
|
+
closure->vec.resize(PAGE_SIZE);
|
|
8
|
+
closure->jpeg_dest_mgr->next_output_byte = &closure->vec[0];
|
|
9
|
+
closure->jpeg_dest_mgr->free_in_buffer = closure->vec.size();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
boolean JpegClosure::empty_output_buffer(j_compress_ptr cinfo) {
|
|
13
|
+
JpegClosure* closure = (JpegClosure*)cinfo->client_data;
|
|
14
|
+
size_t currentSize = closure->vec.size();
|
|
15
|
+
closure->vec.resize(currentSize * 1.5);
|
|
16
|
+
closure->jpeg_dest_mgr->next_output_byte = &closure->vec[currentSize];
|
|
17
|
+
closure->jpeg_dest_mgr->free_in_buffer = closure->vec.size() - currentSize;
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
void JpegClosure::term_destination(j_compress_ptr cinfo) {
|
|
22
|
+
JpegClosure* closure = (JpegClosure*)cinfo->client_data;
|
|
23
|
+
size_t finalSize = closure->vec.size() - closure->jpeg_dest_mgr->free_in_buffer;
|
|
24
|
+
closure->vec.resize(finalSize);
|
|
25
|
+
}
|
|
26
|
+
#endif
|
|
27
|
+
|
|
28
|
+
void
|
|
29
|
+
EncodingWorker::Init(void (*work_fn)(Closure*), Closure* closure) {
|
|
30
|
+
this->work_fn = work_fn;
|
|
31
|
+
this->closure = closure;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
void
|
|
35
|
+
EncodingWorker::Execute() {
|
|
36
|
+
this->work_fn(this->closure);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
void
|
|
40
|
+
EncodingWorker::OnWorkComplete(Napi::Env env, napi_status status) {
|
|
41
|
+
Napi::HandleScope scope(env);
|
|
42
|
+
|
|
43
|
+
if (closure->status) {
|
|
44
|
+
closure->cb.Call({ closure->canvas->CairoError(closure->status).Value() });
|
|
45
|
+
} else {
|
|
46
|
+
Napi::Object buf = Napi::Buffer<uint8_t>::Copy(env, &closure->vec[0], closure->vec.size());
|
|
47
|
+
closure->cb.Call({ env.Null(), buf });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
closure->canvas->Unref();
|
|
51
|
+
delete closure;
|
|
52
|
+
}
|
package/src/closure.h
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
|
2
|
+
|
|
3
|
+
#pragma once
|
|
4
|
+
|
|
5
|
+
class Canvas;
|
|
6
|
+
#include <cairo.h>
|
|
7
|
+
|
|
8
|
+
#include "Canvas.h"
|
|
9
|
+
|
|
10
|
+
#ifdef HAVE_JPEG
|
|
11
|
+
#include <stddef.h>
|
|
12
|
+
#include <stdio.h>
|
|
13
|
+
#include <jpeglib.h>
|
|
14
|
+
#endif
|
|
15
|
+
|
|
16
|
+
#include <napi.h>
|
|
17
|
+
#include <png.h>
|
|
18
|
+
#include <stdint.h> // node < 7 uses libstdc++ on macOS which lacks complete c++11
|
|
19
|
+
#include <vector>
|
|
20
|
+
|
|
21
|
+
#ifndef PAGE_SIZE
|
|
22
|
+
#define PAGE_SIZE 4096
|
|
23
|
+
#endif
|
|
24
|
+
|
|
25
|
+
/*
|
|
26
|
+
* Image encoding closures.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
struct Closure {
|
|
30
|
+
std::vector<uint8_t> vec;
|
|
31
|
+
Napi::FunctionReference cb;
|
|
32
|
+
Canvas* canvas = nullptr;
|
|
33
|
+
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
|
34
|
+
|
|
35
|
+
static cairo_status_t writeVec(void *c, const uint8_t *odata, unsigned len) {
|
|
36
|
+
Closure* closure = static_cast<Closure*>(c);
|
|
37
|
+
try {
|
|
38
|
+
closure->vec.insert(closure->vec.end(), odata, odata + len);
|
|
39
|
+
} catch (const std::bad_alloc &) {
|
|
40
|
+
return CAIRO_STATUS_NO_MEMORY;
|
|
41
|
+
}
|
|
42
|
+
return CAIRO_STATUS_SUCCESS;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
Closure(Canvas* canvas) : canvas(canvas) {};
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
struct PdfSvgClosure : Closure {
|
|
49
|
+
PdfSvgClosure(Canvas* canvas) : Closure(canvas) {};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
struct PngClosure : Closure {
|
|
53
|
+
uint32_t compressionLevel = 6;
|
|
54
|
+
uint32_t filters = PNG_ALL_FILTERS;
|
|
55
|
+
uint32_t resolution = 0; // 0 = unspecified
|
|
56
|
+
// Indexed PNGs:
|
|
57
|
+
uint32_t nPaletteColors = 0;
|
|
58
|
+
uint8_t* palette = nullptr;
|
|
59
|
+
uint8_t backgroundIndex = 0;
|
|
60
|
+
|
|
61
|
+
PngClosure(Canvas* canvas) : Closure(canvas) {};
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
#ifdef HAVE_JPEG
|
|
65
|
+
struct JpegClosure : Closure {
|
|
66
|
+
uint32_t quality = 75;
|
|
67
|
+
uint32_t chromaSubsampling = 2;
|
|
68
|
+
bool progressive = false;
|
|
69
|
+
jpeg_destination_mgr* jpeg_dest_mgr = nullptr;
|
|
70
|
+
|
|
71
|
+
static void init_destination(j_compress_ptr cinfo);
|
|
72
|
+
static boolean empty_output_buffer(j_compress_ptr cinfo);
|
|
73
|
+
static void term_destination(j_compress_ptr cinfo);
|
|
74
|
+
|
|
75
|
+
JpegClosure(Canvas* canvas) : Closure(canvas) {
|
|
76
|
+
jpeg_dest_mgr = new jpeg_destination_mgr;
|
|
77
|
+
jpeg_dest_mgr->init_destination = init_destination;
|
|
78
|
+
jpeg_dest_mgr->empty_output_buffer = empty_output_buffer;
|
|
79
|
+
jpeg_dest_mgr->term_destination = term_destination;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
~JpegClosure() {
|
|
83
|
+
delete jpeg_dest_mgr;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
#endif
|
|
87
|
+
|
|
88
|
+
class EncodingWorker : public Napi::AsyncWorker {
|
|
89
|
+
public:
|
|
90
|
+
EncodingWorker(Napi::Env env): Napi::AsyncWorker(env) {};
|
|
91
|
+
void Init(void (*work_fn)(Closure*), Closure* closure);
|
|
92
|
+
void Execute() override;
|
|
93
|
+
void OnWorkComplete(Napi::Env env, napi_status status) override;
|
|
94
|
+
|
|
95
|
+
private:
|
|
96
|
+
void (*work_fn)(Closure*) = nullptr;
|
|
97
|
+
Closure* closure = nullptr;
|
|
98
|
+
};
|