@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
|
@@ -1,66 +1,72 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RequiredDeep } from 'type-fest';
|
|
2
|
+
import { BoundingBox } from './boundingBox';
|
|
2
3
|
import { ImageType } from './image';
|
|
3
4
|
import { ScaleMode } from './scale';
|
|
5
|
+
import { LayerOptions } from './layer';
|
|
4
6
|
|
|
5
|
-
export type ContainerOptions =
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
export type ContainerOptions<EntryType extends Record<string, string>> =
|
|
8
|
+
LayerOptions<EntryType> & {
|
|
9
|
+
/**
|
|
10
|
+
* This is treated as a minimum length of an unit of space
|
|
11
|
+
* between two items, but it can grow larger than it
|
|
12
|
+
*
|
|
13
|
+
* Defaults to 0
|
|
14
|
+
*/
|
|
15
|
+
gap?: number;
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
*/
|
|
19
|
-
gap?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Defaults to `none`
|
|
19
|
+
*/
|
|
20
|
+
scale?: ScaleMode;
|
|
21
|
+
};
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
*
|
|
25
|
-
* Defaults to `center`
|
|
26
|
-
*/
|
|
27
|
-
alignItems?: AlignItems;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Defaults to `none`
|
|
31
|
-
*/
|
|
32
|
-
scale?: ScaleMode;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export const DEFAULT_CONTAINER_OPTIONS: Required<ContainerOptions> = {
|
|
23
|
+
export const DEFAULT_CONTAINER_OPTIONS: RequiredDeep<
|
|
24
|
+
ContainerOptions<Record<string, string>>
|
|
25
|
+
> = {
|
|
36
26
|
gap: 0,
|
|
37
27
|
justifyContent: 'normal',
|
|
38
28
|
alignItems: 'center',
|
|
39
29
|
scale: 'none',
|
|
30
|
+
skip: false,
|
|
40
31
|
};
|
|
41
32
|
|
|
42
|
-
export type DirectionContainerOptions
|
|
33
|
+
export type DirectionContainerOptions<
|
|
34
|
+
EntryType extends Record<string, string>,
|
|
35
|
+
> = ContainerOptions<EntryType> & {
|
|
43
36
|
reversed?: boolean;
|
|
44
37
|
};
|
|
45
38
|
|
|
46
|
-
export const DEFAULT_DIRECTION_CONTAINER_OPTIONS:
|
|
39
|
+
export const DEFAULT_DIRECTION_CONTAINER_OPTIONS: RequiredDeep<
|
|
40
|
+
DirectionContainerOptions<Record<string, string>>
|
|
41
|
+
> = {
|
|
47
42
|
...DEFAULT_CONTAINER_OPTIONS,
|
|
48
43
|
reversed: false,
|
|
49
|
-
}
|
|
44
|
+
};
|
|
50
45
|
|
|
51
|
-
export type GridContainerOptions
|
|
52
|
-
|
|
53
|
-
|
|
46
|
+
export type GridContainerOptions<EntryType extends Record<string, string>> =
|
|
47
|
+
ContainerOptions<EntryType> & {
|
|
48
|
+
size?: number;
|
|
54
49
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
};
|
|
50
|
+
/**
|
|
51
|
+
* Defines what is considered the main direction of the container.
|
|
52
|
+
* -> `rows` - the items would be placed to fill each row before starting the next
|
|
53
|
+
* -> `cols` - the items would be placed to fill each col before starting the next
|
|
54
|
+
*
|
|
55
|
+
* Defaults to `rows`
|
|
56
|
+
*/
|
|
57
|
+
direction?: 'rows' | 'cols';
|
|
58
|
+
};
|
|
64
59
|
|
|
60
|
+
export const DEFAULT_GRID_CONTAINER_OPTIONS: RequiredDeep<
|
|
61
|
+
GridContainerOptions<Record<string, string>>
|
|
62
|
+
> = {
|
|
63
|
+
...DEFAULT_CONTAINER_OPTIONS,
|
|
64
|
+
size: 3,
|
|
65
|
+
direction: 'rows',
|
|
66
|
+
};
|
|
65
67
|
|
|
66
|
-
export type PackingFn = (
|
|
68
|
+
export type PackingFn = (
|
|
69
|
+
box: BoundingBox,
|
|
70
|
+
background: ImageType,
|
|
71
|
+
images: Array<ImageType>,
|
|
72
|
+
) => Promise<ImageType>;
|
package/src/lib/types/image.ts
CHANGED
|
@@ -1,47 +1,39 @@
|
|
|
1
1
|
import { JimpInstance } from 'jimp';
|
|
2
2
|
import { ScaleMode } from './scale';
|
|
3
|
-
import {
|
|
3
|
+
import { LayerOptions } from './layer';
|
|
4
|
+
import { RequiredDeep } from 'type-fest';
|
|
4
5
|
|
|
5
6
|
export type ImageType = JimpInstance;
|
|
6
7
|
|
|
7
|
-
export type ImageRef<EntryType
|
|
8
|
+
export type ImageRef<EntryType extends Record<string, string>> =
|
|
8
9
|
| { buffer: Buffer }
|
|
9
10
|
| { path: string }
|
|
10
11
|
| { absolutePath: string }
|
|
11
12
|
| { key: keyof EntryType }
|
|
12
13
|
| { pathFn: (entry: EntryType) => string };
|
|
13
14
|
|
|
14
|
-
export type ImageLayerOptions =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Defaults to `none`
|
|
31
|
-
*/
|
|
32
|
-
scale?: ScaleMode;
|
|
33
|
-
|
|
34
|
-
// TODO:
|
|
35
|
-
// processorFn?: (entry: EntryType, image: ImageType) => Promise<ImageType>;
|
|
36
|
-
};
|
|
15
|
+
export type ImageLayerOptions<EntryType extends Record<string, string>> =
|
|
16
|
+
LayerOptions<EntryType> & {
|
|
17
|
+
/**
|
|
18
|
+
* Base path for the assets. Overrides the more global property of the template `defaultAssetsPath`.
|
|
19
|
+
*/
|
|
20
|
+
assetsPath?: string;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Defaults to `none`
|
|
24
|
+
*/
|
|
25
|
+
scale?: ScaleMode;
|
|
26
|
+
|
|
27
|
+
// TODO:
|
|
28
|
+
// processorFn?: (entry: EntryType, image: ImageType) => Promise<ImageType>;
|
|
29
|
+
};
|
|
37
30
|
|
|
38
|
-
export const DEFAULT_IMAGE_LAYER_OPTIONS:
|
|
39
|
-
Omit<ImageLayerOptions, 'assetsPath'>
|
|
40
|
-
> &
|
|
41
|
-
Pick<ImageLayerOptions, 'assetsPath'> = {
|
|
31
|
+
export const DEFAULT_IMAGE_LAYER_OPTIONS: RequiredDeep<ImageLayerOptions<Record<string, string>>> = {
|
|
42
32
|
justifyContent: 'center',
|
|
43
33
|
alignItems: 'center',
|
|
44
34
|
scale: 'none',
|
|
35
|
+
skip: false,
|
|
36
|
+
assetsPath: ''
|
|
45
37
|
};
|
|
46
38
|
|
|
47
39
|
export type Alignment = 'start' | 'center' | 'end';
|
package/src/lib/types/index.ts
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { JustifyContent, AlignItems } from "./css";
|
|
2
|
+
|
|
3
|
+
export type LayerOptions<EntryType extends Record<string, string>> = {
|
|
4
|
+
/**
|
|
5
|
+
* default `center`
|
|
6
|
+
*/
|
|
7
|
+
justifyContent?: JustifyContent;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* default `center`
|
|
11
|
+
*/
|
|
12
|
+
alignItems?: AlignItems;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Decides if a layer should be rendered or not for a certain entry
|
|
16
|
+
*/
|
|
17
|
+
skip?: boolean | ((entry: EntryType) => boolean);
|
|
18
|
+
};
|
package/src/lib/types/text.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { RequiredDeep } from 'type-fest';
|
|
2
|
+
import { LayerOptions } from './layer';
|
|
1
3
|
import { ReplacementMap } from './replacement';
|
|
2
4
|
|
|
3
5
|
export type TextRef<EntryType> =
|
|
@@ -5,59 +7,52 @@ export type TextRef<EntryType> =
|
|
|
5
7
|
| { text: string }
|
|
6
8
|
| { textFn: (entry: EntryType) => string };
|
|
7
9
|
|
|
8
|
-
export type
|
|
9
|
-
font?: {
|
|
10
|
-
/**
|
|
11
|
-
* Size of font is represented in pixels
|
|
12
|
-
*/
|
|
13
|
-
size?: number;
|
|
14
|
-
/**
|
|
15
|
-
* Either use one supported by canvas
|
|
16
|
-
* or load a custom one before rendering
|
|
17
|
-
*/
|
|
18
|
-
family?: string;
|
|
19
|
-
/**
|
|
20
|
-
* Warning: Not supported by all fonts
|
|
21
|
-
*/
|
|
22
|
-
bold?: boolean;
|
|
23
|
-
/**
|
|
24
|
-
* Warning: Not supported by all fonts
|
|
25
|
-
*/
|
|
26
|
-
italic?: boolean;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
color?: string;
|
|
30
|
-
|
|
31
|
-
// TODO: processor fn
|
|
32
|
-
replacement?: ReplacementMap;
|
|
33
|
-
|
|
10
|
+
export type FontOptions = {
|
|
34
11
|
/**
|
|
35
|
-
*
|
|
12
|
+
* Size of font is represented in pixels
|
|
36
13
|
*/
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
| 'justify-center'
|
|
44
|
-
| 'justify-right';
|
|
45
|
-
|
|
14
|
+
size?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Either use one supported by canvas
|
|
17
|
+
* or load a custom one before rendering
|
|
18
|
+
*/
|
|
19
|
+
family?: string;
|
|
46
20
|
/**
|
|
47
|
-
*
|
|
21
|
+
* Warning: Not supported by all fonts
|
|
48
22
|
*/
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
23
|
+
bold?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Warning: Not supported by all fonts
|
|
26
|
+
*/
|
|
27
|
+
italic?: boolean;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type TextLayerOptions<EntryType extends Record<string, string>> =
|
|
31
|
+
LayerOptions<EntryType> & {
|
|
32
|
+
font?: FontOptions;
|
|
33
|
+
|
|
34
|
+
color?: string;
|
|
35
|
+
|
|
36
|
+
// TODO: processor fn
|
|
37
|
+
replacement?: ReplacementMap;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const DEFAULT_FONT: Required<
|
|
41
|
+
FontOptions
|
|
42
|
+
> = {
|
|
43
|
+
size: 28,
|
|
44
|
+
family: 'Arial',
|
|
45
|
+
bold: false,
|
|
46
|
+
italic: false,
|
|
57
47
|
};
|
|
58
48
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
49
|
+
export const DEFAULT_TEXT_LAYER_OPTIONS: RequiredDeep<
|
|
50
|
+
TextLayerOptions<Record<string, string>>
|
|
51
|
+
> = {
|
|
52
|
+
justifyContent: 'center',
|
|
53
|
+
alignItems: 'center',
|
|
54
|
+
font: DEFAULT_FONT,
|
|
55
|
+
color: 'black',
|
|
56
|
+
replacement: {},
|
|
57
|
+
skip: false,
|
|
63
58
|
};
|
|
@@ -1,13 +1,25 @@
|
|
|
1
|
-
|
|
2
1
|
import { h } from 'virtual-dom';
|
|
3
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
DEFAULT_DIRECTION_CONTAINER_OPTIONS,
|
|
4
|
+
DirectionContainerOptions,
|
|
5
|
+
ImageType,
|
|
6
|
+
PackingFn,
|
|
7
|
+
BoundingBox,
|
|
8
|
+
SCALE_MODE_TO_OBJECT_FIT,
|
|
9
|
+
Size,
|
|
10
|
+
GridContainerOptions,
|
|
11
|
+
DEFAULT_GRID_CONTAINER_OPTIONS,
|
|
12
|
+
} from '../types';
|
|
4
13
|
import { boundingBoxToPx, toPx } from './toPx';
|
|
5
14
|
import merge from 'lodash.merge';
|
|
6
15
|
import { htmlToImage } from './htmlToImage';
|
|
16
|
+
import chunk from 'lodash.chunk';
|
|
7
17
|
|
|
8
18
|
export const vboxPackingFn =
|
|
9
|
-
|
|
10
|
-
|
|
19
|
+
<EntryType extends Record<string, string>>(
|
|
20
|
+
options?: DirectionContainerOptions<EntryType>,
|
|
21
|
+
): PackingFn =>
|
|
22
|
+
(box: BoundingBox, background: ImageType, images: Array<ImageType>) =>
|
|
11
23
|
directionalPackingFn({
|
|
12
24
|
isVertical: true,
|
|
13
25
|
backgroundSize: background,
|
|
@@ -17,8 +29,10 @@ export const vboxPackingFn =
|
|
|
17
29
|
});
|
|
18
30
|
|
|
19
31
|
export const hboxPackingFn =
|
|
20
|
-
|
|
21
|
-
|
|
32
|
+
<EntryType extends Record<string, string>>(
|
|
33
|
+
options?: DirectionContainerOptions<EntryType>,
|
|
34
|
+
): PackingFn =>
|
|
35
|
+
(box: BoundingBox, background: ImageType, images: Array<ImageType>) =>
|
|
22
36
|
directionalPackingFn({
|
|
23
37
|
isVertical: false,
|
|
24
38
|
backgroundSize: background,
|
|
@@ -27,7 +41,82 @@ export const hboxPackingFn =
|
|
|
27
41
|
options,
|
|
28
42
|
});
|
|
29
43
|
|
|
30
|
-
const
|
|
44
|
+
export const gridPackingFn =
|
|
45
|
+
<EntryType extends Record<string, string>>(
|
|
46
|
+
options?: GridContainerOptions<EntryType>,
|
|
47
|
+
): PackingFn =>
|
|
48
|
+
async (
|
|
49
|
+
box: BoundingBox,
|
|
50
|
+
background: ImageType,
|
|
51
|
+
images: Array<ImageType>,
|
|
52
|
+
) => {
|
|
53
|
+
const mergedOptions = merge(
|
|
54
|
+
{},
|
|
55
|
+
DEFAULT_GRID_CONTAINER_OPTIONS,
|
|
56
|
+
options,
|
|
57
|
+
);
|
|
58
|
+
const objectFit = SCALE_MODE_TO_OBJECT_FIT[mergedOptions.scale];
|
|
59
|
+
|
|
60
|
+
const children = await Promise.all(
|
|
61
|
+
images.map(async image => {
|
|
62
|
+
const imageBase64 = await image.getBase64('image/png');
|
|
63
|
+
return h(
|
|
64
|
+
'img',
|
|
65
|
+
{
|
|
66
|
+
style: {
|
|
67
|
+
objectFit,
|
|
68
|
+
flex: '1 1 auto',
|
|
69
|
+
minWidth: 0,
|
|
70
|
+
minHeight: 0,
|
|
71
|
+
maxWidth: '100%',
|
|
72
|
+
maxHeight: '100%',
|
|
73
|
+
},
|
|
74
|
+
src: imageBase64,
|
|
75
|
+
},
|
|
76
|
+
[],
|
|
77
|
+
);
|
|
78
|
+
}),
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const items = [];
|
|
82
|
+
for (const subset of chunk(children)) {
|
|
83
|
+
items.push(
|
|
84
|
+
h(
|
|
85
|
+
'div',
|
|
86
|
+
{
|
|
87
|
+
style: {
|
|
88
|
+
display: 'flex',
|
|
89
|
+
flexDirection: 'row',
|
|
90
|
+
overflow: 'hidden',
|
|
91
|
+
|
|
92
|
+
gap: toPx(mergedOptions.gap),
|
|
93
|
+
justifyContent: mergedOptions.justifyContent,
|
|
94
|
+
alignItems: mergedOptions.alignItems,
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
subset,
|
|
98
|
+
),
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
const document = h(
|
|
102
|
+
'div',
|
|
103
|
+
{
|
|
104
|
+
style: {
|
|
105
|
+
display: 'grid',
|
|
106
|
+
gridTemplateColumns: `repeat(${mergedOptions.size}, 1fr)`,
|
|
107
|
+
position: 'absolute',
|
|
108
|
+
|
|
109
|
+
gap: toPx(mergedOptions.gap),
|
|
110
|
+
...boundingBoxToPx(box),
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
items,
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
return htmlToImage(document, background);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const directionalPackingFn = async <EntryType extends Record<string, string>>({
|
|
31
120
|
isVertical,
|
|
32
121
|
backgroundSize: background,
|
|
33
122
|
images,
|
|
@@ -38,9 +127,13 @@ const directionalPackingFn = async ({
|
|
|
38
127
|
backgroundSize: Size;
|
|
39
128
|
images: Array<ImageType>;
|
|
40
129
|
box: BoundingBox;
|
|
41
|
-
options?: DirectionContainerOptions
|
|
130
|
+
options?: DirectionContainerOptions<EntryType>;
|
|
42
131
|
}): Promise<ImageType> => {
|
|
43
|
-
const mergedOptions = merge(
|
|
132
|
+
const mergedOptions = merge(
|
|
133
|
+
{},
|
|
134
|
+
DEFAULT_DIRECTION_CONTAINER_OPTIONS,
|
|
135
|
+
options,
|
|
136
|
+
);
|
|
44
137
|
const objectFit = SCALE_MODE_TO_OBJECT_FIT[mergedOptions.scale];
|
|
45
138
|
|
|
46
139
|
const children = await Promise.all(
|
|
@@ -5,18 +5,21 @@ import { ImageType, Size, BoundingBox } from '../types';
|
|
|
5
5
|
|
|
6
6
|
export const drawBoundingBox = async (
|
|
7
7
|
box: BoundingBox,
|
|
8
|
-
|
|
9
8
|
imageSize: Size,
|
|
10
9
|
): Promise<ImageType> => {
|
|
11
|
-
const document = h(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
const document = h(
|
|
11
|
+
'div',
|
|
12
|
+
{
|
|
13
|
+
style: {
|
|
14
|
+
position: 'absolute',
|
|
15
|
+
border: '2px solid red',
|
|
16
|
+
background: 'transparent',
|
|
17
|
+
boxSizing: 'border-box',
|
|
18
|
+
...boundingBoxToPx(box),
|
|
19
|
+
},
|
|
18
20
|
},
|
|
19
|
-
|
|
21
|
+
[],
|
|
22
|
+
);
|
|
20
23
|
|
|
21
24
|
return htmlToImage(document, imageSize);
|
|
22
25
|
};
|
|
@@ -8,7 +8,6 @@ export const htmlToImage = async (
|
|
|
8
8
|
backgroundSize: Size,
|
|
9
9
|
): Promise<ImageType> => {
|
|
10
10
|
const html = createElement(document).toString();
|
|
11
|
-
// TODO: extract this in a dif function
|
|
12
11
|
const image = await nodeHtmlToImage({
|
|
13
12
|
html,
|
|
14
13
|
transparent: true,
|
|
@@ -17,6 +16,7 @@ export const htmlToImage = async (
|
|
|
17
16
|
defaultViewport: {
|
|
18
17
|
width: backgroundSize.width,
|
|
19
18
|
height: backgroundSize.height,
|
|
19
|
+
deviceScaleFactor: 1,
|
|
20
20
|
},
|
|
21
21
|
},
|
|
22
22
|
});
|
|
@@ -1,31 +1,29 @@
|
|
|
1
1
|
import { h } from 'virtual-dom';
|
|
2
2
|
import { boundingBoxToPx } from './toPx';
|
|
3
3
|
import {
|
|
4
|
-
DEFAULT_IMAGE_LAYER_OPTIONS,
|
|
5
4
|
ImageLayerOptions,
|
|
6
5
|
ImageType,
|
|
7
6
|
BoundingBox,
|
|
8
7
|
SCALE_MODE_TO_OBJECT_FIT,
|
|
9
8
|
} from '../types';
|
|
10
|
-
import merge from 'lodash.merge';
|
|
11
9
|
import { htmlToImage } from './htmlToImage';
|
|
10
|
+
import { RequiredDeep } from 'type-fest';
|
|
12
11
|
|
|
13
|
-
type PlaceImageProps = {
|
|
12
|
+
type PlaceImageProps<EntryType extends Record<string, string>> = {
|
|
14
13
|
image: ImageType;
|
|
15
14
|
box: BoundingBox;
|
|
16
15
|
backgroundSize: { width: number; height: number };
|
|
17
|
-
options: ImageLayerOptions
|
|
16
|
+
options: RequiredDeep<ImageLayerOptions<EntryType>>;
|
|
18
17
|
};
|
|
19
18
|
|
|
20
|
-
export async
|
|
19
|
+
export const placeImage = async <EntryType extends Record<string, string>>({
|
|
21
20
|
image,
|
|
22
21
|
box,
|
|
23
22
|
backgroundSize,
|
|
24
23
|
options,
|
|
25
|
-
}: PlaceImageProps): Promise<ImageType> {
|
|
24
|
+
}: PlaceImageProps<EntryType>): Promise<ImageType> => {
|
|
26
25
|
const imageBase64 = await image.getBase64('image/png');
|
|
27
|
-
const
|
|
28
|
-
const objectFit = SCALE_MODE_TO_OBJECT_FIT[mergedOptions.scale];
|
|
26
|
+
const objectFit = SCALE_MODE_TO_OBJECT_FIT[options.scale];
|
|
29
27
|
|
|
30
28
|
const document = h(
|
|
31
29
|
'div',
|
|
@@ -35,8 +33,8 @@ export async function placeImage({
|
|
|
35
33
|
position: 'absolute',
|
|
36
34
|
scale: 1,
|
|
37
35
|
|
|
38
|
-
justifyContent:
|
|
39
|
-
alignItems:
|
|
36
|
+
justifyContent: options.justifyContent,
|
|
37
|
+
alignItems: options.alignItems,
|
|
40
38
|
|
|
41
39
|
...boundingBoxToPx(box),
|
|
42
40
|
},
|
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
import { h, VNode } from 'virtual-dom';
|
|
2
|
-
import {
|
|
3
|
-
DEFAULT_TEXT_LAYER_OPTIONS,
|
|
4
|
-
ImageType,
|
|
5
|
-
BoundingBox,
|
|
6
|
-
Size,
|
|
7
|
-
TextLayerOptions,
|
|
8
|
-
} from '../types';
|
|
2
|
+
import { ImageType, BoundingBox, Size, TextLayerOptions } from '../types';
|
|
9
3
|
import { boundingBoxToPx, toPx } from './toPx';
|
|
10
4
|
import { htmlToImage } from './htmlToImage';
|
|
5
|
+
import { RequiredDeep } from 'type-fest';
|
|
11
6
|
|
|
12
|
-
export const renderText = async (
|
|
7
|
+
export const renderText = async <EntryType extends Record<string, string>>(
|
|
13
8
|
text: string,
|
|
14
9
|
box: BoundingBox,
|
|
15
10
|
backgroundSize: Size,
|
|
16
|
-
options
|
|
11
|
+
options: RequiredDeep<TextLayerOptions<EntryType>>,
|
|
12
|
+
fonts: Record<string, string>,
|
|
17
13
|
): Promise<ImageType> => {
|
|
18
14
|
let textChildren: Array<string | VNode> = [text];
|
|
19
|
-
for (const [word, image] of Object.entries(options
|
|
15
|
+
for (const [word, image] of Object.entries(options.replacement)) {
|
|
20
16
|
const regex = new RegExp(word, 'gi');
|
|
21
17
|
const imageBase64 = await image.getBase64('image/png');
|
|
22
18
|
|
|
@@ -36,7 +32,7 @@ export const renderText = async (
|
|
|
36
32
|
style: {
|
|
37
33
|
display: 'inline',
|
|
38
34
|
verticalAlign: 'middle',
|
|
39
|
-
height: toPx(options
|
|
35
|
+
height: toPx(options.font.size),
|
|
40
36
|
width: 'auto',
|
|
41
37
|
},
|
|
42
38
|
src: imageBase64,
|
|
@@ -52,7 +48,7 @@ export const renderText = async (
|
|
|
52
48
|
textChildren = tmpChildren;
|
|
53
49
|
}
|
|
54
50
|
|
|
55
|
-
const
|
|
51
|
+
const content = h(
|
|
56
52
|
'div',
|
|
57
53
|
{
|
|
58
54
|
style: {
|
|
@@ -60,10 +56,8 @@ export const renderText = async (
|
|
|
60
56
|
overflow: 'visible',
|
|
61
57
|
position: 'absolute',
|
|
62
58
|
|
|
63
|
-
justifyContent:
|
|
64
|
-
|
|
65
|
-
alignItems:
|
|
66
|
-
options?.yAlign ?? DEFAULT_TEXT_LAYER_OPTIONS.yAlign,
|
|
59
|
+
justifyContent: options.justifyContent,
|
|
60
|
+
alignItems: options.alignItems,
|
|
67
61
|
|
|
68
62
|
...boundingBoxToPx(box),
|
|
69
63
|
},
|
|
@@ -77,11 +71,11 @@ export const renderText = async (
|
|
|
77
71
|
overflowWrap: 'word-wrap',
|
|
78
72
|
whiteSpace: 'normal',
|
|
79
73
|
|
|
80
|
-
color: options
|
|
81
|
-
fontFamily: options
|
|
82
|
-
fontSize: options
|
|
83
|
-
fontStyle: options
|
|
84
|
-
fontWeight: options
|
|
74
|
+
color: options.color,
|
|
75
|
+
fontFamily: options.font.family,
|
|
76
|
+
fontSize: options.font.size,
|
|
77
|
+
fontStyle: options.font.italic ? 'italic' : undefined,
|
|
78
|
+
fontWeight: options.font.bold ? 'bold' : undefined,
|
|
85
79
|
},
|
|
86
80
|
},
|
|
87
81
|
textChildren,
|
|
@@ -89,5 +83,23 @@ export const renderText = async (
|
|
|
89
83
|
],
|
|
90
84
|
);
|
|
91
85
|
|
|
86
|
+
const document = h('html', [
|
|
87
|
+
h('head', [
|
|
88
|
+
h(
|
|
89
|
+
'style',
|
|
90
|
+
Object.entries(fonts)
|
|
91
|
+
.map(
|
|
92
|
+
([name, data]) =>
|
|
93
|
+
`@font-face {
|
|
94
|
+
font-family: '${name}';
|
|
95
|
+
src: url(data:font/ttf;base64,${data}) format('truetype');
|
|
96
|
+
}`,
|
|
97
|
+
)
|
|
98
|
+
.join('\n'),
|
|
99
|
+
),
|
|
100
|
+
]),
|
|
101
|
+
h('body', [content]),
|
|
102
|
+
]);
|
|
103
|
+
|
|
92
104
|
return htmlToImage(document, backgroundSize);
|
|
93
105
|
};
|