@pdfme/generator 2.1.0 → 2.2.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 (69) hide show
  1. package/README.md +6 -2
  2. package/dist/cjs/__tests__/assets/templates/index.js +6 -0
  3. package/dist/cjs/__tests__/assets/templates/index.js.map +1 -1
  4. package/dist/cjs/__tests__/generate.test.js +6 -0
  5. package/dist/cjs/__tests__/generate.test.js.map +1 -1
  6. package/dist/cjs/src/builtInRenderer.js +9 -0
  7. package/dist/cjs/src/builtInRenderer.js.map +1 -0
  8. package/dist/cjs/src/generate.js +29 -30
  9. package/dist/cjs/src/generate.js.map +1 -1
  10. package/dist/cjs/src/pdfUtils.js +65 -0
  11. package/dist/cjs/src/pdfUtils.js.map +1 -0
  12. package/dist/cjs/src/renderUtils.js +65 -0
  13. package/dist/cjs/src/renderUtils.js.map +1 -0
  14. package/dist/cjs/src/renders/barcodes.js +37 -0
  15. package/dist/cjs/src/renders/barcodes.js.map +1 -0
  16. package/dist/cjs/src/renders/image.js +34 -0
  17. package/dist/cjs/src/renders/image.js.map +1 -0
  18. package/dist/cjs/src/renders/text.js +86 -0
  19. package/dist/cjs/src/renders/text.js.map +1 -0
  20. package/dist/cjs/src/types.js +3 -0
  21. package/dist/cjs/src/types.js.map +1 -0
  22. package/dist/esm/__tests__/assets/templates/index.js +6 -0
  23. package/dist/esm/__tests__/assets/templates/index.js.map +1 -1
  24. package/dist/esm/__tests__/generate.test.js +6 -0
  25. package/dist/esm/__tests__/generate.test.js.map +1 -1
  26. package/dist/esm/src/builtInRenderer.js +7 -0
  27. package/dist/esm/src/builtInRenderer.js.map +1 -0
  28. package/dist/esm/src/generate.js +23 -27
  29. package/dist/esm/src/generate.js.map +1 -1
  30. package/dist/esm/src/pdfUtils.js +59 -0
  31. package/dist/esm/src/pdfUtils.js.map +1 -0
  32. package/dist/esm/src/renderUtils.js +56 -0
  33. package/dist/esm/src/renderUtils.js.map +1 -0
  34. package/dist/esm/src/renders/barcodes.js +33 -0
  35. package/dist/esm/src/renders/barcodes.js.map +1 -0
  36. package/dist/esm/src/renders/image.js +30 -0
  37. package/dist/esm/src/renders/image.js.map +1 -0
  38. package/dist/esm/src/renders/text.js +82 -0
  39. package/dist/esm/src/renders/text.js.map +1 -0
  40. package/dist/esm/src/types.js +2 -0
  41. package/dist/esm/src/types.js.map +1 -0
  42. package/dist/types/__tests__/assets/templates/index.d.ts +311 -0
  43. package/dist/types/src/builtInRenderer.d.ts +3 -0
  44. package/dist/types/src/pdfUtils.d.ts +19 -0
  45. package/dist/types/src/renderUtils.d.ts +16 -0
  46. package/dist/types/src/renders/barcodes.d.ts +2 -0
  47. package/dist/types/src/renders/image.d.ts +2 -0
  48. package/dist/types/src/renders/text.d.ts +2 -0
  49. package/dist/types/src/types.d.ts +36 -0
  50. package/package.json +2 -7
  51. package/src/builtInRenderer.ts +14 -0
  52. package/src/generate.ts +28 -46
  53. package/src/pdfUtils.ts +76 -0
  54. package/src/renderUtils.ts +68 -0
  55. package/src/renders/barcodes.ts +32 -0
  56. package/src/renders/image.ts +24 -0
  57. package/src/renders/text.ts +114 -0
  58. package/src/types.ts +23 -0
  59. package/dist/cjs/__tests__/helper.test.js +0 -53
  60. package/dist/cjs/__tests__/helper.test.js.map +0 -1
  61. package/dist/cjs/src/helper.js +0 -252
  62. package/dist/cjs/src/helper.js.map +0 -1
  63. package/dist/esm/__tests__/helper.test.js +0 -48
  64. package/dist/esm/__tests__/helper.test.js.map +0 -1
  65. package/dist/esm/src/helper.js +0 -241
  66. package/dist/esm/src/helper.js.map +0 -1
  67. package/dist/types/__tests__/helper.test.d.ts +0 -1
  68. package/dist/types/src/helper.d.ts +0 -67
  69. package/src/helper.ts +0 -375
