@hellkite/pipkin 0.6.1 → 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.
- package/build/src/lib/template.d.ts +9 -10
- package/build/src/lib/template.js +75 -40
- package/build/src/lib/template.js.map +1 -1
- package/build/src/lib/types/containers.d.ts +14 -2
- package/build/src/lib/types/containers.js.map +1 -1
- package/build/src/lib/types/hypernode.d.ts +2 -0
- package/build/src/lib/types/hypernode.js +3 -0
- package/build/src/lib/types/hypernode.js.map +1 -0
- package/build/src/lib/types/image.d.ts +5 -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/text.d.ts +11 -2
- package/build/src/lib/types/text.js +4 -0
- package/build/src/lib/types/text.js.map +1 -1
- package/build/src/lib/utils/container.js +10 -45
- package/build/src/lib/utils/container.js.map +1 -1
- package/build/src/lib/utils/htmlToImage.d.ts +2 -3
- package/build/src/lib/utils/htmlToImage.js.map +1 -1
- package/build/src/lib/utils/index.d.ts +2 -3
- package/build/src/lib/utils/index.js +2 -3
- package/build/src/lib/utils/index.js.map +1 -1
- package/build/src/lib/utils/placeBoundingBox.d.ts +2 -0
- package/build/src/lib/utils/placeBoundingBox.js +21 -0
- package/build/src/lib/utils/placeBoundingBox.js.map +1 -0
- package/build/src/lib/utils/placeImage.d.ts +7 -6
- package/build/src/lib/utils/placeImage.js +20 -20
- package/build/src/lib/utils/placeImage.js.map +1 -1
- package/build/src/lib/utils/placeText.d.ts +14 -0
- package/build/src/lib/utils/placeText.js +69 -0
- package/build/src/lib/utils/placeText.js.map +1 -0
- package/build/src/lib/utils/renderText.js +1 -0
- package/build/src/lib/utils/renderText.js.map +1 -1
- package/build/src/test.js +36 -10
- package/build/src/test.js.map +1 -1
- package/package.json +3 -1
- package/roadmap.md +3 -2
- package/src/lib/template.ts +100 -70
- package/src/lib/types/containers.ts +22 -4
- package/src/lib/types/hypernode.ts +4 -0
- package/src/lib/types/image.ts +6 -0
- package/src/lib/types/index.ts +1 -0
- package/src/lib/types/text.ts +18 -4
- package/src/lib/utils/container.ts +13 -70
- package/src/lib/utils/htmlToImage.ts +3 -3
- package/src/lib/utils/index.ts +2 -3
- package/src/lib/utils/{drawBoundingBox.ts → placeBoundingBox.ts} +3 -9
- package/src/lib/utils/placeImage.ts +34 -27
- package/src/lib/utils/placeText.ts +110 -0
- package/src/lib/utils/buildFontString.ts +0 -17
- package/src/lib/utils/renderText.ts +0 -105
|
@@ -5,27 +5,23 @@ import {
|
|
|
5
5
|
ImageType,
|
|
6
6
|
BoundingBox,
|
|
7
7
|
SCALE_MODE_TO_OBJECT_FIT,
|
|
8
|
+
HyperNode,
|
|
9
|
+
ImageLayerSpecificOptions,
|
|
8
10
|
} from '../types';
|
|
9
|
-
import { htmlToImage } from './htmlToImage';
|
|
10
11
|
import { RequiredDeep } from 'type-fest';
|
|
11
12
|
|
|
12
13
|
type PlaceImageProps<EntryType extends Record<string, string>> = {
|
|
13
14
|
image: ImageType;
|
|
14
15
|
box: BoundingBox;
|
|
15
|
-
backgroundSize: { width: number; height: number };
|
|
16
16
|
options: RequiredDeep<ImageLayerOptions<EntryType>>;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
export const placeImage = async <EntryType extends Record<string, string>>({
|
|
20
20
|
image,
|
|
21
21
|
box,
|
|
22
|
-
backgroundSize,
|
|
23
22
|
options,
|
|
24
|
-
}: PlaceImageProps<EntryType>): Promise<
|
|
25
|
-
|
|
26
|
-
const objectFit = SCALE_MODE_TO_OBJECT_FIT[options.scale];
|
|
27
|
-
|
|
28
|
-
const document = h(
|
|
23
|
+
}: PlaceImageProps<EntryType>): Promise<HyperNode> => {
|
|
24
|
+
return h(
|
|
29
25
|
'div',
|
|
30
26
|
{
|
|
31
27
|
style: {
|
|
@@ -39,24 +35,35 @@ export const placeImage = async <EntryType extends Record<string, string>>({
|
|
|
39
35
|
...boundingBoxToPx(box),
|
|
40
36
|
},
|
|
41
37
|
},
|
|
42
|
-
[
|
|
43
|
-
h(
|
|
44
|
-
'img',
|
|
45
|
-
{
|
|
46
|
-
style: {
|
|
47
|
-
objectFit,
|
|
48
|
-
flex: '1 1 auto',
|
|
49
|
-
minWidth: 0,
|
|
50
|
-
minHeight: 0,
|
|
51
|
-
maxWidth: '100%',
|
|
52
|
-
maxHeight: '100%',
|
|
53
|
-
},
|
|
54
|
-
src: imageBase64,
|
|
55
|
-
},
|
|
56
|
-
[],
|
|
57
|
-
),
|
|
58
|
-
],
|
|
38
|
+
[await prepareImage({ image, options })],
|
|
59
39
|
);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
type PrepareImageProps<EntryType extends Record<string, string>> = {
|
|
43
|
+
image: ImageType;
|
|
44
|
+
options: RequiredDeep<ImageLayerSpecificOptions<EntryType>>;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const prepareImage = async <EntryType extends Record<string, string>>({
|
|
48
|
+
image,
|
|
49
|
+
options,
|
|
50
|
+
}: PrepareImageProps<EntryType>): Promise<HyperNode> => {
|
|
51
|
+
const imageBase64 = await image.getBase64('image/png');
|
|
52
|
+
const objectFit = SCALE_MODE_TO_OBJECT_FIT[options.scale];
|
|
60
53
|
|
|
61
|
-
return
|
|
62
|
-
|
|
54
|
+
return h(
|
|
55
|
+
'img',
|
|
56
|
+
{
|
|
57
|
+
style: {
|
|
58
|
+
objectFit,
|
|
59
|
+
flex: '1 1 auto',
|
|
60
|
+
minWidth: 0,
|
|
61
|
+
minHeight: 0,
|
|
62
|
+
maxWidth: '100%',
|
|
63
|
+
maxHeight: '100%',
|
|
64
|
+
},
|
|
65
|
+
src: imageBase64,
|
|
66
|
+
},
|
|
67
|
+
[],
|
|
68
|
+
);
|
|
69
|
+
};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { h } from 'virtual-dom';
|
|
2
|
+
import {
|
|
3
|
+
BoundingBox,
|
|
4
|
+
TextLayerOptions,
|
|
5
|
+
HyperNode,
|
|
6
|
+
TextLayerSpecificOptions,
|
|
7
|
+
} from '../types';
|
|
8
|
+
import { boundingBoxToPx, toPx } from './toPx';
|
|
9
|
+
import { RequiredDeep } from 'type-fest';
|
|
10
|
+
|
|
11
|
+
type PlaceTextProps<EntryType extends Record<string, string>> = {
|
|
12
|
+
text: string;
|
|
13
|
+
box: BoundingBox;
|
|
14
|
+
options: RequiredDeep<TextLayerOptions<EntryType>>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const placeText = async <EntryType extends Record<string, string>>({
|
|
18
|
+
text,
|
|
19
|
+
box,
|
|
20
|
+
options,
|
|
21
|
+
}: PlaceTextProps<EntryType>): Promise<HyperNode> => {
|
|
22
|
+
return h(
|
|
23
|
+
'div',
|
|
24
|
+
{
|
|
25
|
+
style: {
|
|
26
|
+
display: 'flex',
|
|
27
|
+
overflow: 'visible',
|
|
28
|
+
position: 'absolute',
|
|
29
|
+
|
|
30
|
+
justifyContent: options.justifyContent,
|
|
31
|
+
alignItems: options.alignItems,
|
|
32
|
+
|
|
33
|
+
...boundingBoxToPx(box),
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
[
|
|
37
|
+
await prepareText({
|
|
38
|
+
text,
|
|
39
|
+
options,
|
|
40
|
+
}),
|
|
41
|
+
],
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
type PrepareTextProps<EntryType extends Record<string, string>> = {
|
|
46
|
+
text: string;
|
|
47
|
+
options: RequiredDeep<TextLayerSpecificOptions<EntryType>>;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const prepareText = async <EntryType extends Record<string, string>>({
|
|
51
|
+
text,
|
|
52
|
+
options,
|
|
53
|
+
}: PrepareTextProps<EntryType>): Promise<HyperNode> => {
|
|
54
|
+
let textChildren: Array<string | HyperNode> = [text];
|
|
55
|
+
for (const [word, image] of Object.entries(options.replacement)) {
|
|
56
|
+
const regex = new RegExp(word, 'gi');
|
|
57
|
+
const imageBase64 = await image.getBase64('image/png');
|
|
58
|
+
|
|
59
|
+
let tmpChildren: Array<string | HyperNode> = [];
|
|
60
|
+
for (const textSegment of textChildren) {
|
|
61
|
+
if (typeof textSegment !== 'string') {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const parts = (textSegment as string).split(regex);
|
|
66
|
+
for (let index = 0; index < parts.length; index++) {
|
|
67
|
+
if (index > 0) {
|
|
68
|
+
tmpChildren.push(
|
|
69
|
+
h(
|
|
70
|
+
'img',
|
|
71
|
+
{
|
|
72
|
+
style: {
|
|
73
|
+
display: 'inline',
|
|
74
|
+
verticalAlign: 'middle',
|
|
75
|
+
height: toPx(options.font.size),
|
|
76
|
+
width: 'auto',
|
|
77
|
+
},
|
|
78
|
+
src: imageBase64,
|
|
79
|
+
},
|
|
80
|
+
[],
|
|
81
|
+
),
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
tmpChildren.push(parts[index]);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
textChildren = tmpChildren;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return h(
|
|
92
|
+
'div',
|
|
93
|
+
{
|
|
94
|
+
style: {
|
|
95
|
+
overflow: 'visible',
|
|
96
|
+
overflowWrap: 'word-wrap',
|
|
97
|
+
whiteSpace: 'normal',
|
|
98
|
+
|
|
99
|
+
color: options.color,
|
|
100
|
+
fontFamily: options.font.family,
|
|
101
|
+
fontSize: options.font.size,
|
|
102
|
+
fontStyle: options.font.italic ? 'italic' : undefined,
|
|
103
|
+
fontWeight: options.font.bold ? 'bold' : undefined,
|
|
104
|
+
|
|
105
|
+
'-webkit-text-stroke': `${options.border.width}px ${options.border.color}`,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
textChildren,
|
|
109
|
+
);
|
|
110
|
+
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { FontOptions } from "../types";
|
|
2
|
-
|
|
3
|
-
export const buildFontString = (
|
|
4
|
-
font: FontOptions,
|
|
5
|
-
defaultFontFamily?: string,
|
|
6
|
-
): string => {
|
|
7
|
-
const fragments: string[] = [];
|
|
8
|
-
if (font?.bold) {
|
|
9
|
-
fragments.push('bold');
|
|
10
|
-
}
|
|
11
|
-
if (font?.italic) {
|
|
12
|
-
fragments.push('italic');
|
|
13
|
-
}
|
|
14
|
-
fragments.push(`${font?.size ?? 16}px`);
|
|
15
|
-
fragments.push(`"${font?.family ?? defaultFontFamily ?? 'Arial'}"`);
|
|
16
|
-
return fragments.join(' ');
|
|
17
|
-
};
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { h, VNode } from 'virtual-dom';
|
|
2
|
-
import { ImageType, BoundingBox, Size, TextLayerOptions } from '../types';
|
|
3
|
-
import { boundingBoxToPx, toPx } from './toPx';
|
|
4
|
-
import { htmlToImage } from './htmlToImage';
|
|
5
|
-
import { RequiredDeep } from 'type-fest';
|
|
6
|
-
|
|
7
|
-
export const renderText = async <EntryType extends Record<string, string>>(
|
|
8
|
-
text: string,
|
|
9
|
-
box: BoundingBox,
|
|
10
|
-
backgroundSize: Size,
|
|
11
|
-
options: RequiredDeep<TextLayerOptions<EntryType>>,
|
|
12
|
-
fonts: Record<string, string>,
|
|
13
|
-
): Promise<ImageType> => {
|
|
14
|
-
let textChildren: Array<string | VNode> = [text];
|
|
15
|
-
for (const [word, image] of Object.entries(options.replacement)) {
|
|
16
|
-
const regex = new RegExp(word, 'gi');
|
|
17
|
-
const imageBase64 = await image.getBase64('image/png');
|
|
18
|
-
|
|
19
|
-
let tmpChildren: Array<string | VNode> = [];
|
|
20
|
-
for (const textSegment of textChildren) {
|
|
21
|
-
if (typeof textSegment !== 'string') {
|
|
22
|
-
continue;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const parts = (textSegment as string).split(regex);
|
|
26
|
-
for (let index = 0; index < parts.length; index++) {
|
|
27
|
-
if (index > 0) {
|
|
28
|
-
tmpChildren.push(
|
|
29
|
-
h(
|
|
30
|
-
'img',
|
|
31
|
-
{
|
|
32
|
-
style: {
|
|
33
|
-
display: 'inline',
|
|
34
|
-
verticalAlign: 'middle',
|
|
35
|
-
height: toPx(options.font.size),
|
|
36
|
-
width: 'auto',
|
|
37
|
-
},
|
|
38
|
-
src: imageBase64,
|
|
39
|
-
},
|
|
40
|
-
[],
|
|
41
|
-
),
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
tmpChildren.push(parts[index]);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
textChildren = tmpChildren;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const content = h(
|
|
52
|
-
'div',
|
|
53
|
-
{
|
|
54
|
-
style: {
|
|
55
|
-
display: 'flex',
|
|
56
|
-
overflow: 'visible',
|
|
57
|
-
position: 'absolute',
|
|
58
|
-
|
|
59
|
-
justifyContent: options.justifyContent,
|
|
60
|
-
alignItems: options.alignItems,
|
|
61
|
-
|
|
62
|
-
...boundingBoxToPx(box),
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
[
|
|
66
|
-
h(
|
|
67
|
-
'div',
|
|
68
|
-
{
|
|
69
|
-
style: {
|
|
70
|
-
overflow: 'visible',
|
|
71
|
-
overflowWrap: 'word-wrap',
|
|
72
|
-
whiteSpace: 'normal',
|
|
73
|
-
|
|
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,
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
textChildren,
|
|
82
|
-
),
|
|
83
|
-
],
|
|
84
|
-
);
|
|
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
|
-
|
|
104
|
-
return htmlToImage(document, backgroundSize);
|
|
105
|
-
};
|