Compare commits
26 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
bfbdda8ffe | ||
![]() |
21a8e014ef | ||
![]() |
a9cbfc5eb3 | ||
![]() |
41db29d24b | ||
![]() |
40eb76b968 | ||
![]() |
5661e690de | ||
![]() |
d8c198f984 | ||
![]() |
b3fb07a6e3 | ||
![]() |
2451c0f25f | ||
![]() |
ca224b9d84 | ||
![]() |
8933550f31 | ||
![]() |
31f01ca386 | ||
![]() |
6876f2cf44 | ||
![]() |
526ef6231a | ||
![]() |
9210d36248 | ||
![]() |
0bb26d6b25 | ||
![]() |
26c660a135 | ||
![]() |
8ca5d334cb | ||
![]() |
367e8ea094 | ||
![]() |
c94b840807 | ||
![]() |
471e0c38b7 | ||
![]() |
848b72b113 | ||
![]() |
3ae90b87c0 | ||
![]() |
1893beda4d | ||
![]() |
ec29473d53 | ||
![]() |
96f410ba6a |
|
@ -1,15 +1,13 @@
|
|||
[default]
|
||||
[meta]
|
||||
schedule = https://pretalx.c3voc.de/camp2023/schedule/export/schedule.xml
|
||||
template = intro.mp4
|
||||
alpha = false
|
||||
prores = false
|
||||
fontfile = true
|
||||
inout = t
|
||||
inout_type = t
|
||||
|
||||
[title]
|
||||
in = 16
|
||||
out = 24
|
||||
fontfamily = BeonRegular
|
||||
fontfile = saira.ttf
|
||||
fontsize = 100
|
||||
fontcolor = #FB48C4
|
||||
|
@ -19,7 +17,6 @@ y = 100
|
|||
[speaker]
|
||||
in = 16
|
||||
out = 24
|
||||
fontfamily = BeonRegular
|
||||
fontfile = saira.ttf
|
||||
fontsize = 70
|
||||
fontcolor = #3FFF21
|
||||
|
@ -29,11 +26,10 @@ 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
|
||||
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
[default]
|
||||
[meta]
|
||||
schedule = https://fahrplan.events.ccc.de/camp/2019/Fahrplan/schedule.xml
|
||||
template = cccamp19_talks_intro_1080p.mov
|
||||
alpha = true
|
||||
prores = true
|
||||
fontfile = true
|
||||
inout = n
|
||||
inout_type = n
|
||||
|
||||
[title]
|
||||
in = 193
|
||||
out = 324
|
||||
fontfamily =
|
||||
fontfile = Marvel-Bold.ttf
|
||||
fontsize = 120
|
||||
fontcolor = #c68100
|
||||
|
@ -19,7 +17,6 @@ y = 480
|
|||
[speaker]
|
||||
in = 233
|
||||
out = 324
|
||||
fontfamily =
|
||||
fontfile = Marvel-Regular.ttf
|
||||
fontsize = 70
|
||||
fontcolor = #c68100
|
||||
|
@ -29,11 +26,10 @@ 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
|
||||
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
[default]
|
||||
[meta]
|
||||
schedule = https://pretalx.denog.de/denog11/schedule/export/schedule.xml
|
||||
template = denog11_intro_template.ts
|
||||
alpha = false
|
||||
prores = false
|
||||
fontfile = true
|
||||
inout = n
|
||||
inout_type = n
|
||||
|
||||
[title]
|
||||
in = 1
|
||||
out = 6.5
|
||||
fontfamily =
|
||||
fontfile = DejaVuSans.ttf
|
||||
fontsize = 100
|
||||
fontcolor = #f9cc12
|
||||
|
@ -19,7 +17,6 @@ y = 200
|
|||
[speaker]
|
||||
in = 2
|
||||
out = 6.5
|
||||
fontfamily =
|
||||
fontfile = DejaVuSans.ttf
|
||||
fontsize = 60
|
||||
fontcolor = #ffffff
|
||||
|
@ -29,11 +26,10 @@ y = 900
|
|||
[text]
|
||||
in = 3
|
||||
out = 6.5
|
||||
fontfamily =
|
||||
fontfile = DejaVuSans.ttf
|
||||
fontsize = 45
|
||||
fontcolor = #ffffff
|
||||
x = 640
|
||||
y = 1000
|
||||
text = ''
|
||||
; text =
|
||||
|
||||
|
|
145
god2024/__init__.py
Normal file
|
@ -0,0 +1,145 @@
|
|||
#!/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(),
|
||||
}
|
||||
))
|
||||
|
101
god2024/artwork/intro.svg
Normal file
After Width: | Height: | Size: 1.9 MiB |
131
god2024/artwork/outro.svg
Normal file
After Width: | Height: | Size: 2.4 MiB |
78
god2024/artwork/pause.svg
Normal file
After Width: | Height: | Size: 1.9 MiB |
|
@ -1,15 +1,13 @@
|
|||
[default]
|
||||
[meta]
|
||||
schedule = https://projects.alpaka.space/media/jhber19-schedule.xml
|
||||
template = intro-alpha.mov
|
||||
alpha = true
|
||||
prores = true
|
||||
fontfile = true
|
||||
inout = n
|
||||
inout_type = n
|
||||
|
||||
[title]
|
||||
in = 175
|
||||
out = 260
|
||||
fontfamily =
|
||||
fontfile = SourceSansPro-Bold.otf
|
||||
fontsize = 90
|
||||
fontcolor = #ffffff
|
||||
|
@ -19,7 +17,6 @@ y = 450
|
|||
[speaker]
|
||||
in = 175
|
||||
out = 260
|
||||
fontfamily =
|
||||
fontfile = SourceSansPro-Regular.otf
|
||||
fontsize = 36
|
||||
fontcolor = #ffffff
|
||||
|
@ -29,11 +26,10 @@ 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 =
|
||||
|
||||
|
|
|
@ -1,37 +1,35 @@
|
|||
[default]
|
||||
[meta]
|
||||
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
|
||||
|
||||
; fields for title and speaker names are empty in the template.ts, so we'll render them in via ffmpeg
|
||||
;; 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
|
||||
[title]
|
||||
; inframe for title
|
||||
in = 20
|
||||
; outframe for totle
|
||||
; outframe for title
|
||||
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
|
||||
|
@ -41,13 +39,10 @@ y = 950
|
|||
[text]
|
||||
in = 3
|
||||
out = 4
|
||||
fontfamily =
|
||||
fontfile = ebisu.ttf
|
||||
fontsize = 45
|
||||
fontcolor = #ffffff
|
||||
x = 640
|
||||
y = 1000
|
||||
text = ''
|
||||
; text =
|
||||
|
||||
|
||||
; build intros via
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
[default]
|
||||
[meta]
|
||||
schedule = https://pretalx.c3voc.de/jugend-hackt-rhein-neckar-2021/schedule/export/schedule.xml
|
||||
template = jh21-rn-template.ts
|
||||
alpha = false
|
||||
prores = false
|
||||
fontfile = true
|
||||
inout = t
|
||||
inout_type = t
|
||||
|
||||
[title]
|
||||
in = 1
|
||||
out = 6.5
|
||||
fontfamily =
|
||||
fontfile = SourceSansPro-Semibold.ttf
|
||||
fontsize = 85
|
||||
fontcolor = #ffffff
|
||||
|
@ -19,7 +17,6 @@ y = 877
|
|||
[speaker]
|
||||
in = 2
|
||||
out = 6.5
|
||||
fontfamily =
|
||||
fontfile = SourceSansPro-Semibold.ttf
|
||||
fontsize = 45
|
||||
fontcolor = #ffffff
|
||||
|
@ -29,11 +26,10 @@ y = 954
|
|||
[text]
|
||||
in = 3
|
||||
out = 6.5
|
||||
fontfamily =
|
||||
fontfile = SourceSansPro-Semibold.ttf
|
||||
fontsize = 45
|
||||
fontcolor = #ffffff
|
||||
x = 1920
|
||||
y = 1080
|
||||
text = ''
|
||||
; text =
|
||||
|
||||
|
|
|
@ -1,39 +1,52 @@
|
|||
[default]
|
||||
[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
|
||||
fontfile = true
|
||||
inout = t
|
||||
;; 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
|
||||
|
||||
;; 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 = ''
|
||||
;text = some additional text
|
||||
|
|
BIN
jugendhackt/source.xcf
Normal file
|
@ -11,8 +11,6 @@ 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',
|
||||
|
@ -57,6 +55,20 @@ 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()
|
||||
|
||||
|
||||
|
@ -101,9 +113,22 @@ 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):
|
||||
|
@ -128,6 +153,13 @@ 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("<", "<")
|
||||
xml = xml.replace(">", ">")
|
||||
xml = xml.replace("\"", """)
|
||||
xml = xml.replace("'", "'")
|
||||
return xml
|
||||
|
||||
def enqueue_job(event):
|
||||
event_id = str(event['id'])
|
||||
|
@ -144,10 +176,11 @@ def enqueue_job(event):
|
|||
fp.write(xmlstr)
|
||||
|
||||
compressor_info = run_output(
|
||||
'/Applications/Compressor.app/Contents/MacOS/Compressor -batchname {batchname} -jobpath {jobpath} -settingpath hd1080p.compressorsetting -locationpath {locationpath}',
|
||||
'/Applications/Compressor.app/Contents/MacOS/Compressor -batchname {batchname} -jobpath {jobpath} -settingpath {settingpath} -locationpath {locationpath}',
|
||||
batchname=describe_event(event),
|
||||
jobpath=work_doc,
|
||||
locationpath=intermediate_clip)
|
||||
locationpath=intermediate_clip,
|
||||
settingpath=settingpath)
|
||||
|
||||
match = re.search(r"<jobID ([A-Z0-9\-]+) ?\/>", compressor_info)
|
||||
if not match:
|
||||
|
@ -202,6 +235,7 @@ 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)
|
||||
|
||||
|
@ -211,6 +245,11 @@ 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)
|
||||
|
||||
|
||||
|
@ -250,5 +289,9 @@ while len(active_jobs) > 0:
|
|||
finalize_job(job_id, event)
|
||||
|
||||
|
||||
print('all done, cleaning up ' + tempdir.name)
|
||||
tempdir.cleanup()
|
||||
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()
|
||||
|
|
|
@ -1,329 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: tabstop=4 shiftwidth=4 expandtab
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import renderlib
|
||||
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:
|
||||
w, _ = translation_font.getsize(" ".join([line, word]))
|
||||
print("{}, {}".format(w, line))
|
||||
if w > (frame_width):
|
||||
print("too wide, breaking")
|
||||
lines += line.strip() + "\n"
|
||||
line = ""
|
||||
|
||||
line += word + " "
|
||||
|
||||
lines += line.strip()
|
||||
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 = "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,
|
||||
text=t)
|
||||
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
|
||||
)
|
||||
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,
|
||||
text=s)
|
||||
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 += "drawtext=fontfile={fontfile}:fontsize={fontsize}:fontcolor={fontcolor}:x={x}:y={y}:text={text}:".format(
|
||||
fontfile=font_tt,
|
||||
fontsize=text_fontsize,
|
||||
fontcolor=text_fontcolor,
|
||||
x=text_x,
|
||||
y=text_y,
|
||||
text=text_text)
|
||||
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=text_in,
|
||||
fade_in_end_time=text_in + fade_duration,
|
||||
fade_out_start_time=text_in + fade_duration + text_duration,
|
||||
fade_out_end_time=text_in + fade_duration + text_duration + fade_duration,
|
||||
fade_duration=fade_duration
|
||||
)
|
||||
|
||||
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')
|
||||
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.")
|
||||
|
|
524
make-ffmpeg.py
|
@ -1,155 +1,167 @@
|
|||
#!/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 schedulelib
|
||||
import argparse
|
||||
import shlex
|
||||
from PIL import ImageFont
|
||||
from configparser import ConfigParser
|
||||
import json
|
||||
import platform
|
||||
import ssl
|
||||
from configparser import ConfigParser
|
||||
from pathlib import PurePath
|
||||
import platform
|
||||
|
||||
from PIL import ImageFont
|
||||
import schedulelib
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
|
||||
# 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 = []
|
||||
FRAME_WIDTH = 1920
|
||||
|
||||
|
||||
def headline(str):
|
||||
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):
|
||||
print("##################################################")
|
||||
print(str)
|
||||
print(err_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'])
|
||||
|
||||
|
@ -158,164 +170,184 @@ 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)
|
||||
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."""
|
||||
|
||||
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_num = 0
|
||||
line = ""
|
||||
line = []
|
||||
for word in split_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 = ""
|
||||
new_line = line + [word.rstrip(':')]
|
||||
w = font.getlength(" ".join(new_line))
|
||||
if w > max_width:
|
||||
lines.append(' '.join(line))
|
||||
line = []
|
||||
|
||||
line += word + " "
|
||||
line.append(word.rstrip(':'))
|
||||
|
||||
if word.endswith(':'):
|
||||
lines.append(' '.join(line))
|
||||
line = []
|
||||
|
||||
if line:
|
||||
lines.append(' '.join(line))
|
||||
|
||||
lines += line.strip()
|
||||
return lines
|
||||
|
||||
|
||||
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))
|
||||
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"\\\'")
|
||||
|
||||
return title
|
||||
return text
|
||||
|
||||
|
||||
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):
|
||||
def enqueue_job(conf: Config, 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(os.path.join(args.project, event_id + '.ts')) or os.path.exists(os.path.join(args.project, event_id + '.mov'))) and not args.force:
|
||||
if (os.path.exists(outfile) or os.path.exists(outfile_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, 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))
|
||||
title = conf.title.fit_text(event_title)
|
||||
speakers = conf.speaker.fit_text(event_personnames)
|
||||
extra_text = conf.text.fit_text(conf.extra_text)
|
||||
|
||||
if args.debug:
|
||||
print('Title: ', t)
|
||||
print('Speaker: ', s)
|
||||
|
||||
outfile = os.path.join(os.path.dirname(args.project), event_id + '.ts')
|
||||
print('Title: ', title)
|
||||
print('Speaker: ', speakers)
|
||||
|
||||
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'
|
||||
|
||||
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:
|
||||
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:
|
||||
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)
|
||||
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)
|
||||
|
||||
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)
|
||||
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]
|
||||
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)
|
||||
cmd += ['-shortest', '-c:v', 'qtrle', '-movflags',
|
||||
'faststart', '-f', 'mov', outfile_mov]
|
||||
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)
|
||||
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]
|
||||
|
||||
if args.debug:
|
||||
print(cmd)
|
||||
|
||||
run(cmd)
|
||||
subprocess.check_call(cmd,
|
||||
stderr=subprocess.STDOUT,
|
||||
stdout=subprocess.DEVNULL
|
||||
)
|
||||
|
||||
return event_id
|
||||
|
||||
|
||||
if args.ids:
|
||||
if len(args.ids) == 1:
|
||||
print("enqueuing {} job".format(len(args.ids)))
|
||||
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',
|
||||
}]
|
||||
|
||||
else:
|
||||
print("enqueuing {} jobs".format(len(args.ids)))
|
||||
else:
|
||||
if len(events) == 1:
|
||||
print("enqueuing {} job".format(len(events)))
|
||||
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)))
|
||||
else:
|
||||
print("enqueuing {} jobs".format(len(events)))
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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']))
|
||||
|
||||
event_print(event, "enqueued as " + str(event['id']))
|
||||
job_id = enqueue_job(config, event)
|
||||
if not job_id:
|
||||
event_print(event, "job was not enqueued successfully, skipping postprocessing")
|
||||
continue
|
||||
|
||||
job_id = enqueue_job(event)
|
||||
if not job_id:
|
||||
event_print(event, "job was not enqueued successfully, skipping postprocessing")
|
||||
continue
|
||||
|
||||
|
||||
print('all done')
|
||||
print('all done')
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
[default]
|
||||
[meta]
|
||||
#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
|
||||
fontfile = true
|
||||
inout = n
|
||||
inout_type = n
|
||||
|
||||
[title]
|
||||
in = 50
|
||||
out = 225
|
||||
fontfamily =
|
||||
fontfile = Jura-Bold.ttf
|
||||
fontsize = 80
|
||||
fontcolor = #47acda
|
||||
|
@ -20,7 +18,6 @@ y = 540
|
|||
[speaker]
|
||||
in = 75
|
||||
out = 225
|
||||
fontfamily =
|
||||
fontfile = Jura-Regular.ttf
|
||||
fontsize = 50
|
||||
fontcolor = #094762
|
||||
|
@ -30,10 +27,9 @@ 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 =
|
||||
|
|
148
osmodevcon24/__init__.py
Normal file
|
@ -0,0 +1,148 @@
|
|||
#!/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
|
||||
))
|
946
osmodevcon24/artwork/background.svg
Normal file
|
@ -0,0 +1,946 @@
|
|||
<?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>
|
After Width: | Height: | Size: 55 KiB |
1372
osmodevcon24/artwork/intro.svg
Normal file
After Width: | Height: | Size: 113 KiB |
1479
osmodevcon24/artwork/outro.svg
Normal file
After Width: | Height: | Size: 123 KiB |
1208
osmodevcon24/artwork/pause.svg
Normal file
After Width: | Height: | Size: 68 KiB |
|
@ -1,5 +1,5 @@
|
|||
pillow
|
||||
pillow>=8.0.0
|
||||
cssutils==1.0.2
|
||||
lxml==4.9.1
|
||||
svg.path==4.0.2
|
||||
Wand==0.6.5
|
||||
lxml~=5.3
|
||||
svg.path~=6.0
|
||||
Wand~=0.6.5
|
||||
|
|
|
@ -100,6 +100,12 @@ 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'),
|
||||
|
@ -109,7 +115,7 @@ def events(scheduleUrl, titlemap={}):
|
|||
'persons': personnames,
|
||||
'personnames': ', '.join(personnames),
|
||||
'room': room.attrib['name'],
|
||||
'track': event.find('track').text,
|
||||
'track': track,
|
||||
'url': url
|
||||
}
|
||||
|
||||
|
|
BIN
vcfb24/Computerfont.ttf
Normal file
BIN
vcfb24/SourceSansPro-Semibold.ttf
Normal file
37
vcfb24/config.ini
Normal file
|
@ -0,0 +1,37 @@
|
|||
[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 =
|
15584
vcfb24/intro.svg
Normal file
After Width: | Height: | Size: 2.1 MiB |
6231
vcfb24/lower-third.svg
Normal file
After Width: | Height: | Size: 1 MiB |
1668
vcfb24/outro.svg
Normal file
After Width: | Height: | Size: 935 KiB |
6626
vcfb24/pause.svg
Normal file
After Width: | Height: | Size: 1,015 KiB |