make-ffmpeg: Use fit_text from make-ffmpeg-fade (break into lines array)
This commit is contained in:
parent
6876f2cf44
commit
31f01ca386
10 changed files with 63 additions and 41 deletions
|
@ -31,5 +31,5 @@ fontsize = 45
|
||||||
fontcolor = #FB48C4
|
fontcolor = #FB48C4
|
||||||
x = (w-text_w)/2
|
x = (w-text_w)/2
|
||||||
y = 1000
|
y = 1000
|
||||||
text = 'Chaos Communication Camp 2023'
|
text = Chaos Communication Camp 2023
|
||||||
|
|
||||||
|
|
|
@ -31,5 +31,5 @@ fontsize = 45
|
||||||
fontcolor = #c68100
|
fontcolor = #c68100
|
||||||
x = (w-text_w)/2
|
x = (w-text_w)/2
|
||||||
y = 927
|
y = 927
|
||||||
text = 'chaos communication camp 2019'
|
text = chaos communication camp 2019
|
||||||
|
|
||||||
|
|
|
@ -31,5 +31,5 @@ fontsize = 45
|
||||||
fontcolor = #ffffff
|
fontcolor = #ffffff
|
||||||
x = 640
|
x = 640
|
||||||
y = 1000
|
y = 1000
|
||||||
text = ''
|
; text =
|
||||||
|
|
||||||
|
|
|
@ -31,5 +31,5 @@ fontsize = 45
|
||||||
fontcolor = #c68100
|
fontcolor = #c68100
|
||||||
x = (w-text_w)/2
|
x = (w-text_w)/2
|
||||||
y = 927
|
y = 927
|
||||||
text = ''
|
; text =
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ fontsize = 45
|
||||||
fontcolor = #ffffff
|
fontcolor = #ffffff
|
||||||
x = 640
|
x = 640
|
||||||
y = 1000
|
y = 1000
|
||||||
text = ''
|
; text =
|
||||||
|
|
||||||
|
|
||||||
; build intros via
|
; build intros via
|
||||||
|
|
|
@ -31,5 +31,5 @@ fontsize = 45
|
||||||
fontcolor = #ffffff
|
fontcolor = #ffffff
|
||||||
x = 1920
|
x = 1920
|
||||||
y = 1080
|
y = 1080
|
||||||
text = ''
|
; text =
|
||||||
|
|
||||||
|
|
|
@ -42,11 +42,11 @@ fontsize = 50
|
||||||
x = 400
|
x = 400
|
||||||
y = 950
|
y = 950
|
||||||
|
|
||||||
;; optional extra text
|
;; optional extra text, comment out "text" field to disable
|
||||||
[text]
|
[text]
|
||||||
in = 0
|
in = 0
|
||||||
out = 0
|
out = 0
|
||||||
fontsize = 0
|
fontsize = 0
|
||||||
x = 0
|
x = 0
|
||||||
y = 0
|
y = 0
|
||||||
text = ''
|
;text = some additional text
|
||||||
|
|
|
@ -16,6 +16,8 @@ from PIL import ImageFont
|
||||||
import schedulelib
|
import schedulelib
|
||||||
ssl._create_default_https_context = ssl._create_unverified_context
|
ssl._create_default_https_context = ssl._create_unverified_context
|
||||||
|
|
||||||
|
FRAME_WIDTH = 1920
|
||||||
|
|
||||||
|
|
||||||
class TextConfig:
|
class TextConfig:
|
||||||
inpoint: float
|
inpoint: float
|
||||||
|
@ -58,31 +60,41 @@ class TextConfig:
|
||||||
self.fontsize = cparser_sect.getint('fontsize')
|
self.fontsize = cparser_sect.getint('fontsize')
|
||||||
self.bordercolor = cparser_sect.get('bordercolor', None)
|
self.bordercolor = cparser_sect.get('bordercolor', None)
|
||||||
|
|
||||||
def fit_text(self, text: str):
|
def fit_text(self, text: str) -> list[str]:
|
||||||
global translation_font
|
if not text:
|
||||||
translation_font = ImageFont.truetype(
|
return [""]
|
||||||
|
|
||||||
|
font = ImageFont.truetype(
|
||||||
self.fontfile_path, size=self.fontsize, encoding="unic")
|
self.fontfile_path, size=self.fontsize, encoding="unic")
|
||||||
|
|
||||||
# TODO: Make this work with font family as well!
|
# TODO: Make this work with font family as well!
|
||||||
|
|
||||||
return fit_text(text, (1920-self.x-100))
|
return fit_text(text, (FRAME_WIDTH-self.x-100), font)
|
||||||
|
|
||||||
def get_ffmpeg_filter(self, inout_type: str, text: str):
|
def get_ffmpeg_filter(self, inout_type: str, text: list[str]):
|
||||||
filter_str = "drawtext=enable='between({},{},{})'".format(
|
if not text:
|
||||||
inout_type, self.inpoint, self.outpoint)
|
return ""
|
||||||
|
|
||||||
if self.uses_fontfile():
|
filter_str = ""
|
||||||
filter_str += ":fontfile='{}'".format(self.fontfile_path)
|
for idx, line in enumerate(text):
|
||||||
else:
|
filter_str += "drawtext=enable='between({},{},{})'".format(
|
||||||
filter_str += ":font='{}'".format(self.fontfamily)
|
inout_type, self.inpoint, self.outpoint)
|
||||||
|
|
||||||
if self.bordercolor is not None:
|
if self.uses_fontfile():
|
||||||
filter_str += ":borderw={}:bordercolor={}".format(self.fontsize / 30, self.bordercolor)
|
filter_str += ":fontfile='{}'".format(self.fontfile_path)
|
||||||
|
else:
|
||||||
|
filter_str += ":font='{}'".format(self.fontfamily)
|
||||||
|
|
||||||
filter_str += ":fontsize={0}:fontcolor={1}:x={2}:y={3}:text={4}".format(
|
if self.bordercolor is not None:
|
||||||
self.fontsize, self.fontcolor, self.x, self.y, ffmpeg_escape_str(text))
|
filter_str += ":borderw={}:bordercolor={}".format(
|
||||||
|
self.fontsize / 30, self.bordercolor)
|
||||||
|
|
||||||
return filter_str
|
filter_str += ":fontsize={0}:fontcolor={1}:x={2}:y={3}:text={4}".format(
|
||||||
|
self.fontsize, self.fontcolor, self.x, self.y + (idx*self.fontsize), ffmpeg_escape_str(line))
|
||||||
|
|
||||||
|
filter_str += ","
|
||||||
|
|
||||||
|
return filter_str[:-1]
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
|
@ -97,7 +109,7 @@ class Config:
|
||||||
title: TextConfig
|
title: TextConfig
|
||||||
speaker: TextConfig
|
speaker: TextConfig
|
||||||
text: TextConfig
|
text: TextConfig
|
||||||
text_text: str = "" # additional text
|
extra_text: str = "" # additional text
|
||||||
|
|
||||||
|
|
||||||
def parse_config(filename) -> Config:
|
def parse_config(filename) -> Config:
|
||||||
|
@ -129,7 +141,7 @@ def parse_config(filename) -> Config:
|
||||||
conf.text = TextConfig()
|
conf.text = TextConfig()
|
||||||
conf.text.parse(cparser['text'], default_fontfile, default_fontfamily, default_fontcolor)
|
conf.text.parse(cparser['text'], default_fontfile, default_fontfamily, default_fontcolor)
|
||||||
|
|
||||||
conf.text_text = cparser['text'].get('text', '')
|
conf.extra_text = cparser['text'].get('text', '')
|
||||||
|
|
||||||
conf.fileext = infile.suffix
|
conf.fileext = infile.suffix
|
||||||
|
|
||||||
|
@ -165,20 +177,29 @@ def event_print(event, message):
|
||||||
print("{} – {}".format(describe_event(event), message))
|
print("{} – {}".format(describe_event(event), message))
|
||||||
|
|
||||||
|
|
||||||
def fit_text(string: str, frame_width):
|
def fit_text(string: str, max_width: int, font: ImageFont) -> list[str]:
|
||||||
|
"""Break text into array of strings which fit certain a width (in pixels) for the specified font."""
|
||||||
|
|
||||||
split_line = [x.strip() for x in string.split()]
|
split_line = [x.strip() for x in string.split()]
|
||||||
lines = ""
|
lines = []
|
||||||
line = ""
|
w = 0
|
||||||
|
line = []
|
||||||
for word in split_line:
|
for word in split_line:
|
||||||
left, top, right, bottom = translation_font.getbbox(" ".join([line, word]))
|
new_line = line + [word.rstrip(':')]
|
||||||
width, height = right - left, bottom - top
|
w = font.getlength(" ".join(new_line))
|
||||||
if width > (frame_width - (2 * 6)):
|
if w > max_width:
|
||||||
lines += line.strip() + "\n"
|
lines.append(' '.join(line))
|
||||||
line = ""
|
line = []
|
||||||
|
|
||||||
line += word + " "
|
line.append(word.rstrip(':'))
|
||||||
|
|
||||||
|
if word.endswith(':'):
|
||||||
|
lines.append(' '.join(line))
|
||||||
|
line = []
|
||||||
|
|
||||||
|
if line:
|
||||||
|
lines.append(' '.join(line))
|
||||||
|
|
||||||
lines += line.strip()
|
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
@ -210,9 +231,10 @@ def enqueue_job(conf: Config, event):
|
||||||
|
|
||||||
title = conf.title.fit_text(event_title)
|
title = conf.title.fit_text(event_title)
|
||||||
speakers = conf.speaker.fit_text(event_personnames)
|
speakers = conf.speaker.fit_text(event_personnames)
|
||||||
|
extra_text = conf.text.fit_text(conf.extra_text)
|
||||||
|
|
||||||
if args.debug:
|
if args.debug:
|
||||||
print('Title: ', title)
|
print('Title: ', title)
|
||||||
print('Speaker: ', speakers)
|
print('Speaker: ', speakers)
|
||||||
|
|
||||||
if platform.system() == 'Windows':
|
if platform.system() == 'Windows':
|
||||||
|
@ -222,7 +244,7 @@ def enqueue_job(conf: Config, event):
|
||||||
|
|
||||||
videofilter = conf.title.get_ffmpeg_filter(conf.inout_type, title) + ","
|
videofilter = conf.title.get_ffmpeg_filter(conf.inout_type, title) + ","
|
||||||
videofilter += conf.speaker.get_ffmpeg_filter(conf.inout_type, speakers) + ","
|
videofilter += conf.speaker.get_ffmpeg_filter(conf.inout_type, speakers) + ","
|
||||||
videofilter += conf.text.get_ffmpeg_filter(conf.inout_type, conf.text_text)
|
videofilter += conf.text.get_ffmpeg_filter(conf.inout_type, extra_text)
|
||||||
|
|
||||||
cmd = [ffmpeg_path, '-y', '-i', conf.template_file, '-vf', videofilter]
|
cmd = [ffmpeg_path, '-y', '-i', conf.template_file, '-vf', videofilter]
|
||||||
|
|
||||||
|
@ -298,7 +320,7 @@ if __name__ == "__main__":
|
||||||
persons = ['Thomas Roth', 'Dmitry Nedospasov', 'Josh Datko',]
|
persons = ['Thomas Roth', 'Dmitry Nedospasov', 'Josh Datko',]
|
||||||
events = [{
|
events = [{
|
||||||
'id': 'debug',
|
'id': 'debug',
|
||||||
'title': 'wallet.fail',
|
'title': 'wallet.fail and the longest talk title to test if the template is big enough',
|
||||||
'subtitle': 'Hacking the most popular cryptocurrency hardware wallets',
|
'subtitle': 'Hacking the most popular cryptocurrency hardware wallets',
|
||||||
'persons': persons,
|
'persons': persons,
|
||||||
'personnames': ', '.join(persons),
|
'personnames': ', '.join(persons),
|
||||||
|
|
|
@ -32,4 +32,4 @@ fontsize = 45
|
||||||
fontcolor = #c68100
|
fontcolor = #c68100
|
||||||
x = (w-text_w)/2
|
x = (w-text_w)/2
|
||||||
y = 927
|
y = 927
|
||||||
text = ''
|
; text =
|
||||||
|
|
|
@ -34,4 +34,4 @@ fontsize = 0
|
||||||
fontcolor = #ffffff
|
fontcolor = #ffffff
|
||||||
x = 0
|
x = 0
|
||||||
y = 0
|
y = 0
|
||||||
text = ''
|
; text =
|
||||||
|
|
Loading…
Add table
Reference in a new issue