@digicole/pdfmake-rtl 1.2.0 → 2.1.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 (100) hide show
  1. package/.vscode/tasks.json +17 -0
  2. package/CHANGELOG.md +83 -128
  3. package/LICENSE +22 -22
  4. package/README.md +188 -681
  5. package/build/fonts/Cairo/Cairo-Black.ttf +0 -0
  6. package/build/fonts/Cairo/Cairo-Bold.ttf +0 -0
  7. package/build/fonts/Cairo/Cairo-ExtraLight.ttf +0 -0
  8. package/build/fonts/Cairo/Cairo-Light.ttf +0 -0
  9. package/build/fonts/Cairo/Cairo-Regular.ttf +0 -0
  10. package/build/fonts/Cairo/Cairo-SemiBold.ttf +0 -0
  11. package/build/fonts/Cairo.js +27 -0
  12. package/build/fonts/Roboto/Roboto-Italic.ttf +0 -0
  13. package/build/fonts/Roboto/Roboto-Medium.ttf +0 -0
  14. package/build/fonts/Roboto/Roboto-MediumItalic.ttf +0 -0
  15. package/build/fonts/Roboto/Roboto-Regular.ttf +0 -0
  16. package/build/fonts/Roboto.js +27 -0
  17. package/build/pdfmake.js +63736 -71285
  18. package/build/pdfmake.js.map +1 -1
  19. package/build/pdfmake.min.js +2 -2
  20. package/build/pdfmake.min.js.map +1 -1
  21. package/build/standard-fonts/Courier.js +27 -0
  22. package/build/standard-fonts/Helvetica.js +27 -0
  23. package/build/standard-fonts/Symbol.js +21 -0
  24. package/build/standard-fonts/Times.js +27 -0
  25. package/build/standard-fonts/ZapfDingbats.js +21 -0
  26. package/build/vfs_fonts.js +11 -7
  27. package/build-vfs.js +44 -44
  28. package/fonts/Cairo/Cairo-Black.ttf +0 -0
  29. package/fonts/Cairo/Cairo-Bold.ttf +0 -0
  30. package/fonts/Cairo/Cairo-ExtraLight.ttf +0 -0
  31. package/fonts/Cairo/Cairo-Light.ttf +0 -0
  32. package/fonts/Cairo/Cairo-Regular.ttf +0 -0
  33. package/fonts/Cairo/Cairo-SemiBold.ttf +0 -0
  34. package/fonts/Cairo.js +8 -0
  35. package/fonts/Roboto/Roboto-Italic.ttf +0 -0
  36. package/fonts/Roboto/Roboto-Medium.ttf +0 -0
  37. package/fonts/Roboto/Roboto-MediumItalic.ttf +0 -0
  38. package/fonts/Roboto/Roboto-Regular.ttf +0 -0
  39. package/fonts/Roboto.js +8 -0
  40. package/index.js +26 -26
  41. package/package.json +42 -39
  42. package/src/3rd-party/svg-to-pdfkit/LICENSE +9 -9
  43. package/src/3rd-party/svg-to-pdfkit/source.js +229 -36
  44. package/src/3rd-party/svg-to-pdfkit.js +3 -3
  45. package/src/OutputDocument.js +64 -0
  46. package/src/OutputDocumentServer.js +32 -0
  47. package/src/PDFDocument.js +174 -0
  48. package/src/PageSize.js +53 -0
  49. package/src/Renderer.js +445 -0
  50. package/src/TextBreaker.js +168 -0
  51. package/src/TextInlines.js +263 -0
  52. package/src/URLResolver.js +43 -0
  53. package/src/base.js +70 -0
  54. package/src/browser-extensions/OutputDocumentBrowser.js +80 -0
  55. package/src/browser-extensions/fonts/Cairo.js +27 -0
  56. package/src/browser-extensions/fonts/Roboto.js +27 -0
  57. package/src/browser-extensions/index.js +61 -0
  58. package/src/browser-extensions/pdfMake.js +1 -355
  59. package/src/browser-extensions/standard-fonts/Courier.js +27 -0
  60. package/src/browser-extensions/standard-fonts/Helvetica.js +27 -0
  61. package/src/browser-extensions/standard-fonts/Symbol.js +21 -0
  62. package/src/browser-extensions/standard-fonts/Times.js +27 -0
  63. package/src/browser-extensions/standard-fonts/ZapfDingbats.js +21 -0
  64. package/src/browser-extensions/virtual-fs-cjs.js +1 -0
  65. package/src/columnCalculator.js +154 -157
  66. package/src/docMeasure.js +802 -810
  67. package/src/docPreprocessor.js +306 -273
  68. package/src/documentContext.js +345 -340
  69. package/src/elementWriter.js +736 -411
  70. package/src/helpers/node.js +136 -0
  71. package/src/helpers/tools.js +44 -0
  72. package/src/helpers/variableType.js +50 -0
  73. package/src/index.js +16 -0
  74. package/src/layoutBuilder.js +1393 -1197
  75. package/src/line.js +122 -104
  76. package/src/pageElementWriter.js +187 -174
  77. package/src/printer.js +370 -727
  78. package/src/qrEnc.js +796 -791
  79. package/src/rtlUtils.js +500 -485
  80. package/src/standardPageSizes.js +52 -54
  81. package/src/styleContextStack.js +208 -138
  82. package/src/svgMeasure.js +109 -70
  83. package/src/tableLayouts.js +100 -0
  84. package/src/tableProcessor.js +620 -606
  85. package/src/textDecorator.js +175 -157
  86. package/src/virtual-fs.js +66 -0
  87. package/standard-fonts/Courier.js +8 -0
  88. package/standard-fonts/Helvetica.js +8 -0
  89. package/standard-fonts/Symbol.js +5 -0
  90. package/standard-fonts/Times.js +8 -0
  91. package/standard-fonts/ZapfDingbats.js +5 -0
  92. package/index.html +0 -396
  93. package/src/browser-extensions/URLBrowserResolver.js +0 -96
  94. package/src/browser-extensions/virtual-fs.js +0 -55
  95. package/src/fontProvider.js +0 -68
  96. package/src/helpers.js +0 -138
  97. package/src/imageMeasure.js +0 -62
  98. package/src/pdfKitEngine.js +0 -21
  99. package/src/textTools.js +0 -391
  100. package/src/traversalTracker.js +0 -47
