@hellkite/pipkin 0.6.2 → 0.7.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.
Files changed (49) hide show
  1. package/build/src/lib/template.d.ts +9 -10
  2. package/build/src/lib/template.js +75 -40
  3. package/build/src/lib/template.js.map +1 -1
  4. package/build/src/lib/types/containers.d.ts +14 -2
  5. package/build/src/lib/types/containers.js.map +1 -1
  6. package/build/src/lib/types/hypernode.d.ts +2 -0
  7. package/build/src/lib/types/hypernode.js +3 -0
  8. package/build/src/lib/types/hypernode.js.map +1 -0
  9. package/build/src/lib/types/image.d.ts +5 -0
  10. package/build/src/lib/types/image.js.map +1 -1
  11. package/build/src/lib/types/index.d.ts +1 -0
  12. package/build/src/lib/types/index.js +1 -0
  13. package/build/src/lib/types/index.js.map +1 -1
  14. package/build/src/lib/types/text.d.ts +7 -2
  15. package/build/src/lib/types/text.js +1 -1
  16. package/build/src/lib/types/text.js.map +1 -1
  17. package/build/src/lib/utils/container.js +10 -45
  18. package/build/src/lib/utils/container.js.map +1 -1
  19. package/build/src/lib/utils/htmlToImage.d.ts +2 -3
  20. package/build/src/lib/utils/htmlToImage.js.map +1 -1
  21. package/build/src/lib/utils/index.d.ts +2 -2
  22. package/build/src/lib/utils/index.js +2 -2
  23. package/build/src/lib/utils/index.js.map +1 -1
  24. package/build/src/lib/utils/placeBoundingBox.d.ts +2 -0
  25. package/build/src/lib/utils/placeBoundingBox.js +21 -0
  26. package/build/src/lib/utils/placeBoundingBox.js.map +1 -0
  27. package/build/src/lib/utils/placeImage.d.ts +7 -6
  28. package/build/src/lib/utils/placeImage.js +20 -20
  29. package/build/src/lib/utils/placeImage.js.map +1 -1
  30. package/build/src/lib/utils/placeText.d.ts +14 -0
  31. package/build/src/lib/utils/placeText.js +69 -0
  32. package/build/src/lib/utils/placeText.js.map +1 -0
  33. package/build/src/test.js +28 -10
  34. package/build/src/test.js.map +1 -1
  35. package/package.json +3 -1
  36. package/roadmap.md +2 -1
  37. package/src/lib/template.ts +100 -70
  38. package/src/lib/types/containers.ts +22 -4
  39. package/src/lib/types/hypernode.ts +4 -0
  40. package/src/lib/types/image.ts +6 -0
  41. package/src/lib/types/index.ts +1 -0
  42. package/src/lib/types/text.ts +10 -5
  43. package/src/lib/utils/container.ts +13 -70
  44. package/src/lib/utils/htmlToImage.ts +3 -3
  45. package/src/lib/utils/index.ts +2 -2
  46. package/src/lib/utils/{drawBoundingBox.ts → placeBoundingBox.ts} +3 -9
  47. package/src/lib/utils/placeImage.ts +34 -27
  48. package/src/lib/utils/placeText.ts +110 -0
  49. package/src/lib/utils/renderText.ts +0 -107
@@ -9,30 +9,30 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.placeImage = void 0;
12
+ exports.prepareImage = exports.placeImage = void 0;
13
13
  const virtual_dom_1 = require("virtual-dom");
14
14
  const toPx_1 = require("./toPx");
15
15
  const types_1 = require("../types");
