@hellkite/pipkin 0.8.0 → 0.9.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/build/src/lib/bundler.d.ts +2 -2
- package/build/src/lib/bundler.js +32 -22
- package/build/src/lib/bundler.js.map +1 -1
- package/build/src/lib/index.d.ts +0 -1
- package/build/src/lib/index.js +0 -1
- package/build/src/lib/index.js.map +1 -1
- package/build/src/lib/template.d.ts +18 -6
- package/build/src/lib/template.js +49 -10
- package/build/src/lib/template.js.map +1 -1
- package/build/src/lib/types/hypernode.d.ts +1 -1
- package/build/src/lib/types/index.d.ts +1 -0
- package/build/src/lib/types/index.js +1 -0
- package/build/src/lib/types/index.js.map +1 -1
- package/build/src/lib/types/layer.d.ts +5 -2
- package/build/src/lib/types/layer.js.map +1 -1
- package/build/src/lib/types/pdf.d.ts +1 -0
- package/build/src/lib/types/pdf.js +3 -0
- package/build/src/lib/types/pdf.js.map +1 -0
- package/build/src/lib/types/text.d.ts +1 -1
- package/build/src/lib/utils/container.js.map +1 -1
- package/build/src/lib/utils/htmlToImage.js +0 -1
- package/build/src/lib/utils/htmlToImage.js.map +1 -1
- package/build/src/lib/utils/imagesToPdf.d.ts +2 -0
- package/build/src/lib/utils/imagesToPdf.js +31 -0
- package/build/src/lib/utils/imagesToPdf.js.map +1 -0
- package/build/src/lib/utils/index.d.ts +1 -0
- package/build/src/lib/utils/index.js +1 -0
- package/build/src/lib/utils/index.js.map +1 -1
- package/build/src/lib/utils/placeBoundingBox.js +11 -3
- package/build/src/lib/utils/placeBoundingBox.js.map +1 -1
- package/build/src/lib/utils/reduceBoundingBox.d.ts +2 -0
- package/build/src/lib/utils/reduceBoundingBox.js +16 -0
- package/build/src/lib/utils/reduceBoundingBox.js.map +1 -0
- package/build/src/test.js +46 -9
- package/build/src/test.js.map +1 -1
- package/package.json +2 -1
- package/roadmap.md +1 -1
- package/src/lib/bundler.ts +41 -29
- package/src/lib/index.ts +0 -1
- package/src/lib/template.ts +67 -16
- package/src/lib/types/containers.ts +1 -1
- package/src/lib/types/hypernode.ts +1 -2
- package/src/lib/types/index.ts +1 -0
- package/src/lib/types/layer.ts +10 -2
- package/src/lib/types/pdf.ts +1 -0
- package/src/lib/types/render.ts +2 -4
- package/src/lib/types/template.ts +1 -1
- package/src/lib/types/text.ts +1 -1
- package/src/lib/utils/container.ts +0 -1
- package/src/lib/utils/htmlToImage.ts +0 -1
- package/src/lib/utils/imagesToPdf.ts +24 -0
- package/src/lib/utils/index.ts +1 -0
- package/src/lib/utils/placeBoundingBox.ts +33 -13
- package/src/lib/utils/reduceBoundingBox.ts +21 -0
- package/src/lib/replacement.ts +0 -22
package/build/src/test.js
CHANGED
|
@@ -11,16 +11,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
const jimp_1 = require("jimp");
|
|
13
13
|
const lib_1 = require("./lib");
|
|
14
|
+
const imagesToPdf_1 = require("./lib/utils/imagesToPdf");
|
|
15
|
+
const promises_1 = require("fs/promises");
|
|
14
16
|
(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
15
17
|
const luigi = (yield jimp_1.Jimp.read('assets/luigi.png'));
|
|
16
|
-
const
|
|
18
|
+
const results = yield lib_1.Template.new({
|
|
19
|
+
height: 1050,
|
|
20
|
+
width: 750,
|
|
17
21
|
defaultFontFamily: 'branela',
|
|
18
22
|
defaultAssetsPath: 'assets',
|
|
19
23
|
color: 0xc3c3c3ff,
|
|
20
24
|
})
|
|
21
25
|
.text({ key: 'title' }, {
|
|
22
26
|
left: 25,
|
|
23
|
-
top:
|
|
27
|
+
top: 0,
|
|
24
28
|
width: 700,
|
|
25
29
|
height: 100,
|
|
26
30
|
}, {
|
|
@@ -32,6 +36,7 @@ const lib_1 = require("./lib");
|
|
|
32
36
|
width: 1,
|
|
33
37
|
color: 'red',
|
|
34
38
|
},
|
|
39
|
+
renderBoundingBox: true,
|
|
35
40
|
})
|
|
36
41
|
.font('assets/BlackFlag.ttf', 'blackflag')
|
|
37
42
|
.text({ key: 'subtitle' }, {
|
|
@@ -51,14 +56,15 @@ const lib_1 = require("./lib");
|
|
|
51
56
|
skip: entry => entry.title.toLowerCase() === 'luigi',
|
|
52
57
|
})
|
|
53
58
|
.font('assets/branela.otf', 'branela')
|
|
54
|
-
.image({ pathFn: entry => `${entry.title.toLowerCase()}.png` }, { left:
|
|
59
|
+
.image({ pathFn: entry => `${entry.title.toLowerCase()}.png` }, { left: 0, top: 225, width: 750, height: 700 }, {
|
|
55
60
|
scale: 'stretch',
|
|
56
61
|
assetsPath: 'assets',
|
|
62
|
+
renderBoundingBox: true,
|
|
57
63
|
})
|
|
58
64
|
.text({ key: 'effect' }, {
|
|
59
|
-
left:
|
|
65
|
+
left: 0,
|
|
60
66
|
top: 900,
|
|
61
|
-
width:
|
|
67
|
+
width: 750,
|
|
62
68
|
height: 150,
|
|
63
69
|
}, {
|
|
64
70
|
renderBoundingBox: true,
|
|
@@ -107,13 +113,39 @@ const lib_1 = require("./lib");
|
|
|
107
113
|
},
|
|
108
114
|
];
|
|
109
115
|
}), {
|
|
110
|
-
left:
|
|
116
|
+
left: 0,
|
|
111
117
|
top: 325,
|
|
112
118
|
width: 100,
|
|
113
119
|
height: 600,
|
|
114
120
|
}, {
|
|
115
121
|
scale: 'stretch',
|
|
116
122
|
gap: 50,
|
|
123
|
+
renderBoundingBox: true,
|
|
124
|
+
})
|
|
125
|
+
.vbox(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
126
|
+
return [
|
|
127
|
+
{
|
|
128
|
+
image: {
|
|
129
|
+
buffer: yield luigi.clone().getBuffer('image/png'),
|
|
130
|
+
},
|
|
131
|
+
options: { scale: 'stretch' },
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
image: {
|
|
135
|
+
buffer: yield luigi.clone().getBuffer('image/png'),
|
|
136
|
+
},
|
|
137
|
+
options: { scale: 'stretch' },
|
|
138
|
+
},
|
|
139
|
+
];
|
|
140
|
+
}), {
|
|
141
|
+
right: 0,
|
|
142
|
+
top: 325,
|
|
143
|
+
width: 100,
|
|
144
|
+
height: 600,
|
|
145
|
+
}, {
|
|
146
|
+
scale: 'stretch',
|
|
147
|
+
gap: 50,
|
|
148
|
+
renderBoundingBox: true,
|
|
117
149
|
})
|
|
118
150
|
.grid(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
119
151
|
return [
|
|
@@ -180,8 +212,13 @@ const lib_1 = require("./lib");
|
|
|
180
212
|
countField: 'copies',
|
|
181
213
|
},
|
|
182
214
|
});
|
|
183
|
-
yield Promise.all(
|
|
184
|
-
|
|
185
|
-
|
|
215
|
+
yield Promise.all(results.map((result, index) => result.write(`assets/test-${index + 1}.png`)));
|
|
216
|
+
const bundledImages = lib_1.Bundler.new({
|
|
217
|
+
gap: 8,
|
|
218
|
+
padding: 4
|
|
219
|
+
}).bundle(results);
|
|
220
|
+
yield Promise.all(bundledImages.map((r, index) => r.write(`assets/test-bundled-${index + 1}.png`)));
|
|
221
|
+
const pdf = yield (0, imagesToPdf_1.imagesToPdf)(bundledImages);
|
|
222
|
+
yield (0, promises_1.writeFile)('assets/result.pdf', pdf);
|
|
186
223
|
}))();
|
|
187
224
|
//# sourceMappingURL=test.js.map
|
package/build/src/test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/test.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,+BAA4B;AAC5B,+
|
|
1
|
+
{"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hellkite/pipkin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Library for board game card generation",
|
|
5
5
|
"main": "build/src/index.js",
|
|
6
6
|
"types": "build/src/index.d.ts",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"lodash.merge": "^4.6.2",
|
|
25
25
|
"node-html-to-image": "^5.0.0",
|
|
26
26
|
"papaparse": "^5.5.2",
|
|
27
|
+
"pdf-lib": "^1.17.1",
|
|
27
28
|
"ts-node": "^10.9.2",
|
|
28
29
|
"virtual-dom": "^2.1.1"
|
|
29
30
|
},
|
package/roadmap.md
CHANGED
package/src/lib/bundler.ts
CHANGED
|
@@ -2,17 +2,14 @@ import { Jimp } from 'jimp';
|
|
|
2
2
|
import { Size, ImageType } from './types';
|
|
3
3
|
|
|
4
4
|
type RequiredBundlerOptions = {
|
|
5
|
-
size: Size;
|
|
6
5
|
rows: number;
|
|
7
6
|
cols: number;
|
|
8
7
|
};
|
|
9
8
|
|
|
9
|
+
// TODO: move
|
|
10
10
|
const PAGE_SIZE_300_PPI: Size = { height: 2480, width: 3508 };
|
|
11
11
|
|
|
12
|
-
const DEFAULT_PAGE_SIZE: Size = PAGE_SIZE_300_PPI;
|
|
13
|
-
|
|
14
12
|
const DEFAULT_BUNDLER_OPTIONS: RequiredBundlerOptions = {
|
|
15
|
-
size: DEFAULT_PAGE_SIZE,
|
|
16
13
|
rows: 2,
|
|
17
14
|
cols: 4,
|
|
18
15
|
};
|
|
@@ -64,33 +61,21 @@ export class Bundler {
|
|
|
64
61
|
const cardsPerPage = this.options.cols * this.options.rows;
|
|
65
62
|
const results: Array<ImageType> = [];
|
|
66
63
|
for (let offset = 0; offset <= images.length; offset += cardsPerPage) {
|
|
67
|
-
results.push(
|
|
68
|
-
this.renderPage(images.slice(offset, offset + cardsPerPage)),
|
|
69
|
-
);
|
|
64
|
+
results.push(this.renderPage(images, offset));
|
|
70
65
|
}
|
|
71
66
|
return results;
|
|
72
67
|
}
|
|
73
68
|
|
|
74
|
-
private renderPage(images: Array<ImageType
|
|
69
|
+
private renderPage(images: Array<ImageType>, offset: number): ImageType {
|
|
70
|
+
const { pageSize, cardSize } = this.computeCardAndPageSize(
|
|
71
|
+
images,
|
|
72
|
+
offset,
|
|
73
|
+
);
|
|
75
74
|
const page = new Jimp({
|
|
76
|
-
height:
|
|
77
|
-
width:
|
|
75
|
+
height: pageSize.height,
|
|
76
|
+
width: pageSize.width,
|
|
78
77
|
color: this.options.bgColor ?? 0xffffffff,
|
|
79
78
|
});
|
|
80
|
-
const cardSize: Size = {
|
|
81
|
-
width:
|
|
82
|
-
(page.width -
|
|
83
|
-
this.getPadding('left') -
|
|
84
|
-
this.getPadding('right') -
|
|
85
|
-
this.getGap('cols')) /
|
|
86
|
-
this.options.cols,
|
|
87
|
-
height:
|
|
88
|
-
(page.height -
|
|
89
|
-
this.getPadding('top') -
|
|
90
|
-
this.getPadding('bottom') -
|
|
91
|
-
this.getGap('rows')) /
|
|
92
|
-
this.options.rows,
|
|
93
|
-
};
|
|
94
79
|
for (let rowIndex = 0; rowIndex < this.options.rows; rowIndex++) {
|
|
95
80
|
for (let colIndex = 0; colIndex < this.options.cols; colIndex++) {
|
|
96
81
|
const imageIndex = rowIndex * this.options.cols + colIndex;
|
|
@@ -98,17 +83,13 @@ export class Bundler {
|
|
|
98
83
|
if (!image) {
|
|
99
84
|
continue;
|
|
100
85
|
}
|
|
101
|
-
image.scaleToFit({
|
|
102
|
-
w: cardSize.width,
|
|
103
|
-
h: cardSize.height,
|
|
104
|
-
});
|
|
105
86
|
const offsetX =
|
|
106
87
|
this.getPadding('left') +
|
|
107
88
|
colIndex * this.getGap('cols') +
|
|
108
89
|
colIndex * cardSize.width;
|
|
109
90
|
const offsetY =
|
|
110
91
|
this.getPadding('top') +
|
|
111
|
-
rowIndex* this.getGap('rows') +
|
|
92
|
+
rowIndex * this.getGap('rows') +
|
|
112
93
|
rowIndex * cardSize.height;
|
|
113
94
|
page.composite(image, offsetX, offsetY);
|
|
114
95
|
}
|
|
@@ -116,6 +97,37 @@ export class Bundler {
|
|
|
116
97
|
return page;
|
|
117
98
|
}
|
|
118
99
|
|
|
100
|
+
private computeCardAndPageSize(
|
|
101
|
+
images: Array<ImageType>,
|
|
102
|
+
offset: number,
|
|
103
|
+
): { cardSize: Size; pageSize: Size } {
|
|
104
|
+
const pageSize: Size = { height: 0, width: 0 };
|
|
105
|
+
const cardSize: Size = { height: 0, width: 0 };
|
|
106
|
+
for (let rowIndex = 0; rowIndex < this.options.rows; rowIndex++) {
|
|
107
|
+
for (let colIndex = 0; colIndex < this.options.cols; colIndex++) {
|
|
108
|
+
const imageIndex =
|
|
109
|
+
offset + rowIndex * this.options.cols + colIndex;
|
|
110
|
+
const image = images[imageIndex];
|
|
111
|
+
if (!image) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
cardSize.height = Math.max(cardSize.height, image.height);
|
|
115
|
+
cardSize.width = Math.max(cardSize.width, image.width);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
pageSize.height +=
|
|
119
|
+
this.getPadding('top') +
|
|
120
|
+
cardSize.height * this.options.rows +
|
|
121
|
+
this.getGap('rows') * (this.options.rows - 1) +
|
|
122
|
+
this.getPadding('bottom');
|
|
123
|
+
pageSize.width +=
|
|
124
|
+
this.getPadding('left') +
|
|
125
|
+
cardSize.width * this.options.cols +
|
|
126
|
+
this.getGap('cols') * (this.options.cols - 1) +
|
|
127
|
+
this.getPadding('right');
|
|
128
|
+
return { pageSize, cardSize };
|
|
129
|
+
}
|
|
130
|
+
|
|
119
131
|
private getGap(direction: keyof Direction2): number {
|
|
120
132
|
if (typeof this.options.gap === 'number') {
|
|
121
133
|
return this.options.gap;
|
package/src/lib/index.ts
CHANGED
package/src/lib/template.ts
CHANGED
|
@@ -40,33 +40,36 @@ import {
|
|
|
40
40
|
StaticImageRef,
|
|
41
41
|
TemplateOptions,
|
|
42
42
|
DEFAULT_TEMPLATE_OPTIONS,
|
|
43
|
+
LayerFn,
|
|
44
|
+
ReplacementMap,
|
|
43
45
|
} from './types';
|
|
44
46
|
import merge from 'lodash.merge';
|
|
45
47
|
import { RequiredDeep } from 'type-fest';
|
|
46
48
|
import { h } from 'virtual-dom';
|
|
47
49
|
import flatten from 'lodash.flatten';
|
|
48
|
-
import {
|
|
49
|
-
|
|
50
|
-
export type LayerFnContext = {};
|
|
51
|
-
|
|
52
|
-
export type LayerFn<EntryType> = (
|
|
53
|
-
entry: EntryType,
|
|
54
|
-
context: LayerFnContext,
|
|
55
|
-
) => Promise<Array<HyperNode>>;
|
|
50
|
+
import { Bundler } from './bundler';
|
|
56
51
|
|
|
57
52
|
export type TemplateLayerFn<EntryType extends Record<string, string>> = (
|
|
58
53
|
template: Template<EntryType>,
|
|
59
54
|
) => Template<EntryType>;
|
|
60
55
|
|
|
61
56
|
export class Template<EntryType extends Record<string, string>> {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Template data
|
|
59
|
+
*/
|
|
65
60
|
private readonly background: ImageType;
|
|
61
|
+
private readonly layers: LayerFn<EntryType>[] = [];
|
|
62
|
+
private readonly fonts: Record<string, string> = {};
|
|
66
63
|
private renderBoundingBox?: boolean;
|
|
67
64
|
private defaultFontFamily?: string;
|
|
68
65
|
private defaultAssetsPath?: string;
|
|
69
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Render data
|
|
69
|
+
*/
|
|
70
|
+
private readonly debugPoints: Array<DebugPoint> = [];
|
|
71
|
+
private bundler?: Bundler;
|
|
72
|
+
|
|
70
73
|
// disallow constructor initialization
|
|
71
74
|
private constructor(options: TemplateOptions) {
|
|
72
75
|
this.background = new Jimp({
|
|
@@ -265,7 +268,9 @@ export class Template<EntryType extends Record<string, string>> {
|
|
|
265
268
|
}
|
|
266
269
|
|
|
267
270
|
debug = (): this => {
|
|
268
|
-
this.debugPoints.push(
|
|
271
|
+
this.debugPoints.push({
|
|
272
|
+
index: this.layers.length,
|
|
273
|
+
});
|
|
269
274
|
return this;
|
|
270
275
|
};
|
|
271
276
|
|
|
@@ -282,6 +287,7 @@ export class Template<EntryType extends Record<string, string>> {
|
|
|
282
287
|
h('head', [
|
|
283
288
|
h(
|
|
284
289
|
'style',
|
|
290
|
+
// load fonts
|
|
285
291
|
Object.entries(this.fonts)
|
|
286
292
|
.map(
|
|
287
293
|
([name, data]) =>
|
|
@@ -293,16 +299,37 @@ export class Template<EntryType extends Record<string, string>> {
|
|
|
293
299
|
.join('\n'),
|
|
294
300
|
),
|
|
295
301
|
]),
|
|
296
|
-
|
|
302
|
+
// fix chromium headless padding issue
|
|
303
|
+
h(
|
|
304
|
+
'body',
|
|
305
|
+
{
|
|
306
|
+
style: {
|
|
307
|
+
margin: 0,
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
[
|
|
311
|
+
h(
|
|
312
|
+
'div',
|
|
313
|
+
{
|
|
314
|
+
style: {
|
|
315
|
+
marginLeft: '-8px',
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
children,
|
|
319
|
+
),
|
|
320
|
+
],
|
|
321
|
+
),
|
|
297
322
|
]);
|
|
298
323
|
|
|
299
324
|
// TODO: move it to a proper place
|
|
300
325
|
for (const debugPoint of this.debugPoints) {
|
|
301
326
|
const debugRender = await htmlToImage(
|
|
302
|
-
buildDocument(flatten(results.slice(0, debugPoint))),
|
|
327
|
+
buildDocument(flatten(results.slice(0, debugPoint.index))),
|
|
303
328
|
this.backgroundSize,
|
|
304
329
|
);
|
|
305
|
-
const debugImage: ImageType = await this.background
|
|
330
|
+
const debugImage: ImageType = await this.background
|
|
331
|
+
.clone()
|
|
332
|
+
.composite(debugRender);
|
|
306
333
|
await debugImage.write('assets/debug-1.png');
|
|
307
334
|
}
|
|
308
335
|
|
|
@@ -520,7 +547,7 @@ export class Template<EntryType extends Record<string, string>> {
|
|
|
520
547
|
);
|
|
521
548
|
const imageBase64 = await image.getBase64('image/png');
|
|
522
549
|
|
|
523
|
-
|
|
550
|
+
const tmpChildren: Array<string | HyperNode> = [];
|
|
524
551
|
for (const textSegment of textChildren) {
|
|
525
552
|
if (typeof textSegment !== 'string') {
|
|
526
553
|
continue;
|
|
@@ -627,3 +654,27 @@ export class Template<EntryType extends Record<string, string>> {
|
|
|
627
654
|
);
|
|
628
655
|
};
|
|
629
656
|
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Represents a replacement map between sets of words and symbols
|
|
660
|
+
*/
|
|
661
|
+
export class Replacement {
|
|
662
|
+
protected readonly replacementMap: ReplacementMap = {};
|
|
663
|
+
|
|
664
|
+
replace(words: Array<string>, symbol: StaticImageRef): this {
|
|
665
|
+
words.forEach(word => {
|
|
666
|
+
this.replacementMap[word] = symbol;
|
|
667
|
+
});
|
|
668
|
+
return this;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
class ReplacementBuilder extends Replacement {
|
|
673
|
+
build(): ReplacementMap {
|
|
674
|
+
return this.replacementMap;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
type DebugPoint = {
|
|
679
|
+
index: number;
|
|
680
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { RequiredDeep } from 'type-fest';
|
|
2
2
|
import { BoundingBox } from './boundingBox';
|
|
3
|
-
import { ImageLayerSpecificOptions, ImageRef
|
|
3
|
+
import { ImageLayerSpecificOptions, ImageRef } from './image';
|
|
4
4
|
import { ScaleMode } from './scale';
|
|
5
5
|
import { DEFAULT_LAYER_OPTIONS, LayerOptions } from './layer';
|
|
6
6
|
import { HyperNode } from './hypernode';
|
package/src/lib/types/index.ts
CHANGED
package/src/lib/types/layer.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { RequiredDeep } from
|
|
2
|
-
import { JustifyContent, AlignItems } from
|
|
1
|
+
import { RequiredDeep } from 'type-fest';
|
|
2
|
+
import { JustifyContent, AlignItems } from './css';
|
|
3
|
+
import { HyperNode } from './hypernode';
|
|
3
4
|
|
|
4
5
|
export type LayerOptions<EntryType extends Record<string, string>> = {
|
|
5
6
|
/**
|
|
@@ -31,3 +32,10 @@ export const DEFAULT_LAYER_OPTIONS: RequiredDeep<
|
|
|
31
32
|
skip: false,
|
|
32
33
|
renderBoundingBox: false,
|
|
33
34
|
};
|
|
35
|
+
|
|
36
|
+
export type LayerFnContext = {};
|
|
37
|
+
|
|
38
|
+
export type LayerFn<EntryType> = (
|
|
39
|
+
entry: EntryType,
|
|
40
|
+
context: LayerFnContext,
|
|
41
|
+
) => Promise<Array<HyperNode>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type PDFData = Uint8Array<ArrayBufferLike>;
|
package/src/lib/types/render.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
1
|
export type RenderOptions<EntryType extends Record<string, string>> = {
|
|
4
2
|
duplication?: DuplicationOptions<EntryType>;
|
|
5
|
-
}
|
|
3
|
+
};
|
|
6
4
|
|
|
7
5
|
export type DuplicationOptions<EntryType extends Record<string, string>> = {
|
|
8
6
|
/**
|
|
@@ -20,4 +18,4 @@ export type DuplicationOptions<EntryType extends Record<string, string>> = {
|
|
|
20
18
|
* default: 1
|
|
21
19
|
*/
|
|
22
20
|
default?: number;
|
|
23
|
-
}
|
|
21
|
+
};
|
package/src/lib/types/text.ts
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { PDFDocument } from 'pdf-lib';
|
|
2
|
+
import { ImageType, PDFData } from '../types';
|
|
3
|
+
|
|
4
|
+
export const imagesToPdf = async (
|
|
5
|
+
images: Array<ImageType>,
|
|
6
|
+
): Promise<PDFData> => {
|
|
7
|
+
const pdf = await PDFDocument.create();
|
|
8
|
+
|
|
9
|
+
for (const image of images) {
|
|
10
|
+
const imageBase64 = await image.getBase64('image/png');
|
|
11
|
+
const embeddedImage = await pdf.embedPng(imageBase64);
|
|
12
|
+
const { width, height } = embeddedImage.scale(1);
|
|
13
|
+
const page = pdf.addPage([width, height]);
|
|
14
|
+
|
|
15
|
+
page.drawImage(embeddedImage, {
|
|
16
|
+
x: 0,
|
|
17
|
+
y: 0,
|
|
18
|
+
width,
|
|
19
|
+
height,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return pdf.save();
|
|
24
|
+
};
|
package/src/lib/utils/index.ts
CHANGED
|
@@ -1,19 +1,39 @@
|
|
|
1
1
|
import { h } from 'virtual-dom';
|
|
2
2
|
import { boundingBoxToPx } from './toPx';
|
|
3
3
|
import { BoundingBox, HyperNode } from '../types';
|
|
4
|
+
import { reduceBoundingBox } from './reduceBoundingBox';
|
|
4
5
|
|
|
5
|
-
export const placeBoundingBox = async (
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
export const placeBoundingBox = async (
|
|
7
|
+
box: BoundingBox,
|
|
8
|
+
): Promise<HyperNode> => {
|
|
9
|
+
const borderWidthPx = 2;
|
|
10
|
+
const reducedBoundingBox = reduceBoundingBox(box, borderWidthPx);
|
|
11
|
+
return h('div', {}, [
|
|
12
|
+
h(
|
|
13
|
+
'div',
|
|
14
|
+
{
|
|
15
|
+
style: {
|
|
16
|
+
position: 'absolute',
|
|
17
|
+
border: `${borderWidthPx}px solid red`,
|
|
18
|
+
background: 'transparent',
|
|
19
|
+
boxSizing: 'border-box',
|
|
20
|
+
...boundingBoxToPx(box),
|
|
21
|
+
},
|
|
15
22
|
},
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
23
|
+
[],
|
|
24
|
+
),
|
|
25
|
+
h(
|
|
26
|
+
'div',
|
|
27
|
+
{
|
|
28
|
+
style: {
|
|
29
|
+
position: 'absolute',
|
|
30
|
+
border: `${borderWidthPx}px dashed blue`,
|
|
31
|
+
background: 'transparent',
|
|
32
|
+
boxSizing: 'border-box',
|
|
33
|
+
...boundingBoxToPx(reducedBoundingBox),
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
[],
|
|
37
|
+
),
|
|
38
|
+
]);
|
|
19
39
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { BoundingBox } from '../types';
|
|
2
|
+
|
|
3
|
+
type KeysOfUnion<T> = T extends unknown ? keyof T : never;
|
|
4
|
+
|
|
5
|
+
export const reduceBoundingBox = (
|
|
6
|
+
boundingBox: BoundingBox,
|
|
7
|
+
reduceWithPx: number,
|
|
8
|
+
): BoundingBox => {
|
|
9
|
+
return (Object.entries(boundingBox) as [KeysOfUnion<BoundingBox>, number][])
|
|
10
|
+
.map(([key, value]) => [
|
|
11
|
+
key,
|
|
12
|
+
value +
|
|
13
|
+
(key === 'width' || key === 'height'
|
|
14
|
+
? -reduceWithPx * 2
|
|
15
|
+
: reduceWithPx),
|
|
16
|
+
])
|
|
17
|
+
.reduce(
|
|
18
|
+
(box, [key, value]) => ({ ...box, [key]: value }),
|
|
19
|
+
{} as BoundingBox,
|
|
20
|
+
);
|
|
21
|
+
};
|
package/src/lib/replacement.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { ReplacementMap, StaticImageRef } from "./types";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Represents a replacement map between sets of words and symbols
|
|
5
|
-
*/
|
|
6
|
-
export class Replacement {
|
|
7
|
-
protected readonly replacementMap: ReplacementMap = {};
|
|
8
|
-
|
|
9
|
-
replace(words: Array<string>, symbol: StaticImageRef): this {
|
|
10
|
-
words.forEach(word => {
|
|
11
|
-
this.replacementMap[word] = symbol;
|
|
12
|
-
});
|
|
13
|
-
return this;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export class ReplacementBuilder extends Replacement {
|
|
18
|
-
build(): ReplacementMap {
|
|
19
|
-
return this.replacementMap;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|