@@ -60,7 +60,8 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
60
60
  'display': {inherit: false, initial: 'inline', values: {'none':'none', 'inline':'inline', 'block':'inline'}},
61
61
  'clip-path': {inherit: false, initial: 'none'},
62
62
  'mask': {inherit: false, initial: 'none'},
63
- 'overflow': {inherit: false, initial: 'hidden', values: {'hidden':'hidden', 'scroll':'hidden', 'visible':'visible'}}
63
+ 'overflow': {inherit: false, initial: 'hidden', values: {'hidden':'hidden', 'scroll':'hidden', 'visible':'visible'}},
64
+ 'vector-effect': {inherit: true, initial: 'none', values: {'none':'none', 'non-scaling-stroke':'non-scaling-stroke'}}
64
65
  };
65
66
 
66
67
  function docBeginGroup(bbox) {
@@ -113,11 +114,13 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
113
114
  doc.addContent('/' + name + ' gs');
114
115
  }
115
116
  function docCreatePattern(group, dx, dy, matrix) {
116
- let pattern = new (function PDFPattern() {})();
117
- pattern.group = group;
118
- pattern.dx = dx;
119
- pattern.dy = dy;
120
- pattern.matrix = matrix || [1, 0, 0, 1, 0, 0];
117
+ let pattern = {
118
+ type: 'PDFPattern',
119
+ group: group,
120
+ dx: dx,
121
+ dy: dy,
122
+ matrix: matrix || [1, 0, 0, 1, 0, 0],
123
+ }
121
124
  return pattern;
122
125
  }
123
126
  function docUsePattern(pattern, stroke) {
@@ -153,14 +156,62 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
153
156
  let mode = fill && stroke ? 2 : stroke ? 1 : fill ? 0 : 3;
154
157
  doc.addContent(mode + ' Tr');
155
158
  }
