Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
Commit
·
deff001
1
Parent(s):
d381f5a
improve text overlay generation
Browse files
src/core/ffmpeg/addTextToVideo.mts
CHANGED
@@ -18,14 +18,19 @@ export async function addTextToVideo({
|
|
18 |
|
19 |
const { filePath: temporaryImageOverlayFilePath } = await createTextOverlayImage({
|
20 |
text,
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
width,
|
22 |
height,
|
23 |
-
fontSize: 5
|
24 |
})
|
25 |
|
26 |
-
console.log("addTextToVideo: temporaryImageOverlayFilePath:", temporaryImageOverlayFilePath)
|
27 |
|
28 |
-
|
29 |
inputVideoPath,
|
30 |
inputImagePath: temporaryImageOverlayFilePath,
|
31 |
outputVideoPath,
|
@@ -33,6 +38,6 @@ export async function addTextToVideo({
|
|
33 |
|
34 |
await deleteFile(temporaryImageOverlayFilePath)
|
35 |
|
36 |
-
console.log("addTextToVideo: outputVideoPath:", outputVideoPath)
|
37 |
return outputVideoPath
|
38 |
}
|
|
|
18 |
|
19 |
const { filePath: temporaryImageOverlayFilePath } = await createTextOverlayImage({
|
20 |
text,
|
21 |
+
textStyle: "outline", // or "highlight"
|
22 |
+
fontSize: 4.5,
|
23 |
+
horizontalPosition: "center",
|
24 |
+
verticalPosition: "end",
|
25 |
+
px: 4,
|
26 |
+
py: 8,
|
27 |
width,
|
28 |
height,
|
|
|
29 |
})
|
30 |
|
31 |
+
// console.log("addTextToVideo: temporaryImageOverlayFilePath:", temporaryImageOverlayFilePath)
|
32 |
|
33 |
+
await addImageToVideo({
|
34 |
inputVideoPath,
|
35 |
inputImagePath: temporaryImageOverlayFilePath,
|
36 |
outputVideoPath,
|
|
|
38 |
|
39 |
await deleteFile(temporaryImageOverlayFilePath)
|
40 |
|
41 |
+
// console.log("addTextToVideo: outputVideoPath:", outputVideoPath)
|
42 |
return outputVideoPath
|
43 |
}
|
src/core/ffmpeg/createTextOverlayImage.mts
CHANGED
@@ -1,25 +1,61 @@
|
|
1 |
|
2 |
-
import { TextOverlayFont, TextOverlayFontWeight, TextOverlayStyle, getCssStyle } from "../utils/getCssStyle.mts"
|
3 |
import { htmlToBase64Png } from "../converters/htmlToBase64Png.mts"
|
4 |
|
5 |
// generate a PNG overlay using HTML
|
|
|
6 |
export async function createTextOverlayImage({
|
7 |
text = "",
|
8 |
textStyle = "outline",
|
9 |
fontFamily = "Montserrat",
|
10 |
-
|
|
|
|
|
|
|
11 |
fontWeight = 600,
|
|
|
|
|
|
|
|
|
|
|
12 |
rotation = 0,
|
|
|
|
|
|
|
|
|
|
|
13 |
width = 1024,
|
14 |
height = 576
|
15 |
}: {
|
16 |
text?: string
|
|
|
|
|
17 |
textStyle?: TextOverlayStyle
|
|
|
18 |
fontFamily?: TextOverlayFont
|
|
|
|
|
19 |
fontSize?: number
|
|
|
|
|
20 |
fontWeight?: TextOverlayFontWeight
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
rotation?: number
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
width?: number
|
|
|
23 |
height?: number
|
24 |
}): Promise<{
|
25 |
filePath: string
|
@@ -32,6 +68,10 @@ export async function createTextOverlayImage({
|
|
32 |
fontFamily,
|
33 |
fontSize,
|
34 |
fontWeight: 600,
|
|
|
|
|
|
|
|
|
35 |
})}</head>
|
36 |
<body>
|
37 |
|
|
|
1 |
|
2 |
+
import { TextOverlayFont, TextOverlayFontWeight, TextOverlayPosition, TextOverlayStyle, getCssStyle } from "../utils/getCssStyle.mts"
|
3 |
import { htmlToBase64Png } from "../converters/htmlToBase64Png.mts"
|
4 |
|
5 |
// generate a PNG overlay using HTML
|
6 |
+
// most sizes are in percentage of the image height
|
7 |
export async function createTextOverlayImage({
|
8 |
text = "",
|
9 |
textStyle = "outline",
|
10 |
fontFamily = "Montserrat",
|
11 |
+
|
12 |
+
// the unit is vh (so `fontSize: 4` = 4% of the window height)
|
13 |
+
fontSize = 3,
|
14 |
+
|
15 |
fontWeight = 600,
|
16 |
+
|
17 |
+
horizontalPosition = "center",
|
18 |
+
|
19 |
+
verticalPosition = "end",
|
20 |
+
|
21 |
rotation = 0,
|
22 |
+
|
23 |
+
px = 10,
|
24 |
+
|
25 |
+
py = 10,
|
26 |
+
|
27 |
width = 1024,
|
28 |
height = 576
|
29 |
}: {
|
30 |
text?: string
|
31 |
+
|
32 |
+
// pre-defined text styling, can be: outline or highlight
|
33 |
textStyle?: TextOverlayStyle
|
34 |
+
|
35 |
fontFamily?: TextOverlayFont
|
36 |
+
|
37 |
+
// font size, in % of the video height
|
38 |
fontSize?: number
|
39 |
+
|
40 |
+
// font weight, can be one of: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
|
41 |
fontWeight?: TextOverlayFontWeight
|
42 |
+
|
43 |
+
// start, center or end
|
44 |
+
horizontalPosition?: TextOverlayPosition
|
45 |
+
|
46 |
+
// start, center or end
|
47 |
+
verticalPosition?: TextOverlayPosition
|
48 |
+
|
49 |
rotation?: number
|
50 |
+
|
51 |
+
// horizontal padding - yes the unit is in vh, *not* vw (so `px: 8` = 8% of the window height)
|
52 |
+
px?: number
|
53 |
+
|
54 |
+
// vertical padding - the unit is in vh (so `py: 8` = 8% of the window height)
|
55 |
+
py?: number
|
56 |
+
|
57 |
width?: number
|
58 |
+
|
59 |
height?: number
|
60 |
}): Promise<{
|
61 |
filePath: string
|
|
|
68 |
fontFamily,
|
69 |
fontSize,
|
70 |
fontWeight: 600,
|
71 |
+
horizontalPosition,
|
72 |
+
verticalPosition,
|
73 |
+
px,
|
74 |
+
py,
|
75 |
})}</head>
|
76 |
<body>
|
77 |
|
src/core/utils/getCssStyle.mts
CHANGED
@@ -18,18 +18,31 @@ export type TextOverlayFontWeight =
|
|
18 |
| 800
|
19 |
| 900
|
20 |
|
|
|
|
|
|
|
|
|
|
|
21 |
export function getCssStyle({
|
22 |
width,
|
23 |
height,
|
24 |
fontSize,
|
25 |
fontFamily,
|
26 |
fontWeight,
|
|
|
|
|
|
|
|
|
27 |
}: {
|
28 |
width?: number | string
|
29 |
height?: number | string
|
30 |
fontSize: number
|
31 |
fontFamily: TextOverlayFont
|
32 |
fontWeight: TextOverlayFontWeight
|
|
|
|
|
|
|
|
|
33 |
}) {
|
34 |
|
35 |
return `
|
@@ -52,8 +65,13 @@ export function getCssStyle({
|
|
52 |
.content {
|
53 |
width: 100%;
|
54 |
display: flex;
|
55 |
-
|
56 |
-
|
|
|
|
|
|
|
|
|
|
|
57 |
}
|
58 |
|
59 |
p {
|
@@ -61,8 +79,11 @@ export function getCssStyle({
|
|
61 |
font-size: ${fontSize}vh;
|
62 |
font-weight: ${fontWeight};
|
63 |
border-radius: 2vh;
|
64 |
-
padding:
|
65 |
-
|
|
|
|
|
|
|
66 |
|
67 |
/*
|
68 |
normally we should use those webkit features:
|
|
|
18 |
| 800
|
19 |
| 900
|
20 |
|
21 |
+
export type TextOverlayPosition =
|
22 |
+
| "start"
|
23 |
+
| "center"
|
24 |
+
| "end"
|
25 |
+
|
26 |
export function getCssStyle({
|
27 |
width,
|
28 |
height,
|
29 |
fontSize,
|
30 |
fontFamily,
|
31 |
fontWeight,
|
32 |
+
horizontalPosition,
|
33 |
+
verticalPosition,
|
34 |
+
px,
|
35 |
+
py,
|
36 |
}: {
|
37 |
width?: number | string
|
38 |
height?: number | string
|
39 |
fontSize: number
|
40 |
fontFamily: TextOverlayFont
|
41 |
fontWeight: TextOverlayFontWeight
|
42 |
+
horizontalPosition: TextOverlayPosition
|
43 |
+
verticalPosition: TextOverlayPosition
|
44 |
+
px: number
|
45 |
+
py: number
|
46 |
}) {
|
47 |
|
48 |
return `
|
|
|
65 |
.content {
|
66 |
width: 100%;
|
67 |
display: flex;
|
68 |
+
flex-direction: column;
|
69 |
+
align-items: ${
|
70 |
+
horizontalPosition
|
71 |
+
};
|
72 |
+
justify-content: ${
|
73 |
+
verticalPosition
|
74 |
+
};
|
75 |
}
|
76 |
|
77 |
p {
|
|
|
79 |
font-size: ${fontSize}vh;
|
80 |
font-weight: ${fontWeight};
|
81 |
border-radius: 2vh;
|
82 |
+
padding-top: ${py}vh;
|
83 |
+
padding-right: ${px}vh;
|
84 |
+
padding-bottom: ${py}vh;
|
85 |
+
padding-left: ${px}vh;
|
86 |
+
text-align: ${horizontalPosition};
|
87 |
|
88 |
/*
|
89 |
normally we should use those webkit features:
|