@pdfme/generator 2.0.2 → 2.2.0
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 +6 -2
- package/dist/cjs/__tests__/assets/templates/index.js +10 -0
- package/dist/cjs/__tests__/assets/templates/index.js.map +1 -1
- package/dist/cjs/__tests__/generate.test.js +9 -0
- package/dist/cjs/__tests__/generate.test.js.map +1 -1
- package/dist/cjs/src/generate.js +0 -1
- package/dist/cjs/src/generate.js.map +1 -1
- package/dist/cjs/src/helper.js +62 -95
- package/dist/cjs/src/helper.js.map +1 -1
- package/dist/esm/__tests__/assets/templates/index.js +10 -0
- package/dist/esm/__tests__/assets/templates/index.js.map +1 -1
- package/dist/esm/__tests__/generate.test.js +9 -0
- package/dist/esm/__tests__/generate.test.js.map +1 -1
- package/dist/esm/src/generate.js +0 -1
- package/dist/esm/src/generate.js.map +1 -1
- package/dist/esm/src/helper.js +60 -93
- package/dist/esm/src/helper.js.map +1 -1
- package/dist/types/__tests__/assets/templates/index.d.ts +308 -0
- package/dist/types/src/helper.d.ts +0 -1
- package/package.json +2 -2
- package/src/generate.ts +0 -1
- package/src/helper.ts +76 -115
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@pdfme/generator",
|
3
|
-
"version": "2.0
|
3
|
+
"version": "2.2.0",
|
4
4
|
"sideEffects": false,
|
5
5
|
"author": "hand-dot",
|
6
6
|
"license": "MIT",
|
@@ -60,7 +60,7 @@
|
|
60
60
|
"pngjs": "^6.0.0"
|
61
61
|
},
|
62
62
|
"peerDependencies": {
|
63
|
-
"@pdfme/common": "^2.
|
63
|
+
"@pdfme/common": "^2.1.0"
|
64
64
|
},
|
65
65
|
"jest": {
|
66
66
|
"resolver": "ts-jest-resolver",
|
package/src/generate.ts
CHANGED
package/src/helper.ts
CHANGED
@@ -25,14 +25,23 @@ import {
|
|
25
25
|
BasePdf,
|
26
26
|
BarCodeType,
|
27
27
|
Alignment,
|
28
|
-
DEFAULT_FONT_SIZE,
|
29
28
|
DEFAULT_ALIGNMENT,
|
30
|
-
DEFAULT_LINE_HEIGHT,
|
31
29
|
DEFAULT_CHARACTER_SPACING,
|
32
30
|
DEFAULT_FONT_COLOR,
|
31
|
+
DEFAULT_FONT_SIZE,
|
32
|
+
DEFAULT_LINE_HEIGHT,
|
33
|
+
DEFAULT_VERTICAL_ALIGNMENT,
|
34
|
+
VERTICAL_ALIGN_TOP,
|
35
|
+
VERTICAL_ALIGN_MIDDLE,
|
36
|
+
VERTICAL_ALIGN_BOTTOM,
|
33
37
|
calculateDynamicFontSize,
|
34
38
|
heightOfFontAtSize,
|
35
|
-
|
39
|
+
getFontDescentInPt,
|
40
|
+
getFontKitFont,
|
41
|
+
getSplittedLines,
|
42
|
+
mm2pt,
|
43
|
+
widthOfTextAtSize,
|
44
|
+
FontWidthCalcValues,
|
36
45
|
} from '@pdfme/common';
|
37
46
|
import { Buffer } from 'buffer';
|
38
47
|
|
@@ -130,14 +139,7 @@ export const getEmbeddedPagesAndEmbedPdfBoxes = async (arg: {
|
|
130
139
|
return { embeddedPages, embedPdfBoxes };
|
131
140
|
};
|
132
141
|
|
133
|
-
const
|
134
|
-
// https://www.ddc.co.jp/words/archives/20090701114500.html
|
135
|
-
const ptRatio = 2.8346;
|
136
|
-
|
137
|
-
return parseFloat(String(mm)) * ptRatio;
|
138
|
-
};
|
139
|
-
|
140
|
-
const getSchemaSizeAndRotate = (schema: Schema) => {
|
142
|
+
const convertSchemaDimensionsToPt = (schema: Schema) => {
|
141
143
|
const width = mm2pt(schema.width);
|
142
144
|
const height = mm2pt(schema.height);
|
143
145
|
const rotate = degrees(schema.rotate ? schema.rotate : 0);
|
@@ -171,13 +173,14 @@ const hex2RgbColor = (hexString: string | undefined) => {
|
|
171
173
|
};
|
172
174
|
|
173
175
|
const getFontProp = async ({ input, font, schema }: { input: string, font: Font, schema: TextSchema }) => {
|
174
|
-
const
|
176
|
+
const fontSize = schema.dynamicFontSize ? await calculateDynamicFontSize({ textSchema: schema, font, input }) : schema.fontSize ?? DEFAULT_FONT_SIZE;
|
175
177
|
const color = hex2RgbColor(schema.fontColor ?? DEFAULT_FONT_COLOR);
|
176
178
|
const alignment = schema.alignment ?? DEFAULT_ALIGNMENT;
|
179
|
+
const verticalAlignment = schema.verticalAlignment ?? DEFAULT_VERTICAL_ALIGNMENT;
|
177
180
|
const lineHeight = schema.lineHeight ?? DEFAULT_LINE_HEIGHT;
|
178
181
|
const characterSpacing = schema.characterSpacing ?? DEFAULT_CHARACTER_SPACING;
|
179
182
|
|
180
|
-
return {
|
183
|
+
return { fontSize, color, alignment, verticalAlignment, lineHeight, characterSpacing };
|
181
184
|
};
|
182
185
|
|
183
186
|
const calcX = (x: number, alignment: Alignment, boxWidth: number, textWidth: number) => {
|
@@ -191,7 +194,7 @@ const calcX = (x: number, alignment: Alignment, boxWidth: number, textWidth: num
|
|
191
194
|
return mm2pt(x) + addition;
|
192
195
|
};
|
193
196
|
|
194
|
-
const calcY = (y: number,
|
197
|
+
const calcY = (y: number, pageHeight: number, itemHeight: number) => pageHeight - mm2pt(y) - itemHeight;
|
195
198
|
|
196
199
|
const drawBackgroundColor = (arg: {
|
197
200
|
templateSchema: TextSchema;
|
@@ -200,7 +203,7 @@ const drawBackgroundColor = (arg: {
|
|
200
203
|
}) => {
|
201
204
|
const { templateSchema, page, pageHeight } = arg;
|
202
205
|
if (!templateSchema.backgroundColor) return;
|
203
|
-
const { width, height } =
|
206
|
+
const { width, height } = convertSchemaDimensionsToPt(templateSchema);
|
204
207
|
const color = hex2RgbColor(templateSchema.backgroundColor);
|
205
208
|
page.drawRectangle({
|
206
209
|
x: calcX(templateSchema.position.x, 'left', width, width),
|
@@ -211,57 +214,6 @@ const drawBackgroundColor = (arg: {
|
|
211
214
|
});
|
212
215
|
};
|
213
216
|
|
214
|
-
type IsOverEval = (testString: string) => boolean;
|
215
|
-
|
216
|
-
/**
|
217
|
-
* Incrementally checks the current line for its real length
|
218
|
-
* and returns the position where it exceeds the box width.
|
219
|
-
* Returns `null` to indicate if inputLine is shorter as the available bbox.
|
220
|
-
*/
|
221
|
-
const getOverPosition = (inputLine: string, isOverEval: IsOverEval) => {
|
222
|
-
for (let i = 0; i <= inputLine.length; i++) {
|
223
|
-
if (isOverEval(inputLine.slice(0, i))) {
|
224
|
-
return i;
|
225
|
-
}
|
226
|
-
}
|
227
|
-
|
228
|
-
return null;
|
229
|
-
};
|
230
|
-
|
231
|
-
/**
|
232
|
-
* Gets the position of the split. Splits the exceeding line at
|
233
|
-
* the last whitespace over it exceeds the bounding box width.
|
234
|
-
*/
|
235
|
-
const getSplitPosition = (inputLine: string, isOverEval: IsOverEval) => {
|
236
|
-
const overPos = getOverPosition(inputLine, isOverEval);
|
237
|
-
if (overPos === null) return inputLine.length; // input line is shorter than the available space
|
238
|
-
|
239
|
-
let overPosTmp = overPos;
|
240
|
-
while (inputLine[overPosTmp] !== ' ' && overPosTmp >= 0) {
|
241
|
-
overPosTmp--;
|
242
|
-
}
|
243
|
-
|
244
|
-
// For very long lines with no whitespace use the original overPos
|
245
|
-
return overPosTmp > 0 ? overPosTmp : overPos - 1;
|
246
|
-
};
|
247
|
-
|
248
|
-
/**
|
249
|
-
* Recursively splits the line at getSplitPosition.
|
250
|
-
* If there is some leftover, split the rest again in the same manner.
|
251
|
-
*/
|
252
|
-
const getSplittedLines = (inputLine: string, isOverEval: IsOverEval): string[] => {
|
253
|
-
const splitPos = getSplitPosition(inputLine, isOverEval);
|
254
|
-
const splittedLine = inputLine.substring(0, splitPos);
|
255
|
-
const rest = inputLine.substring(splitPos).trimStart();
|
256
|
-
|
257
|
-
if (rest.length === 0) {
|
258
|
-
// end recursion if there is no rest
|
259
|
-
return [splittedLine];
|
260
|
-
}
|
261
|
-
|
262
|
-
return [splittedLine, ...getSplittedLines(rest, isOverEval)];
|
263
|
-
};
|
264
|
-
|
265
217
|
interface FontSetting {
|
266
218
|
font: Font;
|
267
219
|
pdfFontObj: {
|
@@ -275,60 +227,72 @@ const drawInputByTextSchema = async (arg: {
|
|
275
227
|
templateSchema: TextSchema;
|
276
228
|
pdfDoc: PDFDocument;
|
277
229
|
page: PDFPage;
|
278
|
-
pageHeight: number;
|
279
230
|
fontSetting: FontSetting;
|
280
231
|
}) => {
|
281
|
-
const { input, templateSchema, page,
|
232
|
+
const { input, templateSchema, page, fontSetting } = arg;
|
282
233
|
const { font, pdfFontObj, fallbackFontName } = fontSetting;
|
283
234
|
|
284
235
|
const pdfFontValue = pdfFontObj[templateSchema.fontName ? templateSchema.fontName : fallbackFontName];
|
285
|
-
const fontKitFont = await getFontKitFont(templateSchema, font)
|
236
|
+
const fontKitFont = await getFontKitFont(templateSchema, font);
|
286
237
|
|
238
|
+
const pageHeight = page.getHeight();
|
287
239
|
drawBackgroundColor({ templateSchema, page, pageHeight });
|
288
240
|
|
289
|
-
const { width, height, rotate } =
|
290
|
-
const {
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
241
|
+
const { width, height, rotate } = convertSchemaDimensionsToPt(templateSchema);
|
242
|
+
const { fontSize, color, alignment, verticalAlignment, lineHeight, characterSpacing } =
|
243
|
+
await getFontProp({
|
244
|
+
input,
|
245
|
+
font,
|
246
|
+
schema: templateSchema,
|
247
|
+
});
|
295
248
|
|
296
249
|
page.pushOperators(setCharacterSpacing(characterSpacing));
|
297
250
|
|
298
|
-
|
251
|
+
const firstLineTextHeight = heightOfFontAtSize(fontKitFont, fontSize);
|
252
|
+
const descent = getFontDescentInPt(fontKitFont, fontSize);
|
253
|
+
const halfLineHeightAdjustment = lineHeight === 0 ? 0 : ((lineHeight - 1) * fontSize) / 2;
|
299
254
|
|
300
|
-
const
|
301
|
-
|
302
|
-
|
303
|
-
|
255
|
+
const fontWidthCalcValues: FontWidthCalcValues = {
|
256
|
+
font: fontKitFont,
|
257
|
+
fontSize,
|
258
|
+
characterSpacing,
|
259
|
+
boxWidthInPt: width,
|
304
260
|
};
|
305
|
-
input.split(/\r|\n|\r\n/g).forEach((inputLine, inputLineIndex) => {
|
306
|
-
const splitLines = getSplittedLines(inputLine, isOverEval);
|
307
|
-
|
308
|
-
const drawLine = (line: string, lineIndex: number) => {
|
309
|
-
const textWidth = pdfFontValue.widthOfTextAtSize(line, size) + (line.length - 1) * characterSpacing;
|
310
|
-
const textHeight = heightOfFontAtSize(fontKitFont, size);
|
311
|
-
|
312
|
-
page.drawText(line, {
|
313
|
-
x: calcX(templateSchema.position.x, alignment, width, textWidth),
|
314
|
-
y:
|
315
|
-
calcY(templateSchema.position.y, pageHeight, height) +
|
316
|
-
height -
|
317
|
-
textHeight -
|
318
|
-
lineHeight * size * (inputLineIndex + lineIndex + beforeLineOver) -
|
319
|
-
(lineHeight === 0 ? 0 : ((lineHeight - 1) * size) / 2),
|
320
|
-
rotate,
|
321
|
-
size,
|
322
|
-
color,
|
323
|
-
lineHeight: lineHeight * size,
|
324
|
-
maxWidth: width,
|
325
|
-
font: pdfFontValue,
|
326
|
-
wordBreaks: [''],
|
327
|
-
});
|
328
|
-
if (splitLines.length === lineIndex + 1) beforeLineOver += lineIndex;
|
329
|
-
};
|
330
261
|
|
331
|
-
|
262
|
+
let lines: string[] = [];
|
263
|
+
input.split(/\r|\n|\r\n/g).forEach((inputLine) => {
|
264
|
+
lines = lines.concat(getSplittedLines(inputLine, fontWidthCalcValues));
|
265
|
+
});
|
266
|
+
|
267
|
+
// Text lines are rendered from the bottom upwards, we need to adjust the position down
|
268
|
+
let yOffset = 0;
|
269
|
+
if (verticalAlignment === VERTICAL_ALIGN_TOP) {
|
270
|
+
yOffset = firstLineTextHeight + halfLineHeightAdjustment;
|
271
|
+
} else {
|
272
|
+
const otherLinesHeight = lineHeight * fontSize * (lines.length - 1);
|
273
|
+
|
274
|
+
if (verticalAlignment === VERTICAL_ALIGN_BOTTOM) {
|
275
|
+
yOffset = height - otherLinesHeight + descent - halfLineHeightAdjustment;
|
276
|
+
} else if (verticalAlignment === VERTICAL_ALIGN_MIDDLE) {
|
277
|
+
yOffset = (height - otherLinesHeight - firstLineTextHeight + descent) / 2 + firstLineTextHeight;
|
278
|
+
}
|
279
|
+
}
|
280
|
+
|
281
|
+
lines.forEach((line, rowIndex) => {
|
282
|
+
const textWidth = widthOfTextAtSize(line, fontKitFont, fontSize, characterSpacing);
|
283
|
+
const rowYOffset = lineHeight * fontSize * rowIndex;
|
284
|
+
|
285
|
+
page.drawText(line, {
|
286
|
+
x: calcX(templateSchema.position.x, alignment, width, textWidth),
|
287
|
+
y: calcY(templateSchema.position.y, pageHeight, yOffset) - rowYOffset,
|
288
|
+
rotate,
|
289
|
+
size: fontSize,
|
290
|
+
color,
|
291
|
+
lineHeight: lineHeight * fontSize,
|
292
|
+
maxWidth: width,
|
293
|
+
font: pdfFontValue,
|
294
|
+
wordBreaks: [''],
|
295
|
+
});
|
332
296
|
});
|
333
297
|
};
|
334
298
|
|
@@ -337,17 +301,16 @@ const getCacheKey = (templateSchema: Schema, input: string) => `${templateSchema
|
|
337
301
|
const drawInputByImageSchema = async (arg: {
|
338
302
|
input: string;
|
339
303
|
templateSchema: ImageSchema;
|
340
|
-
pageHeight: number;
|
341
304
|
pdfDoc: PDFDocument;
|
342
305
|
page: PDFPage;
|
343
306
|
inputImageCache: InputImageCache;
|
344
307
|
}) => {
|
345
|
-
const { input, templateSchema,
|
308
|
+
const { input, templateSchema, pdfDoc, page, inputImageCache } = arg;
|
346
309
|
|
347
|
-
const { width, height, rotate } =
|
310
|
+
const { width, height, rotate } = convertSchemaDimensionsToPt(templateSchema);
|
348
311
|
const opt = {
|
349
312
|
x: calcX(templateSchema.position.x, 'left', width, width),
|
350
|
-
y: calcY(templateSchema.position.y,
|
313
|
+
y: calcY(templateSchema.position.y, page.getHeight(), height),
|
351
314
|
rotate,
|
352
315
|
width,
|
353
316
|
height,
|
@@ -365,18 +328,17 @@ const drawInputByImageSchema = async (arg: {
|
|
365
328
|
const drawInputByBarcodeSchema = async (arg: {
|
366
329
|
input: string;
|
367
330
|
templateSchema: BarcodeSchema;
|
368
|
-
pageHeight: number;
|
369
331
|
pdfDoc: PDFDocument;
|
370
332
|
page: PDFPage;
|
371
333
|
inputImageCache: InputImageCache;
|
372
334
|
}) => {
|
373
|
-
const { input, templateSchema,
|
335
|
+
const { input, templateSchema, pdfDoc, page, inputImageCache } = arg;
|
374
336
|
if (!validateBarcodeInput(templateSchema.type as BarCodeType, input)) return;
|
375
337
|
|
376
|
-
const { width, height, rotate } =
|
338
|
+
const { width, height, rotate } = convertSchemaDimensionsToPt(templateSchema);
|
377
339
|
const opt = {
|
378
340
|
x: calcX(templateSchema.position.x, 'left', width, width),
|
379
|
-
y: calcY(templateSchema.position.y,
|
341
|
+
y: calcY(templateSchema.position.y, page.getHeight(), height),
|
380
342
|
rotate,
|
381
343
|
width,
|
382
344
|
height,
|
@@ -398,7 +360,6 @@ export const drawInputByTemplateSchema = async (arg: {
|
|
398
360
|
templateSchema: Schema;
|
399
361
|
pdfDoc: PDFDocument;
|
400
362
|
page: PDFPage;
|
401
|
-
pageHeight: number;
|
402
363
|
fontSetting: FontSetting;
|
403
364
|
inputImageCache: InputImageCache;
|
404
365
|
}) => {
|