@hellkite/pipkin 0.5.1 → 0.6.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.
- package/build/src/lib/template.d.ts +11 -8
- package/build/src/lib/template.js +54 -22
- package/build/src/lib/template.js.map +1 -1
- package/build/src/lib/types/containers.d.ts +11 -22
- package/build/src/lib/types/containers.js +3 -1
- package/build/src/lib/types/containers.js.map +1 -1
- package/build/src/lib/types/image.d.ts +5 -12
- package/build/src/lib/types/image.js +2 -0
- package/build/src/lib/types/image.js.map +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 +15 -0
- package/build/src/lib/types/layer.js +3 -0
- package/build/src/lib/types/layer.js.map +1 -0
- package/build/src/lib/types/text.d.ts +23 -27
- package/build/src/lib/types/text.js +13 -4
- package/build/src/lib/types/text.js.map +1 -1
- package/build/src/lib/utils/buildFontString.d.ts +2 -2
- package/build/src/lib/utils/buildFontString.js.map +1 -1
- package/build/src/lib/utils/container.d.ts +4 -3
- package/build/src/lib/utils/container.js +41 -4
- package/build/src/lib/utils/container.js.map +1 -1
- package/build/src/lib/utils/drawBoundingBox.js.map +1 -1
- package/build/src/lib/utils/htmlToImage.js +1 -1
- package/build/src/lib/utils/htmlToImage.js.map +1 -1
- package/build/src/lib/utils/placeImage.d.ts +4 -3
- package/build/src/lib/utils/placeImage.js +22 -28
- package/build/src/lib/utils/placeImage.js.map +1 -1
- package/build/src/lib/utils/renderText.d.ts +2 -1
- package/build/src/lib/utils/renderText.js +21 -12
- package/build/src/lib/utils/renderText.js.map +1 -1
- package/build/src/test.js +14 -5
- package/build/src/test.js.map +1 -1
- package/package.json +4 -1
- package/roadmap.md +6 -4
- package/src/lib/template.ts +137 -32
- package/src/lib/types/containers.ts +52 -46
- package/src/lib/types/image.ts +21 -29
- package/src/lib/types/index.ts +1 -0
- package/src/lib/types/layer.ts +18 -0
- package/src/lib/types/text.ts +44 -49
- package/src/lib/utils/buildFontString.ts +2 -2
- package/src/lib/utils/container.ts +102 -9
- package/src/lib/utils/drawBoundingBox.ts +12 -9
- package/src/lib/utils/htmlToImage.ts +1 -1
- package/src/lib/utils/placeImage.ts +8 -10
- package/src/lib/utils/renderText.ts +33 -21
|
@@ -18,7 +18,6 @@ const node_html_to_image_1 = __importDefault(require("node-html-to-image"));
|
|
|
18
18
|
const jimp_1 = require("jimp");
|
|
19
19
|
const htmlToImage = (document, backgroundSize) => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
20
|
const html = (0, virtual_dom_1.create)(document).toString();
|
|
21
|
-
// TODO: extract this in a dif function
|
|
22
21
|
const image = yield (0, node_html_to_image_1.default)({
|
|
23
22
|
html,
|
|
24
23
|
transparent: true,
|
|
@@ -27,6 +26,7 @@ const htmlToImage = (document, backgroundSize) => __awaiter(void 0, void 0, void
|
|
|
27
26
|
defaultViewport: {
|
|
28
27
|
width: backgroundSize.width,
|
|
29
28
|
height: backgroundSize.height,
|
|
29
|
+
deviceScaleFactor: 1,
|
|
30
30
|
},
|
|
31
31
|
},
|
|
32
32
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"htmlToImage.js","sourceRoot":"","sources":["../../../../src/lib/utils/htmlToImage.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,6CAA6D;AAC7D,4EAAiD;AACjD,+BAA4B;AAGrB,MAAM,WAAW,GAAG,CACvB,QAAe,EACf,cAAoB,EACF,EAAE;IACpB,MAAM,IAAI,GAAG,IAAA,oBAAa,EAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;IAChD,
|
|
1
|
+
{"version":3,"file":"htmlToImage.js","sourceRoot":"","sources":["../../../../src/lib/utils/htmlToImage.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,6CAA6D;AAC7D,4EAAiD;AACjD,+BAA4B;AAGrB,MAAM,WAAW,GAAG,CACvB,QAAe,EACf,cAAoB,EACF,EAAE;IACpB,MAAM,IAAI,GAAG,IAAA,oBAAa,EAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;IAChD,MAAM,KAAK,GAAG,MAAM,IAAA,4BAAe,EAAC;QAChC,IAAI;QACJ,WAAW,EAAE,IAAI;QACjB,IAAI,EAAE,KAAK;QACX,aAAa,EAAE;YACX,eAAe,EAAE;gBACb,KAAK,EAAE,cAAc,CAAC,KAAK;gBAC3B,MAAM,EAAE,cAAc,CAAC,MAAM;gBAC7B,iBAAiB,EAAE,CAAC;aACvB;SACJ;KACJ,CAAC,CAAC;IACH,OAAO,WAAI,CAAC,IAAI,CAAC,KAAe,CAAuB,CAAC;AAC5D,CAAC,CAAA,CAAC;AAlBW,QAAA,WAAW,eAkBtB"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { ImageLayerOptions, ImageType, BoundingBox } from '../types';
|
|
2
|
-
|
|
2
|
+
import { RequiredDeep } from 'type-fest';
|
|
3
|
+
type PlaceImageProps<EntryType extends Record<string, string>> = {
|
|
3
4
|
image: ImageType;
|
|
4
5
|
box: BoundingBox;
|
|
5
6
|
backgroundSize: {
|
|
6
7
|
width: number;
|
|
7
8
|
height: number;
|
|
8
9
|
};
|
|
9
|
-
options: ImageLayerOptions
|
|
10
|
+
options: RequiredDeep<ImageLayerOptions<EntryType>>;
|
|
10
11
|
};
|
|
11
|
-
export declare
|
|
12
|
+
export declare const placeImage: <EntryType extends Record<string, string>>({ image, box, backgroundSize, options, }: PlaceImageProps<EntryType>) => Promise<ImageType>;
|
|
12
13
|
export {};
|
|
@@ -8,37 +8,31 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.placeImage =
|
|
12
|
+
exports.placeImage = void 0;
|
|
16
13
|
const virtual_dom_1 = require("virtual-dom");
|
|
17
14
|
const toPx_1 = require("./toPx");
|
|
18
15
|
const types_1 = require("../types");
|
|
19
|
-
const lodash_merge_1 = __importDefault(require("lodash.merge"));
|
|
20
16
|
const htmlToImage_1 = require("./htmlToImage");
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
});
|
|
43
|
-
}
|
|
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', {
|
|
21
|
+
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);
|
|
36
|
+
});
|
|
37
|
+
exports.placeImage = placeImage;
|
|
44
38
|
//# sourceMappingURL=placeImage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"placeImage.js","sourceRoot":"","sources":["../../../../src/lib/utils/placeImage.ts"],"names":[],"mappings":"
|
|
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,2 +1,3 @@
|
|
|
1
1
|
import { ImageType, BoundingBox, Size, TextLayerOptions } from '../types';
|
|
2
|
-
|
|
2
|
+
import { RequiredDeep } from 'type-fest';
|
|
3
|
+
export declare const renderText: <EntryType extends Record<string, string>>(text: string, box: BoundingBox, backgroundSize: Size, options: RequiredDeep<TextLayerOptions<EntryType>>, fonts: Record<string, string>) => Promise<ImageType>;
|
|
@@ -11,13 +11,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.renderText = void 0;
|
|
13
13
|
const virtual_dom_1 = require("virtual-dom");
|
|
14
|
-
const types_1 = require("../types");
|
|
15
14
|
const toPx_1 = require("./toPx");
|
|
16
15
|
const htmlToImage_1 = require("./htmlToImage");
|
|
17
|
-
const renderText = (text, box, backgroundSize, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
18
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
16
|
+
const renderText = (text, box, backgroundSize, options, fonts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
19
17
|
let textChildren = [text];
|
|
20
|
-
for (const [word, image] of Object.entries(
|
|
18
|
+
for (const [word, image] of Object.entries(options.replacement)) {
|
|
21
19
|
const regex = new RegExp(word, 'gi');
|
|
22
20
|
const imageBase64 = yield image.getBase64('image/png');
|
|
23
21
|
let tmpChildren = [];
|
|
@@ -32,7 +30,7 @@ const renderText = (text, box, backgroundSize, options) => __awaiter(void 0, voi
|
|
|
32
30
|
style: {
|
|
33
31
|
display: 'inline',
|
|
34
32
|
verticalAlign: 'middle',
|
|
35
|
-
height: (0, toPx_1.toPx)(
|
|
33
|
+
height: (0, toPx_1.toPx)(options.font.size),
|
|
36
34
|
width: 'auto',
|
|
37
35
|
},
|
|
38
36
|
src: imageBase64,
|
|
@@ -43,22 +41,33 @@ const renderText = (text, box, backgroundSize, options) => __awaiter(void 0, voi
|
|
|
43
41
|
}
|
|
44
42
|
textChildren = tmpChildren;
|
|
45
43
|
}
|
|
46
|
-
const
|
|
47
|
-
style: Object.assign({ display: 'flex', overflow: 'visible', position: 'absolute', justifyContent:
|
|
44
|
+
const content = (0, virtual_dom_1.h)('div', {
|
|
45
|
+
style: Object.assign({ display: 'flex', overflow: 'visible', position: 'absolute', justifyContent: options.justifyContent, alignItems: options.alignItems }, (0, toPx_1.boundingBoxToPx)(box)),
|
|
48
46
|
}, [
|
|
49
47
|
(0, virtual_dom_1.h)('div', {
|
|
50
48
|
style: {
|
|
51
49
|
overflow: 'visible',
|
|
52
50
|
overflowWrap: 'word-wrap',
|
|
53
51
|
whiteSpace: 'normal',
|
|
54
|
-
color: options
|
|
55
|
-
fontFamily:
|
|
56
|
-
fontSize:
|
|
57
|
-
fontStyle:
|
|
58
|
-
fontWeight:
|
|
52
|
+
color: options.color,
|
|
53
|
+
fontFamily: options.font.family,
|
|
54
|
+
fontSize: options.font.size,
|
|
55
|
+
fontStyle: options.font.italic ? 'italic' : undefined,
|
|
56
|
+
fontWeight: options.font.bold ? 'bold' : undefined,
|
|
59
57
|
},
|
|
60
58
|
}, textChildren),
|
|
61
59
|
]);
|
|
60
|
+
const document = (0, virtual_dom_1.h)('html', [
|
|
61
|
+
(0, virtual_dom_1.h)('head', [
|
|
62
|
+
(0, virtual_dom_1.h)('style', Object.entries(fonts)
|
|
63
|
+
.map(([name, data]) => `@font-face {
|
|
64
|
+
font-family: '${name}';
|
|
65
|
+
src: url(data:font/ttf;base64,${data}) format('truetype');
|
|
66
|
+
}`)
|
|
67
|
+
.join('\n')),
|
|
68
|
+
]),
|
|
69
|
+
(0, virtual_dom_1.h)('body', [content]),
|
|
70
|
+
]);
|
|
62
71
|
return (0, htmlToImage_1.htmlToImage)(document, backgroundSize);
|
|
63
72
|
});
|
|
64
73
|
exports.renderText = renderText;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderText.js","sourceRoot":"","sources":["../../../../src/lib/utils/renderText.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6CAAuC;
|
|
1
|
+
{"version":3,"file":"renderText.js","sourceRoot":"","sources":["../../../../src/lib/utils/renderText.ts"],"names":[],"mappings":"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"}
|
package/build/src/test.js
CHANGED
|
@@ -17,8 +17,9 @@ 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
21
|
})
|
|
21
|
-
.text({ key: '
|
|
22
|
+
.text({ key: 'title' }, {
|
|
22
23
|
left: 25,
|
|
23
24
|
top: 25,
|
|
24
25
|
width: 700,
|
|
@@ -40,6 +41,7 @@ const lib_1 = require("./lib");
|
|
|
40
41
|
size: 38,
|
|
41
42
|
},
|
|
42
43
|
color: 'purple',
|
|
44
|
+
skip: (entry) => entry.title.toLowerCase() === 'luigi'
|
|
43
45
|
})
|
|
44
46
|
.font('assets/branela.otf', 'branela')
|
|
45
47
|
.image({ pathFn: entry => `${entry.title.toLowerCase()}.png` }, { left: 25, top: 225, width: 700, height: 700 }, {
|
|
@@ -76,14 +78,21 @@ const lib_1 = require("./lib");
|
|
|
76
78
|
scale: 'stretch',
|
|
77
79
|
gap: 50,
|
|
78
80
|
})
|
|
79
|
-
.
|
|
81
|
+
.grid(() => Promise.resolve([
|
|
82
|
+
luigi.clone(), luigi.clone(), luigi.clone(),
|
|
83
|
+
luigi.clone(), luigi.clone(), luigi.clone(),
|
|
84
|
+
luigi.clone(), luigi.clone(), luigi.clone(),
|
|
85
|
+
]), {
|
|
80
86
|
left: 300,
|
|
81
87
|
top: 325,
|
|
82
|
-
width:
|
|
88
|
+
width: 400,
|
|
83
89
|
height: 600,
|
|
84
90
|
}, {
|
|
85
|
-
scale: '
|
|
86
|
-
gap:
|
|
91
|
+
scale: 'stretch',
|
|
92
|
+
gap: 10,
|
|
93
|
+
alignItems: 'flex-start',
|
|
94
|
+
justifyContent: 'flex-start',
|
|
95
|
+
skip: true,
|
|
87
96
|
})
|
|
88
97
|
.debug()
|
|
89
98
|
.fromCsv('assets/data.csv', {
|
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,+BAAkE;AASlE,CAAC,GAAS,EAAE;IACR,MAAM,QAAQ,GAAG,CAAC,MAAM,WAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAc,CAAC;IACvE,MAAM,KAAK,GAAG,CAAC,MAAM,WAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAc,CAAC;IACjE,MAAM,MAAM,GAAG,MAAM,cAAQ,CAAC,GAAG,CAAe;QAC5C,iBAAiB,EAAE,SAAS;QAC5B,iBAAiB,EAAE,QAAQ;
|
|
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.6.1",
|
|
4
4
|
"description": "Library for board game card generation",
|
|
5
5
|
"main": "build/src/index.js",
|
|
6
6
|
"types": "build/src/index.d.ts",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"canvas": "^3.1.0",
|
|
19
19
|
"jimp": "^1.6.0",
|
|
20
20
|
"lodash.camelcase": "^4.3.0",
|
|
21
|
+
"lodash.chunk": "^4.2.0",
|
|
21
22
|
"lodash.concat": "^4.5.0",
|
|
22
23
|
"lodash.merge": "^4.6.2",
|
|
23
24
|
"node-html-to-image": "^5.0.0",
|
|
@@ -27,12 +28,14 @@
|
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
30
|
"@types/lodash.camelcase": "^4.3.9",
|
|
31
|
+
"@types/lodash.chunk": "^4.2.9",
|
|
30
32
|
"@types/lodash.concat": "^4.5.9",
|
|
31
33
|
"@types/lodash.merge": "^4.6.9",
|
|
32
34
|
"@types/node": "^22.7.5",
|
|
33
35
|
"@types/papaparse": "^5.3.15",
|
|
34
36
|
"@types/virtual-dom": "^2.1.4",
|
|
35
37
|
"gts": "^6.0.2",
|
|
38
|
+
"type-fest": "^4.40.0",
|
|
36
39
|
"typescript": "^5.6.3"
|
|
37
40
|
}
|
|
38
41
|
}
|
package/roadmap.md
CHANGED
|
@@ -2,19 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
### Features
|
|
5
|
-
- [ ] Containers (row, column, grid)
|
|
6
|
-
- [ ] Replace text rendering solution with `html2canvas`
|
|
7
5
|
- [ ] Storage adaptors for fs, web, browser, s3, etc
|
|
8
6
|
- [ ] Draw geometry
|
|
9
|
-
- [ ] Noise overlays
|
|
7
|
+
- [ ] Noise/texture overlays
|
|
8
|
+
- [ ] Text border
|
|
10
9
|
|
|
10
|
+
### Bugfixes
|
|
11
|
+
- [x] Broken custom fonts
|
|
11
12
|
|
|
12
13
|
### Optimizations
|
|
13
14
|
- [ ] Optional image registry that reduce repeating loading of same images
|
|
14
15
|
- [ ] Stream processing support
|
|
16
|
+
- [ ] Overlay the entire card in HTML and render to image only once
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
### Quality of Life Improvements
|
|
18
20
|
- [ ] Expose logging, warnings, stats and progress status data
|
|
19
21
|
- [ ] Runtime resource configuration
|
|
20
|
-
|
|
22
|
+
- [ ] Debugging layer
|
package/src/lib/template.ts
CHANGED
|
@@ -5,8 +5,35 @@ import camelCase from 'lodash.camelcase';
|
|
|
5
5
|
import concat from 'lodash.concat';
|
|
6
6
|
import { registerFont } from 'canvas';
|
|
7
7
|
import path from 'path';
|
|
8
|
-
import {
|
|
9
|
-
|
|
8
|
+
import {
|
|
9
|
+
drawBoundingBox,
|
|
10
|
+
gridPackingFn,
|
|
11
|
+
hboxPackingFn,
|
|
12
|
+
placeImage,
|
|
13
|
+
renderText,
|
|
14
|
+
vboxPackingFn,
|
|
15
|
+
} from './utils';
|
|
16
|
+
import {
|
|
17
|
+
DirectionContainerOptions,
|
|
18
|
+
ImageLayerOptions,
|
|
19
|
+
ImageRef,
|
|
20
|
+
ImageType,
|
|
21
|
+
PackingFn,
|
|
22
|
+
BoundingBox,
|
|
23
|
+
RenderOptions,
|
|
24
|
+
Size,
|
|
25
|
+
TextLayerOptions,
|
|
26
|
+
TextRef,
|
|
27
|
+
GridContainerOptions,
|
|
28
|
+
DEFAULT_TEXT_LAYER_OPTIONS,
|
|
29
|
+
FontOptions,
|
|
30
|
+
DEFAULT_IMAGE_LAYER_OPTIONS,
|
|
31
|
+
LayerOptions,
|
|
32
|
+
ContainerOptions,
|
|
33
|
+
DEFAULT_CONTAINER_OPTIONS,
|
|
34
|
+
} from './types';
|
|
35
|
+
import merge from 'lodash.merge';
|
|
36
|
+
import { RequiredDeep } from 'type-fest';
|
|
10
37
|
|
|
11
38
|
type RequiredTemplateOptions = {
|
|
12
39
|
height: number;
|
|
@@ -34,13 +61,14 @@ export type LayerFnContext = {
|
|
|
34
61
|
export type LayerFn<EntryType> = (
|
|
35
62
|
entry: EntryType,
|
|
36
63
|
context: LayerFnContext,
|
|
37
|
-
) => Promise<ImageType>;
|
|
64
|
+
) => Promise<ImageType | undefined>;
|
|
38
65
|
|
|
39
66
|
export type TemplateLayerFn<EntryType extends Record<string, string>> = (
|
|
40
67
|
template: Template<EntryType>,
|
|
41
68
|
) => Template<EntryType>;
|
|
42
69
|
|
|
43
70
|
export class Template<EntryType extends Record<string, string>> {
|
|
71
|
+
private readonly fonts: Record<string, string> = {};
|
|
44
72
|
private readonly layers: LayerFn<EntryType>[] = [];
|
|
45
73
|
private readonly background: ImageType;
|
|
46
74
|
private debugMode: boolean = false;
|
|
@@ -99,40 +127,83 @@ export class Template<EntryType extends Record<string, string>> {
|
|
|
99
127
|
return template.render(entry);
|
|
100
128
|
});
|
|
101
129
|
|
|
102
|
-
// TODO: logic for rendering debug helpers
|
|
103
130
|
container = (
|
|
104
131
|
imagesFn: (entry: EntryType) => Promise<Array<ImageType>>,
|
|
132
|
+
box: BoundingBox,
|
|
105
133
|
packingFn: PackingFn,
|
|
134
|
+
options?: ContainerOptions<EntryType>,
|
|
106
135
|
): this =>
|
|
107
|
-
this.layer(async (entry: EntryType) => {
|
|
136
|
+
this.layer(async (entry: EntryType, { debugMode }) => {
|
|
137
|
+
const mergedOptions: RequiredDeep<ContainerOptions<EntryType>> =
|
|
138
|
+
merge({}, DEFAULT_CONTAINER_OPTIONS, options);
|
|
139
|
+
if (this.shouldSkipLayerForEntry(entry, mergedOptions)) {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
108
143
|
const images = await imagesFn(entry);
|
|
109
|
-
|
|
144
|
+
const result = await packingFn(
|
|
145
|
+
box,
|
|
146
|
+
this.shadowBackground(),
|
|
147
|
+
images,
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
// debug mode
|
|
151
|
+
if (debugMode) {
|
|
152
|
+
const debugImage = await drawBoundingBox(
|
|
153
|
+
box,
|
|
154
|
+
this.backgroundSize,
|
|
155
|
+
);
|
|
156
|
+
return debugImage.composite(result);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return result;
|
|
110
160
|
});
|
|
111
161
|
|
|
112
162
|
hbox = (
|
|
113
163
|
imagesFn: (entry: EntryType) => Promise<Array<ImageType>>,
|
|
114
164
|
box: BoundingBox,
|
|
115
|
-
options?: DirectionContainerOptions
|
|
116
|
-
): this => this.container(imagesFn, hboxPackingFn(
|
|
165
|
+
options?: DirectionContainerOptions<EntryType>,
|
|
166
|
+
): this => this.container(imagesFn, box, hboxPackingFn(options), options);
|
|
117
167
|
|
|
118
168
|
vbox = (
|
|
119
169
|
imagesFn: (entry: EntryType) => Promise<Array<ImageType>>,
|
|
120
170
|
box: BoundingBox,
|
|
121
|
-
options?: DirectionContainerOptions
|
|
122
|
-
): this => this.container(imagesFn, vboxPackingFn(
|
|
171
|
+
options?: DirectionContainerOptions<EntryType>,
|
|
172
|
+
): this => this.container(imagesFn, box, vboxPackingFn(options), options);
|
|
173
|
+
|
|
174
|
+
grid = (
|
|
175
|
+
imagesFn: (entry: EntryType) => Promise<Array<ImageType>>,
|
|
176
|
+
box: BoundingBox,
|
|
177
|
+
options?: GridContainerOptions<EntryType>,
|
|
178
|
+
): this => this.container(imagesFn, box, gridPackingFn(options), options);
|
|
123
179
|
|
|
124
180
|
image = (
|
|
125
181
|
ref: ImageRef<EntryType>,
|
|
126
182
|
box: BoundingBox,
|
|
127
|
-
options: ImageLayerOptions
|
|
183
|
+
options: ImageLayerOptions<EntryType>,
|
|
128
184
|
): this =>
|
|
129
185
|
this.layer(async (entry, { debugMode }) => {
|
|
130
|
-
const
|
|
186
|
+
const mergedOptions: RequiredDeep<ImageLayerOptions<EntryType>> =
|
|
187
|
+
merge(
|
|
188
|
+
{},
|
|
189
|
+
DEFAULT_IMAGE_LAYER_OPTIONS,
|
|
190
|
+
{ assetsPath: this.defaultAssetsPath },
|
|
191
|
+
options,
|
|
192
|
+
);
|
|
193
|
+
if (this.shouldSkipLayerForEntry(entry, mergedOptions)) {
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const image = await this.pathFromImageRef(
|
|
198
|
+
entry,
|
|
199
|
+
ref,
|
|
200
|
+
mergedOptions,
|
|
201
|
+
);
|
|
131
202
|
const result = await placeImage({
|
|
132
203
|
image,
|
|
133
204
|
box,
|
|
134
205
|
backgroundSize: this.backgroundSize,
|
|
135
|
-
options,
|
|
206
|
+
options: mergedOptions,
|
|
136
207
|
});
|
|
137
208
|
|
|
138
209
|
// debug mode
|
|
@@ -146,6 +217,7 @@ export class Template<EntryType extends Record<string, string>> {
|
|
|
146
217
|
|
|
147
218
|
return result;
|
|
148
219
|
});
|
|
220
|
+
|
|
149
221
|
loadImage = async (imagePath: string | Buffer): Promise<ImageType> => {
|
|
150
222
|
const image = (await Jimp.read(imagePath)) as unknown as ImageType;
|
|
151
223
|
return image;
|
|
@@ -154,22 +226,47 @@ export class Template<EntryType extends Record<string, string>> {
|
|
|
154
226
|
text = (
|
|
155
227
|
ref: TextRef<EntryType>,
|
|
156
228
|
box: BoundingBox,
|
|
157
|
-
options?: TextLayerOptions
|
|
229
|
+
options?: TextLayerOptions<EntryType>,
|
|
158
230
|
): this =>
|
|
159
231
|
this.layer(async (entry, { debugMode }) => {
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
232
|
+
const mergedOptions = merge(
|
|
233
|
+
{},
|
|
234
|
+
DEFAULT_TEXT_LAYER_OPTIONS,
|
|
235
|
+
{
|
|
236
|
+
font: {
|
|
237
|
+
family: this.defaultFontFamily,
|
|
238
|
+
},
|
|
239
|
+
} as FontOptions,
|
|
240
|
+
options,
|
|
241
|
+
);
|
|
242
|
+
if (this.shouldSkipLayerForEntry(entry, mergedOptions)) {
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const text = this.textFromTextRef(entry, ref);
|
|
247
|
+
const result = await renderText(
|
|
248
|
+
text,
|
|
249
|
+
box,
|
|
250
|
+
this.backgroundSize,
|
|
251
|
+
mergedOptions,
|
|
252
|
+
this.fonts,
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
// debug mode
|
|
256
|
+
if (debugMode) {
|
|
257
|
+
const debugImage = await drawBoundingBox(
|
|
258
|
+
box,
|
|
259
|
+
this.backgroundSize,
|
|
260
|
+
);
|
|
261
|
+
return debugImage.composite(result);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return result;
|
|
167
265
|
});
|
|
168
266
|
|
|
169
267
|
font(path: fs.PathLike, name: string): this {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
});
|
|
268
|
+
// TODO: pass font weight and font style as well
|
|
269
|
+
this.fonts[name] = fs.readFileSync(path.toString()).toString('base64');
|
|
173
270
|
return this;
|
|
174
271
|
}
|
|
175
272
|
|
|
@@ -179,13 +276,14 @@ export class Template<EntryType extends Record<string, string>> {
|
|
|
179
276
|
}
|
|
180
277
|
|
|
181
278
|
private async renderLayers(entry: EntryType): Promise<Array<ImageType>> {
|
|
182
|
-
|
|
279
|
+
const results = await Promise.all(
|
|
183
280
|
this.layers.map(layerFn =>
|
|
184
281
|
layerFn(entry, {
|
|
185
282
|
debugMode: this.debugMode,
|
|
186
283
|
}),
|
|
187
284
|
),
|
|
188
285
|
);
|
|
286
|
+
return results.filter(result => !!result);
|
|
189
287
|
}
|
|
190
288
|
|
|
191
289
|
async render(
|
|
@@ -258,12 +356,11 @@ export class Template<EntryType extends Record<string, string>> {
|
|
|
258
356
|
private pathFromImageRef = async (
|
|
259
357
|
entry: EntryType,
|
|
260
358
|
ref: ImageRef<EntryType>,
|
|
261
|
-
options: ImageLayerOptions
|
|
359
|
+
options: RequiredDeep<ImageLayerOptions<EntryType>>,
|
|
262
360
|
): Promise<ImageType> => {
|
|
263
|
-
const assetsPath = options?.assetsPath ?? this.defaultAssetsPath;
|
|
264
361
|
const pathSegments = [];
|
|
265
|
-
if (assetsPath) {
|
|
266
|
-
pathSegments.push(assetsPath);
|
|
362
|
+
if (options.assetsPath) {
|
|
363
|
+
pathSegments.push(options.assetsPath);
|
|
267
364
|
}
|
|
268
365
|
|
|
269
366
|
if ('buffer' in ref) {
|
|
@@ -283,7 +380,7 @@ export class Template<EntryType extends Record<string, string>> {
|
|
|
283
380
|
}
|
|
284
381
|
};
|
|
285
382
|
|
|
286
|
-
private
|
|
383
|
+
private textFromTextRef = (
|
|
287
384
|
entry: EntryType,
|
|
288
385
|
ref: TextRef<EntryType>,
|
|
289
386
|
): string => {
|
|
@@ -297,6 +394,14 @@ export class Template<EntryType extends Record<string, string>> {
|
|
|
297
394
|
throw new Error('Unknown TextRef variant');
|
|
298
395
|
}
|
|
299
396
|
};
|
|
300
|
-
}
|
|
301
397
|
|
|
302
|
-
|
|
398
|
+
private shouldSkipLayerForEntry = (
|
|
399
|
+
entry: EntryType,
|
|
400
|
+
options: LayerOptions<EntryType>,
|
|
401
|
+
): boolean => {
|
|
402
|
+
if (typeof options.skip === 'function') {
|
|
403
|
+
return options.skip(entry);
|
|
404
|
+
}
|
|
405
|
+
return options.skip ?? false;
|
|
406
|
+
};
|
|
407
|
+
}
|