@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.
Files changed (51) hide show
  1. package/Readme.md +654 -0
  2. package/binding.gyp +229 -0
  3. package/browser.js +31 -0
  4. package/index.d.ts +507 -0
  5. package/index.js +94 -0
  6. package/lib/DOMMatrix.js +678 -0
  7. package/lib/bindings.js +113 -0
  8. package/lib/canvas.js +113 -0
  9. package/lib/context2d.js +11 -0
  10. package/lib/image.js +97 -0
  11. package/lib/jpegstream.js +41 -0
  12. package/lib/pattern.js +15 -0
  13. package/lib/pdfstream.js +35 -0
  14. package/lib/pngstream.js +42 -0
  15. package/package.json +77 -0
  16. package/scripts/install.js +19 -0
  17. package/src/Backends.h +9 -0
  18. package/src/Canvas.cc +1026 -0
  19. package/src/Canvas.h +128 -0
  20. package/src/CanvasError.h +37 -0
  21. package/src/CanvasGradient.cc +113 -0
  22. package/src/CanvasGradient.h +20 -0
  23. package/src/CanvasPattern.cc +129 -0
  24. package/src/CanvasPattern.h +33 -0
  25. package/src/CanvasRenderingContext2d.cc +3527 -0
  26. package/src/CanvasRenderingContext2d.h +238 -0
  27. package/src/CharData.h +233 -0
  28. package/src/FontParser.cc +605 -0
  29. package/src/FontParser.h +115 -0
  30. package/src/Image.cc +1719 -0
  31. package/src/Image.h +146 -0
  32. package/src/ImageData.cc +138 -0
  33. package/src/ImageData.h +26 -0
  34. package/src/InstanceData.h +12 -0
  35. package/src/JPEGStream.h +157 -0
  36. package/src/PNG.h +292 -0
  37. package/src/Point.h +11 -0
  38. package/src/Util.h +9 -0
  39. package/src/bmp/BMPParser.cc +459 -0
  40. package/src/bmp/BMPParser.h +60 -0
  41. package/src/bmp/LICENSE.md +24 -0
  42. package/src/closure.cc +52 -0
  43. package/src/closure.h +98 -0
  44. package/src/color.cc +796 -0
  45. package/src/color.h +30 -0
  46. package/src/dll_visibility.h +20 -0
  47. package/src/init.cc +114 -0
  48. package/src/register_font.cc +352 -0
  49. package/src/register_font.h +7 -0
  50. package/util/has_lib.js +119 -0
  51. 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
+ };