@muhammara/native-core 7.0.0-beta.4 → 7.0.0-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 +57 -7
- package/THIRD_PARTY_NOTICES.md +39 -0
- package/index.js +120 -1
- package/lib/PDFRStreamForBuffer.js +52 -7
- package/lib/PDFRStreamForFile.js +56 -7
- package/lib/PDFStreamForResponse.js +22 -5
- package/lib/PDFWStreamForBuffer.js +49 -10
- package/lib/PDFWStreamForFile.js +26 -5
- package/lib/Recipe.js +79 -28
- package/lib/content-stream.js +503 -0
- package/lib/css-colors.js +149 -0
- package/lib/font-text.js +1461 -0
- package/lib/glyph-list.js +1127 -0
- package/lib/recipe/annotation.js +464 -101
- package/lib/recipe/appendPage.js +2 -0
- package/lib/recipe/colors.js +132 -35
- package/lib/recipe/coordinate.js +82 -16
- package/lib/recipe/encrypt.js +32 -13
- package/lib/recipe/font.js +70 -25
- package/lib/recipe/graphics-state.js +3 -2
- package/lib/recipe/htmlToTextObjects.js +121 -24
- package/lib/recipe/image.js +34 -9
- package/lib/recipe/info.js +93 -22
- package/lib/recipe/insertPage.js +12 -3
- package/lib/recipe/overlay.js +4 -2
- package/lib/recipe/page-references.js +436 -0
- package/lib/recipe/page.js +363 -262
- package/lib/recipe/parameters.js +8 -1
- package/lib/recipe/replaceText.js +464 -30
- package/lib/recipe/shapes.js +418 -45
- package/lib/recipe/split.js +6 -2
- package/lib/recipe/table.js +41 -8
- package/lib/recipe/text.helper.js +172 -8
- package/lib/recipe/text.js +294 -56
- package/lib/recipe/utils.js +17 -6
- package/lib/recipe/vector-line.js +101 -39
- package/lib/recipe/vector-polygon.js +18 -6
- package/lib/recipe/vector.helper.js +148 -6
- package/lib/recipe/vector.js +150 -51
- package/lib/recipe/xObjectForm.js +73 -10
- package/lib/recipe-constants.js +373 -0
- package/muhammara.d.ts +3469 -155
- package/package.json +1 -1
package/lib/recipe/vector.js
CHANGED
|
@@ -13,31 +13,37 @@
|
|
|
13
13
|
// PercentColor component values range from 1 to 100.
|
|
14
14
|
|
|
15
15
|
const { linkPdf } = require("./annotation");
|
|
16
|
+
const muhammara = require("../muhammara");
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Draw a circle
|
|
19
20
|
* @name circle
|
|
20
21
|
* @function
|
|
21
22
|
* @memberof Recipe#
|
|
22
|
-
* @param {number} x - The coordinate x
|
|
23
|
-
* @param {number} y - The coordinate y
|
|
23
|
+
* @param {number|"center"} x - The coordinate x of the center
|
|
24
|
+
* @param {number|"center"} y - The coordinate y of the center
|
|
24
25
|
* @param {number} radius - The radius
|
|
25
26
|
* @param {Object} [options] - The options
|
|
26
27
|
* @param {string|number[]} [options.color] - HexColor, PercentColor or DecimalColor
|
|
27
28
|
* @param {string|number[]} [options.stroke] - HexColor, PercentColor or DecimalColor
|
|
28
|
-
* @param {string|number[]}[
|
|
29
|
+
* @param {string|number[]} [options.fill] - HexColor, PercentColor or DecimalColor
|
|
29
30
|
* @param {number} [options.lineWidth] - The line width
|
|
30
31
|
* @param {number} [options.opacity] - The opacity
|
|
31
32
|
* @param {number[]} [options.dash] - The dash style [number, number]
|
|
33
|
+
* @param {string} [options.link] - Make the circle's bounding square open this URL.
|
|
32
34
|
* @returns {Recipe} The recipe instance.
|
|
35
|
+
* @throws {TypeError} If no page is active.
|
|
33
36
|
*/
|
|
34
37
|
exports.circle = function circle(x, y, radius, options = {}) {
|
|
38
|
+
// null options act like omitted options.
|
|
39
|
+
if (options === null) options = {};
|
|
40
|
+
[x, y] = this._centrify(x, y);
|
|
35
41
|
const { nx, ny } = this._calibrateCoordinate(x, y);
|
|
36
42
|
const diameter = radius * 2;
|
|
37
43
|
|
|
38
44
|
if (options.fill) {
|
|
39
45
|
const pathOptions = this._getPathOptions(options, nx, ny);
|
|
40
|
-
pathOptions.type =
|
|
46
|
+
pathOptions.type = muhammara.DrawingPathType.FILL;
|
|
41
47
|
|
|
42
48
|
if (pathOptions.fill !== undefined) {
|
|
43
49
|
pathOptions.color = pathOptions.fill;
|
|
@@ -52,15 +58,20 @@ exports.circle = function circle(x, y, radius, options = {}) {
|
|
|
52
58
|
diameter,
|
|
53
59
|
pathOptions,
|
|
54
60
|
(ctx, xObject) => {
|
|
55
|
-
ctx
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
ctx.gs(xObject.getGsName(pathOptions.fillGsId));
|
|
62
|
+
this._setSeparationColor(xObject, pathOptions.fillModel, false);
|
|
63
|
+
ctx.drawCircle(
|
|
64
|
+
radius,
|
|
65
|
+
radius,
|
|
66
|
+
radius,
|
|
67
|
+
this._devicePathOptions(pathOptions),
|
|
68
|
+
);
|
|
58
69
|
},
|
|
59
70
|
);
|
|
60
71
|
}
|
|
61
72
|
if (options.stroke || options.color || !options.fill) {
|
|
62
73
|
const pathOptions = this._getPathOptions(options);
|
|
63
|
-
pathOptions.type =
|
|
74
|
+
pathOptions.type = muhammara.DrawingPathType.STROKE;
|
|
64
75
|
|
|
65
76
|
if (pathOptions.stroke !== undefined) {
|
|
66
77
|
pathOptions.color = pathOptions.stroke;
|
|
@@ -78,13 +89,18 @@ exports.circle = function circle(x, y, radius, options = {}) {
|
|
|
78
89
|
pathOptions,
|
|
79
90
|
(ctx, xObject) => {
|
|
80
91
|
ctx.gs(xObject.getGsName(pathOptions.strokeGsId));
|
|
92
|
+
this._setSeparationColor(
|
|
93
|
+
xObject,
|
|
94
|
+
pathOptions.strokeModel || pathOptions.colorModel,
|
|
95
|
+
true,
|
|
96
|
+
);
|
|
81
97
|
ctx
|
|
82
98
|
.d(pathOptions.dash, pathOptions.dashPhase)
|
|
83
99
|
.drawCircle(
|
|
84
100
|
radius,
|
|
85
101
|
radius,
|
|
86
|
-
radius - pathOptions.width / 2,
|
|
87
|
-
pathOptions,
|
|
102
|
+
Math.max(0, radius - pathOptions.width / 2),
|
|
103
|
+
this._devicePathOptions(pathOptions),
|
|
88
104
|
);
|
|
89
105
|
|
|
90
106
|
// ... requires adjusting the internal drawing to accomodate line thickness.
|
|
@@ -101,8 +117,8 @@ exports.circle = function circle(x, y, radius, options = {}) {
|
|
|
101
117
|
* @name rectangle
|
|
102
118
|
* @function
|
|
103
119
|
* @memberof Recipe#
|
|
104
|
-
* @param {number} x - The coordinate x
|
|
105
|
-
* @param {number} y - The coordinate y
|
|
120
|
+
* @param {number|"center"} x - The coordinate x of the top-left corner
|
|
121
|
+
* @param {number|"center"} y - The coordinate y of the top-left corner
|
|
106
122
|
* @param {number} width - The width
|
|
107
123
|
* @param {number} height - The height
|
|
108
124
|
* @param {Object} [options] - The options
|
|
@@ -118,9 +134,14 @@ exports.circle = function circle(x, y, radius, options = {}) {
|
|
|
118
134
|
* When a one to four number array can be used to give specific sizees to each corner.
|
|
119
135
|
* The numbering starts from the top, left corner, and goes clockwise around the text box.
|
|
120
136
|
* Missing values in the array are filled in by opposite corner values.
|
|
137
|
+
* @param {string} [options.link] - Make the rectangle open this URL.
|
|
138
|
+
* @param {boolean} [options.useGivenCoords] - Take x and y as PDF coordinates of the bottom-left corner.
|
|
121
139
|
* @returns {Recipe} The recipe instance.
|
|
140
|
+
* @throws {TypeError} If no page is active.
|
|
122
141
|
*/
|
|
123
142
|
exports.rectangle = function rectangle(x, y, width, height, options = {}) {
|
|
143
|
+
// null options act like omitted options.
|
|
144
|
+
if (options === null) options = {};
|
|
124
145
|
const { nx, ny } = options.useGivenCoords
|
|
125
146
|
? { nx: x, ny: y }
|
|
126
147
|
: this._calibrateCoordinate(x, y, 0, -height);
|
|
@@ -130,7 +151,7 @@ exports.rectangle = function rectangle(x, y, width, height, options = {}) {
|
|
|
130
151
|
pathOptions.useGivenCoords = options.useGivenCoords;
|
|
131
152
|
|
|
132
153
|
if (options.fill) {
|
|
133
|
-
pathOptions.type =
|
|
154
|
+
pathOptions.type = muhammara.DrawingPathType.FILL;
|
|
134
155
|
|
|
135
156
|
if (pathOptions.fill !== undefined) {
|
|
136
157
|
pathOptions.color = pathOptions.fill;
|
|
@@ -153,20 +174,28 @@ exports.rectangle = function rectangle(x, y, width, height, options = {}) {
|
|
|
153
174
|
drawRoundedRectangle(ctx, 0, 0, width, height, options.borderRadius);
|
|
154
175
|
ctx.f();
|
|
155
176
|
} else {
|
|
156
|
-
ctx.drawRectangle(
|
|
177
|
+
ctx.drawRectangle(
|
|
178
|
+
0,
|
|
179
|
+
0,
|
|
180
|
+
width,
|
|
181
|
+
height,
|
|
182
|
+
this._devicePathOptions(pathOptions),
|
|
183
|
+
);
|
|
157
184
|
}
|
|
158
185
|
},
|
|
159
186
|
);
|
|
160
187
|
}
|
|
161
188
|
|
|
162
189
|
if (options.stroke || options.color || !options.fill) {
|
|
163
|
-
pathOptions.type =
|
|
190
|
+
pathOptions.type = muhammara.DrawingPathType.STROKE;
|
|
164
191
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
pathOptions.
|
|
168
|
-
|
|
169
|
-
|
|
192
|
+
// The fill above may have replaced the color; stroke with `color`.
|
|
193
|
+
colorModel =
|
|
194
|
+
pathOptions.stroke !== undefined
|
|
195
|
+
? pathOptions.strokeModel
|
|
196
|
+
: pathOptions.colorModel;
|
|
197
|
+
pathOptions.color = colorModel.color;
|
|
198
|
+
pathOptions.colorspace = colorModel.colorspace;
|
|
170
199
|
|
|
171
200
|
// To honor the given width and height of the rectangle ...
|
|
172
201
|
|
|
@@ -186,24 +215,26 @@ exports.rectangle = function rectangle(x, y, width, height, options = {}) {
|
|
|
186
215
|
if (options.borderRadius) {
|
|
187
216
|
ctx.w(pathOptions.width).d(pathOptions.dash, pathOptions.dashPhase);
|
|
188
217
|
|
|
218
|
+
const inset = Math.min(margin / 2, width / 2, height / 2);
|
|
189
219
|
drawRoundedRectangle(
|
|
190
220
|
ctx,
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
width -
|
|
194
|
-
height -
|
|
221
|
+
inset,
|
|
222
|
+
inset,
|
|
223
|
+
width - inset * 2,
|
|
224
|
+
height - inset * 2,
|
|
195
225
|
options.borderRadius,
|
|
226
|
+
inset,
|
|
196
227
|
);
|
|
197
228
|
ctx.S();
|
|
198
229
|
} else {
|
|
199
230
|
ctx
|
|
200
231
|
.d(pathOptions.dash, pathOptions.dashPhase)
|
|
201
232
|
.drawRectangle(
|
|
202
|
-
margin / 2,
|
|
203
|
-
margin / 2,
|
|
204
|
-
width - margin,
|
|
205
|
-
height - margin,
|
|
206
|
-
pathOptions,
|
|
233
|
+
Math.min(margin / 2, width / 2),
|
|
234
|
+
Math.min(margin / 2, height / 2),
|
|
235
|
+
Math.max(0, width - margin),
|
|
236
|
+
Math.max(0, height - margin),
|
|
237
|
+
this._devicePathOptions(pathOptions),
|
|
207
238
|
);
|
|
208
239
|
}
|
|
209
240
|
},
|
|
@@ -218,7 +249,28 @@ exports.rectangle = function rectangle(x, y, width, height, options = {}) {
|
|
|
218
249
|
return this;
|
|
219
250
|
};
|
|
220
251
|
|
|
221
|
-
|
|
252
|
+
/**
|
|
253
|
+
* Append a rectangle path with rounded corners.
|
|
254
|
+
* @private
|
|
255
|
+
* @param {Object} ctx - The content context.
|
|
256
|
+
* @param {number} left - The left edge.
|
|
257
|
+
* @param {number} bottom - The bottom edge.
|
|
258
|
+
* @param {number} width - The width.
|
|
259
|
+
* @param {number} height - The height.
|
|
260
|
+
* @param {number|number[]} radii - One radius, or up to four clockwise from
|
|
261
|
+
* the top-left corner; missing ones come from the opposite corner.
|
|
262
|
+
* @param {number} [inset=0] - How far to move the path inside the rectangle.
|
|
263
|
+
* @returns {void}
|
|
264
|
+
*/
|
|
265
|
+
function drawRoundedRectangle(
|
|
266
|
+
ctx,
|
|
267
|
+
left,
|
|
268
|
+
bottom,
|
|
269
|
+
width,
|
|
270
|
+
height,
|
|
271
|
+
radii,
|
|
272
|
+
inset = 0,
|
|
273
|
+
) {
|
|
222
274
|
let radius = [];
|
|
223
275
|
|
|
224
276
|
// populate radius array accordingly.
|
|
@@ -244,6 +296,8 @@ function drawRoundedRectangle(ctx, left, bottom, width, height, radii) {
|
|
|
244
296
|
break;
|
|
245
297
|
}
|
|
246
298
|
}
|
|
299
|
+
// Keep inset corners concentric with the nominal corners.
|
|
300
|
+
radius = radius.map((value) => Math.max(0, value - inset));
|
|
247
301
|
const K = 0.551784;
|
|
248
302
|
const right = left + width;
|
|
249
303
|
const top = bottom + height;
|
|
@@ -296,8 +350,8 @@ function drawRoundedRectangle(ctx, left, bottom, width, height, radii) {
|
|
|
296
350
|
* @name ellipse
|
|
297
351
|
* @function
|
|
298
352
|
* @memberof Recipe#
|
|
299
|
-
* @param {number} cx x-coordinate of center point of ellipse
|
|
300
|
-
* @param {number} cy y-coordinate of center point of ellipse
|
|
353
|
+
* @param {number|"center"} cx x-coordinate of center point of ellipse
|
|
354
|
+
* @param {number|"center"} cy y-coordinate of center point of ellipse
|
|
301
355
|
* @param {number} rx radius length from the center point along x-axis
|
|
302
356
|
* @param {number} ry radius length from the center point along y-axis
|
|
303
357
|
* @param {Object} [options]
|
|
@@ -310,8 +364,12 @@ function drawRoundedRectangle(ctx, left, bottom, width, height, radii) {
|
|
|
310
364
|
* @param {number} [options.rotation] - Accept: +/- 0 through 360. Default: 0
|
|
311
365
|
* @param {number[]} [options.rotationOrigin] - [originX, originY] Default: x, y
|
|
312
366
|
* @returns {Recipe} The recipe instance.
|
|
367
|
+
* @throws {TypeError} If no page is active.
|
|
313
368
|
*/
|
|
314
369
|
exports.ellipse = function ellipse(cx, cy, rx, ry, options = {}) {
|
|
370
|
+
// null options act like omitted options.
|
|
371
|
+
if (options === null) options = {};
|
|
372
|
+
[cx, cy] = this._centrify(cx, cy);
|
|
315
373
|
const { nx, ny } = this._calibrateCoordinate(cx, cy);
|
|
316
374
|
|
|
317
375
|
const pathOptions = this._getPathOptions(options, nx, ny);
|
|
@@ -322,8 +380,8 @@ exports.ellipse = function ellipse(cx, cy, rx, ry, options = {}) {
|
|
|
322
380
|
|
|
323
381
|
const drawEllipse = (ctx, x, y, w, h) => {
|
|
324
382
|
const magic = 0.551784; // from https://www.tinaja.com/glib/ellipse4.pdf
|
|
325
|
-
const ox =
|
|
326
|
-
const oy =
|
|
383
|
+
const ox = (w / 2) * magic; // control point offset horizontal
|
|
384
|
+
const oy = (h / 2) * magic; // control point offset vertical
|
|
327
385
|
const xe = x + w; // x-end, opposite corner from origin
|
|
328
386
|
const ye = y + h; // y-end, opposite corner from origin
|
|
329
387
|
const xm = rx; // x-middle of enclosing rectangle
|
|
@@ -359,9 +417,11 @@ exports.ellipse = function ellipse(cx, cy, rx, ry, options = {}) {
|
|
|
359
417
|
}
|
|
360
418
|
|
|
361
419
|
if (options.stroke || options.color || !options.fill) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
420
|
+
// The fill above may have replaced colorModel; stroke with `color`.
|
|
421
|
+
colorModel =
|
|
422
|
+
pathOptions.stroke !== undefined
|
|
423
|
+
? pathOptions.strokeModel
|
|
424
|
+
: pathOptions.colorModel;
|
|
365
425
|
|
|
366
426
|
// To honor the given width and height of the enclosing rectangle ...
|
|
367
427
|
|
|
@@ -381,10 +441,10 @@ exports.ellipse = function ellipse(cx, cy, rx, ry, options = {}) {
|
|
|
381
441
|
// ... requires adjusting the internal drawing to accomodate line thickness.
|
|
382
442
|
drawEllipse(
|
|
383
443
|
ctx,
|
|
384
|
-
margin,
|
|
385
|
-
margin,
|
|
386
|
-
width - pathOptions.width,
|
|
387
|
-
height - pathOptions.width,
|
|
444
|
+
Math.min(margin, rx),
|
|
445
|
+
Math.min(margin, ry),
|
|
446
|
+
Math.max(0, width - pathOptions.width),
|
|
447
|
+
Math.max(0, height - pathOptions.width),
|
|
388
448
|
);
|
|
389
449
|
ctx.S();
|
|
390
450
|
},
|
|
@@ -394,6 +454,18 @@ exports.ellipse = function ellipse(cx, cy, rx, ry, options = {}) {
|
|
|
394
454
|
return this;
|
|
395
455
|
};
|
|
396
456
|
|
|
457
|
+
/**
|
|
458
|
+
* Append a circular arc path built from Bézier segments.
|
|
459
|
+
* @private
|
|
460
|
+
* @param {Object} ctx - The content context.
|
|
461
|
+
* @param {number} x - The center x.
|
|
462
|
+
* @param {number} y - The center y.
|
|
463
|
+
* @param {number} radius - The radius.
|
|
464
|
+
* @param {number} startAngle - The start angle in degrees.
|
|
465
|
+
* @param {number} endAngle - The end angle in degrees.
|
|
466
|
+
* @param {boolean} [fromCenter=false] - Start the path at the center, for a sector.
|
|
467
|
+
* @returns {void}
|
|
468
|
+
*/
|
|
397
469
|
function drawArc(ctx, x, y, radius, startAngle, endAngle, fromCenter = false) {
|
|
398
470
|
const TWO_PI = 2.0 * Math.PI;
|
|
399
471
|
const HALF_PI = 0.5 * Math.PI;
|
|
@@ -459,8 +531,8 @@ function drawArc(ctx, x, y, radius, startAngle, endAngle, fromCenter = false) {
|
|
|
459
531
|
* @name arc
|
|
460
532
|
* @function
|
|
461
533
|
* @memberof Recipe#
|
|
462
|
-
* @param {number} x - the x coordinate of the arc center point
|
|
463
|
-
* @param {number} y - the y coordinate of the arc center point
|
|
534
|
+
* @param {number|"center"} x - the x coordinate of the arc center point
|
|
535
|
+
* @param {number|"center"} y - the y coordinate of the arc center point
|
|
464
536
|
* @param {number} radius - the distance from the given x,y coordinates from which to produce the arc
|
|
465
537
|
* @param {number} [startAngle=0] - the start of the arc in degree units +/- 0 through 360. Positive values go clockwise, Negative values, counterclockwise.
|
|
466
538
|
* @param {number} [endAngle=360] - the end of the arc in degree units +/- 0 through 360. Positive values go clockwise, Negative values, counterclockwise.
|
|
@@ -474,6 +546,7 @@ function drawArc(ctx, x, y, radius, startAngle, endAngle, fromCenter = false) {
|
|
|
474
546
|
* @param {number} [options.rotation=0] - Accept: +/- 0 through 360.
|
|
475
547
|
* @param {number[]} [options.rotationOrigin] - [originX, originY] Default: x, y
|
|
476
548
|
* @returns {Recipe} The recipe instance.
|
|
549
|
+
* @throws {TypeError} If no page is active.
|
|
477
550
|
*/
|
|
478
551
|
exports.arc = function arc(
|
|
479
552
|
x,
|
|
@@ -483,6 +556,9 @@ exports.arc = function arc(
|
|
|
483
556
|
endAngle = 360,
|
|
484
557
|
options = {},
|
|
485
558
|
) {
|
|
559
|
+
// null options act like omitted options.
|
|
560
|
+
if (options === null) options = {};
|
|
561
|
+
[x, y] = this._centrify(x, y);
|
|
486
562
|
const { nx, ny } = this._calibrateCoordinate(x, y);
|
|
487
563
|
const diameter = radius * 2;
|
|
488
564
|
const pathOptions = this._getPathOptions(options, nx, ny);
|
|
@@ -517,9 +593,11 @@ exports.arc = function arc(
|
|
|
517
593
|
}
|
|
518
594
|
|
|
519
595
|
if (options.stroke || options.color || !options.fill) {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
596
|
+
// The fill above may have replaced colorModel; stroke with `color`.
|
|
597
|
+
colorModel =
|
|
598
|
+
pathOptions.stroke !== undefined
|
|
599
|
+
? pathOptions.strokeModel
|
|
600
|
+
: pathOptions.colorModel;
|
|
523
601
|
|
|
524
602
|
// To honor the given width and height of the enclosing rectangle ...
|
|
525
603
|
|
|
@@ -537,7 +615,15 @@ exports.arc = function arc(
|
|
|
537
615
|
ctx.w(pathOptions.width).d(pathOptions.dash, pathOptions.dashPhase);
|
|
538
616
|
|
|
539
617
|
// ... requires adjusting the internal drawing to accomodate line thickness.
|
|
540
|
-
drawArc(
|
|
618
|
+
drawArc(
|
|
619
|
+
ctx,
|
|
620
|
+
radius,
|
|
621
|
+
radius,
|
|
622
|
+
Math.max(0, radius - margin),
|
|
623
|
+
sAng,
|
|
624
|
+
eAng,
|
|
625
|
+
sector,
|
|
626
|
+
);
|
|
541
627
|
if (sector) {
|
|
542
628
|
ctx.h();
|
|
543
629
|
} // close off path to create a circle sector.
|
|
@@ -556,13 +642,14 @@ exports.arc = function arc(
|
|
|
556
642
|
* @name pie
|
|
557
643
|
* @function
|
|
558
644
|
* @memberof Recipe#
|
|
559
|
-
* @param {number} x - the x coordinate of the pie center point
|
|
560
|
-
* @param {number} y - the y coordinate of the pie center point
|
|
645
|
+
* @param {number|"center"} x - the x coordinate of the pie center point
|
|
646
|
+
* @param {number|"center"} y - the y coordinate of the pie center point
|
|
561
647
|
* @param {number} radius - the distance from the center point to the arc
|
|
562
648
|
* @param {number} [startAngle=0] - the start of the arc in degree units
|
|
563
649
|
* @param {number} [endAngle=360] - the end of the arc in degree units
|
|
564
650
|
* @param {Object} [options] - The path options.
|
|
565
651
|
* @returns {Recipe} The recipe instance.
|
|
652
|
+
* @throws {TypeError} If no page is active.
|
|
566
653
|
*/
|
|
567
654
|
exports.pie = function pie(x, y, radius, startAngle, endAngle, options = {}) {
|
|
568
655
|
return this.arc(x, y, radius, startAngle, endAngle, {
|
|
@@ -579,14 +666,17 @@ exports.pie = function pie(x, y, radius, startAngle, endAngle, options = {}) {
|
|
|
579
666
|
* @param {Recipe.LineStyleOptions} [options] - The line style options.
|
|
580
667
|
* @param {number} [options.width] - The line width.
|
|
581
668
|
* @param {number} [options.lineWidth] - Alias for width.
|
|
582
|
-
* @param {number} [options.cap] - The PDF line cap style.
|
|
583
|
-
* @param {number} [options.join] - The PDF line join style.
|
|
669
|
+
* @param {number} [options.cap] - The PDF line cap style, a `LineCapStyle` value.
|
|
670
|
+
* @param {number} [options.join] - The PDF line join style: 0 miter, 1 round, 2 bevel.
|
|
584
671
|
* @param {number} [options.miterLimit] - The miter limit.
|
|
585
672
|
* @param {number[]} [options.dash] - The dash pattern.
|
|
586
673
|
* @param {number} [options.dashPhase] - The dash pattern phase.
|
|
587
674
|
* @returns {Recipe} The recipe instance.
|
|
675
|
+
* @throws {TypeError} If no page is active.
|
|
588
676
|
*/
|
|
589
677
|
exports.lineStyle = function lineStyle(options = {}) {
|
|
678
|
+
// null options act like omitted options.
|
|
679
|
+
if (options === null) options = {};
|
|
590
680
|
this.current = this.current || {};
|
|
591
681
|
this.current.lineStyle = this.current.lineStyle || {};
|
|
592
682
|
|
|
@@ -617,6 +707,13 @@ exports.lineStyle = function lineStyle(options = {}) {
|
|
|
617
707
|
return this._setLineStyle(options);
|
|
618
708
|
};
|
|
619
709
|
|
|
710
|
+
/**
|
|
711
|
+
* Write the given line style options to the page content context.
|
|
712
|
+
* @private
|
|
713
|
+
* @param {Object} [options] - The lineStyle() options.
|
|
714
|
+
* @returns {Recipe} The recipe instance.
|
|
715
|
+
* @throws {TypeError} If no page is active.
|
|
716
|
+
*/
|
|
620
717
|
exports._setLineStyle = function _setLineStyle(options = {}) {
|
|
621
718
|
if (options.width !== undefined || options.lineWidth !== undefined)
|
|
622
719
|
this.pageContext.w(options.width ?? options.lineWidth);
|
|
@@ -639,6 +736,7 @@ exports._setLineStyle = function _setLineStyle(options = {}) {
|
|
|
639
736
|
* @memberof Recipe#
|
|
640
737
|
* @param {number} width - The line width.
|
|
641
738
|
* @returns {Recipe} The recipe instance.
|
|
739
|
+
* @throws {TypeError} If no page is active.
|
|
642
740
|
*/
|
|
643
741
|
exports.lineWidth = function lineWidth(width) {
|
|
644
742
|
return this.lineStyle({ width });
|
|
@@ -652,6 +750,7 @@ exports.lineWidth = function lineWidth(width) {
|
|
|
652
750
|
* @memberof Recipe#
|
|
653
751
|
* @param {number} value - The requested opacity from 0 (transparent) to 1 (opaque).
|
|
654
752
|
* @returns {Recipe} The recipe instance.
|
|
753
|
+
* @throws {RangeError} If the value is not a finite number from 0 to 1.
|
|
655
754
|
*/
|
|
656
755
|
exports.opacity = function opacity(value) {
|
|
657
756
|
if (!Number.isFinite(value) || value < 0 || value > 1) {
|
|
@@ -1,33 +1,52 @@
|
|
|
1
|
+
const { Colorspace } = require("../recipe-constants");
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Writes device color operators for a color model.
|
|
5
|
+
* @private
|
|
6
|
+
*/
|
|
1
7
|
const Color = class Color {
|
|
8
|
+
/** Not meant to be instantiated; use the static methods. */
|
|
2
9
|
constructor() {}
|
|
3
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Set the fill color.
|
|
13
|
+
* @param {Object} ctx - The content context.
|
|
14
|
+
* @param {Object} colorModel - The color model from _transformColor().
|
|
15
|
+
* @returns {void}
|
|
16
|
+
*/
|
|
4
17
|
static fill(ctx, colorModel) {
|
|
5
18
|
switch (colorModel.colorspace) {
|
|
6
|
-
case
|
|
19
|
+
case Colorspace.RGB:
|
|
7
20
|
ctx.rg(colorModel.r, colorModel.g, colorModel.b);
|
|
8
21
|
break;
|
|
9
22
|
|
|
10
|
-
case
|
|
23
|
+
case Colorspace.CMYK:
|
|
11
24
|
ctx.k(colorModel.c, colorModel.m, colorModel.y, colorModel.k);
|
|
12
25
|
break;
|
|
13
26
|
|
|
14
|
-
case
|
|
27
|
+
case Colorspace.GRAY:
|
|
15
28
|
ctx.g(colorModel.gray);
|
|
16
29
|
break;
|
|
17
30
|
}
|
|
18
31
|
}
|
|
19
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Set the stroke color.
|
|
35
|
+
* @param {Object} ctx - The content context.
|
|
36
|
+
* @param {Object} colorModel - The color model from _transformColor().
|
|
37
|
+
* @returns {void}
|
|
38
|
+
*/
|
|
20
39
|
static stroke(ctx, colorModel) {
|
|
21
40
|
switch (colorModel.colorspace) {
|
|
22
|
-
case
|
|
41
|
+
case Colorspace.RGB:
|
|
23
42
|
ctx.RG(colorModel.r, colorModel.g, colorModel.b);
|
|
24
43
|
break;
|
|
25
44
|
|
|
26
|
-
case
|
|
45
|
+
case Colorspace.CMYK:
|
|
27
46
|
ctx.K(colorModel.c, colorModel.m, colorModel.y, colorModel.k);
|
|
28
47
|
break;
|
|
29
48
|
|
|
30
|
-
case
|
|
49
|
+
case Colorspace.GRAY:
|
|
31
50
|
ctx.G(colorModel.gray);
|
|
32
51
|
break;
|
|
33
52
|
}
|
|
@@ -36,7 +55,17 @@ const Color = class Color {
|
|
|
36
55
|
|
|
37
56
|
exports.Color = Color;
|
|
38
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Creates a writer form XObject extended with Recipe helpers; the
|
|
60
|
+
* constructor returns the form itself.
|
|
61
|
+
* @private
|
|
62
|
+
*/
|
|
39
63
|
exports.xObjectForm = class xObjectForm {
|
|
64
|
+
/**
|
|
65
|
+
* @param {Object} pdfWriter - The PDF writer.
|
|
66
|
+
* @param {number} [width=100] - The form width.
|
|
67
|
+
* @param {number} [height=100] - The form height.
|
|
68
|
+
*/
|
|
40
69
|
constructor(pdfWriter, width = 100, height = 100) {
|
|
41
70
|
const xObject = pdfWriter.createFormXObject(0, 0, width, height);
|
|
42
71
|
xObject.pdfWriter = pdfWriter;
|
|
@@ -50,32 +79,61 @@ exports.xObjectForm = class xObjectForm {
|
|
|
50
79
|
return xObject;
|
|
51
80
|
}
|
|
52
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Store a value on the form, such as its Recipe cache key.
|
|
84
|
+
* @param {string} key - The key.
|
|
85
|
+
* @param {*} value - The value.
|
|
86
|
+
* @returns {void}
|
|
87
|
+
*/
|
|
53
88
|
set(key, value) {
|
|
54
89
|
this._values = this._values || {};
|
|
55
90
|
this._values[key] = value;
|
|
56
91
|
}
|
|
57
92
|
|
|
93
|
+
/**
|
|
94
|
+
* @param {string} key - The key.
|
|
95
|
+
* @returns {*} The stored value, or undefined.
|
|
96
|
+
*/
|
|
58
97
|
get(key) {
|
|
59
98
|
this._values = this._values || {};
|
|
60
99
|
return this._values[key];
|
|
61
100
|
}
|
|
62
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Map a graphics state into the form resources.
|
|
104
|
+
* @param {number} gsId - The ExtGState object ID.
|
|
105
|
+
* @returns {string} The resource name.
|
|
106
|
+
*/
|
|
63
107
|
getGsName(gsId) {
|
|
64
|
-
const resourcesDict = this.
|
|
108
|
+
const resourcesDict = this.getResourcesDictionary();
|
|
65
109
|
const gsName = resourcesDict.addExtGStateMapping(gsId);
|
|
66
110
|
return gsName;
|
|
67
111
|
}
|
|
68
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Map a color space into the form resources.
|
|
115
|
+
* @param {number} csId - The color space object ID.
|
|
116
|
+
* @returns {string} The resource name.
|
|
117
|
+
*/
|
|
69
118
|
getCsName(csId) {
|
|
70
|
-
const resourcesDict = this.
|
|
119
|
+
const resourcesDict = this.getResourcesDictionary();
|
|
71
120
|
const csName = resourcesDict.addColorSpaceMapping(csId);
|
|
72
121
|
return csName;
|
|
73
122
|
}
|
|
74
123
|
|
|
124
|
+
/**
|
|
125
|
+
* End the form so it can be placed.
|
|
126
|
+
* @returns {void}
|
|
127
|
+
*/
|
|
75
128
|
end() {
|
|
76
129
|
this.pdfWriter.endFormXObject(this);
|
|
77
130
|
}
|
|
78
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Set the fill color in the form, including separation colors.
|
|
134
|
+
* @param {Object} colorModel - The color model from _transformColor().
|
|
135
|
+
* @returns {Object} The form.
|
|
136
|
+
*/
|
|
79
137
|
fill(colorModel) {
|
|
80
138
|
const ctx = this.getContentContext();
|
|
81
139
|
switch (colorModel.colorspace) {
|
|
@@ -83,7 +141,7 @@ exports.xObjectForm = class xObjectForm {
|
|
|
83
141
|
Color.fill(ctx, colorModel);
|
|
84
142
|
break;
|
|
85
143
|
|
|
86
|
-
case
|
|
144
|
+
case Colorspace.SEPARATION:
|
|
87
145
|
ctx.cs(this.getCsName(colorModel.colorspaceId));
|
|
88
146
|
ctx.scn(1);
|
|
89
147
|
break;
|
|
@@ -91,6 +149,11 @@ exports.xObjectForm = class xObjectForm {
|
|
|
91
149
|
return this;
|
|
92
150
|
}
|
|
93
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Set the stroke color in the form, including separation colors.
|
|
154
|
+
* @param {Object} colorModel - The color model from _transformColor().
|
|
155
|
+
* @returns {Object} The form.
|
|
156
|
+
*/
|
|
94
157
|
stroke(colorModel) {
|
|
95
158
|
const ctx = this.getContentContext();
|
|
96
159
|
switch (colorModel.colorspace) {
|
|
@@ -98,7 +161,7 @@ exports.xObjectForm = class xObjectForm {
|
|
|
98
161
|
Color.stroke(ctx, colorModel);
|
|
99
162
|
break;
|
|
100
163
|
|
|
101
|
-
case
|
|
164
|
+
case Colorspace.SEPARATION:
|
|
102
165
|
ctx.CS(this.getCsName(colorModel.colorspaceId));
|
|
103
166
|
ctx.SCN(1);
|
|
104
167
|
break;
|