@@ -0,0 +1,3 @@
1
+ import type { Renderer } from './types';
2
+ declare const renderer: Renderer;
3
+ export default renderer;
@@ -0,0 +1,19 @@
1
+ import { PDFPage, PDFDocument, PDFEmbeddedPage } from '@pdfme/pdf-lib';
2
+ import { Font, BasePdf } from '@pdfme/common';
3
+ import type { EmbedPdfBox } from "./types";
4
+ export declare const embedAndGetFontObj: (arg: {
5
+ pdfDoc: PDFDocument;
6
+ font: Font;
7
+ }) => Promise<any>;
8
+ export declare const getEmbeddedPagesAndEmbedPdfBoxes: (arg: {
9
+ pdfDoc: PDFDocument;
10
+ basePdf: BasePdf;
11
+ }) => Promise<{
12
+ embeddedPages: PDFEmbeddedPage[];
13
+ embedPdfBoxes: EmbedPdfBox[];
14
+ }>;
15
+ export declare const drawEmbeddedPage: (arg: {
16
+ page: PDFPage;
17
+ embeddedPage: PDFEmbeddedPage;
18
+ embedPdfBox: EmbedPdfBox;
19
+ }) => void;
@@ -0,0 +1,16 @@
1
+ import { PDFPage } from '@pdfme/pdf-lib';
2
+ import { Schema, TextSchema, Alignment } from '@pdfme/common';
3
+ export declare const hex2RgbColor: (hexString: string | undefined) => import("@pdfme/pdf-lib").RGB | undefined;
4
+ export declare const calcX: (x: number, alignment: Alignment, boxWidth: number, textWidth: number) => number;
5
+ export declare const calcY: (y: number, pageHeight: number, itemHeight: number) => number;
6
+ export declare const renderBackgroundColor: (arg: {
7
+ schema: TextSchema;
8
+ page: PDFPage;
9
+ pageHeight: number;
10
+ }) => void;
11
+ export declare const convertSchemaDimensionsToPt: (schema: Schema) => {
12
+ width: number;
13
+ height: number;
14
+ rotate: import("@pdfme/pdf-lib").Degrees;
15
+ };
16
+ export declare const getCacheKey: (schema: Schema, input: string) => string;
@@ -0,0 +1,2 @@
1
+ import type { RenderProps } from "../types";
2
+ export declare const renderBarcode: (arg: RenderProps) => Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { RenderProps } from "../types";
2
+ export declare const renderImage: (arg: RenderProps) => Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { RenderProps } from "../types";
2
+ export declare const renderText: (arg: RenderProps) => Promise<void>;
@@ -0,0 +1,36 @@
1
+ import type { PDFImage } from '@pdfme/pdf-lib';
2
+ import type { GeneratorOptions, Schema } from '@pdfme/common';
3
+ import type { PDFPage, PDFDocument } from '@pdfme/pdf-lib';
4
+ export type EmbedPdfBox = {
5
+ mediaBox: {
6
+ x: number;
7
+ y: number;
8
+ width: number;
9
+ height: number;
10
+ };
11
+ bleedBox: {
12
+ x: number;
13
+ y: number;
14
+ width: number;
15
+ height: number;
16
+ };
17
+ trimBox: {
18
+ x: number;
19
+ y: number;
20
+ width: number;
21
+ height: number;
22
+ };
23
+ };
24
+ export interface RenderProps {
25
+ value: string;
26
+ schema: Schema;
27
+ pdfDoc: PDFDocument;
28
+ page: PDFPage;
29
+ options: GeneratorOptions;
30
+ _cache: Map<string, PDFImage>;
31
+ }
32
+ export interface Renderer {
33
+ [key: string]: {
34
+ render: (arg: RenderProps) => Promise<void>;
35
+ } | undefined;
36
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pdfme/generator",
3
- "version": "2.1.0",
3
+ "version": "2.2.1",
4
4
  "sideEffects": false,
5
5
  "author": "hand-dot",
6
6
  "license": "MIT",
@@ -48,16 +48,11 @@
48
48
  "dependencies": {
49
49
  "@pdfme/pdf-lib": "^1.17.3",
50
50
  "atob": "^2.1.2",
51
- "bwip-js": "^3.2.2",
52
51
  "fontkit": "^2.0.2"
53
52
  },
54
53
  "devDependencies": {
55
54
  "@pdfme/common": "file:../common",
56
- "@types/bwip-js": "^3.0.0",
57
- "@types/pngjs": "^6.0.1",
58
- "jsqr": "^1.4.0",
59
- "pdf2json": "^2.0.0",
60
- "pngjs": "^6.0.0"
55
+ "pdf2json": "^2.0.0"
61
56
  },
62
57
  "peerDependencies": {
63
58
  "@pdfme/common": "^2.1.0"
@@ -0,0 +1,14 @@
1
+ import type { BarCodeType } from '@pdfme/common';
2
+ import type { Renderer } from './types';
3
+ import { renderText } from './renders/text';
4
+ import { renderImage } from './renders/image';
5
+ import { renderBarcode } from './renders/barcodes';
6
+
7
+ const barCodeTypes: BarCodeType[] = ['qrcode', 'japanpost', 'ean13', 'ean8', 'code39', 'code128', 'nw7', 'itf14', 'upca', 'upce', 'gs1datamatrix']
8
+
9
+ const renderer: Renderer = {
10
+ text: { render: renderText, },
11
+ image: { render: renderImage, },
12
+ ...barCodeTypes.reduce((acc, barcodeType) => Object.assign(acc, { [barcodeType]: { render: renderBarcode } }), {}),
13
+ }
14
+ export default renderer
package/src/generate.ts CHANGED
@@ -1,43 +1,25 @@
1
1
  import { PDFDocument } from '@pdfme/pdf-lib';
2
2
  import * as fontkit from 'fontkit';
3
- import type {
4
- Font,
5
- GenerateProps,
6
- SchemaInputs,
7
- Template,
8
- } from '@pdfme/common';
9
- import {
10
- getDefaultFont,
11
- getFallbackFontName,
12
- checkGenerateProps,
13
- } from '@pdfme/common';
14
- import {
15
- getEmbeddedPagesAndEmbedPdfBoxes,
16
- drawInputByTemplateSchema,
17
- drawEmbeddedPage,
18
- embedAndGetFontObj,
19
- InputImageCache,
20
- } from './helper.js';
21
- import { TOOL_NAME } from './constants.js';
22
-
23
- const preprocessing = async (arg: { inputs: SchemaInputs[]; template: Template; font: Font }) => {
24
- const { template, font } = arg;
3
+ import type { GenerateProps, Template, } from '@pdfme/common';
4
+ import { checkGenerateProps, } from '@pdfme/common';
5
+ import builtInRenderer from './builtInRenderer';
6
+ import { drawEmbeddedPage, getEmbeddedPagesAndEmbedPdfBoxes, } from './pdfUtils'
7
+ import { TOOL_NAME } from './constants';
8
+
9
+ const preprocessing = async ({ template }: { template: Template; }) => {
25
10
  const { basePdf } = template;
26
- const fallbackFontName = getFallbackFontName(font);
27
11
 
28
12
  const pdfDoc = await PDFDocument.create();
29
13
  // @ts-ignore
30
14
  pdfDoc.registerFontkit(fontkit);
31
15
 
32
- const pdfFontObj = await embedAndGetFontObj({ pdfDoc, font });
33
-
34
16
  const pagesAndBoxes = await getEmbeddedPagesAndEmbedPdfBoxes({ pdfDoc, basePdf });
35
17
  const { embeddedPages, embedPdfBoxes } = pagesAndBoxes;
36
18
 
37
- return { pdfDoc, pdfFontObj, fallbackFontName, embeddedPages, embedPdfBoxes };
19
+ return { pdfDoc, embeddedPages, embedPdfBoxes };
38
20
  };
39
21
 
40
- const postProcessing = (pdfDoc: PDFDocument) => {
22
+ const postProcessing = ({ pdfDoc }: { pdfDoc: PDFDocument }) => {
41
23
  pdfDoc.setProducer(TOOL_NAME);
42
24
  pdfDoc.setCreator(TOOL_NAME);
43
25
  };
@@ -45,13 +27,13 @@ const postProcessing = (pdfDoc: PDFDocument) => {
45
27
  const generate = async (props: GenerateProps) => {
46
28
  checkGenerateProps(props);
47
29
  const { inputs, template, options = {} } = props;
48
- const { font = getDefaultFont() } = options;
49
- const { schemas } = template;
50
30
 
51
- const preRes = await preprocessing({ inputs, template, font });
52
- const { pdfDoc, pdfFontObj, fallbackFontName, embeddedPages, embedPdfBoxes } = preRes;
31
+ const { pdfDoc, embeddedPages, embedPdfBoxes } = await preprocessing({ template });
32
+
33
+ // TODO: In the future, when we support custom schemas, we will create the registry using options.renderer instead of {}.
34
+ const rendererRegistry = Object.assign(builtInRenderer, {});
35
+ const _cache = new Map();
53
36
 
54
- const inputImageCache: InputImageCache = {};
55
37
  for (let i = 0; i < inputs.length; i += 1) {
56
38
  const inputObj = inputs[i];
57
39
  const keys = Object.keys(inputObj);
@@ -65,24 +47,24 @@ const generate = async (props: GenerateProps) => {
65
47
  drawEmbeddedPage({ page, embeddedPage, embedPdfBox });
66
48
  for (let l = 0; l < keys.length; l += 1) {
67
49
  const key = keys[l];
68
- const schema = schemas[j];
69
- const templateSchema = schema[key];
70
- const input = inputObj[key];
71
- const fontSetting = { font, pdfFontObj, fallbackFontName };
72
-
73
- await drawInputByTemplateSchema({
74
- input,
75
- templateSchema,
76
- pdfDoc,
77
- page,
78
- fontSetting,
79
- inputImageCache,
80
- });
50
+ const schemaObj = template.schemas[j];
51
+ const schema = schemaObj[key];
52
+ const value = inputObj[key];
53
+
54
+ if (!schema || !value) {
55
+ continue;
56
+ }
57
+
58
+ const renderer = rendererRegistry[schema.type];
59
+ if (!renderer) {
60
+ throw new Error(`Renderer for type ${schema.type} not found`);
61
+ }
62
+ await renderer.render({ value, schema, pdfDoc, page, options, _cache });
81
63
  }
82
64
  }
83
65
  }
84
66
 
85
- postProcessing(pdfDoc);
67
+ postProcessing({ pdfDoc });
86
68
 
87
69
  return pdfDoc.save();
88
70
  };
@@ -0,0 +1,76 @@
1
+ import { PDFPage, PDFFont, PDFDocument, PDFEmbeddedPage, TransformationMatrix } from '@pdfme/pdf-lib';
2
+ import { getB64BasePdf, Font, BasePdf } from '@pdfme/common';
3
+ import type { EmbedPdfBox } from "./types"
4
+
5
+ const embedAndGetFontObjCache = new WeakMap();
6
+ export const embedAndGetFontObj = async (arg: { pdfDoc: PDFDocument; font: Font }) => {
7
+ const { pdfDoc, font } = arg;
8
+ if (embedAndGetFontObjCache.has(pdfDoc)) {
9
+ return embedAndGetFontObjCache.get(pdfDoc);
10
+ }
11
+
12
+ const fontValues = await Promise.all(
13
+ Object.values(font).map(async (v) => {
14
+ let fontData = v.data;
15
+ if (typeof fontData === 'string' && fontData.startsWith('http')) {
16
+ fontData = await fetch(fontData).then((res) => res.arrayBuffer());
17
+ }
18
+ return pdfDoc.embedFont(fontData, {
19
+ subset: typeof v.subset === 'undefined' ? true : v.subset,
20
+ });
21
+ })
22
+ );
23
+
24
+ const fontObj = Object.keys(font).reduce(
25
+ (acc, cur, i) => Object.assign(acc, { [cur]: fontValues[i] }),
26
+ {} as { [key: string]: PDFFont }
27
+ )
28
+
29
+ embedAndGetFontObjCache.set(pdfDoc, fontObj);
30
+ return fontObj;
31
+ };
32
+
33
+ export const getEmbeddedPagesAndEmbedPdfBoxes = async (arg: {
34
+ pdfDoc: PDFDocument;
35
+ basePdf: BasePdf;
36
+ }) => {
37
+ const { pdfDoc, basePdf } = arg;
38
+ let embeddedPages: PDFEmbeddedPage[] = [];
39
+ let embedPdfBoxes: EmbedPdfBox[] = [];
40
+ const willLoadPdf = typeof basePdf === 'string' ? await getB64BasePdf(basePdf) : basePdf;
41
+ const embedPdf = await PDFDocument.load(willLoadPdf);
42
+ const embedPdfPages = embedPdf.getPages();
43
+
44
+ embedPdfBoxes = embedPdfPages.map((p) => ({
45
+ mediaBox: p.getMediaBox(),
46
+ bleedBox: p.getBleedBox(),
47
+ trimBox: p.getTrimBox(),
48
+ }));
49
+
50
+ const boundingBoxes = embedPdfPages.map((p) => {
51
+ const { x, y, width, height } = p.getMediaBox();
52
+
53
+ return { left: x, bottom: y, right: width, top: height + y };
54
+ });
55
+
56
+ const transformationMatrices = embedPdfPages.map(
57
+ () => [1, 0, 0, 1, 0, 0] as TransformationMatrix
58
+ );
59
+
60
+ embeddedPages = await pdfDoc.embedPages(embedPdfPages, boundingBoxes, transformationMatrices);
61
+
62
+ return { embeddedPages, embedPdfBoxes };
63
+ };
64
+
65
+ export const drawEmbeddedPage = (arg: {
66
+ page: PDFPage;
67
+ embeddedPage: PDFEmbeddedPage;
68
+ embedPdfBox: EmbedPdfBox;
69
+ }) => {
70
+ const { page, embeddedPage, embedPdfBox } = arg;
71
+ page.drawPage(embeddedPage);
72
+ const { mediaBox: mb, bleedBox: bb, trimBox: tb } = embedPdfBox;
73
+ page.setMediaBox(mb.x, mb.y, mb.width, mb.height);
74
+ page.setBleedBox(bb.x, bb.y, bb.width, bb.height);
75
+ page.setTrimBox(tb.x, tb.y, tb.width, tb.height);
76
+ };
@@ -0,0 +1,68 @@
1
+ import { PDFPage, degrees, rgb, } from '@pdfme/pdf-lib';
2
+ import { Schema, TextSchema, Alignment, mm2pt } from '@pdfme/common';
3
+
4
+ const hex2rgb = (hex: string) => {
5
+ if (hex.slice(0, 1) === '#') hex = hex.slice(1);
6
+ if (hex.length === 3)
7
+ hex =
8
+ hex.slice(0, 1) +
9
+ hex.slice(0, 1) +
10
+ hex.slice(1, 2) +
11
+ hex.slice(1, 2) +
12
+ hex.slice(2, 3) +
13
+ hex.slice(2, 3);
14
+
15
+ return [hex.slice(0, 2), hex.slice(2, 4), hex.slice(4, 6)].map((str) => parseInt(str, 16));
16
+ };
17
+
18
+ export const hex2RgbColor = (hexString: string | undefined) => {
19
+ if (hexString) {
20
+ const [r, g, b] = hex2rgb(hexString);
21
+
22
+ return rgb(r / 255, g / 255, b / 255);
23
+ }
24
+
25
+ // eslint-disable-next-line no-undefined
26
+ return undefined;
27
+ };
28
+
29
+ export const calcX = (x: number, alignment: Alignment, boxWidth: number, textWidth: number) => {
30
+ let addition = 0;
31
+ if (alignment === 'center') {
32
+ addition = (boxWidth - textWidth) / 2;
33
+ } else if (alignment === 'right') {
34
+ addition = boxWidth - textWidth;
35
+ }
36
+
37
+ return mm2pt(x) + addition;
38
+ };
39
+
40
+ export const calcY = (y: number, pageHeight: number, itemHeight: number) => pageHeight - mm2pt(y) - itemHeight;
41
+
42
+ export const renderBackgroundColor = (arg: {
43
+ schema: TextSchema;
44
+ page: PDFPage;
45
+ pageHeight: number;
46
+ }) => {
47
+ const { schema, page, pageHeight } = arg;
48
+ if (!schema.backgroundColor) return;
49
+ const { width, height } = convertSchemaDimensionsToPt(schema);
50
+ const color = hex2RgbColor(schema.backgroundColor);
51
+ page.drawRectangle({
52
+ x: calcX(schema.position.x, 'left', width, width),
53
+ y: calcY(schema.position.y, pageHeight, height),
54
+ width,
55
+ height,
56
+ color,
57
+ });
58
+ };
59
+
60
+ export const convertSchemaDimensionsToPt = (schema: Schema) => {
61
+ const width = mm2pt(schema.width);
62
+ const height = mm2pt(schema.height);
63
+ const rotate = degrees(schema.rotate ? schema.rotate : 0);
64
+
65
+ return { width, height, rotate };
66
+ };
67
+
68
+ export const getCacheKey = (schema: Schema, input: string) => `${schema.type}${input}`;
@@ -0,0 +1,32 @@
1
+ import {
2
+ createBarCode,
3
+ validateBarcodeInput,
4
+ BarCodeType,
5
+ } from '@pdfme/common';
6
+ import type { RenderProps } from "../types"
7
+ import { calcX, calcY, convertSchemaDimensionsToPt, getCacheKey } from '../renderUtils'
8
+
9
+ export const renderBarcode = async (arg: RenderProps) => {
10
+ const { value, schema, pdfDoc, page, _cache } = arg;
11
+ if (!validateBarcodeInput(schema.type as BarCodeType, value)) return;
12
+
13
+ const { width, height, rotate } = convertSchemaDimensionsToPt(schema);
14
+ const opt = {
15
+ x: calcX(schema.position.x, 'left', width, width),
16
+ y: calcY(schema.position.y, page.getHeight(), height),
17
+ rotate,
18
+ width,
19
+ height,
20
+ };
21
+ const inputBarcodeCacheKey = getCacheKey(schema, value);
22
+ let image = _cache.get(inputBarcodeCacheKey);
23
+ if (!image) {
24
+ const imageBuf = await createBarCode(
25
+ Object.assign(schema, { type: schema.type as BarCodeType, input: value })
26
+ );
27
+ image = await pdfDoc.embedPng(imageBuf);
28
+ _cache.set(inputBarcodeCacheKey, image)
29
+ }
30
+
31
+ page.drawImage(image, opt);
32
+ }
@@ -0,0 +1,24 @@
1
+ import type { RenderProps } from "../types"
2
+ import { calcX, calcY, convertSchemaDimensionsToPt, getCacheKey } from '../renderUtils'
3
+
4
+
5
+ export const renderImage = async (arg: RenderProps) => {
6
+ const { value, schema, pdfDoc, page, _cache } = arg;
7
+
8
+ const { width, height, rotate } = convertSchemaDimensionsToPt(schema);
9
+ const opt = {
10
+ x: calcX(schema.position.x, 'left', width, width),
11
+ y: calcY(schema.position.y, page.getHeight(), height),
12
+ rotate,
13
+ width,
14
+ height,
15
+ };
16
+ const inputImageCacheKey = getCacheKey(schema, value);
17
+ let image = _cache.get(inputImageCacheKey);
18
+ if (!image) {
19
+ const isPng = value.startsWith('data:image/png;');
20
+ image = await (isPng ? pdfDoc.embedPng(value) : pdfDoc.embedJpg(value));
21
+ _cache.set(inputImageCacheKey, image);
22
+ }
23
+ page.drawImage(image, opt);
24
+ }
@@ -0,0 +1,114 @@
1
+ import { setCharacterSpacing, } from '@pdfme/pdf-lib';
2
+ import {
3
+ TextSchema,
4
+ Font,
5
+ DEFAULT_FONT_SIZE,
6
+ DEFAULT_ALIGNMENT,
7
+ DEFAULT_LINE_HEIGHT,
8
+ DEFAULT_CHARACTER_SPACING,
9
+ DEFAULT_FONT_COLOR,
10
+ DEFAULT_VERTICAL_ALIGNMENT,
11
+ VERTICAL_ALIGN_TOP,
12
+ VERTICAL_ALIGN_MIDDLE,
13
+ VERTICAL_ALIGN_BOTTOM,
14
+ calculateDynamicFontSize,
15
+ heightOfFontAtSize,
16
+ getFontDescentInPt,
17
+ getFontKitFont,
18
+ getSplittedLines,
19
+ widthOfTextAtSize,
20
+ FontWidthCalcValues,
21
+ getDefaultFont,
22
+ getFallbackFontName,
23
+ } from '@pdfme/common';
24
+ import type { RenderProps } from "../types"
25
+ import { embedAndGetFontObj } from '../pdfUtils'
26
+ import {
27
+ hex2RgbColor,
28
+ calcX,
29
+ calcY,
30
+ renderBackgroundColor,
31
+ convertSchemaDimensionsToPt
32
+ } from '../renderUtils'
33
+
34
+ const getFontProp = async ({ value, font, schema }: { value: string, font: Font, schema: TextSchema }) => {
35
+ const fontSize = schema.dynamicFontSize ? await calculateDynamicFontSize({ textSchema: schema, font, value }) : schema.fontSize ?? DEFAULT_FONT_SIZE;
36
+ const color = hex2RgbColor(schema.fontColor ?? DEFAULT_FONT_COLOR);
37
+ const alignment = schema.alignment ?? DEFAULT_ALIGNMENT;
38
+ const verticalAlignment = schema.verticalAlignment ?? DEFAULT_VERTICAL_ALIGNMENT;
39
+ const lineHeight = schema.lineHeight ?? DEFAULT_LINE_HEIGHT;
40
+ const characterSpacing = schema.characterSpacing ?? DEFAULT_CHARACTER_SPACING;
41
+
42
+ return { fontSize, color, alignment, verticalAlignment, lineHeight, characterSpacing };
43
+ };
44
+
45
+ export const renderText = async (arg: RenderProps) => {
46
+ const { value, pdfDoc, page, options } = arg;
47
+ const schema = arg.schema as TextSchema;
48
+
49
+ const { font = getDefaultFont() } = options;
50
+
51
+ const [pdfFontObj, fontKitFont, fontProp] = await Promise.all([
52
+ embedAndGetFontObj({ pdfDoc, font }),
53
+ getFontKitFont(schema, font),
54
+ getFontProp({ value, font, schema: schema })
55
+ ])
56
+
57
+ const { fontSize, color, alignment, verticalAlignment, lineHeight, characterSpacing } = fontProp;
58
+
59
+ const pdfFontValue = pdfFontObj[schema.fontName ? schema.fontName : getFallbackFontName(font)];
60
+
61
+ const pageHeight = page.getHeight();
62
+ renderBackgroundColor({ schema, page, pageHeight });
63
+
64
+ const { width, height, rotate } = convertSchemaDimensionsToPt(schema);
65
+
66
+ page.pushOperators(setCharacterSpacing(characterSpacing));
67
+
68
+ const firstLineTextHeight = heightOfFontAtSize(fontKitFont, fontSize);
69
+ const descent = getFontDescentInPt(fontKitFont, fontSize);
70
+ const halfLineHeightAdjustment = lineHeight === 0 ? 0 : ((lineHeight - 1) * fontSize) / 2;
71
+
72
+ const fontWidthCalcValues: FontWidthCalcValues = {
73
+ font: fontKitFont,
74
+ fontSize,
75
+ characterSpacing,
76
+ boxWidthInPt: width,
77
+ };
78
+
79
+ let lines: string[] = [];
80
+ value.split(/\r|\n|\r\n/g).forEach((line) => {
81
+ lines = lines.concat(getSplittedLines(line, fontWidthCalcValues));
82
+ });
83
+
84
+ // Text lines are rendered from the bottom upwards, we need to adjust the position down
85
+ let yOffset = 0;
86
+ if (verticalAlignment === VERTICAL_ALIGN_TOP) {
87
+ yOffset = firstLineTextHeight + halfLineHeightAdjustment;
88
+ } else {
89
+ const otherLinesHeight = lineHeight * fontSize * (lines.length - 1);
90
+
91
+ if (verticalAlignment === VERTICAL_ALIGN_BOTTOM) {
92
+ yOffset = height - otherLinesHeight + descent - halfLineHeightAdjustment;
93
+ } else if (verticalAlignment === VERTICAL_ALIGN_MIDDLE) {
94
+ yOffset = (height - otherLinesHeight - firstLineTextHeight + descent) / 2 + firstLineTextHeight;
95
+ }
96
+ }
97
+
98
+ lines.forEach((line, rowIndex) => {
99
+ const textWidth = widthOfTextAtSize(line, fontKitFont, fontSize, characterSpacing);
100
+ const rowYOffset = lineHeight * fontSize * rowIndex;
101
+
102
+ page.drawText(line, {
103
+ x: calcX(schema.position.x, alignment, width, textWidth),
104
+ y: calcY(schema.position.y, pageHeight, yOffset) - rowYOffset,
105
+ rotate,
106
+ size: fontSize,
107
+ color,
108
+ lineHeight: lineHeight * fontSize,
109
+ maxWidth: width,
110
+ font: pdfFontValue,
111
+ wordBreaks: [''],
112
+ });
113
+ });
114
+ };
package/src/types.ts ADDED
@@ -0,0 +1,23 @@
1
+ import type { PDFImage } from '@pdfme/pdf-lib';
2
+ import type { GeneratorOptions, Schema, } from '@pdfme/common';
3
+ import type { PDFPage, PDFDocument, } from '@pdfme/pdf-lib';
4
+
5
+ export type EmbedPdfBox = {
6
+ mediaBox: { x: number; y: number; width: number; height: number };
7
+ bleedBox: { x: number; y: number; width: number; height: number };
8
+ trimBox: { x: number; y: number; width: number; height: number };
9
+ };
10
+
11
+ export interface RenderProps {
12
+ value: string;
13
+ schema: Schema;
14
+ pdfDoc: PDFDocument;
15
+ page: PDFPage;
16
+ options: GeneratorOptions;
17
+
18
+ _cache: Map<string, PDFImage>;
19
+ }
20
+
21
+ export interface Renderer {
22
+ [key: string]: { render: (arg: RenderProps) => Promise<void> } | undefined;
23
+ }
@@ -1,53 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- const helper_1 = require("../src/helper");
16
- const jsqr_1 = __importDefault(require("jsqr"));
17
- const pngjs_1 = require("pngjs");
18
- /**
19
- * 生成したQRコード(png)画像から入力データが正常に読み取れるかをテスト
20
- */
21
- describe('createBarCode', () => {
22
- describe('qrcode', () => {
23
- // テスト名, input, expected
24
- const tests = [
25
- ['URL', 'https://www.google.com/', 'https://www.google.com/'],
26
- ['ひらがな', 'てすとです', 'てすとです'],
27
- ['ひらがな2', 'あいうえおあいうえお2', 'あいうえおあいうえお2'],
28
- ['カタカナ', 'テストです', 'テストです'],
29
- ['漢字', 'お正月', 'お正月'],
30
- ['中国語', '新年快乐', '新年快乐'],
31
- ['タイ語', 'สวัสดีปีใหม่', 'สวัสดีปีใหม่'],
32
- ];
33
- for (const t of tests) {
34
- // eslint-disable-next-line no-loop-func
35
- test(`${t[0]}: ${t[1]}`, () => __awaiter(void 0, void 0, void 0, function* () {
36
- const buffer = (yield (0, helper_1.createBarCode)({
37
- type: 'qrcode',
38
- input: t[1],
39
- width: 10,
40
- height: 10,
41
- backgroundColor: '00000000', // 背景色を指定しないとjsQRでうまく解析できない
42
- }));
43
- const png = pngjs_1.PNG.sync.read(buffer);
44
- const pngData = new Uint8ClampedArray(png.data);
45
- const qr = (0, jsqr_1.default)(pngData, png.width, png.height);
46
- expect(qr).not.toBeNull();
47
- const dataBuffer = Buffer.from(qr.binaryData);
48
- expect(dataBuffer.toString('utf8')).toEqual(t[2]);
49
- }));
50
- }
51
- });
52
- });
53
- //# sourceMappingURL=helper.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"helper.test.js","sourceRoot":"","sources":["../../../__tests__/helper.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,0CAA8C;AAC9C,gDAAoC;AACpC,iCAA4B;AAE5B;;GAEG;AACH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;QACtB,wBAAwB;QACxB,MAAM,KAAK,GAAG;YACZ,CAAC,KAAK,EAAE,yBAAyB,EAAE,yBAAyB,CAAC;YAC7D,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC;YAC1B,CAAC,OAAO,EAAE,aAAa,EAAE,aAAa,CAAC;YACvC,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC;YAC1B,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC;YACpB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC;YACvB,CAAC,KAAK,EAAE,cAAc,EAAE,cAAc,CAAC;SACxC,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE;YACrB,wCAAwC;YACxC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,GAAS,EAAE;gBAClC,MAAM,MAAM,GAAG,CAAC,MAAM,IAAA,sBAAa,EAAC;oBAClC,IAAI,EAAE,QAAQ;oBACd,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;oBACX,KAAK,EAAE,EAAE;oBACT,MAAM,EAAE,EAAE;oBACV,eAAe,EAAE,UAAU,EAAE,2BAA2B;iBACzD,CAAC,CAAW,CAAC;gBACd,MAAM,GAAG,GAAG,WAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAClC,MAAM,OAAO,GAAG,IAAI,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAChD,MAAM,EAAE,GAAG,IAAA,cAAI,EAAC,OAAO,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAW,CAAC;gBAC1D,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;gBAC1B,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;gBAC9C,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACpD,CAAC,CAAA,CAAC,CAAC;SACJ;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}