Compare commits

..

1 commit

Author SHA1 Message Date
Sophie Schiller
893c0d94e6 froscon2024: init 2024-08-15 20:32:03 +02:00
35 changed files with 4100 additions and 36156 deletions

1
.gitignore vendored
View file

@ -12,3 +12,4 @@ schedule.de.xml
snapshot-*.png
env
.DS_Store
.python-version

View file

@ -1,13 +1,15 @@
[meta]
[default]
schedule = https://pretalx.c3voc.de/camp2023/schedule/export/schedule.xml
template = intro.mp4
alpha = false
prores = false
inout_type = t
fontfile = true
inout = t
[title]
in = 16
out = 24
fontfamily = BeonRegular
fontfile = saira.ttf
fontsize = 100
fontcolor = #FB48C4
@ -17,6 +19,7 @@ y = 100
[speaker]
in = 16
out = 24
fontfamily = BeonRegular
fontfile = saira.ttf
fontsize = 70
fontcolor = #3FFF21
@ -26,10 +29,11 @@ y = 800
[text]
in = 16
out = 24
fontfamily = BeonRegular
fontfile = saira.ttf
fontsize = 45
fontcolor = #FB48C4
x = (w-text_w)/2
y = 1000
text = Chaos Communication Camp 2023
text = 'Chaos Communication Camp 2023'

View file

@ -1,13 +1,15 @@
[meta]
[default]
schedule = https://fahrplan.events.ccc.de/camp/2019/Fahrplan/schedule.xml
template = cccamp19_talks_intro_1080p.mov
alpha = true
prores = true
inout_type = n
fontfile = true
inout = n
[title]
in = 193
out = 324
fontfamily =
fontfile = Marvel-Bold.ttf
fontsize = 120
fontcolor = #c68100
@ -17,6 +19,7 @@ y = 480
[speaker]
in = 233
out = 324
fontfamily =
fontfile = Marvel-Regular.ttf
fontsize = 70
fontcolor = #c68100
@ -26,10 +29,11 @@ y = 845
[text]
in = 242
out = 324
fontfamily =
fontfile = Marvel-Regular.ttf
fontsize = 45
fontcolor = #c68100
x = (w-text_w)/2
y = 927
text = chaos communication camp 2019
text = 'chaos communication camp 2019'

View file

@ -1,13 +1,15 @@
[meta]
[default]
schedule = https://pretalx.denog.de/denog11/schedule/export/schedule.xml
template = denog11_intro_template.ts
alpha = false
prores = false
inout_type = n
fontfile = true
inout = n
[title]
in = 1
out = 6.5
fontfamily =
fontfile = DejaVuSans.ttf
fontsize = 100
fontcolor = #f9cc12
@ -17,6 +19,7 @@ y = 200
[speaker]
in = 2
out = 6.5
fontfamily =
fontfile = DejaVuSans.ttf
fontsize = 60
fontcolor = #ffffff
@ -26,10 +29,11 @@ y = 900
[text]
in = 3
out = 6.5
fontfamily =
fontfile = DejaVuSans.ttf
fontsize = 45
fontcolor = #ffffff
x = 640
y = 1000
; text =
text = ''

BIN
froscon2024/Exo-Medium.ttf Normal file

Binary file not shown.

Binary file not shown.

39
froscon2024/config.ini Normal file
View file

@ -0,0 +1,39 @@
[default]
schedule = https://programm.froscon.org/2024/schedule.xml
template = intro-background.ts
alpha = false
prores = false
fontfile = true
inout = t
[title]
in = 1
out = 9.5
fontfamily =
font = Exo-Medium.ttf
fontsize = 67
fontcolor = #493fa0
x = 230
y = 650
[speaker]
in = 2
out = 9
fontfamily =
font = OpenSans-Regular.ttf
fontsize = 50
fontcolor = #493fa0
x = 230
y = 950
[text]
in = 0
out = 0
fontfamily =
font = OpenSans-Regular.ttf
fontsize = 0
fontcolor = #ffffff
x = 0
y = 0
text = ''

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 2 MiB

View file

@ -1,145 +0,0 @@
#!/usr/bin/python3
from renderlib import *
from schedulelib import *
from easing import *
# URL to Schedule-XML
scheduleUrl = 'https://import.c3voc.de/schedule/god2024.xml?showall=yes'
titlemap = {
}
def introFrames(p):
givenFrame = 0
nr = p['$id'];
# 1 Sekunden nix
frames = 1*fps
for i in range(0, frames):
givenFrame += 1
yield (
('bg', 'attr', '{http://www.w3.org/1999/xlink}href', "given-frames/frame%04d.png" % (givenFrame)),
('layer1', 'style', 'opacity', "%.4f" % 0), # nix
# ('text', 'attr', 'transform', 'translate(%.4f, 0)' % easeOutQuad(i, move, -move, frames)),
)
# 1 Sekunde Text Fadein
frames = 1*fps
for i in range(0, frames):
givenFrame += 1
yield (
('bg', 'attr', '{http://www.w3.org/1999/xlink}href', "given-frames/frame%04d.png" % (givenFrame)),
('layer1', 'style', 'opacity', "%.4f" % easeLinear(i, 0, 1, frames)),
# ('text', 'attr', 'transform', 'translate(%.4f, 0)' % easeOutQuad(i, move, -move, frames)),
)
# 5 Sekunden Text
frames = 5*fps
for i in range(0, frames):
givenFrame += 1
yield (
('bg', 'attr', '{http://www.w3.org/1999/xlink}href', "given-frames/frame%04d.png" % (givenFrame)),
('layer1', 'style', 'opacity', "%.4f" %1),
# ('text', 'attr', 'transform', 'translate(%.4f, 0)' % easeOutQuad(i, move, -move, frames)),
)
def outroFrames(p):
xml = etree.parse('god2024/artwork/outro.svg').getroot()
frames = int(5*fps)
for i in range(0, frames):
yield ()
def pauseFrames(p):
# 1 sekunden fade in
frames = 1*fps
for i in range(0, frames):
yield (
('text1', 'style', 'opacity', "%.4f" % easeLinear(i, 0, 1, frames)),
)
# 1 sekunde sehen
for i in range(0, frames):
yield (
('text1', 'style', 'opacity', "%.4f" % 1),
)
# 1 sekunde fadeout
for i in range(0, frames):
yield (
('text1', 'style', 'opacity', "%.4f" % easeLinear(i, 1, -1, frames)),
)
# 1 sekunde bild
for i in range(0, frames):
yield (
('text1', 'style', 'opacity', "%.4f" % 0),
)
def debug():
render(
'intro.svg',
'../intro.ts',
introFrames,
{
'$id': 65,
'$title': 'OWASP Juice Shop 10th anniversary: Is it still fresh?'.upper(),
'$subtitle': '',
'$personnames': 'Jannik Hollenbach'.upper(),
#'only_render_frame': 353
'only_rerender_frames_after': 225
}
)
# render(
# 'pause.svg',
# '../pause.ts',
# pauseFrames
# )
def tasks(queue, args, id_list, skip_list):
if not 'outro' in skip_list:
# place a task for the outro into the queue
queue.put(Rendertask(
infile = 'outro.svg',
outfile = 'outro.ts',
sequence = outroFrames
))
if not 'pause' in skip_list:
# place the pause-sequence into the queue
queue.put(Rendertask(
infile = 'pause.svg',
outfile = 'pause.ts',
sequence = pauseFrames
))
# iterate over all events extracted from the schedule xml-export
for event in events(scheduleUrl, titlemap):
# skip events which will not be recorded
if event['room'] not in ('Da Capo',) or event['track'] == 'Nomnom':
print("skipping room %s (%s [%s])" % (event['room'], event['title'], event['id']))
continue
# when id_list is not empty, only render events which are in id_list
if id_list and int(event['id']) not in id_list:
print("skipping id (%s [%s])" % (event['title'], event['id']))
continue
# generate a task description and put them into the queue
queue.put(Rendertask(
infile = 'intro.svg',
outfile = str(event['id']) + ".ts",
sequence = introFrames,
parameters = {
'$id': event['id'],
'$title': event['title'].upper(),
'$subtitle': event['subtitle'],
'$personnames': event['personnames'].upper(),
}
))

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.9 MiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 2.4 MiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.9 MiB

View file

@ -1,13 +1,15 @@
[meta]
[default]
schedule = https://projects.alpaka.space/media/jhber19-schedule.xml
template = intro-alpha.mov
alpha = true
prores = true
inout_type = n
fontfile = true
inout = n
[title]
in = 175
out = 260
fontfamily =
fontfile = SourceSansPro-Bold.otf
fontsize = 90
fontcolor = #ffffff
@ -17,6 +19,7 @@ y = 450
[speaker]
in = 175
out = 260
fontfamily =
fontfile = SourceSansPro-Regular.otf
fontsize = 36
fontcolor = #ffffff
@ -26,10 +29,11 @@ y = 900
[text]
in = 200
out = 250
fontfamily =
fontfile = SourceSansPro-Regular.otf
fontsize = 45
fontcolor = #c68100
x = (w-text_w)/2
y = 927
; text =
text = ''

View file

@ -1,35 +1,37 @@
[meta]
[default]
schedule = https://releasing.c3voc.de/releases/jhjue2020/schedule-jhjue20.xml
; intro_template.ts was derived from a png which was derived from jhjue-20-intro.svg
; ffmpeg -loop 1 -i jh20-jue/jh20-jue-intro.png -ar 48000 -ac 2 -f s16le -i /dev/zero -c:v mpeg2video -pix_fmt:v yuv420p -qscale:v 2 -qmin:v 2 -qmax:v 7 -keyint_min 0 -bf 0 -g 0 -intra:0 -maxrate:0 90M -c:a mp2 -b:a 384k -t 5 jh20-jue/jh20-jue_intro_template.ts
template = jh20-jue_intro_template.ts
alpha = false
prores = false
; enable using a font file
fontfile = true
; in and out time format: t for seconds, n for frame number
inout = n
;; Some font settings can have defaults, which can be overridden in the
;; 'title', 'speaker' and 'text' sections below.
[default]
;; default font
fontfile = ebisu.ttf
;; default font color
fontcolor = #ffffff
;; fields for title and speaker names are empty in the template.ts, so we'll render them in via ffmpeg
; fields for title and speaker names are empty in the template.ts, so we'll render them in via ffmpeg
[title]
; inframe for title
in = 20
; outframe for title
; outframe for totle
out = 225
; title font (either font family or file, see default setting above)
fontfamily =
fontfile = ebisu.ttf
; title font size
fontsize = 70
; title color
fontcolor = #ffffff
; title position from upper left corner
x = 600
y = 865
[speaker]
in = 40
out = 225
fontfamily =
fontfile = ebisu.ttf
fontsize = 40
fontcolor = #eeeeee
x = 600
@ -39,10 +41,13 @@ y = 950
[text]
in = 3
out = 4
fontfamily =
fontfile = ebisu.ttf
fontsize = 45
fontcolor = #ffffff
x = 640
y = 1000
; text =
text = ''
; build intros via

View file

@ -1,13 +1,15 @@
[meta]
[default]
schedule = https://pretalx.c3voc.de/jugend-hackt-rhein-neckar-2021/schedule/export/schedule.xml
template = jh21-rn-template.ts
alpha = false
prores = false
inout_type = t
fontfile = true
inout = t
[title]
in = 1
out = 6.5
fontfamily =
fontfile = SourceSansPro-Semibold.ttf
fontsize = 85
fontcolor = #ffffff
@ -17,6 +19,7 @@ y = 877
[speaker]
in = 2
out = 6.5
fontfamily =
fontfile = SourceSansPro-Semibold.ttf
fontsize = 45
fontcolor = #ffffff
@ -26,10 +29,11 @@ y = 954
[text]
in = 3
out = 6.5
fontfamily =
fontfile = SourceSansPro-Semibold.ttf
fontsize = 45
fontcolor = #ffffff
x = 1920
y = 1080
; text =
text = ''

View file

@ -1,52 +1,39 @@
[meta]
schedule = https://pretalx.c3voc.de/jhhh23/schedule/export/schedule.xml
;; path to background video
template = intro-background.ts
;; whether background video uses transparency (needs to be .mov)
alpha = false
;; whether background video is prores 4444
prores = false
;; in and out time format: t for seconds, n for frame number
inout_type = t
;; fade-in duration (seconds), leave out or set to zero to disable
;fade_duration = 0.5
;; Some font settings can have defaults, which can be overridden in the
;; 'title', 'speaker' and 'text' sections below.
[default]
;; default font
fontfile = SourceSansPro-Semibold.ttf
;; default font color
fontcolor = #ffffff
schedule = https://pretalx.c3voc.de/jhhh23/schedule/export/schedule.xml
template = intro-background.ts
alpha = false
prores = false
fontfile = true
inout = t
;; fields for title and speaker names are empty in the template.ts, so we'll render them in via ffmpeg
;; parameters are:
;; - in: start frame/ time
;; - out: end frame/ time
;; - fontfile: font file
;; - fontcolor: font color
;; - fontsize: font size (pixel)
;; - x: horizontal position (top left corner)
;; - y: vertical position (top left corner)
[title]
in = 1
out = 9.5
fontfamily =
fontfile = SourceSansPro-Semibold.ttf
fontsize = 67
fontcolor = #ffffff
x = 400
y = 870
[speaker]
in = 2
out = 9
fontfamily =
fontfile = SourceSansPro-Semibold.ttf
fontsize = 50
fontcolor = #ffffff
x = 400
y = 950
;; optional extra text, comment out "text" field to disable
[text]
in = 0
out = 0
fontfamily =
fontfile = SourceSansPro-Semibold.ttf
fontsize = 0
fontcolor = #ffffff
x = 0
y = 0
;text = some additional text
text = ''