16
- const htmlToImage_1 = require("./htmlToImage");
17
- const placeImage = (_a) => __awaiter(void 0, [_a], void 0, function* ({ image, box, backgroundSize, options, }) {
18
- const imageBase64 = yield image.getBase64('image/png');
19
- const objectFit = types_1.SCALE_MODE_TO_OBJECT_FIT[options.scale];
20
- const document = (0, virtual_dom_1.h)('div', {
16
+ const placeImage = (_a) => __awaiter(void 0, [_a], void 0, function* ({ image, box, options, }) {
17
+ return (0, virtual_dom_1.h)('div', {
21
18
  style: Object.assign({ display: 'flex', position: 'absolute', scale: 1, justifyContent: options.justifyContent, alignItems: options.alignItems }, (0, toPx_1.boundingBoxToPx)(box)),
22
- }, [
23
- (0, virtual_dom_1.h)('img', {
24
- style: {
25
- objectFit,
26
- flex: '1 1 auto',
27
- minWidth: 0,
28
- minHeight: 0,
29
- maxWidth: '100%',
30
- maxHeight: '100%',
31
- },
32
- src: imageBase64,
33
- }, []),
34
- ]);
35
- return (0, htmlToImage_1.htmlToImage)(document, backgroundSize);
19
+ }, [yield (0, exports.prepareImage)({ image, options })]);
36
20
  });
37
21
  exports.placeImage = placeImage;
22
+ const prepareImage = (_a) => __awaiter(void 0, [_a], void 0, function* ({ image, options, }) {
23
+ const imageBase64 = yield image.getBase64('image/png');
24
+ const objectFit = types_1.SCALE_MODE_TO_OBJECT_FIT[options.scale];
25
+ return (0, virtual_dom_1.h)('img', {
26
+ style: {
27
+ objectFit,
28
+ flex: '1 1 auto',
29
+ minWidth: 0,
30
+ minHeight: 0,
31
+ maxWidth: '100%',
32
+ maxHeight: '100%',
33
+ },
34
+ src: imageBase64,
35
+ }, []);
36
+ });
37
+ exports.prepareImage = prepareImage;
38
38
  //# sourceMappingURL=placeImage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"placeImage.js","sourceRoot":"","sources":["../../../../src/lib/utils/placeImage.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6CAAgC;AAChC,iCAAyC;AACzC,oCAKkB;AAClB,+CAA4C;AAUrC,MAAM,UAAU,GAAG,KAKyB,EAAE,4CALsB,EACvE,KAAK,EACL,GAAG,EACH,cAAc,EACd,OAAO,GACkB;IACzB,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,gCAAwB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAE1D,MAAM,QAAQ,GAAG,IAAA,eAAC,EACd,KAAK,EACL;QACI,KAAK,kBACD,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,UAAU,EACpB,KAAK,EAAE,CAAC,EAER,cAAc,EAAE,OAAO,CAAC,cAAc,EACtC,UAAU,EAAE,OAAO,CAAC,UAAU,IAE3B,IAAA,sBAAe,EAAC,GAAG,CAAC,CAC1B;KACJ,EACD;QACI,IAAA,eAAC,EACG,KAAK,EACL;YACI,KAAK,EAAE;gBACH,SAAS;gBACT,IAAI,EAAE,UAAU;gBAChB,QAAQ,EAAE,CAAC;gBACX,SAAS,EAAE,CAAC;gBACZ,QAAQ,EAAE,MAAM;gBAChB,SAAS,EAAE,MAAM;aACpB;YACD,GAAG,EAAE,WAAW;SACnB,EACD,EAAE,CACL;KACJ,CACJ,CAAC;IAEF,OAAO,IAAA,yBAAW,EAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;AACjD,CAAC,CAAA,CAAA;AA3CY,QAAA,UAAU,cA2CtB"}
1
+ {"version":3,"file":"placeImage.js","sourceRoot":"","sources":["../../../../src/lib/utils/placeImage.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6CAAgC;AAChC,iCAAyC;AACzC,oCAOkB;AASX,MAAM,UAAU,GAAG,KAIyB,EAAE,4CAJsB,EACvE,KAAK,EACL,GAAG,EACH,OAAO,GACkB;IACzB,OAAO,IAAA,eAAC,EACJ,KAAK,EACL;QACI,KAAK,kBACD,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,UAAU,EACpB,KAAK,EAAE,CAAC,EAER,cAAc,EAAE,OAAO,CAAC,cAAc,EACtC,UAAU,EAAE,OAAO,CAAC,UAAU,IAE3B,IAAA,sBAAe,EAAC,GAAG,CAAC,CAC1B;KACJ,EACD,CAAC,MAAM,IAAA,oBAAY,EAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAC3C,CAAC;AACN,CAAC,CAAA,CAAC;AArBW,QAAA,UAAU,cAqBrB;AAOK,MAAM,YAAY,GAAG,KAGyB,EAAE,4CAHsB,EACzE,KAAK,EACL,OAAO,GACoB;IAC3B,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,gCAAwB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAE1D,OAAO,IAAA,eAAC,EACJ,KAAK,EACL;QACI,KAAK,EAAE;YACH,SAAS;YACT,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE,CAAC;YACX,SAAS,EAAE,CAAC;YACZ,QAAQ,EAAE,MAAM;YAChB,SAAS,EAAE,MAAM;SACpB;QACD,GAAG,EAAE,WAAW;KACnB,EACD,EAAE,CACL,CAAC;AACN,CAAC,CAAA,CAAC;AAtBW,QAAA,YAAY,gBAsBvB"}
@@ -0,0 +1,14 @@
1
+ import { BoundingBox, TextLayerOptions, HyperNode, TextLayerSpecificOptions } from '../types';
2
+ import { RequiredDeep } from 'type-fest';
3
+ type PlaceTextProps<EntryType extends Record<string, string>> = {
4
+ text: string;
5
+ box: BoundingBox;
6
+ options: RequiredDeep<TextLayerOptions<EntryType>>;
7
+ };
8
+ export declare const placeText: <EntryType extends Record<string, string>>({ text, box, options, }: PlaceTextProps<EntryType>) => Promise<HyperNode>;
9
+ type PrepareTextProps<EntryType extends Record<string, string>> = {
10
+ text: string;
11
+ options: RequiredDeep<TextLayerSpecificOptions<EntryType>>;
12
+ };
13
+ export declare const prepareText: <EntryType extends Record<string, string>>({ text, options, }: PrepareTextProps<EntryType>) => Promise<HyperNode>;
14
+ export {};
@@ -0,0 +1,69 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.prepareText = exports.placeText = void 0;
13
+ const virtual_dom_1 = require("virtual-dom");
14
+ const toPx_1 = require("./toPx");
15
+ const placeText = (_a) => __awaiter(void 0, [_a], void 0, function* ({ text, box, options, }) {
16
+ return (0, virtual_dom_1.h)('div', {
17
+ style: Object.assign({ display: 'flex', overflow: 'visible', position: 'absolute', justifyContent: options.justifyContent, alignItems: options.alignItems }, (0, toPx_1.boundingBoxToPx)(box)),
18
+ }, [
19
+ yield (0, exports.prepareText)({
20
+ text,
21
+ options,
22
+ }),
23
+ ]);
24
+ });
25
+ exports.placeText = placeText;
26
+ const prepareText = (_a) => __awaiter(void 0, [_a], void 0, function* ({ text, options, }) {
27
+ let textChildren = [text];
28
+ for (const [word, image] of Object.entries(options.replacement)) {
29
+ const regex = new RegExp(word, 'gi');
30
+ const imageBase64 = yield image.getBase64('image/png');
31
+ let tmpChildren = [];
32
+ for (const textSegment of textChildren) {
33
+ if (typeof textSegment !== 'string') {
34
+ continue;
35
+ }
36
+ const parts = textSegment.split(regex);
37
+ for (let index = 0; index < parts.length; index++) {
38
+ if (index > 0) {
39
+ tmpChildren.push((0, virtual_dom_1.h)('img', {
40
+ style: {
41
+ display: 'inline',
42
+ verticalAlign: 'middle',
43
+ height: (0, toPx_1.toPx)(options.font.size),
44
+ width: 'auto',
45
+ },
46
+ src: imageBase64,
47
+ }, []));
48
+ }
49
+ tmpChildren.push(parts[index]);
50
+ }
51
+ }
52
+ textChildren = tmpChildren;
53
+ }
54
+ return (0, virtual_dom_1.h)('div', {
55
+ style: {
56
+ overflow: 'visible',
57
+ overflowWrap: 'word-wrap',
58
+ whiteSpace: 'normal',
59
+ color: options.color,
60
+ fontFamily: options.font.family,
61
+ fontSize: options.font.size,
62
+ fontStyle: options.font.italic ? 'italic' : undefined,
63
+ fontWeight: options.font.bold ? 'bold' : undefined,
64
+ '-webkit-text-stroke': `${options.border.width}px ${options.border.color}`,
65
+ },
66
+ }, textChildren);
67
+ });
68
+ exports.prepareText = prepareText;
69
+ //# sourceMappingURL=placeText.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"placeText.js","sourceRoot":"","sources":["../../../../src/lib/utils/placeText.ts"],"names":[],"mappings":"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"}
package/build/src/test.js CHANGED
@@ -17,7 +17,7 @@ const lib_1 = require("./lib");
17
17
  const result = yield lib_1.Template.new({
18
18
  defaultFontFamily: 'branela',
19
19
  defaultAssetsPath: 'assets',
20
- color: 0xC3C3C3FF,
20
+ color: 0xc3c3c3ff,
21
21
  })
22
22
  .text({ key: 'title' }, {
23
23
  left: 25,
@@ -47,9 +47,9 @@ const lib_1 = require("./lib");
47
47
  color: 'pink',
48
48
  border: {
49
49
  width: 2,
50
- color: 'purple'
50
+ color: 'purple',
51
51
  },
52
- skip: (entry) => entry.title.toLowerCase() === 'luigi'
52
+ skip: entry => entry.title.toLowerCase() === 'luigi',
53
53
  })
54
54
  .font('assets/branela.otf', 'branela')
55
55
  .image({ pathFn: entry => `${entry.title.toLowerCase()}.png` }, { left: 25, top: 225, width: 700, height: 700 }, {
@@ -69,7 +69,12 @@ const lib_1 = require("./lib");
69
69
  .replace(['Fireball'], fireball)
70
70
  .build(),
71
71
  })
72
- .hbox(() => Promise.resolve([luigi.clone(), luigi.clone()]), {
72
+ .hbox(() => __awaiter(void 0, void 0, void 0, function* () {
73
+ return [
74
+ { image: { buffer: yield luigi.clone().getBuffer('image/png') }, options: { scale: 'keep-ratio' } },
75
+ { image: { buffer: yield luigi.clone().getBuffer('image/png') }, options: { scale: 'keep-ratio' } },
76
+ ];
77
+ }), {
73
78
  left: 25,
74
79
  top: 25,
75
80
  width: 300,
@@ -77,7 +82,12 @@ const lib_1 = require("./lib");
77
82
  }, {
78
83
  gap: 100,
79
84
  })
80
- .vbox(() => Promise.resolve([luigi.clone(), luigi.clone()]), {
85
+ .vbox(() => __awaiter(void 0, void 0, void 0, function* () {
86
+ return [
87
+ { image: { buffer: yield luigi.clone().getBuffer('image/png') }, options: { scale: 'stretch' } },
88
+ { image: { buffer: yield luigi.clone().getBuffer('image/png') }, options: { scale: 'stretch' } },
89
+ ];
90
+ }), {
81
91
  left: 25,
82
92
  top: 325,
83
93
  width: 100,
@@ -86,11 +96,19 @@ const lib_1 = require("./lib");
86
96
  scale: 'stretch',
87
97
  gap: 50,
88
98
  })
89
- .grid(() => Promise.resolve([
90
- luigi.clone(), luigi.clone(), luigi.clone(),
91
- luigi.clone(), luigi.clone(), luigi.clone(),
92
- luigi.clone(), luigi.clone(), luigi.clone(),
93
- ]), {
99
+ .grid(() => __awaiter(void 0, void 0, void 0, function* () {
100
+ return [
101
+ { image: { buffer: yield luigi.clone().getBuffer('image/png') } },
102
+ { image: { buffer: yield luigi.clone().getBuffer('image/png') } },
103
+ { image: { buffer: yield luigi.clone().getBuffer('image/png') } },
104
+ { image: { buffer: yield luigi.clone().getBuffer('image/png') } },
105
+ { image: { buffer: yield luigi.clone().getBuffer('image/png') } },
106
+ { image: { buffer: yield luigi.clone().getBuffer('image/png') } },
107
+ { image: { buffer: yield luigi.clone().getBuffer('image/png') } },
108
+ { image: { buffer: yield luigi.clone().getBuffer('image/png') } },
109
+ { image: { buffer: yield luigi.clone().getBuffer('image/png') } },
110
+ ];
111
+ }), {
94
112
  left: 300,
95
113
  top: 325,
96
114
  width: 400,
@@ -1 +1 @@
1
- {"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/test.ts"],"names":[],"mappings":"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"}
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.6.2",
3
+ "version": "0.7.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",
@@ -20,6 +20,7 @@
20
20
  "lodash.camelcase": "^4.3.0",
21
21
  "lodash.chunk": "^4.2.0",
22
22
  "lodash.concat": "^4.5.0",
23
+ "lodash.flatten": "^4.4.0",
23
24
  "lodash.merge": "^4.6.2",
24
25
  "node-html-to-image": "^5.0.0",
25
26
  "papaparse": "^5.5.2",
@@ -30,6 +31,7 @@
30
31
  "@types/lodash.camelcase": "^4.3.9",
31
32
  "@types/lodash.chunk": "^4.2.9",
32
33
  "@types/lodash.concat": "^4.5.9",
34
+ "@types/lodash.flatten": "^4.4.9",
33
35
  "@types/lodash.merge": "^4.6.9",
34
36
  "@types/node": "^22.7.5",
35
37
  "@types/papaparse": "^5.3.15",
package/roadmap.md CHANGED
@@ -9,11 +9,12 @@
9
9
 
10
10
  ### Bugfixes
11
11
  - [x] Broken custom fonts
12
+ - [ ] keep-ration scale option seem broken
12
13
 
13
14
  ### Optimizations
14
15
  - [ ] Optional image registry that reduce repeating loading of same images
15
16
  - [ ] Stream processing support
16
- - [ ] Overlay the entire card in HTML and render to image only once
17
+ - [x] Overlay the entire card in HTML and render to image only once
17
18
 
18
19
 
19
20
  ### Quality of Life Improvements
@@ -3,15 +3,17 @@ import { parse as parseCsv } from 'papaparse';
3
3
  import { Jimp, rgbaToInt } from 'jimp';
4
4
  import camelCase from 'lodash.camelcase';
5
5
  import concat from 'lodash.concat';
6
- import { registerFont } from 'canvas';
7
6
  import path from 'path';
8
7
  import {
9
- drawBoundingBox,
8
+ placeBoundingBox,
10
9
  gridPackingFn,
11
10
  hboxPackingFn,
11
+ htmlToImage,
12
12
  placeImage,
13
- renderText,
13
+ placeText,
14
14
  vboxPackingFn,
15
+ prepareText,
16
+ prepareImage,
15
17
  } from './utils';
16
18
  import {
17
19
  DirectionContainerOptions,
@@ -31,9 +33,15 @@ import {
31
33
  LayerOptions,
32
34
  ContainerOptions,
33
35
  DEFAULT_CONTAINER_OPTIONS,
36
+ HyperNode,
37
+ ElementsFn,
38
+ ElementRef,
39
+ ImageLayerSpecificOptions,
34
40
  } from './types';
35
41
  import merge from 'lodash.merge';
36
42
  import { RequiredDeep } from 'type-fest';
43
+ import { h } from 'virtual-dom';
44
+ import flatten from 'lodash.flatten';
37
45
 
38
46
  type RequiredTemplateOptions = {
39
47
  height: number;
@@ -61,7 +69,7 @@ export type LayerFnContext = {
61
69
  export type LayerFn<EntryType> = (
62
70
  entry: EntryType,
63
71
  context: LayerFnContext,
64
- ) => Promise<ImageType | undefined>;
72
+ ) => Promise<Array<HyperNode>>;
65
73
 
66
74
  export type TemplateLayerFn<EntryType extends Record<string, string>> = (
67
75
  template: Template<EntryType>,
@@ -102,13 +110,6 @@ export class Template<EntryType extends Record<string, string>> {
102
110
  });
103
111
  }
104
112
 
105
- private shadowBackground(): ImageType {
106
- return new Jimp({
107
- width: this.background.width,
108
- height: this.background.height,
109
- });
110
- }
111
-
112
113
  private get backgroundSize(): Size {
113
114
  return {
114
115
  width: this.background.width,
@@ -122,13 +123,24 @@ export class Template<EntryType extends Record<string, string>> {
122
123
  }
123
124
 
124
125
  template = (fn: TemplateLayerFn<EntryType>): this =>
125
- this.layer(entry => {
126
+ this.layer(async entry => {
126
127
  const template = fn(this.shadowTemplate());
127
- return template.render(entry);
128
+ const image = await template.render(entry);
129
+ return [
130
+ await placeImage({
131
+ image,
132
+ box: {
133
+ left: 0,
134
+ top: 0,
135
+ ...this.backgroundSize,
136
+ },
137
+ options: DEFAULT_IMAGE_LAYER_OPTIONS,
138
+ }),
139
+ ];
128
140
  });
129
141
 
130
142
  container = (
131
- imagesFn: (entry: EntryType) => Promise<Array<ImageType>>,
143
+ elementsFn: ElementsFn,
132
144
  box: BoundingBox,
133
145
  packingFn: PackingFn,
134
146
  options?: ContainerOptions<EntryType>,
@@ -137,45 +149,39 @@ export class Template<EntryType extends Record<string, string>> {
137
149
  const mergedOptions: RequiredDeep<ContainerOptions<EntryType>> =
138
150
  merge({}, DEFAULT_CONTAINER_OPTIONS, options);
139
151
  if (this.shouldSkipLayerForEntry(entry, mergedOptions)) {
140
- return undefined;
152
+ return [];
141
153
  }
142
154
 
143
- const images = await imagesFn(entry);
144
- const result = await packingFn(
145
- box,
146
- this.shadowBackground(),
147
- images,
148
- );
155
+ const elementRefs = await elementsFn(entry);
156
+ const elements = await Promise.all(elementRefs.map(elementRef => this.elementFromElementRef(entry, elementRef)))
157
+ const result = await packingFn(box, elements);
149
158
 
150
159
  // debug mode
151
160
  if (debugMode) {
152
- const debugImage = await drawBoundingBox(
153
- box,
154
- this.backgroundSize,
155
- );
156
- return debugImage.composite(result);
161
+ const debugImage = await placeBoundingBox(box);
162
+ return [result, debugImage];
157
163
  }
158
164
 
159
- return result;
165
+ return [result];
160
166
  });
161
167
 
162
168
  hbox = (
163
- imagesFn: (entry: EntryType) => Promise<Array<ImageType>>,
169
+ elementsFn: ElementsFn,
164
170
  box: BoundingBox,
165
171
  options?: DirectionContainerOptions<EntryType>,
166
- ): this => this.container(imagesFn, box, hboxPackingFn(options), options);
172
+ ): this => this.container(elementsFn, box, hboxPackingFn(options), options);
167
173
 
168
174
  vbox = (
169
- imagesFn: (entry: EntryType) => Promise<Array<ImageType>>,
175
+ elementsFn: ElementsFn,
170
176
  box: BoundingBox,
171
177
  options?: DirectionContainerOptions<EntryType>,
172
- ): this => this.container(imagesFn, box, vboxPackingFn(options), options);
178
+ ): this => this.container(elementsFn, box, vboxPackingFn(options), options);
173
179
 
174
180
  grid = (
175
- imagesFn: (entry: EntryType) => Promise<Array<ImageType>>,
181
+ elementsFn: ElementsFn,
176
182
  box: BoundingBox,
177
183
  options?: GridContainerOptions<EntryType>,
178
- ): this => this.container(imagesFn, box, gridPackingFn(options), options);
184
+ ): this => this.container(elementsFn, box, gridPackingFn(options), options);
179
185
 
180
186
  image = (
181
187
  ref: ImageRef<EntryType>,
@@ -191,10 +197,10 @@ export class Template<EntryType extends Record<string, string>> {
191
197
  options,
192
198
  );
193
199
  if (this.shouldSkipLayerForEntry(entry, mergedOptions)) {
194
- return undefined;
200
+ return [];
195
201
  }
196
202
 
197
- const image = await this.pathFromImageRef(
203
+ const image = await this.imageFromImageRef(
198
204
  entry,
199
205
  ref,
200
206
  mergedOptions,
@@ -202,20 +208,16 @@ export class Template<EntryType extends Record<string, string>> {
202
208
  const result = await placeImage({
203
209
  image,
204
210
  box,
205
- backgroundSize: this.backgroundSize,
206
211
  options: mergedOptions,
207
212
  });
208
213
 
209
214
  // debug mode
210
215
  if (debugMode) {
211
- const debugImage = await drawBoundingBox(
212
- box,
213
- this.backgroundSize,
214
- );
215
- return debugImage.composite(result);
216
+ const debugImage = await placeBoundingBox(box);
217
+ return [result, debugImage];
216
218
  }
217
219
 
218
- return result;
220
+ return [result];
219
221
  });
220
222
 
221
223
  loadImage = async (imagePath: string | Buffer): Promise<ImageType> => {
@@ -240,28 +242,23 @@ export class Template<EntryType extends Record<string, string>> {
240
242
  options,
241
243
  );
242
244
  if (this.shouldSkipLayerForEntry(entry, mergedOptions)) {
243
- return undefined;
245
+ return [];
244
246
  }
245
247
 
246
248
  const text = this.textFromTextRef(entry, ref);
247
- const result = await renderText(
249
+ const result = await placeText({
248
250
  text,
249
251
  box,
250
- this.backgroundSize,
251
- mergedOptions,
252
- this.fonts,
253
- );
252
+ options: mergedOptions,
253
+ });
254
254
 
255
255
  // debug mode
256
256
  if (debugMode) {
257
- const debugImage = await drawBoundingBox(
258
- box,
259
- this.backgroundSize,
260
- );
261
- return debugImage.composite(result);
257
+ const debugImage = await placeBoundingBox(box);
258
+ return [result, debugImage];
262
259
  }
263
260
 
264
- return result;
261
+ return [result];
265
262
  });
266
263
 
267
264
  font(path: fs.PathLike, name: string): this {
@@ -275,7 +272,7 @@ export class Template<EntryType extends Record<string, string>> {
275
272
  return this;
276
273
  }
277
274
 
278
- private async renderLayers(entry: EntryType): Promise<Array<ImageType>> {
275
+ async render(entry: EntryType): Promise<ImageType> {
279
276
  const results = await Promise.all(
280
277
  this.layers.map(layerFn =>
281
278
  layerFn(entry, {
@@ -283,18 +280,28 @@ export class Template<EntryType extends Record<string, string>> {
283
280
  }),
284
281
  ),
285
282
  );
286
- return results.filter(result => !!result);
287
- }
288
-
289
- async render(
290
- entry: EntryType,
291
- options?: RenderOptions<EntryType>,
292
- ): Promise<ImageType> {
293
- const renderedLayers = await this.renderLayers(entry);
294
- return renderedLayers.reduce(
295
- (acc, layerRender) => acc.composite(layerRender),
296
- this.background.clone(),
297
- );
283
+ const document = h('html', [
284
+ h('head', [
285
+ h(
286
+ 'style',
287
+ Object.entries(this.fonts)
288
+ .map(
289
+ ([name, data]) =>
290
+ `@font-face {
291
+ font-family: '${name}';
292
+ src: url(data:font/ttf;base64,${data}) format('truetype');
293
+ }`,
294
+ )
295
+ .join('\n'),
296
+ ),
297
+ ]),
298
+ h(
299
+ 'body',
300
+ flatten(results),
301
+ ),
302
+ ]);
303
+ const renderedLayers = await htmlToImage(document, this.backgroundSize);
304
+ return this.background.clone().composite(renderedLayers);
298
305
  }
299
306
 
300
307
  async renderAll(
@@ -305,7 +312,7 @@ export class Template<EntryType extends Record<string, string>> {
305
312
  entries.map(
306
313
  entry =>
307
314
  new Promise<Array<ImageType>>(resolve =>
308
- this.render(entry, options).then(image => {
315
+ this.render(entry).then(image => {
309
316
  if (!options?.duplication) {
310
317
  return resolve([image]);
311
318
  }
@@ -353,10 +360,10 @@ export class Template<EntryType extends Record<string, string>> {
353
360
  });
354
361
  }
355
362
 
356
- private pathFromImageRef = async (
363
+ private imageFromImageRef = async (
357
364
  entry: EntryType,
358
365
  ref: ImageRef<EntryType>,
359
- options: RequiredDeep<ImageLayerOptions<EntryType>>,
366
+ options: RequiredDeep<ImageLayerSpecificOptions<EntryType>>,
360
367
  ): Promise<ImageType> => {
361
368
  const pathSegments = [];
362
369
  if (options.assetsPath) {
@@ -395,6 +402,29 @@ export class Template<EntryType extends Record<string, string>> {
395
402
  }
396
403
  };
397
404
 
405
+ private elementFromElementRef = async (
406
+ entry: EntryType,
407
+ ref: ElementRef<EntryType>,
408
+ ): Promise<HyperNode> => {
409
+ if ('text' in ref) {
410
+ const options = merge({}, DEFAULT_TEXT_LAYER_OPTIONS, ref.options);
411
+ return prepareText({
412
+ text: this.textFromTextRef(entry, ref.text),
413
+ options,
414
+ });
415
+ } else if ('image' in ref) {
416
+ const options = merge({}, DEFAULT_IMAGE_LAYER_OPTIONS, ref.options);
417
+ return prepareImage({
418
+ image: await this.imageFromImageRef(entry, ref.image, options),
419
+ options,
420
+ });
421
+ } else if ('node' in ref) {
422
+ return ref.node
423
+ } else {
424
+ throw new Error('Unknown TextRef variant');
425
+ }
426
+ };
427
+
398
428
  private shouldSkipLayerForEntry = (
399
429
  entry: EntryType,
400
430
  options: LayerOptions<EntryType>,
@@ -1,8 +1,10 @@
1
1
  import { RequiredDeep } from 'type-fest';
2
2
  import { BoundingBox } from './boundingBox';
3
- import { ImageType } from './image';
3
+ import { ImageLayerSpecificOptions, ImageRef, ImageType } from './image';
4
4
  import { ScaleMode } from './scale';
5
5
  import { LayerOptions } from './layer';
6
+ import { HyperNode } from './hypernode';
7
+ import { TextLayerSpecificOptions, TextRef } from './text';
6
8
 
7
9
  export type ContainerOptions<EntryType extends Record<string, string>> =
8
10
  LayerOptions<EntryType> & {
@@ -65,8 +67,24 @@ export const DEFAULT_GRID_CONTAINER_OPTIONS: RequiredDeep<
65
67
  direction: 'rows',
66
68
  };
67
69
 
70
+ export type ElementRef<EntryType extends Record<string, string>> =
71
+ | {
72
+ image: ImageRef<EntryType>;
73
+ options?: ImageLayerSpecificOptions<EntryType>;
74
+ }
75
+ | {
76
+ text: TextRef<EntryType>;
77
+ options?: TextLayerSpecificOptions<EntryType>;
78
+ }
79
+ | {
80
+ node: HyperNode;
81
+ };
82
+
83
+ export type ElementsFn = <EntryType extends Record<string, string>>(
84
+ entry: EntryType,
85
+ ) => Promise<Array<ElementRef<EntryType>>>;
86
+
68
87
  export type PackingFn = (
69
88
  box: BoundingBox,
70
- background: ImageType,
71
- images: Array<ImageType>,
72
- ) => Promise<ImageType>;
89
+ elements: Array<HyperNode>,
90
+ ) => Promise<HyperNode>;
@@ -0,0 +1,4 @@
1
+ import { VNode } from "virtual-dom";
2
+
3
+ export type HyperNode = VNode;
4
+