pdfkit 0.17.0 → 0.17.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 +10 -0
- package/js/pdfkit.es.js +38 -38
- package/js/pdfkit.es.js.map +1 -1
- package/js/pdfkit.js +38 -38
- package/js/pdfkit.js.map +1 -1
- package/js/pdfkit.standalone.js +336 -151
- package/jsconfig.json +13 -0
- package/package.json +2 -2
- package/types/jest.custom-matchers.d.ts +28 -0
- package/.git-blame-ignore-revs +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
### Unreleased
|
|
4
4
|
|
|
5
|
+
### [v0.17.2] - 2025-08-30
|
|
6
|
+
|
|
7
|
+
- Fix rendering lists that spans across pages
|
|
8
|
+
|
|
9
|
+
### [v0.17.1] - 2025-05-02
|
|
10
|
+
|
|
11
|
+
- Fix null values in table cells rendering as `[object Object]`
|
|
12
|
+
- Fix further LineWrapper precision issues
|
|
13
|
+
- Optmize standard font handling. Less code, less memory usage
|
|
14
|
+
|
|
5
15
|
### [v0.17.0] - 2025-04-12
|
|
6
16
|
|
|
7
17
|
- Fix precision rounding issues in LineWrapper
|
package/js/pdfkit.es.js
CHANGED
|
@@ -222,8 +222,18 @@ class PDFReference extends PDFAbstractReference {
|
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
+
const fArray = new Float32Array(1);
|
|
226
|
+
const uArray = new Uint32Array(fArray.buffer);
|
|
225
227
|
function PDFNumber(n) {
|
|
226
|
-
|
|
228
|
+
const rounded = Math.fround(n);
|
|
229
|
+
if (rounded <= n) return rounded;
|
|
230
|
+
fArray[0] = n;
|
|
231
|
+
if (n <= 0) {
|
|
232
|
+
uArray[0] += 1;
|
|
233
|
+
} else {
|
|
234
|
+
uArray[0] -= 1;
|
|
235
|
+
}
|
|
236
|
+
return fArray[0];
|
|
227
237
|
}
|
|
228
238
|
function normalizeSides(sides) {
|
|
229
239
|
let defaultDefinition = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
|
|
@@ -2155,20 +2165,12 @@ oslash ugrave uacute ucircumflex
|
|
|
2155
2165
|
udieresis yacute thorn ydieresis\
|
|
2156
2166
|
`.split(/\s+/);
|
|
2157
2167
|
class AFMFont {
|
|
2158
|
-
static open(filename) {
|
|
2159
|
-
return new AFMFont(fs.readFileSync(filename, 'utf8'));
|
|
2160
|
-
}
|
|
2161
2168
|
constructor(contents) {
|
|
2162
|
-
this.contents = contents;
|
|
2163
2169
|
this.attributes = {};
|
|
2164
2170
|
this.glyphWidths = {};
|
|
2165
2171
|
this.boundingBoxes = {};
|
|
2166
2172
|
this.kernPairs = {};
|
|
2167
|
-
this.parse();
|
|
2168
|
-
this.charWidths = new Array(256);
|
|
2169
|
-
for (let char = 0; char <= 255; char++) {
|
|
2170
|
-
this.charWidths[char] = this.glyphWidths[characters[char]];
|
|
2171
|
-
}
|
|
2173
|
+
this.parse(contents);
|
|
2172
2174
|
this.bbox = this.attributes['FontBBox'].split(/\s+/).map(e => +e);
|
|
2173
2175
|
this.ascender = +(this.attributes['Ascender'] || 0);
|
|
2174
2176
|
this.descender = +(this.attributes['Descender'] || 0);
|
|
@@ -2176,9 +2178,9 @@ class AFMFont {
|
|
|
2176
2178
|
this.capHeight = +(this.attributes['CapHeight'] || 0);
|
|
2177
2179
|
this.lineGap = this.bbox[3] - this.bbox[1] - (this.ascender - this.descender);
|
|
2178
2180
|
}
|
|
2179
|
-
parse() {
|
|
2181
|
+
parse(contents) {
|
|
2180
2182
|
let section = '';
|
|
2181
|
-
for (let line of
|
|
2183
|
+
for (let line of contents.split('\n')) {
|
|
2182
2184
|
var match;
|
|
2183
2185
|
var a;
|
|
2184
2186
|
if (match = line.match(/^Start(\w+)/)) {
|
|
@@ -2838,7 +2840,7 @@ class LineWrapper extends EventEmitter {
|
|
|
2838
2840
|
});
|
|
2839
2841
|
}
|
|
2840
2842
|
wordWidth(word) {
|
|
2841
|
-
return this.document.widthOfString(word, this) + this.characterSpacing + this.wordSpacing;
|
|
2843
|
+
return PDFNumber(this.document.widthOfString(word, this) + this.characterSpacing + this.wordSpacing);
|
|
2842
2844
|
}
|
|
2843
2845
|
canFit(word, w) {
|
|
2844
2846
|
if (word[word.length - 1] != SOFT_HYPHEN) {
|
|
@@ -2979,12 +2981,14 @@ class LineWrapper extends EventEmitter {
|
|
|
2979
2981
|
}
|
|
2980
2982
|
emitLine();
|
|
2981
2983
|
if (PDFNumber(this.document.y + lh) > this.maxY) {
|
|
2984
|
+
this.emit('sectionEnd', options, this);
|
|
2982
2985
|
const shouldContinue = this.nextSection();
|
|
2983
2986
|
if (!shouldContinue) {
|
|
2984
2987
|
wc = 0;
|
|
2985
2988
|
buffer = '';
|
|
2986
2989
|
return false;
|
|
2987
2990
|
}
|
|
2991
|
+
this.emit('sectionStart', options, this);
|
|
2988
2992
|
}
|
|
2989
2993
|
if (bk.required) {
|
|
2990
2994
|
this.spaceLeft = this.lineWidth;
|
|
@@ -3017,7 +3021,6 @@ class LineWrapper extends EventEmitter {
|
|
|
3017
3021
|
}
|
|
3018
3022
|
}
|
|
3019
3023
|
nextSection(options) {
|
|
3020
|
-
this.emit('sectionEnd', options, this);
|
|
3021
3024
|
if (++this.column > this.columns) {
|
|
3022
3025
|
if (this.height != null) {
|
|
3023
3026
|
return false;
|
|
@@ -3036,7 +3039,6 @@ class LineWrapper extends EventEmitter {
|
|
|
3036
3039
|
this.document.y = this.startY;
|
|
3037
3040
|
this.emit('columnBreak', options, this);
|
|
3038
3041
|
}
|
|
3039
|
-
this.emit('sectionStart', options, this);
|
|
3040
3042
|
return true;
|
|
3041
3043
|
}
|
|
3042
3044
|
}
|
|
@@ -3044,6 +3046,15 @@ class LineWrapper extends EventEmitter {
|
|
|
3044
3046
|
const {
|
|
3045
3047
|
number
|
|
3046
3048
|
} = PDFObject;
|
|
3049
|
+
function formatListLabel(n, listType) {
|
|
3050
|
+
if (listType === 'numbered') {
|
|
3051
|
+
return `${n}.`;
|
|
3052
|
+
}
|
|
3053
|
+
var letter = String.fromCharCode((n - 1) % 26 + 65);
|
|
3054
|
+
var times = Math.floor((n - 1) / 26 + 1);
|
|
3055
|
+
var text = Array(times + 1).join(letter);
|
|
3056
|
+
return `${text}.`;
|
|
3057
|
+
}
|
|
3047
3058
|
var TextMixin = {
|
|
3048
3059
|
initText() {
|
|
3049
3060
|
this._line = this._line.bind(this);
|
|
@@ -3221,7 +3232,7 @@ var TextMixin = {
|
|
|
3221
3232
|
this.y = y;
|
|
3222
3233
|
return height;
|
|
3223
3234
|
},
|
|
3224
|
-
list(list, x, y, options
|
|
3235
|
+
list(list, x, y, options) {
|
|
3225
3236
|
options = this._initOptions(x, y, options);
|
|
3226
3237
|
const listType = options.listType || 'bullet';
|
|
3227
3238
|
const unit = Math.round(this._font.ascender / 1000 * this._fontSize);
|
|
@@ -3251,19 +3262,8 @@ var TextMixin = {
|
|
|
3251
3262
|
}
|
|
3252
3263
|
};
|
|
3253
3264
|
flatten(list);
|
|
3254
|
-
const label = function (n) {
|
|
3255
|
-
switch (listType) {
|
|
3256
|
-
case 'numbered':
|
|
3257
|
-
return `${n}.`;
|
|
3258
|
-
case 'lettered':
|
|
3259
|
-
var letter = String.fromCharCode((n - 1) % 26 + 65);
|
|
3260
|
-
var times = Math.floor((n - 1) / 26 + 1);
|
|
3261
|
-
var text = Array(times + 1).join(letter);
|
|
3262
|
-
return `${text}.`;
|
|
3263
|
-
}
|
|
3264
|
-
};
|
|
3265
3265
|
const drawListItem = function (listItem, i) {
|
|
3266
|
-
wrapper = new LineWrapper(this, options);
|
|
3266
|
+
const wrapper = new LineWrapper(this, options);
|
|
3267
3267
|
wrapper.on('line', this._line);
|
|
3268
3268
|
level = 1;
|
|
3269
3269
|
wrapper.once('firstLine', () => {
|
|
@@ -3298,7 +3298,7 @@ var TextMixin = {
|
|
|
3298
3298
|
break;
|
|
3299
3299
|
case 'numbered':
|
|
3300
3300
|
case 'lettered':
|
|
3301
|
-
var text =
|
|
3301
|
+
var text = formatListLabel(numbers[i - 1], listType);
|
|
3302
3302
|
this._fragment(text, this.x - indent, this.y, options);
|
|
3303
3303
|
break;
|
|
3304
3304
|
}
|
|
@@ -3371,11 +3371,11 @@ var TextMixin = {
|
|
|
3371
3371
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
3372
3372
|
let wrapper = arguments.length > 2 ? arguments[2] : undefined;
|
|
3373
3373
|
this._fragment(text, this.x, this.y, options);
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
this.x += this.widthOfString(text, options);
|
|
3377
|
-
} else {
|
|
3374
|
+
if (wrapper) {
|
|
3375
|
+
const lineGap = options.lineGap || this._lineGap || 0;
|
|
3378
3376
|
this.y += this.currentLineHeight(true) + lineGap;
|
|
3377
|
+
} else {
|
|
3378
|
+
this.x += this.widthOfString(text, options);
|
|
3379
3379
|
}
|
|
3380
3380
|
},
|
|
3381
3381
|
_fragment(text, x, y, options) {
|
|
@@ -3762,8 +3762,8 @@ class PDFImage {
|
|
|
3762
3762
|
} else if (src instanceof ArrayBuffer) {
|
|
3763
3763
|
data = Buffer.from(new Uint8Array(src));
|
|
3764
3764
|
} else {
|
|
3765
|
-
|
|
3766
|
-
if (match
|
|
3765
|
+
const match = /^data:.+?;base64,(.*)$/.exec(src);
|
|
3766
|
+
if (match) {
|
|
3767
3767
|
data = Buffer.from(match[1], 'base64');
|
|
3768
3768
|
} else {
|
|
3769
3769
|
data = fs.readFileSync(src);
|
|
@@ -4884,8 +4884,8 @@ var AttachmentsMixin = {
|
|
|
4884
4884
|
} else if (src instanceof ArrayBuffer) {
|
|
4885
4885
|
data = Buffer.from(new Uint8Array(src));
|
|
4886
4886
|
} else {
|
|
4887
|
-
|
|
4888
|
-
if (match
|
|
4887
|
+
const match = /^data:(.*?);base64,(.*)$/.exec(src);
|
|
4888
|
+
if (match) {
|
|
4889
4889
|
if (match[1]) {
|
|
4890
4890
|
refBody.Subtype = match[1].replace('/', '#2F');
|
|
4891
4891
|
}
|
|
@@ -5085,7 +5085,7 @@ function deepMerge(target) {
|
|
|
5085
5085
|
}
|
|
5086
5086
|
function deepClone(obj) {
|
|
5087
5087
|
let result = obj;
|
|
5088
|
-
if (typeof obj == 'object') {
|
|
5088
|
+
if (obj && typeof obj == 'object') {
|
|
5089
5089
|
result = Array.isArray(obj) ? [] : {};
|
|
5090
5090
|
for (const key in obj) result[key] = deepClone(obj[key]);
|
|
5091
5091
|
}
|