156
- function docWriteGlyph(glyph) {
157
- doc.addContent('<' + glyph + '> Tj');
159
+ function docWriteGlyphs(positions, font) {
160
+ let commands = [];
161
+ let commandStr = '';
162
+ const skew = font.fauxItalic ? -0.25 : 0;
163
+
164
+ // Add the given character to the 'TJ' command string.
165
+ function addChar(char) {
166
+ commandStr += char.glyph;
167
+ if (char.kern === 0) return;
168
+ commands.push(`<${commandStr}> ${validateNumber(char.kern)}`);
169
+ commandStr = '';
170
+ };
171
+
172
+ // Flush the current TJ command string to the output stream.
173
+ function flush() {
174
+ if (commandStr.length) {
175
+ commands.push(`<${commandStr}> 0`);
176
+ commandStr = '';
177
+ }
178
+ if (commands.length) {
179
+ doc.addContent(`[${commands.join(' ')}] TJ`);
180
+ commands = [];
181
+ }
182
+ };
183
+
184
+ for (let i = 0; i < positions.length; i++) {
185
+ const pos = positions[i];
186
+
187
+ if (pos.hidden || isEqual(pos.width, 0)) {
188
+ flush();
189
+ continue;
190
+ }
191
+
192
+ if (pos.continuous) {
193
+ addChar(pos);
194
+ continue;
195
+ }
196
+
197
+ // If this character is non-continuous, flush the command buffer.
198
+ flush();
199
+
200
+ // Start a new TJ command after writing a Text Matrix (Tm)
201
+ const cos = Math.cos(pos.rotate);
202
+ const sin = Math.sin(pos.rotate);
203
+ docSetTextMatrix(cos * pos.scale, sin * pos.scale, cos * skew - sin, sin * skew + cos, pos.x, pos.y);
204
+ addChar(pos);
205
+ };
206
+
207
+ // Flush any remaining characters in the buffer.
208
+ flush();
158
209
  }
159
210
  function docEndText() {
160
211
  doc.addContent('ET');
161
212
  }
162
213
  function docFillColor(color) {
163
- if (color[0].constructor.name === 'PDFPattern') {
214
+ if (color[0].type === 'PDFPattern') {
164
215
  doc.fillOpacity(color[1]);
165
216
  docUsePattern(color[0], false);
166
217
  } else {
@@ -168,13 +219,127 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
168
219
  }
169
220
  }
170
221
  function docStrokeColor(color) {
171
- if (color[0].constructor.name === 'PDFPattern') {
222
+ if (color[0].type === 'PDFPattern') {
172
223
  doc.strokeOpacity(color[1]);
173
224
  docUsePattern(color[0], true);
174
225
  } else {
175
226
  doc.strokeColor(color[0], color[1]);
176
227
  }
177
228
  }
229
+ // PDFKit doesn't accept any 0s in the dash array, but that's perfectly
230
+ // valid in SVG. So this function applys a dash array and offset, detecting
231
+ // any 0s in the dash array and updating it and the dash offset as needed to
232
+ // remove the zeros, but preserve the end result.
233
+ //
234
+ // `dashArray` must have an even number of elements
235
+ function docApplyDash(dashArray, dashOffset) {
236
+ let index;
237
+ // Anytime there's a 0 that isn't the first or last element of the array,
238
+ // we can remove it by combining the previous or next value. If it's a
239
+ // dash, then it's a zero-length dash between two spaces, so the dash can
240
+ // be eliminated and spaces combined by summing them, replacing all three
241
+ // values with the sum of the two spaces. If the 0 value is a space, then
242
+ // it's a zero-length space between two dashes, and the dashes can be
243
+ // similarly combined. So first we run that logic iteratively to remove
244
+ // all the 0s from the dash array that aren't the first or last element.
245
+ // Note that because we replace 3 values with one value, this doesn't
246
+ // change the even-ness of the length of dashArray.
247
+ while ((index = dashArray.slice(1, -1).indexOf(0)) !== -1) {
248
+ let actualIndex = index + 1;
249
+ let replacementValue = dashArray[actualIndex - 1] + dashArray[actualIndex + 1];
250
+ dashArray = dashArray
251
+ .slice(0, actualIndex - 1)
252
+ .concat([replacementValue])
253
+ .concat(dashArray.slice(actualIndex + 2));
254
+ }
255
+
256
+ // The stroke array only having two elements (a dash value and space
257
+ // value) is a special case.
258
+ if (dashArray.length === 2) {
259
+ if (dashArray[0] === 0) {
260
+ // Regardless of the space value, the dash length is zero, so we're
261
+ // not actually drawing a stroke. We can't describe that in a
262
+ // doc.dash() call in a way that PDFKit will accept, so we set the
263
+ // stroke opacity to zero as our best approximation.
264
+ doc.strokeOpacity(0);
265
+ return;
266
+ } else if (dashArray[1] === 0) {
267
+ // Regardless of the dash value, the space value is zero, meaning
268
+ // we're actually drawing a solid stroke, not a dashed one. We can
269
+ // make this happen by just emptying out the dash array.
270
+ dashArray = [];
271
+ }
272
+ } else {
273
+ if (dashArray[0] === 0) {
274
+ // The first dash is zero-length. We fix this by combining the first
275
+ // space (just after the first dash) with the last space and updating
276
+ // the dash offset accordingly. For example, if we had
277
+ //
278
+ // [ 0 4 3 2 5 1 ] (dash offset 0)
279
+ //
280
+ // ␣␣␣␣---␣␣-----␣
281
+ // ⎸
282
+ //
283
+ // we'd end up with
284
+ //
285
+ // [ 3 2 5 5 ] (dash offset -4)
286
+ //
287
+ // ---␣␣-----␣␣␣␣␣
288
+ // ⎸
289
+ //
290
+ // Another example where the dash array also ends with a 0:
291
+ //
292
+ // [ 0 4 3 2 5 0 ] (dash offset 0)
293
+ //
294
+ // ␣␣␣␣---␣␣-----
295
+ // ⎸
296
+ //
297
+ // we'd end up with
298
+ //
299
+ // [ 3 2 5 4 ] (dash offset -4)
300
+ //
301
+ // ---␣␣-----␣␣␣␣
302
+ // ⎸
303
+ dashOffset -= dashArray[1];
304
+ dashArray[dashArray.length - 1] += dashArray[1];
305
+ dashArray = dashArray.slice(2);
306
+ }
307
+ if (dashArray[dashArray.length - 1] === 0) {
308
+ // The last space is zero-length. We fix this by combining the last dash
309
+ // (just before the last space) with the first dash and updating the
310
+ // dash offset accordingly. For example, if we had
311
+ //
312
+ // [ 1 4 3 2 5 0 ] (dash offset 0)
313
+ //
314
+ // -␣␣␣␣---␣␣-----
315
+ // ⎸
316
+ //
317
+ // we'd end up with
318
+ //
319
+ // [ 6 4 3 2 ] (dash offset 5)
320
+ //
321
+ // ------␣␣␣␣---␣␣
322
+ // ⎸
323
+ //
324
+ dashOffset += dashArray[dashArray.length - 2];
325
+ dashArray[0] += dashArray[dashArray.length - 2];
326
+ dashArray = dashArray.slice(0, -2);
327
+ }
328
+ }
329
+
330
+ // Ensure the dash offset is non-negative (because of crbug.com/660850).
331
+ // First compute the total length of the dash array so we can add it to
332
+ // dash offset until dash offset is non-negative.
333
+ let length = 0;
334
+ for (let i = 0; i < dashArray.length; i++) {length += dashArray[i];}
335
+ if (length > 0) {
336
+ while (dashOffset < 0) {
337
+ dashOffset += length;
338
+ }
339
+ }
340
+
341
+ doc.dash(dashArray, {phase: dashOffset});
342
+ }
178
343
  function docInsertLink(x, y, w, h, url) {
179
344
  let ref = doc.ref({
180
345
  Type: 'Annot',
@@ -308,6 +473,11 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
308
473
  raw = (raw || '').trim();
309
474
  if (temp = NamedColors[raw]) {
310
475
  result = [temp.slice(), 1];
476
+ } else if (temp = raw.match(/^cmyk\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9.]+)\s*\)$/i)) {
477
+ temp[1] = parseInt(temp[1]); temp[2] = parseInt(temp[2]); temp[3] = parseInt(temp[3]); temp[4] = parseFloat(temp[4]);
478
+ if (temp[1] <= 100 && temp[2] <= 100 && temp[3] <= 100 && temp[4] <= 100) {
479
+ result = [temp.slice(1, 5), 1];
480
+ }
311
481
  } else if (temp = raw.match(/^rgba\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9.]+)\s*\)$/i)) {
312
482
  temp[1] = parseInt(temp[1]); temp[2] = parseInt(temp[2]); temp[3] = parseInt(temp[3]); temp[4] = parseFloat(temp[4]);
313
483
  if (temp[1] < 256 && temp[2] < 256 && temp[3] < 256 && temp[4] <= 1) {
@@ -367,6 +537,11 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
367
537
  return new SvgShape().M(0, 0).L(doc.page.width, 0).L(doc.page.width, doc.page.height).L(0, doc.page.height)
368
538
  .transform(inverseMatrix(getGlobalMatrix())).getBoundingBox();
369
539
  }
540
+ function getPageScale() {
541
+ const bbox = getPageBBox();
542
+ const width = doc.page.width;
543
+ return width / bbox[2];
544
+ }
370
545
  function inverseMatrix(m) {
371
546
  let dt = m[0] * m[3] - m[1] * m[2];
372
547
  return [m[3] / dt, -m[1] / dt, -m[2] / dt, m[0] / dt, (m[2]*m[5] - m[3]*m[4]) / dt, (m[1]*m[4] - m[0]*m[5]) / dt];
@@ -615,6 +790,7 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
615
790
  data.push({
616
791
  glyph: hex[i],
617
792
  unicode: unicode,
793
+ kern: pos[i].advanceWidth - pos[i].xAdvance,
618
794
  width: pos[i].advanceWidth * size / 1000,
619
795
  xOffset: pos[i].xOffset * size / 1000,
620
796
  yOffset: pos[i].yOffset * size / 1000,
@@ -1266,12 +1442,6 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
1266
1442
  break;
1267
1443
  case 'stroke-dashoffset':
1268
1444
  result = this.computeLength(value, this.getViewport());
1269
- if (result != null) {
1270
- if (result < 0) { // fix for crbug.com/660850
1271
- let dasharray = this.get('stroke-dasharray');
1272
- for (let j = 0; j < dasharray.length; j++) {result += dasharray[j];}
1273
- }
1274
- }
1275
1445
  break;
1276
1446
  }
1277
1447
  if (result != null) {return styleCache[key] = result;}
@@ -1322,7 +1492,7 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
1322
1492
  this.clip = function() {
1323
1493
  if (this.get('clip-path') !== 'none') {
1324
1494
  let clipPath = new SvgElemClipPath(this.get('clip-path'), null);
1325
- clipPath.useMask(this.getBoundingBox());
1495
+ clipPath.useMask((clipPath.attr('clipPathUnits') === 'objectBoundingBox') ? this.getBoundingBox() : null);
1326
1496
  return true;
1327
1497
  }
1328
1498
  };
@@ -1788,7 +1958,11 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
1788
1958
  this.drawInDocument = function(isClip, isMask) {
1789
1959
  if (this.get('visibility') === 'hidden' || !this.shape) {return;}
1790
1960
  doc.save();
1791
- this.transform();
1961
+ if (this.get('vector-effect') === 'non-scaling-stroke') {
1962
+ this.shape.transform(this.getTransformation());
1963
+ } else {
1964
+ this.transform();
1965
+ }
1792
1966
  this.clip();
1793
1967
  if (!isClip) {
1794
1968
  let masked = this.mask(),
@@ -1801,6 +1975,11 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
1801
1975
  stroke = this.getStroke(isClip, isMask),
1802
1976
  lineWidth = this.get('stroke-width'),
1803
1977
  lineCap = this.get('stroke-linecap');
1978
+
1979
+ if (this.get('vector-effect') === 'non-scaling-stroke') {
1980
+ lineWidth = lineWidth / getPageScale();
1981
+ }
1982
+
1804
1983
  if (fill || stroke) {
1805
1984
  if (fill) {
1806
1985
  docFillColor(fill);
@@ -1835,8 +2014,8 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
1835
2014
  doc.lineWidth(lineWidth)
1836
2015
  .miterLimit(this.get('stroke-miterlimit'))
1837
2016
  .lineJoin(this.get('stroke-linejoin'))
1838
- .lineCap(lineCap)
1839
- .dash(dashArray, {phase: dashOffset});
2017
+ .lineCap(lineCap);
2018
+ docApplyDash(dashArray, dashOffset);
1840
2019
  }
1841
2020
  for (let j = 0; j < subPaths.length; j++) {
1842
2021
  if (subPaths[j].totalLength > 0) {
@@ -1856,7 +2035,7 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
1856
2035
  markerEnd = this.get('marker-end');
1857
2036
  if (markerStart !== 'none' || markerMid !== 'none' || markerEnd !== 'none') {
1858
2037
  let markersPos = this.shape.getMarkers();
1859
- if (markerStart !== 'none') {
2038
+ if (markerStart !== 'none' && markersPos.length > 0) {
1860
2039
  let marker = new SvgElemMarker(markerStart, null);
1861
2040
  marker.drawMarker(false, isMask, markersPos[0], lineWidth);
1862
2041
  }
@@ -1866,7 +2045,7 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
1866
2045
  marker.drawMarker(false, isMask, markersPos[i], lineWidth);
1867
2046
  }
1868
2047
  }
1869
- if (markerEnd !== 'none') {
2048
+ if (markerEnd !== 'none' && markersPos.length > 0) {
1870
2049
  let marker = new SvgElemMarker(markerEnd, null);
1871
2050
  marker.drawMarker(false, isMask, markersPos[markersPos.length - 1], lineWidth);
1872
2051
  }
@@ -2028,6 +2207,7 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
2028
2207
  this.useMask = function(bBox) {
2029
2208
  let group = docBeginGroup(getPageBBox());
2030
2209
  doc.save();
2210
+ doc.transform.apply(doc, this.get('transform'));
2031
2211
  if (this.attr('clipPathUnits') === 'objectBoundingBox') {
2032
2212
  doc.transform(bBox[2] - bBox[0], 0, 0, bBox[3] - bBox[1], bBox[0], bBox[1]);
2033
2213
  }
@@ -2056,7 +2236,6 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
2056
2236
  w = this.getLength('width', this.getVWidth(), 1.2) * (bBox[2] - bBox[0]);
2057
2237
  h = this.getLength('height', this.getVHeight(), 1.2) * (bBox[3] - bBox[1]);
2058
2238
  }
2059
- doc.rect(x, y, w, h).clip();
2060
2239
  if (this.attr('maskContentUnits') === 'objectBoundingBox') {
2061
2240
  doc.transform(bBox[2] - bBox[0], 0, 0, bBox[3] - bBox[1], bBox[0], bBox[1]);
2062
2241
  }
@@ -2125,18 +2304,12 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
2125
2304
  doc.lineWidth(strokeWidth)
2126
2305
  .miterLimit(this.get('stroke-miterlimit'))
2127
2306
  .lineJoin(this.get('stroke-linejoin'))
2128
- .lineCap(this.get('stroke-linecap'))
2129
- .dash(this.get('stroke-dasharray'), {phase:this.get('stroke-dashoffset')});
2307
+ .lineCap(this.get('stroke-linecap'));
2308
+ docApplyDash(this.get('stroke-dasharray'), this.get('stroke-dashoffset'));
2130
2309
  }
2131
2310
  docBeginText(this._font.font, this._font.size);
2132
2311
  docSetTextMode(!!fill, !!stroke);
2133
- for (let j = 0, pos = childElem._pos; j < pos.length; j++) {
2134
- if (!pos[j].hidden && isNotEqual(pos[j].width, 0)) {
2135
- let cos = Math.cos(pos[j].rotate), sin = Math.sin(pos[j].rotate), skew = (this._font.fauxItalic ? -0.25 : 0);
2136
- docSetTextMatrix(cos * pos[j].scale, sin * pos[j].scale, cos * skew - sin, sin * skew + cos, pos[j].x, pos[j].y);
2137
- docWriteGlyph(pos[j].glyph);
2138
- }
2139
- }
2312
+ docWriteGlyphs(childElem._pos, this._font);
2140
2313
  docEndText();
2141
2314
  }
2142
2315
  break;
@@ -2157,8 +2330,8 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
2157
2330
  doc.lineWidth(this.get('stroke-width'))
2158
2331
  .miterLimit(this.get('stroke-miterlimit'))
2159
2332
  .lineJoin(this.get('stroke-linejoin'))
2160
- .lineCap(this.get('stroke-linecap'))
2161
- .dash(this.get('stroke-dasharray'), {phase:this.get('stroke-dashoffset')});
2333
+ .lineCap(this.get('stroke-linecap'));
2334
+ docApplyDash(this.get('stroke-dasharray'), this.get('stroke-dashoffset'));
2162
2335
  }
2163
2336
  for (let j = 0, pos = this._pos; j < pos.length; j++) {
2164
2337
  if (!pos[j].hidden && isNotEqual(pos[j].width, 0)) {
@@ -2234,6 +2407,7 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
2234
2407
  let textScale = length / (endX - startX);
2235
2408
  if (textScale > 0 && textScale < Infinity) {
2236
2409
  for (let j = 0; j < pos.length; j++) {
2410
+ pos[j].continuous = false;
2237
2411
  pos[j].x = startX + textScale * (pos[j].x - startX);
2238
2412
  pos[j].scale *= textScale;
2239
2413
  pos[j].width *= textScale;
@@ -2243,6 +2417,7 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
2243
2417
  if (pos.length >= 2) {
2244
2418
  let spaceDiff = (length - (endX - startX)) / (pos.length - 1);
2245
2419
  for (let j = 0; j < pos.length; j++) {
2420
+ pos[j].continuous = false;
2246
2421
  pos[j].x += j * spaceDiff;
2247
2422
  }
2248
2423
  }
@@ -2262,7 +2437,7 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
2262
2437
  try {
2263
2438
  doc.font(fontNameorLink);
2264
2439
  } catch(e) {
2265
- warningCallback('SVGElemText: failed to open font "' + fontNameorLink + '" in PDFKit');
2440
+ warningCallback('SVGElemText: failed to open font "' + fontNameorLink + '" in PDFKit: ' + e.message);
2266
2441
  }
2267
2442
  currentElem._pos = [];
2268
2443
  currentElem._index = 0;
@@ -2273,7 +2448,22 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
2273
2448
  letterSpacing = currentElem.get('letter-spacing'),
2274
2449
  textAnchor = currentElem.get('text-anchor'),
2275
2450
  textDirection = currentElem.get('direction'),
2276
- baseline = getBaseline(currentElem._font.font, currentElem._font.size, currentElem.get('alignment-baseline') || currentElem.get('dominant-baseline'), currentElem.get('baseline-shift'));
2451
+ // `alignment-baseline` and `baseline-shift` have no effect on
2452
+ // `<text>` elements according to the SVG spec. So, detect when
2453
+ // we're styling a `<text>` element and ignore
2454
+ // `alignment-baseline` (only factoring in `dominant-baseline`)
2455
+ // and `baseline-shift` (which can only have the default value of
2456
+ // `baseline`).
2457
+ //
2458
+ // Note that Chrome (as of v99) incorrectly factors in
2459
+ // `alignment-baseline` on `<text>` elements, while Firefox
2460
+ // correctly follows the spec and ignores it. This means that our
2461
+ // output will differ from Chrome's in these cases, but conform to
2462
+ // SVG specification.
2463
+ isTextElem = currentElem.name === 'text',
2464
+ baselineAttr = isTextElem ? currentElem.get('dominant-baseline') : (currentElem.get('alignment-baseline') || currentElem.get('dominant-baseline')),
2465
+ baselineShiftAttr = isTextElem ? 'baseline' : currentElem.get('baseline-shift'),
2466
+ baseline = getBaseline(currentElem._font.font, currentElem._font.size, baselineAttr, baselineShiftAttr);
2277
2467
  if (currentElem.name === 'textPath') {
2278
2468
  doAnchoring();
2279
2469
  currentX = currentY = 0;
@@ -2313,6 +2503,8 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
2313
2503
  dyAttr = currentElem._dy[index],
2314
2504
  rotAttr = currentElem._rot[index],
2315
2505
  continuous = !(w === 0 && j === 0);
2506
+ if (letterSpacing !== 0) {continuous = false}
2507
+ if (wordSpacing !== 0) {continuous = false}
2316
2508
  if (xAttr !== undefined) {continuous = false; doAnchoring(); currentX = xAttr;}
2317
2509
  if (yAttr !== undefined) {continuous = false; doAnchoring(); currentY = yAttr;}
2318
2510
  if (dxAttr !== undefined) {continuous = false; currentX += dxAttr;}
@@ -2322,6 +2514,7 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
2322
2514
  glyph: pos[j].glyph,
2323
2515
  rotate: (Math.PI / 180) * currentElem.chooseValue(rotAttr, currentElem._defRot),
2324
2516
  x: currentX + pos[j].xOffset,
2517
+ kern: pos[j].kern,
2325
2518
  y: currentY + baseline + pos[j].yOffset,
2326
2519
  width: pos[j].width,
2327
2520
  ascent: getAscent(currentElem._font.font, currentElem._font.size),
@@ -1,3 +1,3 @@
1
- var SVGtoPDF = require('./svg-to-pdfkit/source.js');
2
-
3
- module.exports = SVGtoPDF;
1
+ import SVGtoPDF from './svg-to-pdfkit/source.js';
2
+
3
+ export default SVGtoPDF;
@@ -0,0 +1,64 @@
1
+ class OutputDocument {
2
+
3
+ /**
4
+ * @param {Promise<object>} pdfDocumentPromise
5
+ */
6
+ constructor(pdfDocumentPromise) {
7
+ this.bufferSize = 1073741824;
8
+ this.pdfDocumentPromise = pdfDocumentPromise;
9
+ this.bufferPromise = null;
10
+ }
11
+
12
+ /**
13
+ * @returns {Promise<object>}
14
+ */
15
+ getStream() {
16
+ return this.pdfDocumentPromise;
17
+ }
18
+
19
+ /**
20
+ * @returns {Promise<Buffer>}
21
+ */
22
+ getBuffer() {
23
+ const getBufferInternal = (async () => {
24
+ const stream = await this.getStream();
25
+ return new Promise((resolve) => {
26
+ let chunks = [];
27
+ stream.on('readable', () => {
28
+ let chunk;
29
+ while ((chunk = stream.read(this.bufferSize)) !== null) {
30
+ chunks.push(chunk);
31
+ }
32
+ });
33
+ stream.on('end', () => {
34
+ resolve(Buffer.concat(chunks));
35
+ });
36
+ stream.end();
37
+ });
38
+ });
39
+
40
+ if (this.bufferPromise === null) {
41
+ this.bufferPromise = getBufferInternal();
42
+ }
43
+ return this.bufferPromise;
44
+ }
45
+
46
+ /**
47
+ * @returns {Promise<string>}
48
+ */
49
+ async getBase64() {
50
+ const buffer = await this.getBuffer();
51
+ return buffer.toString('base64');
52
+ }
53
+
54
+ /**
55
+ * @returns {Promise<string>}
56
+ */
57
+ async getDataUrl() {
58
+ const data = await this.getBase64();
59
+ return 'data:application/pdf;base64,' + data;
60
+ }
61
+
62
+ }
63
+
64
+ export default OutputDocument;
@@ -0,0 +1,32 @@
1
+ import OutputDocument from './OutputDocument';
2
+ import fs from 'fs';
3
+
4
+ class OutputDocumentServer extends OutputDocument {
5
+
6
+ /**
7
+ * @param {string} filename
8
+ * @returns {Promise}
9
+ */
10
+ async write(filename) {
11
+ const stream = await this.getStream();
12
+ const writeStream = fs.createWriteStream(filename);
13
+
14
+ const streamEnded = new Promise((resolve, reject) => {
15
+ stream.on('end', resolve);
16
+ stream.on('error', reject);
17
+ });
18
+
19
+ const writeClosed = new Promise((resolve, reject) => {
20
+ writeStream.on('close', resolve);
21
+ writeStream.on('error', reject);
22
+ });
23
+
24
+ stream.pipe(writeStream);
25
+ stream.end();
26
+
27
+ await Promise.all([streamEnded, writeClosed]);
28
+ }
29
+
30
+ }
31
+
32
+ export default OutputDocumentServer;