pdfmake 0.3.0 → 0.3.2
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/CHANGELOG.md +18 -1
- package/README.md +78 -78
- package/build/pdfmake.js +58792 -58550
- package/build/pdfmake.js.map +1 -1
- package/build/pdfmake.min.js +2 -2
- package/build/pdfmake.min.js.map +1 -1
- package/build-vfs.js +1 -1
- package/js/3rd-party/svg-to-pdfkit/source.js +241 -44
- package/js/DocMeasure.js +20 -12
- package/js/OutputDocumentServer.js +10 -3
- package/js/Printer.js +11 -14
- package/js/Renderer.js +6 -4
- package/js/SVGMeasure.js +41 -18
- package/js/StyleContextStack.js +1 -1
- package/js/TextInlines.js +2 -2
- package/js/base.js +7 -0
- package/js/browser-extensions/OutputDocumentBrowser.js +2 -1
- package/js/helpers/variableType.js +1 -1
- package/js/qrEnc.js +6 -6
- package/package.json +4 -4
- package/src/3rd-party/svg-to-pdfkit/source.js +230 -37
- package/src/DocMeasure.js +23 -12
- package/src/OutputDocumentServer.js +14 -3
- package/src/Printer.js +11 -14
- package/src/Renderer.js +9 -3
- package/src/SVGMeasure.js +47 -17
- package/src/StyleContextStack.js +1 -1
- package/src/TextInlines.js +2 -2
- package/src/base.js +9 -0
- package/src/browser-extensions/OutputDocumentBrowser.js +2 -1
- package/src/helpers/variableType.js +1 -1
- package/src/qrEnc.js +6 -6
package/build-vfs.js
CHANGED
|
@@ -41,4 +41,4 @@ const vfsFileContent = vfsBefore + JSON.stringify(vfs, null, 2) + vfsAfter;
|
|
|
41
41
|
fs.writeFileSync(vfsFilename, vfsFileContent);
|
|
42
42
|
|
|
43
43
|
console.log('');
|
|
44
|
-
console.log('
|
|
44
|
+
console.log('Built ' + files.length + ' files to ' + vfsFilename + '.');
|
|
@@ -717,6 +717,14 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
717
717
|
'scroll': 'hidden',
|
|
718
718
|
'visible': 'visible'
|
|
719
719
|
}
|
|
720
|
+
},
|
|
721
|
+
'vector-effect': {
|
|
722
|
+
inherit: true,
|
|
723
|
+
initial: 'none',
|
|
724
|
+
values: {
|
|
725
|
+
'none': 'none',
|
|
726
|
+
'non-scaling-stroke': 'non-scaling-stroke'
|
|
727
|
+
}
|
|
720
728
|
}
|
|
721
729
|
};
|
|
722
730
|
function docBeginGroup(bbox) {
|
|
@@ -797,11 +805,13 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
797
805
|
doc.addContent('/' + name + ' gs');
|
|
798
806
|
}
|
|
799
807
|
function docCreatePattern(group, dx, dy, matrix) {
|
|
800
|
-
let pattern =
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
808
|
+
let pattern = {
|
|
809
|
+
type: 'PDFPattern',
|
|
810
|
+
group: group,
|
|
811
|
+
dx: dx,
|
|
812
|
+
dy: dy,
|
|
813
|
+
matrix: matrix || [1, 0, 0, 1, 0, 0]
|
|
814
|
+
};
|
|
805
815
|
return pattern;
|
|
806
816
|
}
|
|
807
817
|
function docUsePattern(pattern, stroke) {
|
|
@@ -848,14 +858,62 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
848
858
|
let mode = fill && stroke ? 2 : stroke ? 1 : fill ? 0 : 3;
|
|
849
859
|
doc.addContent(mode + ' Tr');
|
|
850
860
|
}
|
|
851
|
-
function
|
|
852
|
-
|
|
861
|
+
function docWriteGlyphs(positions, font) {
|
|
862
|
+
let commands = [];
|
|
863
|
+
let commandStr = '';
|
|
864
|
+
const skew = font.fauxItalic ? -0.25 : 0;
|
|
865
|
+
|
|
866
|
+
// Add the given character to the 'TJ' command string.
|
|
867
|
+
function addChar(char) {
|
|
868
|
+
commandStr += char.glyph;
|
|
869
|
+
if (char.kern === 0) return;
|
|
870
|
+
commands.push(`<${commandStr}> ${validateNumber(char.kern)}`);
|
|
871
|
+
commandStr = '';
|
|
872
|
+
}
|
|
873
|
+
;
|
|
874
|
+
|
|
875
|
+
// Flush the current TJ command string to the output stream.
|
|
876
|
+
function flush() {
|
|
877
|
+
if (commandStr.length) {
|
|
878
|
+
commands.push(`<${commandStr}> 0`);
|
|
879
|
+
commandStr = '';
|
|
880
|
+
}
|
|
881
|
+
if (commands.length) {
|
|
882
|
+
doc.addContent(`[${commands.join(' ')}] TJ`);
|
|
883
|
+
commands = [];
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
;
|
|
887
|
+
for (let i = 0; i < positions.length; i++) {
|
|
888
|
+
const pos = positions[i];
|
|
889
|
+
if (pos.hidden || isEqual(pos.width, 0)) {
|
|
890
|
+
flush();
|
|
891
|
+
continue;
|
|
892
|
+
}
|
|
893
|
+
if (pos.continuous) {
|
|
894
|
+
addChar(pos);
|
|
895
|
+
continue;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
// If this character is non-continuous, flush the command buffer.
|
|
899
|
+
flush();
|
|
900
|
+
|
|
901
|
+
// Start a new TJ command after writing a Text Matrix (Tm)
|
|
902
|
+
const cos = Math.cos(pos.rotate);
|
|
903
|
+
const sin = Math.sin(pos.rotate);
|
|
904
|
+
docSetTextMatrix(cos * pos.scale, sin * pos.scale, cos * skew - sin, sin * skew + cos, pos.x, pos.y);
|
|
905
|
+
addChar(pos);
|
|
906
|
+
}
|
|
907
|
+
;
|
|
908
|
+
|
|
909
|
+
// Flush any remaining characters in the buffer.
|
|
910
|
+
flush();
|
|
853
911
|
}
|
|
854
912
|
function docEndText() {
|
|
855
913
|
doc.addContent('ET');
|
|
856
914
|
}
|
|
857
915
|
function docFillColor(color) {
|
|
858
|
-
if (color[0].
|
|
916
|
+
if (color[0].type === 'PDFPattern') {
|
|
859
917
|
doc.fillOpacity(color[1]);
|
|
860
918
|
docUsePattern(color[0], false);
|
|
861
919
|
} else {
|
|
@@ -863,13 +921,127 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
863
921
|
}
|
|
864
922
|
}
|
|
865
923
|
function docStrokeColor(color) {
|
|
866
|
-
if (color[0].
|
|
924
|
+
if (color[0].type === 'PDFPattern') {
|
|
867
925
|
doc.strokeOpacity(color[1]);
|
|
868
926
|
docUsePattern(color[0], true);
|
|
869
927
|
} else {
|
|
870
928
|
doc.strokeColor(color[0], color[1]);
|
|
871
929
|
}
|
|
872
930
|
}
|
|
931
|
+
// PDFKit doesn't accept any 0s in the dash array, but that's perfectly
|
|
932
|
+
// valid in SVG. So this function applys a dash array and offset, detecting
|
|
933
|
+
// any 0s in the dash array and updating it and the dash offset as needed to
|
|
934
|
+
// remove the zeros, but preserve the end result.
|
|
935
|
+
//
|
|
936
|
+
// `dashArray` must have an even number of elements
|
|
937
|
+
function docApplyDash(dashArray, dashOffset) {
|
|
938
|
+
let index;
|
|
939
|
+
// Anytime there's a 0 that isn't the first or last element of the array,
|
|
940
|
+
// we can remove it by combining the previous or next value. If it's a
|
|
941
|
+
// dash, then it's a zero-length dash between two spaces, so the dash can
|
|
942
|
+
// be eliminated and spaces combined by summing them, replacing all three
|
|
943
|
+
// values with the sum of the two spaces. If the 0 value is a space, then
|
|
944
|
+
// it's a zero-length space between two dashes, and the dashes can be
|
|
945
|
+
// similarly combined. So first we run that logic iteratively to remove
|
|
946
|
+
// all the 0s from the dash array that aren't the first or last element.
|
|
947
|
+
// Note that because we replace 3 values with one value, this doesn't
|
|
948
|
+
// change the even-ness of the length of dashArray.
|
|
949
|
+
while ((index = dashArray.slice(1, -1).indexOf(0)) !== -1) {
|
|
950
|
+
let actualIndex = index + 1;
|
|
951
|
+
let replacementValue = dashArray[actualIndex - 1] + dashArray[actualIndex + 1];
|
|
952
|
+
dashArray = dashArray.slice(0, actualIndex - 1).concat([replacementValue]).concat(dashArray.slice(actualIndex + 2));
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// The stroke array only having two elements (a dash value and space
|
|
956
|
+
// value) is a special case.
|
|
957
|
+
if (dashArray.length === 2) {
|
|
958
|
+
if (dashArray[0] === 0) {
|
|
959
|
+
// Regardless of the space value, the dash length is zero, so we're
|
|
960
|
+
// not actually drawing a stroke. We can't describe that in a
|
|
961
|
+
// doc.dash() call in a way that PDFKit will accept, so we set the
|
|
962
|
+
// stroke opacity to zero as our best approximation.
|
|
963
|
+
doc.strokeOpacity(0);
|
|
964
|
+
return;
|
|
965
|
+
} else if (dashArray[1] === 0) {
|
|
966
|
+
// Regardless of the dash value, the space value is zero, meaning
|
|
967
|
+
// we're actually drawing a solid stroke, not a dashed one. We can
|
|
968
|
+
// make this happen by just emptying out the dash array.
|
|
969
|
+
dashArray = [];
|
|
970
|
+
}
|
|
971
|
+
} else {
|
|
972
|
+
if (dashArray[0] === 0) {
|
|
973
|
+
// The first dash is zero-length. We fix this by combining the first
|
|
974
|
+
// space (just after the first dash) with the last space and updating
|
|
975
|
+
// the dash offset accordingly. For example, if we had
|
|
976
|
+
//
|
|
977
|
+
// [ 0 4 3 2 5 1 ] (dash offset 0)
|
|
978
|
+
//
|
|
979
|
+
// ␣␣␣␣---␣␣-----␣
|
|
980
|
+
// ⎸
|
|
981
|
+
//
|
|
982
|
+
// we'd end up with
|
|
983
|
+
//
|
|
984
|
+
// [ 3 2 5 5 ] (dash offset -4)
|
|
985
|
+
//
|
|
986
|
+
// ---␣␣-----␣␣␣␣␣
|
|
987
|
+
// ⎸
|
|
988
|
+
//
|
|
989
|
+
// Another example where the dash array also ends with a 0:
|
|
990
|
+
//
|
|
991
|
+
// [ 0 4 3 2 5 0 ] (dash offset 0)
|
|
992
|
+
//
|
|
993
|
+
// ␣␣␣␣---␣␣-----
|
|
994
|
+
// ⎸
|
|
995
|
+
//
|
|
996
|
+
// we'd end up with
|
|
997
|
+
//
|
|
998
|
+
// [ 3 2 5 4 ] (dash offset -4)
|
|
999
|
+
//
|
|
1000
|
+
// ---␣␣-----␣␣␣␣
|
|
1001
|
+
// ⎸
|
|
1002
|
+
dashOffset -= dashArray[1];
|
|
1003
|
+
dashArray[dashArray.length - 1] += dashArray[1];
|
|
1004
|
+
dashArray = dashArray.slice(2);
|
|
1005
|
+
}
|
|
1006
|
+
if (dashArray[dashArray.length - 1] === 0) {
|
|
1007
|
+
// The last space is zero-length. We fix this by combining the last dash
|
|
1008
|
+
// (just before the last space) with the first dash and updating the
|
|
1009
|
+
// dash offset accordingly. For example, if we had
|
|
1010
|
+
//
|
|
1011
|
+
// [ 1 4 3 2 5 0 ] (dash offset 0)
|
|
1012
|
+
//
|
|
1013
|
+
// -␣␣␣␣---␣␣-----
|
|
1014
|
+
// ⎸
|
|
1015
|
+
//
|
|
1016
|
+
// we'd end up with
|
|
1017
|
+
//
|
|
1018
|
+
// [ 6 4 3 2 ] (dash offset 5)
|
|
1019
|
+
//
|
|
1020
|
+
// ------␣␣␣␣---␣␣
|
|
1021
|
+
// ⎸
|
|
1022
|
+
//
|
|
1023
|
+
dashOffset += dashArray[dashArray.length - 2];
|
|
1024
|
+
dashArray[0] += dashArray[dashArray.length - 2];
|
|
1025
|
+
dashArray = dashArray.slice(0, -2);
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// Ensure the dash offset is non-negative (because of crbug.com/660850).
|
|
1030
|
+
// First compute the total length of the dash array so we can add it to
|
|
1031
|
+
// dash offset until dash offset is non-negative.
|
|
1032
|
+
let length = 0;
|
|
1033
|
+
for (let i = 0; i < dashArray.length; i++) {
|
|
1034
|
+
length += dashArray[i];
|
|
1035
|
+
}
|
|
1036
|
+
if (length > 0) {
|
|
1037
|
+
while (dashOffset < 0) {
|
|
1038
|
+
dashOffset += length;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
doc.dash(dashArray, {
|
|
1042
|
+
phase: dashOffset
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
873
1045
|
function docInsertLink(x, y, w, h, url) {
|
|
874
1046
|
let ref = doc.ref({
|
|
875
1047
|
Type: 'Annot',
|
|
@@ -1033,6 +1205,14 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
1033
1205
|
raw = (raw || '').trim();
|
|
1034
1206
|
if (temp = NamedColors[raw]) {
|
|
1035
1207
|
result = [temp.slice(), 1];
|
|
1208
|
+
} else if (temp = raw.match(/^cmyk\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9.]+)\s*\)$/i)) {
|
|
1209
|
+
temp[1] = parseInt(temp[1]);
|
|
1210
|
+
temp[2] = parseInt(temp[2]);
|
|
1211
|
+
temp[3] = parseInt(temp[3]);
|
|
1212
|
+
temp[4] = parseFloat(temp[4]);
|
|
1213
|
+
if (temp[1] <= 100 && temp[2] <= 100 && temp[3] <= 100 && temp[4] <= 100) {
|
|
1214
|
+
result = [temp.slice(1, 5), 1];
|
|
1215
|
+
}
|
|
1036
1216
|
} else if (temp = raw.match(/^rgba\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9.]+)\s*\)$/i)) {
|
|
1037
1217
|
temp[1] = parseInt(temp[1]);
|
|
1038
1218
|
temp[2] = parseInt(temp[2]);
|
|
@@ -1097,6 +1277,11 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
1097
1277
|
function getPageBBox() {
|
|
1098
1278
|
return new SvgShape().M(0, 0).L(doc.page.width, 0).L(doc.page.width, doc.page.height).L(0, doc.page.height).transform(inverseMatrix(getGlobalMatrix())).getBoundingBox();
|
|
1099
1279
|
}
|
|
1280
|
+
function getPageScale() {
|
|
1281
|
+
const bbox = getPageBBox();
|
|
1282
|
+
const width = doc.page.width;
|
|
1283
|
+
return width / bbox[2];
|
|
1284
|
+
}
|
|
1100
1285
|
function inverseMatrix(m) {
|
|
1101
1286
|
let dt = m[0] * m[3] - m[1] * m[2];
|
|
1102
1287
|
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];
|
|
@@ -1357,7 +1542,7 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
1357
1542
|
}
|
|
1358
1543
|
}
|
|
1359
1544
|
for (let i = 0; i < selector.classes.length; i++) {
|
|
1360
|
-
if (elem.classList.
|
|
1545
|
+
if (!elem.classList.contains(selector.classes[i])) {
|
|
1361
1546
|
return false;
|
|
1362
1547
|
}
|
|
1363
1548
|
}
|
|
@@ -1449,6 +1634,7 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
1449
1634
|
data.push({
|
|
1450
1635
|
glyph: hex[i],
|
|
1451
1636
|
unicode: unicode,
|
|
1637
|
+
kern: pos[i].advanceWidth - pos[i].xAdvance,
|
|
1452
1638
|
width: pos[i].advanceWidth * size / 1000,
|
|
1453
1639
|
xOffset: pos[i].xOffset * size / 1000,
|
|
1454
1640
|
yOffset: pos[i].yOffset * size / 1000,
|
|
@@ -2253,15 +2439,6 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
2253
2439
|
break;
|
|
2254
2440
|
case 'stroke-dashoffset':
|
|
2255
2441
|
result = this.computeLength(value, this.getViewport());
|
|
2256
|
-
if (result != null) {
|
|
2257
|
-
if (result < 0) {
|
|
2258
|
-
// fix for crbug.com/660850
|
|
2259
|
-
let dasharray = this.get('stroke-dasharray');
|
|
2260
|
-
for (let j = 0; j < dasharray.length; j++) {
|
|
2261
|
-
result += dasharray[j];
|
|
2262
|
-
}
|
|
2263
|
-
}
|
|
2264
|
-
}
|
|
2265
2442
|
break;
|
|
2266
2443
|
}
|
|
2267
2444
|
if (result != null) {
|
|
@@ -2315,7 +2492,7 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
2315
2492
|
this.clip = function () {
|
|
2316
2493
|
if (this.get('clip-path') !== 'none') {
|
|
2317
2494
|
let clipPath = new SvgElemClipPath(this.get('clip-path'), null);
|
|
2318
|
-
clipPath.useMask(this.getBoundingBox());
|
|
2495
|
+
clipPath.useMask(clipPath.attr('clipPathUnits') === 'objectBoundingBox' ? this.getBoundingBox() : null);
|
|
2319
2496
|
return true;
|
|
2320
2497
|
}
|
|
2321
2498
|
};
|
|
@@ -2788,7 +2965,11 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
2788
2965
|
return;
|
|
2789
2966
|
}
|
|
2790
2967
|
doc.save();
|
|
2791
|
-
this.
|
|
2968
|
+
if (this.get('vector-effect') === 'non-scaling-stroke') {
|
|
2969
|
+
this.shape.transform(this.getTransformation());
|
|
2970
|
+
} else {
|
|
2971
|
+
this.transform();
|
|
2972
|
+
}
|
|
2792
2973
|
this.clip();
|
|
2793
2974
|
if (!isClip) {
|
|
2794
2975
|
let masked = this.mask(),
|
|
@@ -2801,6 +2982,9 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
2801
2982
|
stroke = this.getStroke(isClip, isMask),
|
|
2802
2983
|
lineWidth = this.get('stroke-width'),
|
|
2803
2984
|
lineCap = this.get('stroke-linecap');
|
|
2985
|
+
if (this.get('vector-effect') === 'non-scaling-stroke') {
|
|
2986
|
+
lineWidth = lineWidth / getPageScale();
|
|
2987
|
+
}
|
|
2804
2988
|
if (fill || stroke) {
|
|
2805
2989
|
if (fill) {
|
|
2806
2990
|
docFillColor(fill);
|
|
@@ -2832,9 +3016,8 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
2832
3016
|
dashOffset *= this.dashScale;
|
|
2833
3017
|
}
|
|
2834
3018
|
docStrokeColor(stroke);
|
|
2835
|
-
doc.lineWidth(lineWidth).miterLimit(this.get('stroke-miterlimit')).lineJoin(this.get('stroke-linejoin')).lineCap(lineCap)
|
|
2836
|
-
|
|
2837
|
-
});
|
|
3019
|
+
doc.lineWidth(lineWidth).miterLimit(this.get('stroke-miterlimit')).lineJoin(this.get('stroke-linejoin')).lineCap(lineCap);
|
|
3020
|
+
docApplyDash(dashArray, dashOffset);
|
|
2838
3021
|
}
|
|
2839
3022
|
for (let j = 0; j < subPaths.length; j++) {
|
|
2840
3023
|
if (subPaths[j].totalLength > 0) {
|
|
@@ -2854,7 +3037,7 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
2854
3037
|
markerEnd = this.get('marker-end');
|
|
2855
3038
|
if (markerStart !== 'none' || markerMid !== 'none' || markerEnd !== 'none') {
|
|
2856
3039
|
let markersPos = this.shape.getMarkers();
|
|
2857
|
-
if (markerStart !== 'none') {
|
|
3040
|
+
if (markerStart !== 'none' && markersPos.length > 0) {
|
|
2858
3041
|
let marker = new SvgElemMarker(markerStart, null);
|
|
2859
3042
|
marker.drawMarker(false, isMask, markersPos[0], lineWidth);
|
|
2860
3043
|
}
|
|
@@ -2864,7 +3047,7 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
2864
3047
|
marker.drawMarker(false, isMask, markersPos[i], lineWidth);
|
|
2865
3048
|
}
|
|
2866
3049
|
}
|
|
2867
|
-
if (markerEnd !== 'none') {
|
|
3050
|
+
if (markerEnd !== 'none' && markersPos.length > 0) {
|
|
2868
3051
|
let marker = new SvgElemMarker(markerEnd, null);
|
|
2869
3052
|
marker.drawMarker(false, isMask, markersPos[markersPos.length - 1], lineWidth);
|
|
2870
3053
|
}
|
|
@@ -3027,6 +3210,7 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
3027
3210
|
this.useMask = function (bBox) {
|
|
3028
3211
|
let group = docBeginGroup(getPageBBox());
|
|
3029
3212
|
doc.save();
|
|
3213
|
+
doc.transform.apply(doc, this.get('transform'));
|
|
3030
3214
|
if (this.attr('clipPathUnits') === 'objectBoundingBox') {
|
|
3031
3215
|
doc.transform(bBox[2] - bBox[0], 0, 0, bBox[3] - bBox[1], bBox[0], bBox[1]);
|
|
3032
3216
|
}
|
|
@@ -3054,7 +3238,6 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
3054
3238
|
w = this.getLength('width', this.getVWidth(), 1.2) * (bBox[2] - bBox[0]);
|
|
3055
3239
|
h = this.getLength('height', this.getVHeight(), 1.2) * (bBox[3] - bBox[1]);
|
|
3056
3240
|
}
|
|
3057
|
-
doc.rect(x, y, w, h).clip();
|
|
3058
3241
|
if (this.attr('maskContentUnits') === 'objectBoundingBox') {
|
|
3059
3242
|
doc.transform(bBox[2] - bBox[0], 0, 0, bBox[3] - bBox[1], bBox[0], bBox[1]);
|
|
3060
3243
|
}
|
|
@@ -3128,21 +3311,12 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
3128
3311
|
}
|
|
3129
3312
|
if (stroke && strokeWidth) {
|
|
3130
3313
|
docStrokeColor(stroke);
|
|
3131
|
-
doc.lineWidth(strokeWidth).miterLimit(this.get('stroke-miterlimit')).lineJoin(this.get('stroke-linejoin')).lineCap(this.get('stroke-linecap'))
|
|
3132
|
-
|
|
3133
|
-
});
|
|
3314
|
+
doc.lineWidth(strokeWidth).miterLimit(this.get('stroke-miterlimit')).lineJoin(this.get('stroke-linejoin')).lineCap(this.get('stroke-linecap'));
|
|
3315
|
+
docApplyDash(this.get('stroke-dasharray'), this.get('stroke-dashoffset'));
|
|
3134
3316
|
}
|
|
3135
3317
|
docBeginText(this._font.font, this._font.size);
|
|
3136
3318
|
docSetTextMode(!!fill, !!stroke);
|
|
3137
|
-
|
|
3138
|
-
if (!pos[j].hidden && isNotEqual(pos[j].width, 0)) {
|
|
3139
|
-
let cos = Math.cos(pos[j].rotate),
|
|
3140
|
-
sin = Math.sin(pos[j].rotate),
|
|
3141
|
-
skew = this._font.fauxItalic ? -0.25 : 0;
|
|
3142
|
-
docSetTextMatrix(cos * pos[j].scale, sin * pos[j].scale, cos * skew - sin, sin * skew + cos, pos[j].x, pos[j].y);
|
|
3143
|
-
docWriteGlyph(pos[j].glyph);
|
|
3144
|
-
}
|
|
3145
|
-
}
|
|
3319
|
+
docWriteGlyphs(childElem._pos, this._font);
|
|
3146
3320
|
docEndText();
|
|
3147
3321
|
}
|
|
3148
3322
|
break;
|
|
@@ -3160,9 +3334,8 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
3160
3334
|
}
|
|
3161
3335
|
if (stroke) {
|
|
3162
3336
|
docStrokeColor(stroke);
|
|
3163
|
-
doc.lineWidth(this.get('stroke-width')).miterLimit(this.get('stroke-miterlimit')).lineJoin(this.get('stroke-linejoin')).lineCap(this.get('stroke-linecap'))
|
|
3164
|
-
|
|
3165
|
-
});
|
|
3337
|
+
doc.lineWidth(this.get('stroke-width')).miterLimit(this.get('stroke-miterlimit')).lineJoin(this.get('stroke-linejoin')).lineCap(this.get('stroke-linecap'));
|
|
3338
|
+
docApplyDash(this.get('stroke-dasharray'), this.get('stroke-dashoffset'));
|
|
3166
3339
|
}
|
|
3167
3340
|
for (let j = 0, pos = this._pos; j < pos.length; j++) {
|
|
3168
3341
|
if (!pos[j].hidden && isNotEqual(pos[j].width, 0)) {
|
|
@@ -3246,6 +3419,7 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
3246
3419
|
let textScale = length / (endX - startX);
|
|
3247
3420
|
if (textScale > 0 && textScale < Infinity) {
|
|
3248
3421
|
for (let j = 0; j < pos.length; j++) {
|
|
3422
|
+
pos[j].continuous = false;
|
|
3249
3423
|
pos[j].x = startX + textScale * (pos[j].x - startX);
|
|
3250
3424
|
pos[j].scale *= textScale;
|
|
3251
3425
|
pos[j].width *= textScale;
|
|
@@ -3255,6 +3429,7 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
3255
3429
|
if (pos.length >= 2) {
|
|
3256
3430
|
let spaceDiff = (length - (endX - startX)) / (pos.length - 1);
|
|
3257
3431
|
for (let j = 0; j < pos.length; j++) {
|
|
3432
|
+
pos[j].continuous = false;
|
|
3258
3433
|
pos[j].x += j * spaceDiff;
|
|
3259
3434
|
}
|
|
3260
3435
|
}
|
|
@@ -3279,7 +3454,7 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
3279
3454
|
try {
|
|
3280
3455
|
doc.font(fontNameorLink);
|
|
3281
3456
|
} catch (e) {
|
|
3282
|
-
warningCallback('SVGElemText: failed to open font "' + fontNameorLink + '" in PDFKit');
|
|
3457
|
+
warningCallback('SVGElemText: failed to open font "' + fontNameorLink + '" in PDFKit: ' + e.message);
|
|
3283
3458
|
}
|
|
3284
3459
|
currentElem._pos = [];
|
|
3285
3460
|
currentElem._index = 0;
|
|
@@ -3295,7 +3470,22 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
3295
3470
|
letterSpacing = currentElem.get('letter-spacing'),
|
|
3296
3471
|
textAnchor = currentElem.get('text-anchor'),
|
|
3297
3472
|
textDirection = currentElem.get('direction'),
|
|
3298
|
-
|
|
3473
|
+
// `alignment-baseline` and `baseline-shift` have no effect on
|
|
3474
|
+
// `<text>` elements according to the SVG spec. So, detect when
|
|
3475
|
+
// we're styling a `<text>` element and ignore
|
|
3476
|
+
// `alignment-baseline` (only factoring in `dominant-baseline`)
|
|
3477
|
+
// and `baseline-shift` (which can only have the default value of
|
|
3478
|
+
// `baseline`).
|
|
3479
|
+
//
|
|
3480
|
+
// Note that Chrome (as of v99) incorrectly factors in
|
|
3481
|
+
// `alignment-baseline` on `<text>` elements, while Firefox
|
|
3482
|
+
// correctly follows the spec and ignores it. This means that our
|
|
3483
|
+
// output will differ from Chrome's in these cases, but conform to
|
|
3484
|
+
// SVG specification.
|
|
3485
|
+
isTextElem = currentElem.name === 'text',
|
|
3486
|
+
baselineAttr = isTextElem ? currentElem.get('dominant-baseline') : currentElem.get('alignment-baseline') || currentElem.get('dominant-baseline'),
|
|
3487
|
+
baselineShiftAttr = isTextElem ? 'baseline' : currentElem.get('baseline-shift'),
|
|
3488
|
+
baseline = getBaseline(currentElem._font.font, currentElem._font.size, baselineAttr, baselineShiftAttr);
|
|
3299
3489
|
if (currentElem.name === 'textPath') {
|
|
3300
3490
|
doAnchoring();
|
|
3301
3491
|
currentX = currentY = 0;
|
|
@@ -3344,6 +3534,12 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
3344
3534
|
dyAttr = currentElem._dy[index],
|
|
3345
3535
|
rotAttr = currentElem._rot[index],
|
|
3346
3536
|
continuous = !(w === 0 && j === 0);
|
|
3537
|
+
if (letterSpacing !== 0) {
|
|
3538
|
+
continuous = false;
|
|
3539
|
+
}
|
|
3540
|
+
if (wordSpacing !== 0) {
|
|
3541
|
+
continuous = false;
|
|
3542
|
+
}
|
|
3347
3543
|
if (xAttr !== undefined) {
|
|
3348
3544
|
continuous = false;
|
|
3349
3545
|
doAnchoring();
|
|
@@ -3369,6 +3565,7 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
3369
3565
|
glyph: pos[j].glyph,
|
|
3370
3566
|
rotate: Math.PI / 180 * currentElem.chooseValue(rotAttr, currentElem._defRot),
|
|
3371
3567
|
x: currentX + pos[j].xOffset,
|
|
3568
|
+
kern: pos[j].kern,
|
|
3372
3569
|
y: currentY + baseline + pos[j].yOffset,
|
|
3373
3570
|
width: pos[j].width,
|
|
3374
3571
|
ascent: getAscent(currentElem._font.font, currentElem._font.size),
|
package/js/DocMeasure.js
CHANGED
|
@@ -86,8 +86,9 @@ class DocMeasure {
|
|
|
86
86
|
node._width = node._minWidth = node._maxWidth = node.cover.width;
|
|
87
87
|
node._height = node._minHeight = node._maxHeight = node.cover.height;
|
|
88
88
|
} else {
|
|
89
|
-
|
|
90
|
-
node.
|
|
89
|
+
let ratio = dimensions.width / dimensions.height;
|
|
90
|
+
node._width = node._minWidth = node._maxWidth = node.width || (node.height ? node.height * ratio : dimensions.width);
|
|
91
|
+
node._height = node.height || (node.width ? node.width / ratio : dimensions.height);
|
|
91
92
|
if ((0, _variableType.isNumber)(node.maxWidth) && node.maxWidth < node._width) {
|
|
92
93
|
node._width = node._minWidth = node._maxWidth = node.maxWidth;
|
|
93
94
|
node._height = node._width * dimensions.height / dimensions.width;
|
|
@@ -138,6 +139,15 @@ class DocMeasure {
|
|
|
138
139
|
this.measureImageWithDimensions(node, dimensions);
|
|
139
140
|
node.font = this.styleStack.getProperty('font');
|
|
140
141
|
|
|
142
|
+
// SVG requires a defined width and height
|
|
143
|
+
if (!(0, _variableType.isNumber)(node._width) && !(0, _variableType.isNumber)(node._height)) {
|
|
144
|
+
throw new Error('SVG is missing defined width and height.');
|
|
145
|
+
} else if (!(0, _variableType.isNumber)(node._width)) {
|
|
146
|
+
throw new Error('SVG is missing defined width.');
|
|
147
|
+
} else if (!(0, _variableType.isNumber)(node._height)) {
|
|
148
|
+
throw new Error('SVG is missing defined height.');
|
|
149
|
+
}
|
|
150
|
+
|
|
141
151
|
// scale SVG based on final dimension
|
|
142
152
|
node.svg = this.svgMeasure.writeDimensions(node.svg, {
|
|
143
153
|
width: node._width,
|
|
@@ -216,7 +226,7 @@ class DocMeasure {
|
|
|
216
226
|
gapSizeForList() {
|
|
217
227
|
return this.textInlines.sizeOfText('9. ', this.styleStack);
|
|
218
228
|
}
|
|
219
|
-
buildUnorderedMarker(styleStack, gapSize, type) {
|
|
229
|
+
buildUnorderedMarker(item, styleStack, gapSize, type) {
|
|
220
230
|
function buildDisc(gapSize, color) {
|
|
221
231
|
// TODO: ascender-based calculations
|
|
222
232
|
let radius = gapSize.fontSize / 6;
|
|
@@ -260,7 +270,7 @@ class DocMeasure {
|
|
|
260
270
|
};
|
|
261
271
|
}
|
|
262
272
|
let marker;
|
|
263
|
-
let color =
|
|
273
|
+
let color = _StyleContextStack.default.getStyleProperty(item, styleStack, 'markerColor', undefined) || styleStack.getProperty('color') || 'black';
|
|
264
274
|
switch (type) {
|
|
265
275
|
case 'circle':
|
|
266
276
|
marker = buildCircle(gapSize, color);
|
|
@@ -280,7 +290,7 @@ class DocMeasure {
|
|
|
280
290
|
marker._minHeight = marker._maxHeight = gapSize.height;
|
|
281
291
|
return marker;
|
|
282
292
|
}
|
|
283
|
-
buildOrderedMarker(counter, styleStack, type, separator) {
|
|
293
|
+
buildOrderedMarker(item, counter, styleStack, type, separator) {
|
|
284
294
|
function prepareAlpha(counter) {
|
|
285
295
|
function toAlpha(num) {
|
|
286
296
|
return (num >= 26 ? toAlpha((num / 26 >> 0) - 1) : '') + 'abcdefghijklmnopqrstuvwxyz'[num % 26 >> 0];
|
|
@@ -360,13 +370,11 @@ class DocMeasure {
|
|
|
360
370
|
counterText += `${separator} `;
|
|
361
371
|
}
|
|
362
372
|
}
|
|
373
|
+
let markerColor = _StyleContextStack.default.getStyleProperty(item, styleStack, 'markerColor', undefined) || styleStack.getProperty('color') || 'black';
|
|
363
374
|
let textArray = {
|
|
364
|
-
text: counterText
|
|
375
|
+
text: counterText,
|
|
376
|
+
color: markerColor
|
|
365
377
|
};
|
|
366
|
-
let markerColor = styleStack.getProperty('markerColor');
|
|
367
|
-
if (markerColor) {
|
|
368
|
-
textArray.color = markerColor;
|
|
369
|
-
}
|
|
370
378
|
return {
|
|
371
379
|
_inlines: this.textInlines.buildInlines(textArray, styleStack).items
|
|
372
380
|
};
|
|
@@ -381,7 +389,7 @@ class DocMeasure {
|
|
|
381
389
|
for (let i = 0, l = items.length; i < l; i++) {
|
|
382
390
|
let item = items[i] = this.measureNode(items[i]);
|
|
383
391
|
if (!item.ol && !item.ul) {
|
|
384
|
-
item.listMarker = this.buildUnorderedMarker(style, node._gapSize, item.listType || node.type);
|
|
392
|
+
item.listMarker = this.buildUnorderedMarker(item, style, node._gapSize, item.listType || node.type);
|
|
385
393
|
}
|
|
386
394
|
node._minWidth = Math.max(node._minWidth, items[i]._minWidth + node._gapSize.width);
|
|
387
395
|
node._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth + node._gapSize.width);
|
|
@@ -405,7 +413,7 @@ class DocMeasure {
|
|
|
405
413
|
let item = items[i] = this.measureNode(items[i]);
|
|
406
414
|
if (!item.ol && !item.ul) {
|
|
407
415
|
let counterValue = (0, _variableType.isNumber)(item.counter) ? item.counter : counter;
|
|
408
|
-
item.listMarker = this.buildOrderedMarker(counterValue, style, item.listType || node.type, node.separator);
|
|
416
|
+
item.listMarker = this.buildOrderedMarker(item, counterValue, style, item.listType || node.type, node.separator);
|
|
409
417
|
if (item.listMarker._inlines) {
|
|
410
418
|
node._gapSize.width = Math.max(node._gapSize.width, item.listMarker._inlines[0].width);
|
|
411
419
|
}
|
|
@@ -12,11 +12,18 @@ class OutputDocumentServer extends _OutputDocument.default {
|
|
|
12
12
|
*/
|
|
13
13
|
async write(filename) {
|
|
14
14
|
const stream = await this.getStream();
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const writeStream = _fs.default.createWriteStream(filename);
|
|
16
|
+
const streamEnded = new Promise((resolve, reject) => {
|
|
17
17
|
stream.on('end', resolve);
|
|
18
|
-
stream.
|
|
18
|
+
stream.on('error', reject);
|
|
19
19
|
});
|
|
20
|
+
const writeClosed = new Promise((resolve, reject) => {
|
|
21
|
+
writeStream.on('close', resolve);
|
|
22
|
+
writeStream.on('error', reject);
|
|
23
|
+
});
|
|
24
|
+
stream.pipe(writeStream);
|
|
25
|
+
stream.end();
|
|
26
|
+
await Promise.all([streamEnded, writeClosed]);
|
|
20
27
|
}
|
|
21
28
|
}
|
|
22
29
|
var _default = exports.default = OutputDocumentServer;
|
package/js/Printer.js
CHANGED
|
@@ -99,12 +99,11 @@ class PdfPrinter {
|
|
|
99
99
|
|
|
100
100
|
// if pageSize.height is set to Infinity, calculate the actual height of the page that
|
|
101
101
|
// was laid out using the height of each of the items in the page.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
102
|
+
pages.forEach(page => {
|
|
103
|
+
if (page.pageSize.height === Infinity) {
|
|
104
|
+
page.pageSize.height = calculatePageHeight(page, page.pageMargins);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
108
107
|
const renderer = new _Renderer.default(this.pdfKitDoc, options.progressCallback);
|
|
109
108
|
renderer.renderPages(pages);
|
|
110
109
|
return this.pdfKitDoc;
|
|
@@ -253,7 +252,7 @@ function embedFiles(docDefinition, pdfKitDoc) {
|
|
|
253
252
|
}
|
|
254
253
|
}
|
|
255
254
|
}
|
|
256
|
-
function calculatePageHeight(
|
|
255
|
+
function calculatePageHeight(page, margins) {
|
|
257
256
|
function getItemHeight(item) {
|
|
258
257
|
if (typeof item.item.getHeight === 'function') {
|
|
259
258
|
return item.item.getHeight();
|
|
@@ -277,13 +276,11 @@ function calculatePageHeight(pages, margins) {
|
|
|
277
276
|
}
|
|
278
277
|
let fixedMargins = (0, _PageSize.normalizePageMargin)(margins || 40);
|
|
279
278
|
let height = fixedMargins.top;
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
});
|
|
279
|
+
page.items.forEach(item => {
|
|
280
|
+
let bottomPosition = getBottomPosition(item);
|
|
281
|
+
if (bottomPosition > height) {
|
|
282
|
+
height = bottomPosition;
|
|
283
|
+
}
|
|
287
284
|
});
|
|
288
285
|
height += fixedMargins.bottom;
|
|
289
286
|
return height;
|
package/js/Renderer.js
CHANGED
|
@@ -127,7 +127,7 @@ class Renderer {
|
|
|
127
127
|
textDecorator.drawBackground(line, x, y);
|
|
128
128
|
|
|
129
129
|
//TODO: line.optimizeInlines();
|
|
130
|
-
//
|
|
130
|
+
//TODO: lines without differently styled inlines should be written to pdf as one stream
|
|
131
131
|
for (let i = 0, l = line.inlines.length; i < l; i++) {
|
|
132
132
|
let inline = line.inlines[i];
|
|
133
133
|
let shiftToBaseline = lineHeight - inline.font.ascender / 1000 * inline.fontSize - descent;
|
|
@@ -312,11 +312,13 @@ class Renderer {
|
|
|
312
312
|
}
|
|
313
313
|
}
|
|
314
314
|
renderSVG(svg) {
|
|
315
|
-
let options =
|
|
315
|
+
let options = {
|
|
316
316
|
width: svg._width,
|
|
317
317
|
height: svg._height,
|
|
318
|
-
assumePt: true
|
|
319
|
-
|
|
318
|
+
assumePt: true,
|
|
319
|
+
useCSS: !(0, _variableType.isString)(svg.svg),
|
|
320
|
+
...svg.options
|
|
321
|
+
};
|
|
320
322
|
options.fontCallback = (family, bold, italic) => {
|
|
321
323
|
let fontsFamily = family.split(',').map(f => f.trim().replace(/('|")/g, ''));
|
|
322
324
|
let font = findFont(this.pdfDocument.fonts, fontsFamily, svg.font || 'Roboto');
|