Binary file not shown.

View file

@ -11,6 +11,8 @@ import sys
import os
import re
from xml.sax.saxutils import escape as xmlescape
# Parse arguments
parser = argparse.ArgumentParser(
description='C3VOC Intro-Outro-Generator - Variant to use with apple Motion Files',
@ -55,20 +57,6 @@ parser.add_argument('--num-audio-streams', dest='naudio', type=int, default=1, h
number of audio-streams to generate. defaults to 1
''')
parser.add_argument('--no-cleanup', action='store_true', help='''
keep temp-dir for debugging purposes
''')
parser.add_argument('--snapshot-sec', type=int, default=3, help='''
number of seconds into the final clip when to take a snapshot (for inspection purposes or as thumbnail)
''')
parser.add_argument('--setting-path', default='hd1080p.compressorsetting', help='''
filename in the script-dir (where this python script resides),
the work-dir (where the .motn-file resides) or absolute path to
a .compressorsetting file
''')
args = parser.parse_args()
@ -113,22 +101,9 @@ def describe_event(event):
def event_print(event, message):
print("{} {}".format(describe_event(event), message))
def find_settingpath():
artwork_dir = os.path.dirname(args.motn)
setting_path = os.path.join(artwork_dir, args.setting_path)
if os.path.exists(setting_path):
return setting_path
setting_path = os.path.join(os.path.dirname(__file__), args.setting_path)
if os.path.exists(setting_path):
return setting_path
return args.setting_path
tempdir = tempfile.TemporaryDirectory()
print('working in ' + tempdir.name)
settingpath = find_settingpath()
def fmt_command(command, **kwargs):
@ -153,13 +128,6 @@ def run_output(command, **kwargs):
os.system(f'{cmd} >{t.name} 2>&1')
return t.read().decode('utf-8')
def xmlescape(xml):
xml = xml.replace("&", "&")
xml = xml.replace("<", "&lt;")
xml = xml.replace(">", "&gt;")
xml = xml.replace("\"", "&quot;")
xml = xml.replace("'", "&apos;")
return xml
def enqueue_job(event):
event_id = str(event['id'])
@ -176,11 +144,10 @@ def enqueue_job(event):
fp.write(xmlstr)
compressor_info = run_output(
'/Applications/Compressor.app/Contents/MacOS/Compressor -batchname {batchname} -jobpath {jobpath} -settingpath {settingpath} -locationpath {locationpath}',
'/Applications/Compressor.app/Contents/MacOS/Compressor -batchname {batchname} -jobpath {jobpath} -settingpath hd1080p.compressorsetting -locationpath {locationpath}',
batchname=describe_event(event),
jobpath=work_doc,
locationpath=intermediate_clip,
settingpath=settingpath)
locationpath=intermediate_clip)
match = re.search(r"<jobID ([A-Z0-9\-]+) ?\/>", compressor_info)
if not match:
@ -235,7 +202,6 @@ def finalize_job(job_id, event):
intermediate_clip = os.path.join(tempdir.name, event_id + '.mov')
final_clip = os.path.join(os.path.dirname(args.motn), event_id + '.ts')
copy_clip = os.path.join(os.path.dirname(args.motn), event_id + '.mov')
snapshot_file = os.path.join(os.path.dirname(args.motn), event_id + '.png')
shutil.copy(intermediate_clip, copy_clip)
@ -245,11 +211,6 @@ def finalize_job(job_id, event):
vcodec=args.vcodec,
acodec=args.acodec)
run('ffmpeg -y -hide_banner -loglevel error -i {input} -ss {snapshot_sec} -frames:v 1 -vf scale="iw*sar:ih" -f image2 -y -c png {output}',
input=intermediate_clip,
output=snapshot_file,
snapshot_sec=str(args.snapshot_sec))
event_print(event, "finalized intro to " + final_clip)
@ -289,9 +250,5 @@ while len(active_jobs) > 0:
finalize_job(job_id, event)
if args.no_cleanup:
print('all done, *NOT* cleaning up, *TEMPFILES REMAIN* in ' + tempdir.name)
else:
print('all done, cleaning up ' + tempdir.name)
tempdir.cleanup()
print('all done, cleaning up ' + tempdir.name)
tempdir.cleanup()

View file

@ -1,5 +1,328 @@
#!/usr/bin/env python3
# vim: tabstop=4 shiftwidth=4 expandtab
print("ERROR: The functionality of this script was added to 'make-ffmpeg.py'!")
print("Specify meta.fade_duration = 0.5 in the config.ini for the same effect.")
import os
import sys
import subprocess
import renderlib
import schedulelib
import argparse
import shlex
from PIL import ImageFont
from configparser import ConfigParser
import json
# Parse arguments
parser = argparse.ArgumentParser(
description='C3VOC Intro-Outro-Generator - Variant which renders only using video filters in ffmpeg',
usage="./make-ffmpeg.py yourproject/",
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('project', action="store", metavar='Project folder', type=str, help='''
Path to your project folder
''')
parser.add_argument('--debug', action="store_true", default=False, help='''
Run script in debug mode and render with placeholder texts,
not parsing or accessing a schedule.
This argument must not be used together with --id
Usage: ./make-ffmpeg.py yourproject/ --debug
''')
parser.add_argument('--id', dest='ids', nargs='+', action="store", type=int, help='''
Only render the given ID(s) from your projects schedule.
This argument must not be used together with --debug
Usage: ./make-adobe-after-effects.py yourproject/ --id 4711 0815 4223 1337
''')
parser.add_argument('--room', dest='rooms', nargs='+', action="store", type=str, help='''
Only render the given room(s) from your projects schedule.
This argument must not be used together with --debug
Usage: ./make-adobe-after-effects.py yourproject/ --room "HfG_Studio" "ZKM_Vortragssaal"
''')
parser.add_argument('--skip', nargs='+', action="store", type=str, help='''
Skip ID(s) not needed to be rendered.
Usage: ./make-ffmpeg.py yourproject/ --skip 4711 0815 4223 1337
''')
parser.add_argument('--force', action="store_true", default=False, help='''
Force render if file exists.
''')
args = parser.parse_args()
if (args.skip is None):
args.skip = []
def headline(str):
print("##################################################")
print(str)
print("##################################################")
print()
def error(str):
headline(str)
parser.print_help()
sys.exit(1)
cparser = ConfigParser()
cparser.read(os.path.join(os.path.dirname(args.project), 'config.ini'))
template = cparser['default']['template']
alpha = cparser['default']['alpha']
prores = cparser['default']['prores']
fade_duration = 0.5
title_in = float(cparser['title']['in'])
title_out = float(cparser['title']['out'])
title_duration = title_out - title_in
title_font = cparser['title']['font']
title_fontsize = int(cparser['title']['fontsize'])
title_fontcolor = cparser['title']['fontcolor']
title_x = int(cparser['title']['x'])
title_y = int(cparser['title']['y'])
speaker_in = float(cparser['speaker']['in'])
speaker_out = float(cparser['speaker']['out'])
speaker_duration = speaker_out - speaker_in
speaker_font = cparser['speaker']['font']
speaker_fontsize = int(cparser['speaker']['fontsize'])
speaker_fontcolor = cparser['speaker']['fontcolor']
speaker_x = int(cparser['speaker']['x'])
speaker_y = int(cparser['speaker']['y'])
text_in = float(cparser['text']['in'])
text_out = float(cparser['text']['out'])
text_duration = text_out - text_in
text_font = cparser['text']['font']
text_fontsize = int(cparser['text']['fontsize'])
text_fontcolor = cparser['text']['fontcolor']
text_x = int(cparser['text']['x'])
text_y = int(cparser['text']['y'])
text_text = cparser['text']['text']
font_t = os.path.join(os.path.dirname(args.project), title_font)
font_s = os.path.join(os.path.dirname(args.project), speaker_font)
font_tt = os.path.join(os.path.dirname(args.project), text_font)
fileformat = os.path.splitext(template)[1]
infile = os.path.join(os.path.dirname(args.project), template)
schedule = cparser['default']['schedule']
if not (os.path.exists(os.path.join(args.project, template))):
error("Template file {} in Project Path is missing".format(template))
for ffile in (title_font, speaker_font, text_font):
if not (os.path.exists(os.path.join(args.project, ffile))):
error("Font file {} in Project Path is missing".format(ffile))
if not (os.path.exists(os.path.join(args.project, 'config.ini'))):
error("config.ini file in Project Path is missing")
if alpha == 'true' and not fileformat == '.mov':
error("Alpha can only be rendered with .mov source files")
if not args.project:
error("The Project Path is a required argument")
if not args.debug and not schedule:
error("Either specify --debug or supply a schedule in config.ini")
if args.debug:
persons = ['Thomas Roth', 'Dmitry Nedospasov', 'Josh Datko']
events = [{
'id': 'debug',
'title': 'wallet.fail',
'subtitle': 'Hacking the most popular cryptocurrency hardware wallets',
'persons': persons,
'personnames': ', '.join(persons),
'room': 'Borg',
}]
else:
events = list(schedulelib.events(schedule))
def describe_event(event):
return "#{}: {}".format(event['id'], event['title'])
def event_print(event, message):
print("{} {}".format(describe_event(event), message))
def fmt_command(command, **kwargs):
args = {}
for key, value in kwargs.items():
args[key] = shlex.quote(value)
command = command.format(**args)
return shlex.split(command)
def run(command, **kwargs):
return subprocess.check_call(
fmt_command(command, **kwargs),
stderr=subprocess.STDOUT,
stdout=subprocess.DEVNULL)
def fit_text(string: str, frame_width):
split_line = [x.strip() for x in string.split()]
lines = []
w = 0
line_num = 0
line = []
for word in split_line:
new_line = line + [word.rstrip(':')]
w = translation_font.getlength(" ".join(new_line))
print(w, new_line)
if w > frame_width:
print("too wide, breaking", line)
lines.append(' '.join(line))
line = []
line.append(word.rstrip(':'))
if word.endswith(':'):
print(':, breaking', line)
lines.append(' '.join(line))
line = []
if line:
lines.append(' '.join(line))
return lines
def fit_title(string: str):
global translation_font
translation_font = ImageFont.truetype(font_t, size=title_fontsize-10, encoding="unic")
title = fit_text(string, 1080)
return title
def fit_speaker(string: str):
global translation_font
translation_font = ImageFont.truetype(font_s, size=speaker_fontsize-10, encoding="unic")
speaker = fit_text(string, 1080)
return speaker
def enqueue_job(event):
event_id = str(event['id'])
if event_id in args.skip:
event_print(event, "skipping " + str(event['id']))
return
if (os.path.exists(os.path.join(args.project, event_id + '.ts')) or os.path.exists(os.path.join(args.project, event_id + '.mov'))) and not args.force:
event_print(event, "file exist, skipping " + str(event['id']))
return
event_title = str(event['title'])
event_personnames = str(event['personnames'])
event_title = event_title.replace('"', '')
event_title = event_title.replace('\'', '')
event_personnames = event_personnames.replace('"', '')
t = fit_title(event_title)
s = fit_speaker(event_personnames)
print(s)
if args.debug:
print('Title: ', t)
print('Speaker: ', s)
outfile = os.path.join(os.path.dirname(args.project), event_id + '.ts')
videofilter = ""
for idx, line in enumerate(t):
videofilter += "drawtext=fontfile={fontfile}:fontsize={fontsize}:fontcolor={fontcolor}:x={x}:y={y}:text='{text}':".format(
fontfile=font_t,
fontsize=title_fontsize,
fontcolor=title_fontcolor,
x=title_x,
y=title_y + (idx * title_fontsize),
text=line)
videofilter += "alpha='if(lt(t,{fade_in_start_time}),0,if(lt(t,{fade_in_end_time}),(t-{fade_in_start_time})/{fade_duration},if(lt(t,{fade_out_start_time}),1,if(lt(t,{fade_out_end_time}),({fade_duration}-(t-{fade_out_start_time}))/{fade_duration},0))))',".format(
fade_in_start_time=title_in,
fade_in_end_time=title_in + fade_duration,
fade_out_start_time=title_in + fade_duration + title_duration,
fade_out_end_time=title_in + fade_duration + title_duration + fade_duration,
fade_duration=fade_duration
)
for idx, line in enumerate(s):
videofilter += "drawtext=fontfile={fontfile}:fontsize={fontsize}:fontcolor={fontcolor}:x={x}:y={y}:text='{text}':".format(
fontfile=font_s,
fontsize=speaker_fontsize,
fontcolor=speaker_fontcolor,
x=speaker_x,
y=speaker_y + (idx * speaker_fontsize),
text=line)
videofilter += "alpha='if(lt(t,{fade_in_start_time}),0,if(lt(t,{fade_in_end_time}),(t-{fade_in_start_time})/{fade_duration},if(lt(t,{fade_out_start_time}),1,if(lt(t,{fade_out_end_time}),({fade_duration}-(t-{fade_out_start_time}))/{fade_duration},0))))',".format(
fade_in_start_time=speaker_in,
fade_in_end_time=speaker_in + fade_duration,
fade_out_start_time=speaker_in + fade_duration + speaker_duration,
fade_out_end_time=speaker_in + fade_duration + speaker_duration + fade_duration,
fade_duration=fade_duration
)
videofilter = videofilter.strip(',')
if fileformat == '.mov':
if alpha == 'true':
if prores == 'true':
cmd = 'ffmpeg -y -i "{0}" -vf "{1}" -vcodec prores_ks -pix_fmt yuva444p10le -profile:v 4444 -shortest -movflags faststart -f mov "{2}"'.format(
infile, videofilter, outfile)
else:
cmd = 'ffmpeg -y -i "{0}" -vf "{1}" -shortest -c:v qtrle -movflags faststart -f mov "{2}"'.format(
infile, videofilter, outfile)
else:
cmd = 'ffmpeg -y -i "{0}" -vf "{1}" -map 0:0 -c:v mpeg2video -q:v 2 -aspect 16:9 -map 0:1 -c:a mp2 -b:a 384k -shortest -f mpegts "{2}"'.format(
infile, videofilter, outfile)
else:
cmd = 'ffmpeg -y -i "{0}" -vf "{1}" -map 0:0 -c:v mpeg2video -pix_fmt:v yuv420p -qscale:v 2 -qmin:v 2 -qmax:v 7 -keyint_min 0 -bf 0 -g 0 -maxrate:0 90M -aspect 16:9 -map 0:1 -c:a mp2 -b:a 384k -shortest -f mpegts "{2}"'.format(
infile, videofilter, outfile)
if args.debug:
print(cmd)
run(cmd)
return event_id
if args.ids:
if len(args.ids) == 1:
print("enqueuing {} job".format(len(args.ids)))
else:
print("enqueuing {} jobs".format(len(args.ids)))
else:
if len(events) == 1:
print("enqueuing {} job".format(len(events)))
else:
print("enqueuing {} jobs".format(len(events)))
for event in events:
if args.ids and event['id'] not in args.ids:
continue
if args.rooms and event['room'] not in args.rooms:
print("skipping room %s (%s)" % (event['room'], event['title']))
continue
event_print(event, "enqueued as " + str(event['id']))
job_id = enqueue_job(event)
if not job_id:
event_print(event, "job was not enqueued successfully, skipping postprocessing")
continue
print('all done')

View file

@ -1,167 +1,155 @@
#!/usr/bin/env python3
# vim: tabstop=4 shiftwidth=4 expandtab
"""See jugendhackt/config.ini for some config file documentation."""
import os
import sys
import subprocess
import argparse
import ssl
from configparser import ConfigParser
from pathlib import PurePath
import platform
from PIL import ImageFont
import schedulelib
import argparse
import shlex
from PIL import ImageFont
from configparser import ConfigParser
import json
import platform
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
FRAME_WIDTH = 1920
# Parse arguments
parser = argparse.ArgumentParser(
description='C3VOC Intro-Outro-Generator - Variant which renders only using video filters in ffmpeg',
usage="./make-ffmpeg.py yourproject/",
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('project', action="store", metavar='Project folder', type=str, help='''
Path to your project folder
''')
parser.add_argument('--debug', action="store_true", default=False, help='''
Run script in debug mode and render with placeholder texts,
not parsing or accessing a schedule.
This argument must not be used together with --id
Usage: ./make-ffmpeg.py yourproject/ --debug
''')
parser.add_argument('--id', dest='ids', nargs='+', action="store", type=int, help='''
Only render the given ID(s) from your projects schedule.
This argument must not be used together with --debug
Usage: ./make-adobe-after-effects.py yourproject/ --id 4711 0815 4223 1337
''')
parser.add_argument('--room', dest='rooms', nargs='+', action="store", type=str, help='''
Only render the given room(s) from your projects schedule.
This argument must not be used together with --debug
Usage: ./make-adobe-after-effects.py yourproject/ --room "HfG_Studio" "ZKM_Vortragssaal"
''')
parser.add_argument('--skip', nargs='+', action="store", type=str, help='''
Skip ID(s) not needed to be rendered.
Usage: ./make-ffmpeg.py yourproject/ --skip 4711 0815 4223 1337
''')
parser.add_argument('--force', action="store_true", default=False, help='''
Force render if file exists.
''')
args = parser.parse_args()
if (args.skip is None):
args.skip = []
class TextConfig:
inpoint: float
outpoint: float
x: int
y: int
fontfile_path: str
fontsize: int
fontcolor: str
bordercolor: str = None # border is added, if a color is set
def uses_fontfile(self):
return self.fontfile_path is not None
def parse(self, cparser_sect, default_fontfile, default_fontcolor):
self.inpoint = cparser_sect.getfloat('in')
self.outpoint = cparser_sect.getfloat('out')
self.x = cparser_sect.getint('x')
self.y = cparser_sect.getint('y')
self.fontcolor = cparser_sect.get('fontcolor', default_fontcolor)
fontfile = cparser_sect.get('fontfile', default_fontfile)
self.fontfile_path = str(PurePath(args.project, fontfile).as_posix())
if not os.path.exists(self.fontfile_path):
error("Font file {} in Project Path is missing".format(self.fontfile_path))
self.fontsize = cparser_sect.getint('fontsize')
self.bordercolor = cparser_sect.get('bordercolor', None)
def fit_text(self, text: str) -> list[str]:
if not text:
return [""]
font = ImageFont.truetype(
self.fontfile_path, size=self.fontsize, encoding="unic")
return fit_text(text, (FRAME_WIDTH-self.x-100), font)
def get_ffmpeg_filter(self, inout_type: str, fade_time: float, text: list[str]):
if not text:
return ""
text_duration = self.outpoint - self.inpoint
filter_str = ""
for idx, line in enumerate(text):
filter_str += "drawtext=enable='between({},{},{})':x={}:y={}".format(
inout_type, self.inpoint, self.outpoint, self.x, self.y + (idx*self.fontsize))
filter_str += ":fontfile='{}':fontsize={}:fontcolor={}:text={}".format(
self.fontfile_path, self.fontsize, self.fontcolor, ffmpeg_escape_str(line))
if self.bordercolor is not None:
filter_str += ":borderw={}:bordercolor={}".format(
self.fontsize / 30, self.bordercolor)
if fade_time > 0:
filter_str += ":alpha='if(lt(t,{fade_in_start_time}),0,if(lt(t,{fade_in_end_time}),(t-{fade_in_start_time})/{fade_duration},if(lt(t,{fade_out_start_time}),1,if(lt(t,{fade_out_end_time}),({fade_duration}-(t-{fade_out_start_time}))/{fade_duration},0))))'".format(
fade_in_start_time=self.inpoint,
fade_in_end_time=self.inpoint + fade_time,
fade_out_start_time=self.inpoint + fade_time + text_duration,
fade_out_end_time=self.inpoint + fade_time + text_duration + fade_time,
fade_duration=fade_time)
filter_str += ","
return filter_str[:-1]
class Config:
schedule: str
template_file: str # video background
alpha: bool = False
prores: bool = False
inout_type: str = "t" # in and out time format: t for seconds, n for frame number
fade_duration: float = 0 # fade duration in seconds, 0 to disable
fileext: str
title: TextConfig
speaker: TextConfig
text: TextConfig
extra_text: str = "" # additional text
def parse_config(filename) -> Config:
if not os.path.exists(filename):
error("config.ini file in Project Path is missing")
conf = Config()
cparser = ConfigParser()
cparser.read(filename)
meta = cparser['meta']
conf.schedule = meta.get('schedule')
infile = PurePath(args.project, meta.get('template'))
conf.template_file = str(infile)
conf.alpha = meta.getboolean('alpha', conf.alpha)
conf.prores = meta.getboolean('prores', conf.prores)
conf.inout_type = meta.get('inout_type', conf.inout_type)
conf.fade_duration = meta.getfloat('fade_duration', conf.fade_duration)
defaults = cparser['default']
default_fontfile = defaults.get('fontfile', None)
default_fontcolor = defaults.get('fontcolor', "#ffffff")
conf.title = TextConfig()
conf.title.parse(cparser['title'], default_fontfile, default_fontcolor)
conf.speaker = TextConfig()
conf.speaker.parse(cparser['speaker'], default_fontfile, default_fontcolor)
conf.text = TextConfig()
conf.text.parse(cparser['text'], default_fontfile, default_fontcolor)
conf.extra_text = cparser['text'].get('text', '')
conf.fileext = infile.suffix
if not os.path.exists(conf.template_file):
error("Template file {} in Project Path is missing".format(conf.template_file))
if conf.alpha and conf.fileext != '.mov':
error("Alpha can only be rendered with .mov source files")
if not args.project:
error("The Project Path is a required argument")
if not args.debug and not conf.schedule:
error("Either specify --debug or supply a schedule in config.ini")
return conf
def error(err_str):
def headline(str):
print("##################################################")
print(err_str)
print(str)
print("##################################################")
print()
def error(str):
headline(str)
parser.print_help()
sys.exit(1)
cparser = ConfigParser()
cparser.read(os.path.join(os.path.dirname(args.project), 'config.ini'))
template = cparser['default']['template']
alpha = cparser['default']['alpha']
prores = cparser['default']['prores']
fontfile = cparser['default']['fontfile'] # use a font file instead of a font family
inout = cparser['default']['inout'] # in and out time format: t for seconds, n for frame number
title_in = cparser['title']['in']
title_out = cparser['title']['out']
title_fontfamily = cparser['title']['fontfamily']
title_fontfile = cparser['title']['fontfile']
title_fontsize = cparser['title']['fontsize']
title_fontcolor = cparser['title']['fontcolor']
title_x = cparser['title']['x']
title_y = cparser['title']['y']
speaker_in = cparser['speaker']['in']
speaker_out = cparser['speaker']['out']
speaker_fontfamily = cparser['speaker']['fontfamily']
speaker_fontfile = cparser['speaker']['fontfile']
speaker_fontsize = cparser['speaker']['fontsize']
speaker_fontcolor = cparser['speaker']['fontcolor']
speaker_x = cparser['speaker']['x']
speaker_y = cparser['speaker']['y']
text_in = cparser['text']['in']
text_out = cparser['text']['out']
text_fontfamily = cparser['text']['fontfamily']
text_fontfile = cparser['text']['fontfile']
text_fontsize = cparser['text']['fontsize']
text_fontcolor = cparser['text']['fontcolor']
text_x = cparser['text']['x']
text_y = cparser['text']['y']
text_text = cparser['text']['text']
font_t = os.path.join(os.path.dirname(args.project), title_fontfile)
font_s = os.path.join(os.path.dirname(args.project), speaker_fontfile)
font_tt = os.path.join(os.path.dirname(args.project), text_fontfile)
fileformat = os.path.splitext(template)[1]
infile = os.path.join(os.path.dirname(args.project), template)
schedule = cparser['default']['schedule']
if not (os.path.exists(os.path.join(args.project, template))):
error("Template file {} in Project Path is missing".format(template))
for ffile in (title_fontfile, speaker_fontfile, text_fontfile):
if not (os.path.exists(os.path.join(args.project, ffile))):
error("Font file {} in Project Path is missing".format(ffile))
if not (os.path.exists(os.path.join(args.project, 'config.ini'))):
error("config.ini file in Project Path is missing")
if alpha == 'true' and not fileformat == '.mov':
error("Alpha can only be rendered with .mov source files")
if not args.project:
error("The Project Path is a required argument")
if not args.debug and not schedule:
error("Either specify --debug or supply a schedule in config.ini")
if args.debug:
persons = ['Thomas Roth', 'Dmitry Nedospasov', 'Josh Datko',]
events = [{
'id': 'debug',
'title': 'wallet.fail',
'subtitle': 'Hacking the most popular cryptocurrency hardware wallets',
'persons': persons,
'personnames': ', '.join(persons),
'room': 'Borg',
}]
else:
events = list(schedulelib.events(schedule))
def describe_event(event):
return "#{}: {}".format(event['id'], event['title'])
@ -170,184 +158,164 @@ def event_print(event, message):
print("{} {}".format(describe_event(event), message))
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."""
def fmt_command(command, **kwargs):
args = {}
for key, value in kwargs.items():
args[key] = shlex.quote(value)
command = command.format(**args)
return shlex.split(command)
def run(command, **kwargs):
return subprocess.check_call(
fmt_command(command, **kwargs),
stderr=subprocess.STDOUT,
stdout=subprocess.DEVNULL)
def fit_text(string: str, frame_width):
split_line = [x.strip() for x in string.split()]
lines = []
lines = ""
w = 0
line = []
line_num = 0
line = ""
for word in split_line:
new_line = line + [word.rstrip(':')]
w = font.getlength(" ".join(new_line))
if w > max_width:
lines.append(' '.join(line))
line = []
left, top, right, bottom = translation_font.getbbox(" ".join([line, word]))
width, height = right - left, bottom - top
if width > (frame_width - (2 * 6)):
lines += line.strip() + "\n"
line = ""
line.append(word.rstrip(':'))
if word.endswith(':'):
lines.append(' '.join(line))
line = []
if line:
lines.append(' '.join(line))
line += word + " "
lines += line.strip()
return lines
def ffmpeg_escape_str(text: str) -> str:
# Escape according to https://ffmpeg.org/ffmpeg-filters.html#Notes-on-filtergraph-escaping
# and don't put the string in quotes afterwards!
text = text.replace(",", r"\,")
text = text.replace(':', r"\\:")
text = text.replace("'", r"\\\'")
def fit_title(string: str, fontsize: int, x_offset: int):
global translation_font
translation_font = ImageFont.truetype(
font_t, size=fontsize, encoding="unic")
title = fit_text(string, (1920-x_offset-100))
return text
return title
def enqueue_job(conf: Config, event):
def fit_speaker(string: str, fontsize: int, x_offset: int):
global translation_font
translation_font = ImageFont.truetype(
font_s, size=fontsize, encoding="unic")
speaker = fit_text(string, (1920-x_offset-100))
return speaker
def enqueue_job(event):
event_id = str(event['id'])
outfile = str(PurePath(args.project, event_id + '.ts'))
outfile_mov = str(PurePath(args.project, event_id + '.mov'))
if event_id in args.skip:
event_print(event, "skipping " + str(event['id']))
return
if (os.path.exists(outfile) or os.path.exists(outfile_mov)) and not args.force:
if (os.path.exists(os.path.join(args.project, event_id + '.ts')) or os.path.exists(os.path.join(args.project, event_id + '.mov'))) and not args.force:
event_print(event, "file exist, skipping " + str(event['id']))
return
event_title = str(event['title'])
event_personnames = str(event['personnames'])
event_title = event_title.replace('"', '\\"')
event_title = event_title.replace('\'', '')
event_personnames = event_personnames.replace('"', '\\"')
title = conf.title.fit_text(event_title)
speakers = conf.speaker.fit_text(event_personnames)
extra_text = conf.text.fit_text(conf.extra_text)
t = fit_title(event_title, int(title_fontsize), int(title_x))
t = t.replace(':', "\:") # the ffmpeg command needs colons to be escaped
s = fit_speaker(event_personnames, int(speaker_fontsize), int(speaker_x))
if args.debug:
print('Title: ', title)
print('Speaker: ', speakers)
print('Title: ', t)
print('Speaker: ', s)
outfile = os.path.join(os.path.dirname(args.project), event_id + '.ts')
if platform.system() == 'Windows':
ffmpeg_path = './ffmpeg.exe'
font_t_win = "/".join(font_t.split("\\"))
font_s_win = "/".join(font_s.split("\\"))
font_tt_win = "/".join(font_tt.split("\\"))
else:
ffmpeg_path = 'ffmpeg'
videofilter = conf.title.get_ffmpeg_filter(conf.inout_type, conf.fade_duration, title) + ","
videofilter += conf.speaker.get_ffmpeg_filter(conf.inout_type,
conf.fade_duration, speakers) + ","
videofilter += conf.text.get_ffmpeg_filter(conf.inout_type, conf.fade_duration, extra_text)
cmd = [ffmpeg_path, '-y', '-i', conf.template_file, '-vf', videofilter]
if conf.fileext == '.mov' and conf.alpha:
if conf.prores:
cmd += ['-vcodec', 'prores_ks', '-pix_fmt', 'yuva444p10le', '-profile:v',
'4444', '-shortest', '-movflags', 'faststart', '-f', 'mov', outfile_mov]
if fontfile == 'true':
if platform.system() == 'Windows':
videofilter = "drawtext=enable='between({8},{0},{1})':fontfile='{2}':fontsize={3}:fontcolor={4}:x={5}:y={6}:text='{7}',".format(
title_in, title_out, font_t_win, title_fontsize, title_fontcolor, title_x, title_y, t, inout)
videofilter += "drawtext=enable='between({8},{0},{1})':fontfile='{2}':fontsize={3}:fontcolor={4}:x={5}:y={6}:text='{7}',".format(
speaker_in, speaker_out, font_s_win, speaker_fontsize, speaker_fontcolor, speaker_x, speaker_y, s, inout)
videofilter += "drawtext=enable='between({8},{0},{1})':fontfile='{2}':fontsize={3}:fontcolor={4}:x={5}:y={6}:text='{7}'".format(
text_in, text_out, font_tt_win, text_fontsize, text_fontcolor, text_x, text_y, text_text, inout)
else:
cmd += ['-shortest', '-c:v', 'qtrle', '-movflags',
'faststart', '-f', 'mov', outfile_mov]
videofilter = "drawtext=enable='between({8},{0},{1})':fontfile='{2}':fontsize={3}:fontcolor={4}:x={5}:y={6}:text='{7}',".format(
title_in, title_out, font_t, title_fontsize, title_fontcolor, title_x, title_y, t, inout)
videofilter += "drawtext=enable='between({8},{0},{1})':fontfile='{2}':fontsize={3}:fontcolor={4}:x={5}:y={6}:text='{7}',".format(
speaker_in, speaker_out, font_s, speaker_fontsize, speaker_fontcolor, speaker_x, speaker_y, s, inout)
videofilter += "drawtext=enable='between({8},{0},{1})':fontfile='{2}':fontsize={3}:fontcolor={4}:x={5}:y={6}:text='{7}'".format(
text_in, text_out, font_tt, text_fontsize, text_fontcolor, text_x, text_y, text_text, inout)
else:
cmd += ['-map', '0:0', '-c:v', 'mpeg2video', '-q:v', '2', '-aspect', '16:9', '-map',
'0:1', '-c:a', 'mp2', '-b:a', '384k', '-shortest', '-f', 'mpegts', outfile]
videofilter = "drawtext=enable='between({8},{0},{1})':font='{2}':fontsize={3}:fontcolor={4}:x={5}:y={6}:text='{7}',".format(
title_in, title_out, title_fontfamily, title_fontsize, title_fontcolor, title_x, title_y, t, inout)
videofilter += "drawtext=enable='between({8},{0},{1})':font='{2}':fontsize={3}:fontcolor={4}:x={5}:y={6}:text='{7}',".format(
speaker_in, speaker_out, speaker_fontfamily, speaker_fontsize, speaker_fontcolor, speaker_x, speaker_y, s, inout)
videofilter += "drawtext=enable='between({8},{0},{1})':font='{2}':fontsize={3}:fontcolor={4}:x={5}:y={6}:text='{7}'".format(
text_in, text_out, text_fontfamily, text_fontsize, text_fontcolor, text_x, text_y, text_text, inout)
if fileformat == '.mov':
if alpha == 'true':
if prores == 'true':
cmd = '{3} -y -i "{0}" -vf "{1}" -vcodec prores_ks -pix_fmt yuva444p10le -profile:v 4444 -shortest -movflags faststart -f mov "{2}"'.format(
infile, videofilter, outfile, ffmpeg_path)
else:
cmd = '{3} -y -i "{0}" -vf "{1}" -shortest -c:v qtrle -movflags faststart -f mov "{2}"'.format(
infile, videofilter, outfile, ffmpeg_path)
else:
cmd = '{3} -y -i "{0}" -vf "{1}" -map 0:0 -c:v mpeg2video -q:v 2 -aspect 16:9 -map 0:1 -c:a mp2 -b:a 384k -shortest -f mpegts "{2}"'.format(
infile, videofilter, outfile, ffmpeg_path)
else:
cmd = '{3} -y -i "{0}" -vf "{1}" -map 0:0 -c:v mpeg2video -q:v 2 -aspect 16:9 -map 0:1 -c:a mp2 -b:a 384k -shortest -f mpegts "{2}"'.format(
infile, videofilter, outfile, ffmpeg_path)
if args.debug:
print(cmd)
subprocess.check_call(cmd,
stderr=subprocess.STDOUT,
stdout=subprocess.DEVNULL
)
run(cmd)
return event_id
if __name__ == "__main__":
# Parse arguments
parser = argparse.ArgumentParser(
description='C3VOC Intro-Outro-Generator - Variant which renders only using video filters in ffmpeg',
usage="./make-ffmpeg.py yourproject/",
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('project', action="store", metavar='Project folder', type=str, help='''
Path to your project folder
''')
parser.add_argument('--debug', action="store_true", default=False, help='''
Run script in debug mode and render with placeholder texts,
not parsing or accessing a schedule.
This argument must not be used together with --id
Usage: ./make-ffmpeg.py yourproject/ --debug
''')
parser.add_argument('--id', dest='ids', nargs='+', action="store", type=int, help='''
Only render the given ID(s) from your projects schedule.
This argument must not be used together with --debug
Usage: ./make-adobe-after-effects.py yourproject/ --id 4711 0815 4223 1337
''')
parser.add_argument('--room', dest='rooms', nargs='+', action="store", type=str, help='''
Only render the given room(s) from your projects schedule.
This argument must not be used together with --debug
Usage: ./make-adobe-after-effects.py yourproject/ --room "HfG_Studio" "ZKM_Vortragssaal"
''')
parser.add_argument('--skip', nargs='+', action="store", type=str, help='''
Skip ID(s) not needed to be rendered.
Usage: ./make-ffmpeg.py yourproject/ --skip 4711 0815 4223 1337
''')
parser.add_argument('--force', action="store_true", default=False, help='''
Force render if file exists.
''')
args = parser.parse_args()
if (args.skip is None):
args.skip = []
config = parse_config(PurePath(args.project, 'config.ini'))
if args.debug:
persons = ['Thomas Roth', 'Dmitry Nedospasov', 'Josh Datko',]
events = [{
'id': 'debug',
'title': 'wallet.fail and the longest talk title to test if the template is big enough',
'subtitle': 'Hacking the most popular cryptocurrency hardware wallets',
'persons': persons,
'personnames': ', '.join(persons),
'room': 'Borg',
}]
if args.ids:
if len(args.ids) == 1:
print("enqueuing {} job".format(len(args.ids)))
else:
events = list(schedulelib.events(config.schedule))
if args.ids:
if len(args.ids) == 1:
print("enqueuing {} job".format(len(args.ids)))
else:
print("enqueuing {} jobs".format(len(args.ids)))
print("enqueuing {} jobs".format(len(args.ids)))
else:
if len(events) == 1:
print("enqueuing {} job".format(len(events)))
else:
if len(events) == 1:
print("enqueuing {} job".format(len(events)))
else:
print("enqueuing {} jobs".format(len(events)))
print("enqueuing {} jobs".format(len(events)))
for event in events:
if args.ids and event['id'] not in args.ids:
continue
if args.rooms and event['room'] not in args.rooms:
print("skipping room %s (%s)" % (event['room'], event['title']))
continue
for event in events:
if args.ids and event['id'] not in args.ids:
continue
event_print(event, "enqueued as " + str(event['id']))
if args.rooms and event['room'] not in args.rooms:
print("skipping room %s (%s)" % (event['room'], event['title']))
continue
job_id = enqueue_job(config, event)
if not job_id:
event_print(event, "job was not enqueued successfully, skipping postprocessing")
continue
event_print(event, "enqueued as " + str(event['id']))
print('all done')
job_id = enqueue_job(event)
if not job_id:
event_print(event, "job was not enqueued successfully, skipping postprocessing")
continue
print('all done')

View file

@ -1,14 +1,16 @@
[meta]
[default]
#schedule = https://talks.mrmcd.net/2019/schedule/export/schedule.xml
schedule = file:///home/thorti/git/c3voc/intro-outro-generator/mrmcd2019/schedule.xml
template = mrmcd2019.mov
alpha = false
prores = false
inout_type = n
fontfile = true
inout = n
[title]
in = 50
out = 225
fontfamily =
fontfile = Jura-Bold.ttf
fontsize = 80
fontcolor = #47acda
@ -18,6 +20,7 @@ y = 540
[speaker]
in = 75
out = 225
fontfamily =
fontfile = Jura-Regular.ttf
fontsize = 50
fontcolor = #094762
@ -27,9 +30,10 @@ y = 950
[text]
in = 242
out = 324
fontfamily =
fontfile = Jura-Regular.ttf
fontsize = 45
fontcolor = #c68100
x = (w-text_w)/2
y = 927
; text =
text = ''

View file

@ -1,148 +0,0 @@
#!/usr/bin/python3
from renderlib import *
from schedulelib import *
from easing import *
# URL to Schedule-XML
scheduleUrl = 'https://pretalx.sysmocom.de/osmodevcon2024/schedule/export/schedule.xml'
def introFrames(args):
#fade in title
frames = 3*fps
for i in range(0, frames):
yield(
('title', 'style', 'opacity', easeInQuad(i, 0, 1, frames)),
)
# fade in subtitle and names
frames = 1*fps
for i in range(0, frames):
yield(
('title', 'style', 'opacity', 1),
('subtitle', 'style', 'opacity', easeInQuad(i, 0, 1, frames)),
('personnames', 'style', 'opacity', easeInQuad(i, 0, 1, frames)),
)
#show whole image for 2 seconds
frames = 2*fps
for i in range(0, frames):
yield(
('title', 'style', 'opacity', 1),
('personnames', 'style', 'opacity', 1),
('subtitle', 'style', 'opacity', 1),
)
def backgroundFrames(parameters):
frames = 5*fps
for i in range(0, frames):
yield(
('logo', 'style', 'opacity', 1),
)
def outroFrames(args):
frames = 2*fps
for i in range(0, frames):
yield(
('logo', 'style', 'opacity', 1),
('sublogo', 'style', 'opacity', 1),
('cclogo', 'style', 'opacity', 1),
)
# fade out
frames = 3*fps
for i in range(0, frames):
yield(
('logo', 'style', 'opacity', "%.4f" % easeInCubic(i, 1, -1, frames)),
('sublogo', 'style', 'opacity', "%.4f" % easeInCubic(i, 1, -1, frames)),
('cclogo', 'style', 'opacity', "%.4f" % easeInCubic(i, 1, -1, frames)),
)
def pauseFrames(args):
#fade in pause
frames = 4*fps
for i in range(0, frames):
yield(
('pause', 'style', 'opacity', "%.4f" % easeInCubic(i, 0.2, 1, frames)),
)
# fade out
frames = 4*fps
for i in range(0, frames):
yield(
('pause', 'style', 'opacity', "%.4f" % easeInCubic(i, 1, -0.8, frames)),
)
def debug():
render('intro.svg',
'../intro.ts',
introFrames,
{
'$id': 7776,
'$title': 'Configuring + running GPRS/EDGE data services with OsmoPCU, OsmoSGSN and OpenGGSN',
'$subtitle': 'With some subtitle!',
'$personnames': 'Alexander Chemeris + Harald Welte'
}
)
render('outro.svg',
'../outro.ts',
outroFrames
)
render(
'background.svg',
'../background.ts',
backgroundFrames
)
render('pause.svg',
'../pause.ts',
pauseFrames
)
def tasks(queue, args, idlist, skiplist):
# iterate over all events extracted from the schedule xml-export
for event in events(scheduleUrl):
if not (idlist==[]):
if 000000 in idlist:
print("skipping id (%s [%s])" % (event['title'], event['id']))
continue
if int(event['id']) not in idlist:
print("skipping id (%s [%s])" % (event['title'], event['id']))
continue
# generate a task description and put them into the queue
queue.put(Rendertask(
infile = 'intro.svg',
outfile = str(event['id'])+".ts",
sequence = introFrames,
parameters = {
'$id': event['id'],
'$title': event['title'],
'$subtitle': event['subtitle'],
'$personnames': event['personnames']
}
))
# place a task for the outro into the queue
if not "out" in skiplist:
queue.put(Rendertask(
infile = 'outro.svg',
outfile = 'outro.ts',
sequence = outroFrames
))
# place the pause-sequence into the queue
if not "pause" in skiplist:
queue.put(Rendertask(
infile = 'pause.svg',
outfile = 'pause.ts',
sequence = pauseFrames
))
# place the background-sequence into the queue
if not "bg" in skiplist:
queue.put(Rendertask(
infile = 'background.svg',
outfile = 'background.ts',
sequence = backgroundFrames
))

View file

@ -1,946 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="508mm"
height="285.74997mm"
viewBox="0 0 1800 1012.4999"
id="svg2"
version="1.1"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="background.svg"
inkscape:export-filename="background.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs4">
<linearGradient
id="linearGradient3374-5-7-7-0">
<stop
id="stop3376-8-6-4-2"
style="stop-color:#729fcf;stop-opacity:1"
offset="0" />
<stop
id="stop3378-6-7-4-9"
style="stop-color:#729fcf;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient3362-8-6-0-9">
<stop
id="stop3364-4-5-78-9"
style="stop-color:#3465a4;stop-opacity:1"
offset="0" />
<stop
id="stop3366-7-6-6-4"
style="stop-color:#3465a4;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
x1="24.837126"
y1="44.528019"
x2="21.036427"
y2="21.041553"
id="linearGradient3991-3-88-5"
xlink:href="#linearGradient7101-4-9-4-1"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient7101-4-9-4-1">
<stop
id="stop7103-0-4-31-0"
style="stop-color:#babdb6;stop-opacity:1"
offset="0" />
<stop
id="stop7105-6-8-4-3"
style="stop-color:#ffffff;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
x1="39.06765"
y1="28.5"
x2="39.421204"
y2="10.934953"
id="linearGradient3993-1-9-7"
xlink:href="#linearGradient6979-9-2-2-8"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient6979-9-2-2-8">
<stop
id="stop6981-9-9-0-8"
style="stop-color:#888a85;stop-opacity:1"
offset="0" />
<stop
id="stop6983-0-3-6-6"
style="stop-color:#555753;stop-opacity:1"
offset="1" />
</linearGradient>
<radialGradient
cx="10.28125"
cy="7.8249326"
r="4.5250292"
fx="10.28125"
fy="7.8249326"
id="radialGradient3995-7-4-0"
xlink:href="#linearGradient3374-5-7-7-0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.2651111,0,0,2.2923498,16.215361,52.593597)" />
<radialGradient
cx="10.28125"
cy="9.8424416"
r="4.5250292"
fx="10.28125"
fy="9.8424416"
id="radialGradient3997-3-3-4"
xlink:href="#linearGradient3362-8-6-0-9"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(15.1803,0,0,5.0647752,-116.56897,28.614297)" />
<radialGradient
cx="8.9057236"
cy="1.7286602"
r="1.9952321"
fx="8.9057236"
fy="1.7286602"
id="radialGradient3999-1-4-6"
xlink:href="#linearGradient7131-6-1-5-7"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7375073,0,0,0.7201806,2.4345312,0.6617371)" />
<linearGradient
id="linearGradient7131-6-1-5-7">
<stop
id="stop7133-4-5-2-6"
style="stop-color:#ffffff;stop-opacity:1"
offset="0" />
<stop
id="stop7135-6-9-5-0"
style="stop-color:#d3d7cf;stop-opacity:1"
offset="1" />
</linearGradient>
<radialGradient
cx="8.3046875"
cy="1.1256332"
r="2.0507698"
fx="8.3046875"
fy="1.1256332"
id="radialGradient4001-9-6-9"
xlink:href="#linearGradient7153-0-1-9-75"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(5.2943491,0,0,5.2881329,-7.02204,58.291497)" />
<linearGradient
id="linearGradient7153-0-1-9-75">
<stop
id="stop7155-8-7-3-9"
style="stop-color:#ffffff;stop-opacity:1"
offset="0" />
<stop
id="stop7157-5-7-7-7"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
x1="24.837126"
y1="44.528019"
x2="21.036427"
y2="21.041553"
id="linearGradient3991-3-88-5-3"
xlink:href="#linearGradient7101-4-9-4-1"
gradientUnits="userSpaceOnUse" />
<linearGradient
x1="39.06765"
y1="28.5"
x2="39.421204"
y2="10.934953"
id="linearGradient3993-1-9-7-2"
xlink:href="#linearGradient6979-9-2-2-8"
gradientUnits="userSpaceOnUse" />
<radialGradient
cx="10.28125"
cy="7.8249326"
r="4.5250292"
fx="10.28125"
fy="7.8249326"
id="radialGradient3995-7-4-0-2"
xlink:href="#linearGradient3374-5-7-7-0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.2651111,0,0,2.2923498,16.215361,52.593597)" />
<radialGradient
cx="10.28125"
cy="9.8424416"
r="4.5250292"
fx="10.28125"
fy="9.8424416"
id="radialGradient3997-3-3-4-7"
xlink:href="#linearGradient3362-8-6-0-9"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(15.1803,0,0,5.0647752,-116.56897,28.614297)" />
<radialGradient
cx="8.9057236"
cy="1.7286602"
r="1.9952321"
fx="8.9057236"
fy="1.7286602"
id="radialGradient3999-1-4-6-0"
xlink:href="#linearGradient7131-6-1-5-7"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7375073,0,0,0.7201806,2.4345312,0.6617371)" />
<radialGradient
cx="8.3046875"
cy="1.1256332"
r="2.0507698"
fx="8.3046875"
fy="1.1256332"
id="radialGradient4001-9-6-9-6"
xlink:href="#linearGradient7153-0-1-9-75"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(5.2943491,0,0,5.2881329,-7.02204,58.291497)" />
<linearGradient
x1="24.837126"
y1="44.528019"
x2="21.036427"
y2="21.041553"
id="linearGradient3991-3-88-5-3-4"
xlink:href="#linearGradient7101-4-9-4-1"
gradientUnits="userSpaceOnUse" />
<linearGradient
x1="39.06765"
y1="28.5"
x2="39.421204"
y2="10.934953"
id="linearGradient3993-1-9-7-2-4"
xlink:href="#linearGradient6979-9-2-2-8"
gradientUnits="userSpaceOnUse" />
<radialGradient
cx="10.28125"
cy="7.8249326"
r="4.5250292"
fx="10.28125"
fy="7.8249326"
id="radialGradient3995-7-4-0-2-3"
xlink:href="#linearGradient3374-5-7-7-0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.2651111,0,0,2.2923498,16.215361,52.593597)" />
<radialGradient
cx="10.28125"
cy="9.8424416"
r="4.5250292"
fx="10.28125"
fy="9.8424416"
id="radialGradient3997-3-3-4-7-1"
xlink:href="#linearGradient3362-8-6-0-9"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(15.1803,0,0,5.0647752,-116.56897,28.614297)" />
<radialGradient
cx="8.9057236"
cy="1.7286602"
r="1.9952321"
fx="8.9057236"
fy="1.7286602"
id="radialGradient3999-1-4-6-0-7"
xlink:href="#linearGradient7131-6-1-5-7"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7375073,0,0,0.7201806,2.4345312,0.6617371)" />
<radialGradient
cx="8.3046875"
cy="1.1256332"
r="2.0507698"
fx="8.3046875"
fy="1.1256332"
id="radialGradient4001-9-6-9-6-6"
xlink:href="#linearGradient7153-0-1-9-75"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(5.2943491,0,0,5.2881329,-7.02204,58.291497)" />
<radialGradient
cx="10.28125"
cy="7.8249326"
r="4.5250292"
fx="10.28125"
fy="7.8249326"
id="radialGradient3995-7-4-0-2-2"
xlink:href="#linearGradient3374-5-7-7-0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.2651111,0,0,2.2923498,16.215361,52.593597)" />
<radialGradient
cx="10.28125"
cy="9.8424416"
r="4.5250292"
fx="10.28125"
fy="9.8424416"
id="radialGradient3997-3-3-4-7-7"
xlink:href="#linearGradient3362-8-6-0-9"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(15.1803,0,0,5.0647752,-116.56897,28.614297)" />
<radialGradient
cx="8.9057236"
cy="1.7286602"
r="1.9952321"
fx="8.9057236"
fy="1.7286602"
id="radialGradient3999-1-4-6-0-0"
xlink:href="#linearGradient7131-6-1-5-7"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7375073,0,0,0.7201806,2.4345312,0.6617371)" />
<radialGradient
cx="8.3046875"
cy="1.1256332"
r="2.0507698"
fx="8.3046875"
fy="1.1256332"
id="radialGradient4001-9-6-9-6-60"
xlink:href="#linearGradient7153-0-1-9-75"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(5.2943491,0,0,5.2881329,-7.02204,58.291497)" />
<radialGradient
cx="10.28125"
cy="7.8249326"
r="4.5250292"
fx="10.28125"
fy="7.8249326"
id="radialGradient3995-7-4-0-2-2-0"
xlink:href="#linearGradient3374-5-7-7-0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.2651111,0,0,2.2923498,16.215361,52.593597)" />
<radialGradient
cx="10.28125"
cy="9.8424416"
r="4.5250292"
fx="10.28125"
fy="9.8424416"
id="radialGradient3997-3-3-4-7-7-6"
xlink:href="#linearGradient3362-8-6-0-9"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(15.1803,0,0,5.0647752,-116.56897,28.614297)" />
<radialGradient
cx="8.9057236"
cy="1.7286602"
r="1.9952321"
fx="8.9057236"
fy="1.7286602"
id="radialGradient3999-1-4-6-0-0-3"
xlink:href="#linearGradient7131-6-1-5-7"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7375073,0,0,0.7201806,2.4345312,0.6617371)" />
<radialGradient
cx="8.3046875"
cy="1.1256332"
r="2.0507698"
fx="8.3046875"
fy="1.1256332"
id="radialGradient4001-9-6-9-6-60-6"
xlink:href="#linearGradient7153-0-1-9-75"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(5.2943491,0,0,5.2881329,-7.02204,58.291497)" />
<radialGradient
cx="10.28125"
cy="7.8249326"
r="4.5250292"
fx="10.28125"
fy="7.8249326"
id="radialGradient3995-7-4-0-2-2-0-4"
xlink:href="#linearGradient3374-5-7-7-0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.2651111,0,0,2.2923498,16.215361,52.593597)" />
<radialGradient
cx="10.28125"
cy="9.8424416"
r="4.5250292"
fx="10.28125"
fy="9.8424416"
id="radialGradient3997-3-3-4-7-7-6-7"
xlink:href="#linearGradient3362-8-6-0-9"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(15.1803,0,0,5.0647752,-116.56897,28.614297)" />
<radialGradient
cx="8.9057236"
cy="1.7286602"
r="1.9952321"
fx="8.9057236"
fy="1.7286602"
id="radialGradient3999-1-4-6-0-0-3-4"
xlink:href="#linearGradient7131-6-1-5-7"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7375073,0,0,0.7201806,2.4345312,0.6617371)" />
<radialGradient
cx="8.3046875"
cy="1.1256332"
r="2.0507698"
fx="8.3046875"
fy="1.1256332"
id="radialGradient4001-9-6-9-6-60-6-0"
xlink:href="#linearGradient7153-0-1-9-75"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(5.2943491,0,0,5.2881329,-7.02204,58.291497)" />
<radialGradient
r="4.5250292"
fy="8.0709476"
fx="10.28125"
cy="8.0709476"
cx="10.28125"
gradientTransform="matrix(4.9499444,0,0,4.9510321,-11.38809,35.312197)"
gradientUnits="userSpaceOnUse"
id="radialGradient3637-3"
xlink:href="#linearGradient3374-5-7-7-0"
inkscape:collect="always" />
<radialGradient
r="4.5250292"
fy="9.8424416"
fx="10.28125"
cy="9.8424416"
cx="10.28125"
gradientTransform="matrix(23.169932,0,0,7.6402677,-198.71238,8.843597)"
gradientUnits="userSpaceOnUse"
id="radialGradient3639-5"
xlink:href="#linearGradient3362-8-6-0-9"
inkscape:collect="always" />
<radialGradient
cx="10.28125"
cy="7.8249326"
r="4.5250292"
fx="10.28125"
fy="7.8249326"
id="radialGradient3995-7-4-0-2-2-0-9"
xlink:href="#linearGradient3374-5-7-7-0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.2651111,0,0,2.2923498,16.215361,52.593597)" />
<radialGradient
cx="10.28125"
cy="9.8424416"
r="4.5250292"
fx="10.28125"
fy="9.8424416"
id="radialGradient3997-3-3-4-7-7-6-1"
xlink:href="#linearGradient3362-8-6-0-9"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(15.1803,0,0,5.0647752,-116.56897,28.614297)" />
<radialGradient
cx="8.9057236"
cy="1.7286602"
r="1.9952321"
fx="8.9057236"
fy="1.7286602"
id="radialGradient3999-1-4-6-0-0-3-2"
xlink:href="#linearGradient7131-6-1-5-7"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7375073,0,0,0.7201806,2.4345312,0.6617371)" />
<radialGradient
cx="8.3046875"
cy="1.1256332"
r="2.0507698"
fx="8.3046875"
fy="1.1256332"
id="radialGradient4001-9-6-9-6-60-6-9"
xlink:href="#linearGradient7153-0-1-9-75"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(5.2943491,0,0,5.2881329,-7.02204,58.291497)" />
<radialGradient
cx="10.28125"
cy="7.8249326"
r="4.5250292"
fx="10.28125"
fy="7.8249326"
id="radialGradient3995-7-4-0-2-2-0-9-7"
xlink:href="#linearGradient3374-5-7-7-0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.2651111,0,0,2.2923498,16.215361,52.593597)" />
<radialGradient
cx="10.28125"
cy="9.8424416"
r="4.5250292"
fx="10.28125"
fy="9.8424416"
id="radialGradient3997-3-3-4-7-7-6-1-5"
xlink:href="#linearGradient3362-8-6-0-9"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(15.1803,0,0,5.0647752,-116.56897,28.614297)" />
<radialGradient
cx="8.9057236"
cy="1.7286602"
r="1.9952321"
fx="8.9057236"
fy="1.7286602"
id="radialGradient3999-1-4-6-0-0-3-2-9"
xlink:href="#linearGradient7131-6-1-5-7"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7375073,0,0,0.7201806,2.4345312,0.6617371)" />
<radialGradient
cx="8.3046875"
cy="1.1256332"
r="2.0507698"
fx="8.3046875"
fy="1.1256332"
id="radialGradient4001-9-6-9-6-60-6-9-8"
xlink:href="#linearGradient7153-0-1-9-75"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(5.2943491,0,0,5.2881329,-7.02204,58.291497)" />
<radialGradient
cx="10.28125"
cy="7.8249326"
r="4.5250292"
fx="10.28125"
fy="7.8249326"
id="radialGradient3995-7-4-0-9"
xlink:href="#linearGradient3374-5-7-7-0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.2651111,0,0,2.2923498,16.215361,52.593597)" />
<radialGradient
cx="10.28125"
cy="9.8424416"
r="4.5250292"
fx="10.28125"
fy="9.8424416"
id="radialGradient3997-3-3-4-1"
xlink:href="#linearGradient3362-8-6-0-9"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(15.1803,0,0,5.0647752,-116.56897,28.614297)" />
<radialGradient
cx="8.9057236"
cy="1.7286602"
r="1.9952321"
fx="8.9057236"
fy="1.7286602"
id="radialGradient3999-1-4-6-2"
xlink:href="#linearGradient7131-6-1-5-7"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7375073,0,0,0.7201806,2.4345312,0.6617371)" />
<radialGradient
cx="8.3046875"
cy="1.1256332"
r="2.0507698"
fx="8.3046875"
fy="1.1256332"
id="radialGradient4001-9-6-9-9"
xlink:href="#linearGradient7153-0-1-9-75"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(5.2943491,0,0,5.2881329,-7.02204,58.291497)" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="0.49497476"
inkscape:cx="-330.66755"
inkscape:cy="386.73989"
inkscape:document-units="px"
inkscape:current-layer="layer2"
showgrid="false"
units="mm"
inkscape:window-width="956"
inkscape:window-height="1041"
inkscape:window-x="960"
inkscape:window-y="37"
inkscape:window-maximized="0"
showguides="true"
inkscape:guide-bbox="true"
inkscape:measure-start="63.3968,-113.628"
inkscape:measure-end="34.3452,-129.3"
inkscape:snap-page="true"
inkscape:pagecheckerboard="true"
gridtolerance="5"
objecttolerance="10"
guidetolerance="10"
inkscape:lockguides="false">
<inkscape:grid
type="xygrid"
id="grid20483"
originx="0"
originy="-0.00012144696" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Background"
transform="translate(0,-67.5)"
style="display:inline">
<rect
style="opacity:1;fill:#1a1a1a;fill-opacity:1;stroke:none;stroke-width:1.00031257;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect20497"
width="1800"
height="1012.4999"
x="0"
y="67.5"
inkscape:label="bg color" />
</g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Text"
style="display:inline"
transform="translate(0,-67.5)">
<flowRoot
xml:space="preserve"
id="title"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;line-height:125%;font-family:'Trebuchet MS';-inkscape-font-specification:'Trebuchet MS, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;opacity:0;fill:#555555;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
transform="matrix(0.9375,0,0,0.9375,596.82417,403.33401)"
inkscape:label="title"
inkscape:transform-center-x="4.0178571"
inkscape:transform-center-y="-24.107143"><flowRegion
id="flowRegion20435"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;font-family:'Trebuchet MS';-inkscape-font-specification:'Trebuchet MS, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#555555;fill-opacity:1"><rect
id="rect20437"
width="604.28571"
height="189.99998"
x="61.42857"
y="67.714287"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;font-family:'Trebuchet MS';-inkscape-font-specification:'Trebuchet MS, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#555555;fill-opacity:1" /></flowRegion><flowPara
id="flowPara24792"
style="font-size:192px">Pause</flowPara></flowRoot> <flowRoot
xml:space="preserve"
id="flowRoot25337"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"><flowRegion
id="flowRegion25339"><rect
id="rect25341"
width="14.285714"
height="90"
x="902.85712"
y="472.85715" /></flowRegion><flowPara
id="flowPara25343" /></flowRoot> <flowRoot
inkscape:transform-center-y="-24.107143"
inkscape:transform-center-x="4.0178571"
inkscape:label="title"
transform="matrix(0.9375,0,0,0.9375,604.85988,449.04839)"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;line-height:125%;font-family:'Trebuchet MS';-inkscape-font-specification:'Trebuchet MS, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;opacity:0;fill:#555555;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="pause"
xml:space="preserve"><flowRegion
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;font-family:'Trebuchet MS';-inkscape-font-specification:'Trebuchet MS, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#555555;fill-opacity:1"
id="flowRegion25395"><rect
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;font-family:'Trebuchet MS';-inkscape-font-specification:'Trebuchet MS, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#555555;fill-opacity:1"
y="67.714287"
x="61.42857"
height="189.99998"
width="604.28571"
id="rect25393" /></flowRegion><flowPara
style="font-size:192px"
id="flowPara25397">Pause</flowPara></flowRoot> <g
id="g441"
transform="matrix(0.84639363,0,0,0.84639363,37.064912,38.785126)">
<text
id="text3760-7"
y="243.6349"
x="277.56836"
style="font-style:normal;font-weight:normal;font-size:81.56085968px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#a00000;fill-opacity:1;stroke:none;stroke-width:2.03902125"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.49736023px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';fill:#a00000;fill-opacity:1;stroke-width:2.03902125"
y="243.6349"
x="277.56836"
id="tspan3762-0"
sodipodi:role="line">o</tspan></text>
<path
inkscape:connector-curvature="0"
id="path3959-9-26-3"
d="m 221.54901,178.00783 -8.8372,15.20901 -4.0423,-6.95739 1.1988,54.79873 c 3.8707,-2.70354 5.2943,1.46986 5.3524,-0.6173 l 1.4178,-50.79232 c 3.0015,-1.56596 6.002,-2.21826 8.8729,-2.21826 5.22,0 7.2929,1.82538 7.4234,6.52328 l 0.5775,46.96519 c 3.6204,-1.02991 6.8905,0.79083 6.9055,-0.35065 l 0.6452,-48.85683 c 2.8709,-1.82699 7.1579,-4.15375 10.1592,-4.15375 5.22,0 6.2837,2.61406 6.3918,8.87693 l 0.7847,45.42003 c 2.4547,-0.3861 5.9417,1.23813 5.9736,-0.39459 l 0.9002,-45.80627 c 0.2308,-11.74253 1.3452,-17.49097 -11.7046,-17.49097 -5.3503,0 -11.6124,1.56672 -16.0494,4.04615 -2.4795,-2.60972 -6.1326,-4.04615 -11.7441,-4.04615 -1.5299,0 -2.9125,-0.0694 -4.2254,-0.15573 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:64px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Andale Mono';writing-mode:lr-tb;display:inline;fill:#a00000;fill-opacity:1;stroke:#a00000;stroke-width:2.03902125;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';display:inline;fill:none;fill-opacity:1;stroke:#e19c9c;stroke-width:10.19510746;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
id="path3981-0-4-1"
d="m 212.71081,193.21678 -9.1897,-15.80983 -9.1896,-15.80995 h 18.3793 18.3792 l -9.1896,15.80995 z" />
<path
inkscape:connector-curvature="0"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';display:inline;fill:none;stroke:#e19c9c;stroke-width:10.24006462;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path3983-4-9-2"
d="M 261.34211,239.81102 V 183.28218" />
<path
inkscape:connector-curvature="0"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';display:inline;fill:none;stroke:#e19c9c;stroke-width:10.19510746;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path3985-4-0-9"
d="M 236.92411,239.78722 V 199.37075" />
<path
inkscape:connector-curvature="0"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';display:inline;fill:none;stroke:#e19c9c;stroke-width:9.52051163;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path3951-0-4-91-2"
d="m 212.70941,240.14133 -0.022,-23.96402" />
<g
id="text5473"
style="font-style:normal;font-weight:normal;font-size:16.93333244px;line-height:125%;font-family:Sans;letter-spacing:0.03704167px;word-spacing:0px;display:inline;fill:#a00000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
transform="matrix(7.7065378,0,0,7.7065378,-370.09593,-1045.102)"
aria-label="Os">
<path
inkscape:connector-curvature="0"
id="path5483"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.93333244px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';letter-spacing:0.03704167px;fill:#a00000;fill-opacity:1;stroke-width:0.26458332"
d="m 60.829899,161.23206 c 0,4.8768 0.8636,6.1468 3.048,6.1468 2.2352,0 3.2004,-1.54094 3.2004,-6.1976 0,-4.572 -0.8128,-5.96054 -3.014133,-5.96054 -2.1844,0 -3.234267,1.50707 -3.234267,6.01134 z m 1.540934,0.33866 c 0,-3.6576 0.474133,-4.94453 1.659466,-4.94453 1.2192,0 1.557867,1.20227 1.557867,4.58893 0,3.4544 -0.423334,4.75827 -1.642533,4.75827 -1.202267,0 -1.5748,-1.25307 -1.5748,-4.40267 z" />
<path
inkscape:connector-curvature="0"
id="path5485"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.93333244px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';letter-spacing:0.03704167px;fill:#a00000;fill-opacity:1;stroke-width:0.26458332"
d="m 70.886976,158.59046 c -1.896533,0 -2.760133,0.8128 -2.760133,1.99813 0,0.5588 0.2032,1.1684 0.9652,1.79493 l 1.642533,1.40547 c 0.508,0.4572 0.677333,0.8636 0.677333,1.3208 0,0.67733 -0.508,1.04987 -1.371599,1.04987 -0.6604,0 -1.202267,-0.13547 -1.693334,-0.42334 -0.186266,0.3048 -0.237066,0.59267 -0.237066,0.79587 0,0.59267 0.8636,0.8636 2.065866,0.8636 1.7272,0 2.794,-0.84667 2.794,-2.35373 0,-0.84667 -0.270933,-1.40547 -0.999067,-2.11667 l -1.5748,-1.27 c -0.575733,-0.47413 -0.677333,-0.74507 -0.677333,-1.04987 0,-0.52493 0.541867,-0.8128 1.337733,-0.8128 0.643467,0 1.151467,0.13547 1.659467,0.44027 0.186267,-0.2032 0.3048,-0.47413 0.3048,-0.69427 0,-0.33866 -0.389467,-0.94826 -2.1336,-0.94826 z" />
</g>
</g>
<g
aria-label="DevCon"
transform="matrix(6.5227642,0,0,6.5227642,-489.80588,-735.6063)"
style="font-style:normal;font-weight:bold;font-size:16.93333244px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Yanone Kaffeesatz Bold';letter-spacing:0px;word-spacing:0px;display:inline;fill:#a00000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
id="text5477">
<path
d="m 91.538186,154.66105 c -0.372533,0 -0.474133,0.11853 -0.474133,0.33867 v 11.51466 h 2.1844 c 2.286,0 3.234267,-1.99813 3.234267,-6.51933 0,-4.35187 -1.0668,-5.334 -3.318934,-5.334 z m 2.760134,5.1308 c 0,4.30107 -0.474134,4.9276 -0.999067,4.9276 h -0.338667 v -8.3312 h 0.321734 c 0.6096,0 1.016,0.37253 1.016,3.4036 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16.93333244px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz Bold';fill:#a00000;fill-opacity:1;stroke-width:0.26458332"
id="path5488"
inkscape:connector-curvature="0" />
<path
d="m 100.15963,157.87838 c -1.591729,0 -2.980262,0.7112 -2.980262,4.80907 0,3.21733 1.083733,3.99627 2.624666,3.99627 1.320796,0 2.404536,-0.37254 2.404536,-1.04987 0,-0.38947 -0.0508,-0.93133 -0.1524,-1.27 -0.59267,0.28787 -1.18534,0.47413 -1.79494,0.47413 -0.812796,0 -1.049863,-0.47413 -1.100663,-1.54093 0.829734,-0.0169 2.099733,-0.0847 2.929463,-0.254 0.16934,-0.6604 0.23707,-1.59173 0.23707,-2.40453 0,-1.96427 -0.8128,-2.76014 -2.16747,-2.76014 z m -0.253996,1.64254 c 0.423336,0 0.575736,0.16933 0.575736,1.25306 0,0.27094 -0.0169,0.67734 -0.0847,0.88054 -0.254,0.11853 -0.778933,0.1524 -1.253066,0.1524 0.0508,-1.54094 0.237067,-2.286 0.762,-2.286 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16.93333244px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz Bold';fill:#a00000;fill-opacity:1;stroke-width:0.26458332"
id="path5490"
inkscape:connector-curvature="0" />
<path
d="m 104.26941,165.75238 c 0.1016,0.47414 0.3048,0.84667 0.79586,0.84667 0.3556,0 0.98214,-0.0169 1.3716,-0.0847 l 1.69334,-8.46666 c -1.94734,0 -1.94734,0 -1.99814,0.37253 l -0.23706,2.06587 c -0.16934,1.45626 -0.32174,4.04706 -0.32174,4.04706 h -0.0339 c 0,0 -0.1524,-2.5908 -0.33867,-4.04706 l -0.3048,-2.4384 c -2.16747,0 -2.1844,0 -2.06587,0.5588 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16.93333244px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz Bold';fill:#a00000;fill-opacity:1;stroke-width:0.26458332"
id="path5492"
inkscape:connector-curvature="0" />
<path
d="m 112.00926,154.40705 c -1.524,0 -3.38666,1.016 -3.38666,6.57013 0,4.74134 0.9144,5.7912 2.82786,5.7912 1.28694,0 2.06587,-0.4572 2.06587,-1.25306 0,-0.4064 -0.11853,-0.82974 -0.254,-1.1176 -0.32173,0.16933 -0.79587,0.254 -1.3208,0.254 -0.94827,0 -1.3208,-0.88054 -1.3208,-3.82694 0,-3.69146 0.88053,-4.572 1.84573,-4.572 0.37254,0 0.67734,0.13547 0.88054,0.28787 0.13546,-0.28787 0.27093,-0.67733 0.27093,-1.13453 0,-0.508 -0.16933,-0.99907 -1.60867,-0.99907 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16.93333244px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz Bold';fill:#a00000;fill-opacity:1;stroke-width:0.26458332"
id="path5494"
inkscape:connector-curvature="0" />
<path
d="m 113.8288,162.26412 c 0,3.79306 0.84667,4.4196 2.67547,4.4196 1.8288,0 2.77707,-1.2192 2.77707,-4.48734 0,-3.42053 -0.82974,-4.318 -2.6416,-4.318 -1.79494,0 -2.81094,1.3208 -2.81094,4.38574 z m 2.0828,-0.0169 c 0,-2.40453 0.28787,-2.7432 0.6604,-2.7432 0.49107,0 0.62654,0.3048 0.62654,2.7432 0,2.60774 -0.32174,2.86174 -0.64347,2.86174 -0.42333,0 -0.64347,-0.22014 -0.64347,-2.86174 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16.93333244px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz Bold';fill:#a00000;fill-opacity:1;stroke-width:0.26458332"
id="path5496"
inkscape:connector-curvature="0" />
<path
d="m 120.08673,166.51438 c 1.86266,0 1.89653,0 1.89653,-0.33866 v -6.46854 c 0.18627,-0.13546 0.42333,-0.2032 0.64347,-0.2032 0.47413,0 0.5588,0.27094 0.5588,1.15147 v 5.85893 c 1.91346,0 1.96426,0 1.96426,-0.33866 v -6.11294 c 0,-1.69333 -0.72813,-2.1844 -2.4384,-2.1844 -0.84666,0 -2.09973,0.3048 -2.62466,0.5588 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16.93333244px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz Bold';fill:#a00000;fill-opacity:1;stroke-width:0.26458332"
id="path5498"
inkscape:connector-curvature="0" />
</g>
<g
aria-label="2019"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:135.91038513px;line-height:101.93280029px;font-family:Galette;-inkscape-font-specification:'Galette Bold';letter-spacing:0px;word-spacing:0px;fill:#3566a5;fill-opacity:1;stroke:none;stroke-width:4.07731199px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text1093"
transform="matrix(0.84639363,0,0,0.84639363,-1098.677,81.683415)">
<path
d="m 1450.8965,383.02967 c 4.6209,-2.44639 13.4551,-4.07731 17.8042,-4.07731 4.8928,0 8.0188,2.58229 8.0188,7.20325 0,11.28056 -15.3579,23.51249 -26.7744,43.49132 -2.99,5.30051 -3.5337,7.20325 -3.5337,12.09602 0,0.40774 0,2.5823 0.5437,4.21323 h 44.8504 c 3.3978,0 3.5337,-3.12594 3.5337,-15.76561 0,0 -7.3392,1.49502 -18.6197,1.49502 h -10.0574 c 12.5037,-20.25065 27.5898,-31.80303 27.5898,-48.11228 0,-12.36785 -5.4364,-19.16336 -20.7943,-19.16336 -12.2319,0 -24.4639,3.39776 -24.4639,7.61098 0,2.31047 0.136,7.20325 1.9028,11.14465 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz Bold';fill:#3566a5;fill-opacity:1;stroke-width:4.07731199px"
id="path1095"
inkscape:connector-curvature="0" />
<path
d="m 1500.8287,405.7267 c 0,25.82298 4.2132,41.45267 24.0561,41.45267 19.5711,0 24.8716,-15.49378 24.8716,-46.48135 0,-23.78432 -7.2032,-36.28807 -24.5998,-36.28807 -17.1247,0 -24.3279,14.13468 -24.3279,41.31675 z m 16.5811,0.54364 c 0,-17.39652 1.2231,-28.54118 8.5623,-28.54118 6.2519,0 7.7469,8.42645 7.7469,22.96886 0,24.46387 -2.7182,32.89031 -8.2905,32.89031 -7.0674,0 -8.0187,-6.79552 -8.0187,-27.31799 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz Bold';fill:#3566a5;fill-opacity:1;stroke-width:4.07731199px"
id="path1097"
inkscape:connector-curvature="0" />
<path
d="m 1560.6823,381.53465 c 0,0 5.8442,-1.3591 12.9115,-1.63092 l -1.2232,51.78186 c -12.6396,0 -17.2606,0.81546 -17.2606,4.21322 0,3.53367 0.1359,6.65961 0.4078,10.05737 h 45.2581 c 3.3978,0 3.3978,-3.26185 3.3978,-14.81424 0,0 -4.0773,0.54365 -8.2906,0.54365 h -7.6109 l 1.6309,-66.46018 c -0.6796,-0.54364 -2.7182,-0.81546 -3.9414,-0.81546 -7.2033,0 -27.5898,4.62095 -27.5898,7.74689 0,3.66958 0.6795,6.5237 2.3104,9.37781 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz Bold';fill:#3566a5;fill-opacity:1;stroke-width:4.07731199px"
id="path1099"
inkscape:connector-curvature="0" />
<path
d="m 1622.7106,445.68436 c -3.3978,0 -6.9314,-0.67956 -9.6497,-1.49502 -0.8154,2.85412 -1.3591,7.47507 -1.3591,10.05737 0,4.48504 5.7083,5.84415 13.0474,5.84415 24.1921,0 33.434,-17.39653 33.8417,-53.27687 -0.6795,-34.79306 -4.0773,-43.62724 -23.6484,-43.62724 -16.3092,0 -25.5511,10.05737 -25.5511,33.9776 0,17.39653 7.6109,27.86163 18.4838,27.86163 7.7469,0 12.096,-2.31048 15.7656,-6.93143 -0.9514,14.95014 -5.0287,27.58981 -20.9302,27.58981 z m 9.9214,-34.65715 c -5.5723,0 -8.2905,-6.11597 -8.2905,-15.49379 0,-12.77557 4.621,-18.89154 10.8728,-18.89154 6.9315,0 8.8342,6.38779 8.8342,27.31799 v 0.81546 c -3.6696,4.75686 -7.4751,6.25188 -11.4165,6.25188 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz Bold';fill:#3566a5;fill-opacity:1;stroke-width:4.07731199px"
id="path1101"
inkscape:connector-curvature="0" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="title"
style="display:none">
<g
style="display:inline"
id="g3732-6"
transform="matrix(2.0475567,0,0,2.0475567,979.07911,-71.674635)">
<path
inkscape:connector-curvature="0"
d="m 60.69548,67.493897 c 0,11.5675 -9.48796,20.9448 -21.19195,20.9448 -11.703989,0 -21.191949,-9.3773 -21.191949,-20.9448 0,-11.5674 9.48796,-20.9447 21.191949,-20.9447 11.70399,0 21.19195,9.3773 21.19195,20.9447 z"
id="path3544-1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';display:inline;opacity:0.8;fill:url(#radialGradient3637-3);fill-opacity:1;stroke:url(#radialGradient3639-5);stroke-width:1.46151388;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" />
<g
transform="matrix(1.4615138,0,0,2.5218672,4.4272,31.547917)"
id="g3546-8"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';display:inline;fill:#000000;fill-opacity:1;stroke:none">
<path
inkscape:connector-curvature="0"
d="m 24,13 -8.1875,15.225744 c 11.445471,0 5.976697,0 16.34375,0 z m 0,4.96875 4,7.421875 h -7.953125 z"
id="path3548-79"
style="fill:url(#linearGradient3991-3-88-5);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3993-1-9-7);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
d="M 26.355979,42.522608 20,21.277828 13.644021,42.522609"
transform="matrix(1,0,0,0.57953638,4,2.7937247)"
id="path3550-2"
style="fill:none;stroke:#ffffff;stroke-width:1.31358945px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<path
inkscape:connector-curvature="0"
d="m 53.38791,67.493897 c 0,7.6681 -6.21625,13.8844 -13.88438,13.8844 -7.66813,0 -13.884379,-6.2163 -13.884379,-13.8844 0,-7.6681 6.216249,-13.8844 13.884379,-13.8844 7.66813,0 13.88438,6.2163 13.88438,13.8844 z"
id="path3552-0"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';display:inline;fill:url(#radialGradient3995-7-4-0-2-2-0-9);fill-opacity:1;stroke:url(#radialGradient3997-3-3-4-7-7-6-1);stroke-width:1.46151388;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" />
<g
transform="matrix(3.2735609,0,0,3.2593101,-24.33091,59.292917)"
id="g3554-2"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';display:inline;fill:#000000;fill-opacity:1;stroke:none">
<path
inkscape:connector-curvature="0"
d="M 11,2.25 C 11,3.2164983 10.195512,4 9.203125,4 8.2107383,4 7.40625,3.2164983 7.40625,2.25 7.40625,1.2835017 8.2107383,0.5 9.203125,0.5 10.195512,0.5 11,1.2835017 11,2.25 Z"
transform="matrix(1.1130433,0,0,1.1428572,9.2565233,-0.07142864)"
id="path3556-3"
style="fill:url(#radialGradient3999-1-4-6-0-0-3-2);fill-opacity:1;stroke:#555753;stroke-width:0.39671427;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
d="M 20,1.5 C 20,1.7761424 19.776142,2 19.5,2 19.223858,2 19,1.7761424 19,1.5 19,1.2238576 19.223858,1 19.5,1 19.776142,1 20,1.2238576 20,1.5 Z"
transform="matrix(1.8125,0,0,1.8125,-16.465404,-0.9288198)"
id="path3558-7"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
</g>
<path
inkscape:connector-curvature="0"
d="m 44.61882,67.441097 c 0,2.8124 -2.2902,5.0924 -5.1153,5.0924 -2.8251,0 -5.1153,-2.28 -5.1153,-5.0924 0,-2.8125 2.2902,-5.0924 5.1153,-5.0924 2.8251,0 5.1153,2.2799 5.1153,5.0924 z"
id="path3560-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';display:inline;fill:none;stroke:url(#radialGradient4001-9-6-9-6-60-6-9);stroke-width:1.46151364;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" />
</g>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:131.04367065px;line-height:125%;font-family:Sans;letter-spacing:0.28665793px;word-spacing:0px;display:inline;fill:#a00000;fill-opacity:1;stroke:none;stroke-width:2.04755735"
x="1104.8673"
y="136.28465"
id="text3743-6-9"><tspan
sodipodi:role="line"
id="tspan3745-0-2"
x="1104.8673"
y="136.28465"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:131.04367065px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';letter-spacing:0.28665793px;fill:#a00000;fill-opacity:1;stroke-width:2.04755735"
dx="0 0">Os</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:81.90226746px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#a00000;fill-opacity:1;stroke:none;stroke-width:2.04755735"
x="1288.4238"
y="136.28465"
id="text3760-7-2"><tspan
sodipodi:role="line"
id="tspan3762-0-8"
x="1288.4238"
y="136.28465"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:131.04367065px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';fill:#a00000;fill-opacity:1;stroke-width:2.04755735">o</tspan></text>
<text
id="text4707-97"
y="137.59502"
x="1338.8434"
style="font-style:normal;font-weight:bold;font-size:131.04367065px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Yanone Kaffeesatz Bold';letter-spacing:0px;word-spacing:0px;display:inline;fill:#a00000;fill-opacity:1;stroke:none;stroke-width:2.04755735"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:131.04367065px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz Bold';fill:#a00000;fill-opacity:1;stroke-width:2.04755735"
y="137.59502"
x="1338.8434"
id="tspan4705-36"
sodipodi:role="line">Con</tspan></text>
<path
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:64px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Andale Mono';writing-mode:lr-tb;display:inline;fill:#a00000;fill-opacity:1;stroke:#a00000;stroke-width:2.04755735;stroke-opacity:1"
d="m 1232.1703,70.382814 -8.8741,15.272702 -4.0593,-6.9865 1.2039,55.028084 c 3.887,-2.71488 5.3164,1.47605 5.3748,-0.61985 l 1.4237,-51.004974 c 3.0141,-1.57252 6.0272,-2.227521 8.9101,-2.227521 5.2418,0 7.3232,1.833021 7.4545,6.550591 l 0.5798,47.161764 c 3.6356,-1.03422 6.9193,0.79411 6.9344,-0.35191 l 0.6478,-49.061364 c 2.883,-1.834611 7.188,-4.171091 10.202,-4.171091 5.2417,0 6.3099,2.625001 6.4185,8.914071 l 0.7878,45.610104 c 2.4651,-0.38781 5.9664,1.24339 5.9987,-0.39591 l 0.9038,-45.998034 c 0.2319,-11.791681 1.3508,-17.564192 -11.7533,-17.564192 -5.3728,0 -11.6612,1.57328 -16.1166,4.063111 -2.4899,-2.620651 -6.1586,-4.063111 -11.7935,-4.063111 -1.5361,0 -2.9245,-0.0721 -4.243,-0.15595 z"
id="path3959-9-26-3-1"
inkscape:connector-curvature="0" />
<path
d="m 1223.2952,85.655406 -9.2281,-15.875942 -9.2281,-15.876132 h 18.4562 18.4561 l -9.2281,15.876132 z"
id="path3981-0-4-1-2"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';display:inline;fill:none;fill-opacity:1;stroke:#e19c9c;stroke-width:10.23778343;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
d="M 1272.1299,132.44473 V 75.679295"
id="path3983-4-9-2-9"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';display:inline;fill:none;stroke:#e19c9c;stroke-width:10.28292942;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
d="M 1247.6099,132.4208 V 91.835136"
id="path3985-4-0-9-3"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';display:inline;fill:none;stroke:#e19c9c;stroke-width:10.23778343;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
d="m 1223.2938,132.77645 -0.022,-24.06433"
id="path3951-0-4-91-2-1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';display:inline;fill:none;stroke:#e19c9c;stroke-width:9.56036377;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<text
id="text4707-9"
y="138.64339"
x="1700.7795"
style="font-style:normal;font-weight:bold;font-size:131.04367065px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Yanone Kaffeesatz Bold';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;display:inline;fill:#3566a5;fill-opacity:1;stroke:none;stroke-width:2.04755735"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:131.04367065px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz Bold';text-align:end;text-anchor:end;fill:#3566a5;fill-opacity:1;stroke-width:2.04755735"
y="138.64339"
x="1700.7795"
id="tspan4705-3"
sodipodi:role="line">2018</tspan></text>
</g>
<g
inkscape:groupmode="layer"
id="layer6"
inkscape:label="subtitle"
style="display:none">
<g
style="display:inline"
id="g1750"
transform="matrix(19.592171,0,0,19.592171,-1582.9761,-2384.3012)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:3.16364908px;line-height:100%;font-family:Galette;-inkscape-font-specification:'Galette Bold';letter-spacing:0px;word-spacing:0px;fill:#3465a4;fill-opacity:1;stroke:none;stroke-width:0.02372737px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="167.53929"
y="132.21951"
id="text1124"><tspan
sodipodi:role="line"
id="tspan1122"
x="167.53929"
y="132.21951"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100%;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';text-align:end;letter-spacing:0px;text-anchor:end;fill:#3465a4;fill-opacity:1;stroke-width:0.02372737px">0x2B || <tspan
style="letter-spacing:0px;fill:#a00000;fill-opacity:1"
id="tspan1454">!</tspan>0x2B</tspan><tspan
sodipodi:role="line"
x="167.53929"
y="135.49736"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100%;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';text-align:end;letter-spacing:0px;text-anchor:end;fill:#3465a4;fill-opacity:1;stroke-width:0.02372737px"
id="tspan1126">18-19 Oct. 2018</tspan><tspan
sodipodi:role="line"
x="167.53929"
y="138.77521"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100%;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';text-align:end;letter-spacing:0px;text-anchor:end;fill:#3465a4;fill-opacity:1;stroke-width:0.02372737px"
id="tspan1128">Berl n</tspan></text>
<g
transform="matrix(0.20459945,0,0,0.20459945,152.35276,113.27741)"
id="g27740">
<g
id="g28309">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:normal;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98000004;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#3465a4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6.24451828;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 3820.6562,472.26172 c -40.3422,0 -73.1445,32.3975 -73.1445,72.32812 0,30.32091 18.9212,56.28015 45.6875,67.02735 l 1.8555,-5.95508 c -24.2644,-9.91834 -41.2988,-33.51066 -41.2988,-61.07227 0,-36.51604 29.8935,-66.08398 66.9003,-66.08398 37.0069,0 66.8985,29.56794 66.8985,66.08398 0,24.66524 -13.6587,46.14338 -33.918,57.50977 -2.3907,1.34129 -4.8745,2.53952 -7.4355,3.58594 l 1.8535,5.96875 c 2.9828,-1.19355 5.8704,-2.56971 8.6426,-4.125 22.1465,-12.42531 37.1035,-35.96788 37.1035,-62.93946 0,-39.93062 -32.8023,-72.32812 -73.1446,-72.32812 z m 7.5,137.99414 c -2.4618,0.2706 -4.962,0.41602 -7.5,0.41602 -2.5028,0 -4.9696,-0.14473 -7.4003,-0.40821 l -1.8633,6.05469 c 3.0363,0.3807 6.1241,0.59767 9.2636,0.59766 3.182,0 6.3161,-0.2044 9.3926,-0.59571 z"
id="path3544-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ssccsssscccsscsccccc"
transform="matrix(0.04785074,0,0,0.04785074,-118.05951,92.995687)" />
<path
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#a00000;stroke-width:6.34386444px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 3811.3887,563.87891 -30.2735,97.13867 h 78.9297 l -30.1523,-97.125 c -2.8017,1.31925 -5.9315,2.05859 -9.2364,2.05859 -3.3169,0 -6.4581,-0.74396 -9.2675,-2.07226 z m 9.2675,11.66406 19.3165,61.84961 h -38.4082 z"
transform="matrix(0.04785074,0,0,0.04785074,-118.05951,92.995687)"
id="path3548-6"
inkscape:connector-curvature="0" />
<path
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';display:inline;fill:none;fill-opacity:1;stroke:#a00000;stroke-width:0.3038334;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path3556-1"
d="m 65.796938,119.04618 c 0,0.56924 -0.463484,1.03071 -1.035215,1.03071 -0.571734,0 -1.035215,-0.46147 -1.035215,-1.03071 0,-0.56925 0.463481,-1.03071 1.035215,-1.03071 0.571731,0 1.035215,0.46146 1.035215,1.03071 z"
inkscape:connector-curvature="0" />
</g>
<path
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;font-family:'Yanone Kaffeesatz';-inkscape-font-specification:'Yanone Kaffeesatz';display:inline;fill:none;fill-opacity:1;stroke:#3465a4;stroke-width:0.29880485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
id="path3552-8"
d="m 66.957088,119.05451 c 0,1.21246 -0.982899,2.19537 -2.195365,2.19537 -1.212466,0 -2.195365,-0.98291 -2.195365,-2.19537 0,-1.21246 0.982899,-2.19537 2.195365,-2.19537 1.212466,0 2.195365,0.98291 2.195365,2.19537 z"
inkscape:connector-curvature="0" />
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 55 KiB

File diff suppressed because it is too large Load diff

Before

Width:  |  Height:  |  Size: 113 KiB

File diff suppressed because it is too large Load diff

Before

Width:  |  Height:  |  Size: 123 KiB

File diff suppressed because it is too large Load diff

Before

Width:  |  Height:  |  Size: 68 KiB

View file

@ -1,5 +1,5 @@
pillow>=8.0.0
pillow
cssutils==1.0.2
lxml~=5.3
svg.path~=6.0
Wand~=0.6.5
lxml==4.9.1
svg.path==4.0.2
Wand==0.6.5

View file

@ -100,12 +100,6 @@ def events(scheduleUrl, titlemap={}):
url = event.find('url').text.strip()
else:
url = ''
if event.find('track') is not None and event.find('track').text is not None:
track = event.find('track').text
else:
track = ''
# yield a tupel with the event-id, event-title and person-names
yield {
'day': day.get('index'),
@ -115,7 +109,7 @@ def events(scheduleUrl, titlemap={}):
'persons': personnames,
'personnames': ', '.join(personnames),
'room': room.attrib['name'],
'track': track,
'track': event.find('track').text,
'url': url
}

Binary file not shown.

Binary file not shown.

View file

@ -1,37 +0,0 @@
[meta]
schedule = http://vcfb.de/2024/schedule.xml
# ffmpeg -loop 1 -i intro.png -f lavfi -i anullsrc=channel_layout=stereo:sample_rate=44100 -c:v libx264 -tune stillimage -pix_fmt yuv420p -c:a aac -r 25 -t 10 intro.mp4
template = intro.mp4
alpha = false
prores = false
inout_type = t
fade_duration = 0.5
[title]
in = 1
out = 9.5
fontfile = Computerfont.ttf
fontsize = 100
fontcolor = #ffffff
x = 85
y = 122
[speaker]
in = 2
out = 9
fontfile = SourceSansPro-Semibold.ttf
fontsize = 65
fontcolor = #ffffff
x = 85
y = 861
[text]
in = 0
out = 0
fontfile = Computerfont.ttf
fontsize = 0
fontcolor = #ffffff
x = 0
y = 0
; text =

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 2.1 MiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1 MiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 935 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1,015 KiB