Merge branch 'master' of github.com:MaZderMind/c3voc-toolz
This commit is contained in:
commit
3102e07ea3
3 changed files with 137 additions and 63 deletions
82
README.md
Normal file
82
README.md
Normal file
|
@ -0,0 +1,82 @@
|
|||
Frab-Based Pre- and Postroll-Generator
|
||||
===========================================
|
||||
|
||||
This is a scripted pre-, postroll and pause-clip generator. It takes a Frab/frab schedule-xml and artwork as svg and generates .dv-clips ready-to-use with the [VOC](https://c3voc.de/wiki/)-CRS (Continuous Recording System) or any other System. It can aĺso be modified to generate Lossless h264 or something different if reqired.
|
||||
|
||||
Following the requirements of the CRS-Setup it generates one postroll, one pause-sequence and multiple prerolls - one per Talk in your Schedule-xml, but it should be simple to modify this if your Setup needs it.
|
||||
|
||||
Yes! That's what I want!
|
||||
------------------------
|
||||
Okay, let's go.
|
||||
|
||||
- Install python2.7, python-lxml, python-cssutils, inkscape and libav-tools
|
||||
- Fork this repo on github and clone your personal fork to your local system.
|
||||
- Copy one of the existing setups (I'd suggest sotmeu14 for a start).
|
||||
- Open ```artwork/vorspann.svg``` (preroll template) in inkscape and modify it. You can also just create a new one. For the VOC-Setup you should use a Pixel-Resolution of ```1024x576``` (16:9 Aspect Ratio).
|
||||
- Group things togeter that should be animated together (like subtitle and speaker-text)
|
||||
- Use Flow-Text (in Inkscape drag an Area of Text instead of just placing a single line). This way the text will automatically wrap inside the specified area if it gets too long.
|
||||
- Type Placeholder-Texts where the script should substitute content from your schedule-xml. By default the following placeholders are substituted
|
||||
- ```$id``` - Talk-ID (useful in links to the Frab-Page)
|
||||
- ```$title``` - Title of the Talk
|
||||
- ```$subtitle``` - You guessed it...
|
||||
- ```$personnames``` - Comma-Separated list of Speaker-Names
|
||||
- Give IDs to the Objects and Groups you want to animate (Inkscape Shift-Ctrl-O)
|
||||
- Edit your copy of make.py
|
||||
- set ```scheduleUrl``` to the url of your schedule.xml-file
|
||||
- modify vorspannFrames (preroll) - see section about the frame-generators below
|
||||
- search for ```!!! DEBUG MODE !!!``` and comment the sections about abspann (postroll) and pause
|
||||
- run ```./make.py --debug``` to generate your first preroll
|
||||
- if it looks good, duplicate vorspann.svg to abspann.svg (postroll) and pause.svg (pause-loop) and modify them according to your needs. You can use different IDs if required
|
||||
- modify abspannFrames and pauseFrames liek before an test them using ```./make.py --debug```
|
||||
- it they look like you'd want them to, run ```make.py```.
|
||||
- You can use any debianesque linux (can be headless) to generate the videos. More cores help more.
|
||||
|
||||
The Frame-Generators
|
||||
--------------------
|
||||
The animation sequence is controlled by the three frame-generator routines vorspanFrames, abspannFrames and pauseFrames. Each of them yields one tupel per frame. This Frame-Tupel contains one Sub-Tupel per Animated Element, which has one of two forms:
|
||||
|
||||
### CSS-Style-Modifications
|
||||
```('logo', 'style', 'opacity', 1),``` - locate object with id ```logo``` in the svg, parse its ```style```-attribute as css-inline-string and change the value of the css-property ```opacity``` to 1. The Tupel-Element ```'style'``` is fixed and declares the type of action which is applied to the specified element. All other tupele-mebers can be modified to suit your needs.
|
||||
|
||||
To form an fade-in-opacity-animation, the frame-generator could look like this:
|
||||
|
||||
# three seconds of animation
|
||||
frames = 3*fps
|
||||
for i in range(0, frames):
|
||||
yield (
|
||||
('logo', 'style', 'opacity', "%.4f" % easeInCubic(i, 0, 1, frames)),
|
||||
)
|
||||
|
||||
```easeInCubic``` is an easing-function stolen from the [jquery-easing plugin](http://gsgd.co.uk/sandbox/jquery/easing/jquery.easing.1.3.js) ([easing-cheat-sheet](http://easings.net/)). They take 4 parameters:
|
||||
- t: current time
|
||||
- b: beginning value
|
||||
- c: change In value
|
||||
- d: duration (of time)
|
||||
|
||||
So to fade the logo out, the generator yould look like this:
|
||||
|
||||
# three seconds of animation
|
||||
frames = 3*fps
|
||||
for i in range(0, frames):
|
||||
yield (
|
||||
('logo', 'style', 'opacity', "%.4f" % easeInCubic(i, 1, -1, frames)),
|
||||
)
|
||||
|
||||
By yielding multiple sub-tuples, you can animate multiple elements at the same time using different easings. Its up to you to find a combination that looks nice with your artwork.
|
||||
|
||||
### XML-Attribute-Modifications
|
||||
The other form a sub-tuble can have is ```('box', 'attr', 'transform', 'translate(0,0)')``` - locate object with id ```box``` in the svg, and set its ```transform```-attribute to ```translate(0,0)```. This can be used to animate things not specifiable by css - like the spacial translation of an object. A suitable generator, that animates the element ```box``` in an upward movement, could look like this:
|
||||
|
||||
# three seconds of animation
|
||||
frames = 3*fps
|
||||
for i in range(0, frames):
|
||||
yield (
|
||||
('box', 'attr', 'transform', 'translate(0,%.4f)' % easeOutQuad(i, 100, -100, frames) ),
|
||||
)
|
||||
|
||||
|
||||
It works! It doesn't work!
|
||||
--------------------------
|
||||
If it works, push your code to github. This way everybody can see which beautiful animations you created and we can all learn from each other.
|
||||
If it doesn't work, ask [on IRC](irc://irc.hackint.org/voc), on [the Mailinglist](video@lists.ccc.de) or drop me a [personal mail](github@mazdermind.de) and we'll see that we can solve your problem.
|
||||
If you think you found a bug, [file an Issue](https://github.com/MaZderMind/c3voc-toolz/issues). Or even better, fix it and [send a Pull-Request](https://github.com/MaZderMind/c3voc-toolz/pulls).
|
|
@ -168,9 +168,9 @@
|
|||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.98994949"
|
||||
inkscape:cx="83.861659"
|
||||
inkscape:cy="280.49488"
|
||||
inkscape:zoom="5.6"
|
||||
inkscape:cx="167.31824"
|
||||
inkscape:cy="174.4509"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="box"
|
||||
showgrid="false"
|
||||
|
@ -242,12 +242,12 @@
|
|||
<image
|
||||
sodipodi:absref="/home/peter/AAA-VOC/mazdermind-c3voc-toolz/vor-abspann/sotmeu14/artwork/img-townhall-soft.jpg"
|
||||
xlink:href="img-townhall-soft.jpg"
|
||||
y="471.36218"
|
||||
x="0"
|
||||
id="image2993"
|
||||
height="681"
|
||||
style="opacity:1"
|
||||
width="1024"
|
||||
style="opacity:1" />
|
||||
height="681"
|
||||
id="image2993"
|
||||
x="0"
|
||||
y="471.36218" />
|
||||
<g
|
||||
transform="matrix(0.48994061,0,0,0.48994061,704.93504,274.4227)"
|
||||
id="logo"
|
||||
|
@ -255,11 +255,11 @@
|
|||
<image
|
||||
sodipodi:absref="/home/peter/AAA-VOC/mazdermind-c3voc-toolz/vor-abspann/sotmeu14/artwork/Logo.de.svg"
|
||||
xlink:href="Logo.de.svg"
|
||||
y="471.36218"
|
||||
x="0"
|
||||
id="manuimage2993"
|
||||
width="590"
|
||||
height="300"
|
||||
width="590" />
|
||||
id="manuimage2993"
|
||||
x="0"
|
||||
y="471.36218" />
|
||||
</g>
|
||||
<g
|
||||
id="box">
|
||||
|
@ -275,25 +275,36 @@
|
|||
sodipodi:linespacing="125%"
|
||||
id="text4531"
|
||||
y="881"
|
||||
x="122"
|
||||
x="119.29951"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;filter:url(#filter4858);font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#4b9dd0;fill-opacity:1;font-family:DejaVu Sans;-inkscape-font-specification:DejaVu Sans"
|
||||
y="881"
|
||||
x="120"
|
||||
x="119.29951"
|
||||
id="tspan4533"
|
||||
sodipodi:role="line">$personnames</tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text4535"
|
||||
y="922"
|
||||
x="122"
|
||||
style="font-size:32px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#444448;fill-opacity:0.94117647000000004;font-family:DejaVu Sans;-inkscape-font-specification:DejaVu Sans;filter:url(#filter4858)"
|
||||
xml:space="preserve"><tspan
|
||||
y="921"
|
||||
x="120"
|
||||
sodipodi:role="line"
|
||||
id="tspan91">$title</tspan></text>
|
||||
</g>
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot3041"
|
||||
style="fill:black;stroke:none;stroke-opacity:1;stroke-width:1px;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;font-family:Sans;font-style:normal;font-weight:normal;font-size:40px;line-height:125%;letter-spacing:0px;word-spacing:0px"><flowRegion
|
||||
id="flowRegion3043"><rect
|
||||
id="rect3045"
|
||||
width="268.70059"
|
||||
height="81.822357"
|
||||
x="212.13203"
|
||||
y="457.81216" /></flowRegion><flowPara
|
||||
id="flowPara3047"></flowPara></flowRoot> <flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot3049"
|
||||
style="font-size:32px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#444448;fill-opacity:0.94117647;stroke:none;filter:url(#filter4858);font-family:Sans"
|
||||
transform="translate(-115.67858,459.97825)"><flowRegion
|
||||
id="flowRegion3051"><rect
|
||||
id="rect3053"
|
||||
width="864.31305"
|
||||
height="138.8662"
|
||||
x="235.36554"
|
||||
y="428.51773"
|
||||
style="font-size:32px;fill:#444448;fill-opacity:0.94117647" /></flowRegion><flowPara
|
||||
id="flowPara3055">$title</flowPara></flowRoot> </g>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 9.6 KiB |
|
@ -8,19 +8,25 @@ import re
|
|||
import math
|
||||
import shutil
|
||||
import errno
|
||||
import unicodedata
|
||||
import urllib2
|
||||
#import xml.etree.ElementTree as etree
|
||||
from lxml import etree
|
||||
from xml.sax.saxutils import escape as xmlescape
|
||||
import cssutils
|
||||
import logging
|
||||
import textwrap
|
||||
import tempfile
|
||||
import threading
|
||||
import multiprocessing
|
||||
from threading import Thread, Lock
|
||||
from Queue import Queue
|
||||
|
||||
# URL to Schedule-XML
|
||||
scheduleUrl = 'http://www.fossgis.de/konferenz/2014/programm/schedule.de.xml'
|
||||
|
||||
# For (really) too long titles
|
||||
titlemap = {
|
||||
#708: "Neue WEB-Anwendungen des LGRB Baden-Württemberg im Überblick"
|
||||
}
|
||||
|
||||
# Frames per second. Increasing this renders more frames, the avconf-statements would still need modifications
|
||||
fps = 25
|
||||
|
||||
|
@ -62,27 +68,6 @@ def ensureFilesRemoved(pattern):
|
|||
for f in glob.glob(pattern):
|
||||
os.unlink(f)
|
||||
|
||||
# Normalizes string, converts to lowercase, removes non-alpha characters,
|
||||
#and converts spaces to hyphens.
|
||||
def slugify(value):
|
||||
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
|
||||
value = unicode(re.sub('[^\w\s-]', '', value).strip().lower())
|
||||
value = unicode(re.sub('[-\s]+', '-', value))
|
||||
return value
|
||||
|
||||
# create a filename from the events' id and a slugified version of the title
|
||||
def vorspannFilename(id, title):
|
||||
return u'{0:04d}-{1}.dv'.format(id, slugify(unicode(title)))
|
||||
|
||||
# svg does not have a method for automatic line breaking, that rsvg is capable of
|
||||
# so we do it in python as good as we can
|
||||
def vorspannTitle(title):
|
||||
return '</tspan><tspan x="120" dy="35">'.join(textwrap.wrap(title, 50))
|
||||
|
||||
def vorspannUrl(id):
|
||||
return 'fossgis.de/konferenz/2014/programm/events/'+str(id)+'.de.html'
|
||||
|
||||
|
||||
def abspannFrames():
|
||||
# 9 Sekunden
|
||||
|
||||
|
@ -199,7 +184,7 @@ def render(infile, outfile, sequence, parameters={}, workdir='artwork'):
|
|||
with open(os.path.join(workdir, infile), 'r') as fp:
|
||||
svgstr = fp.read()
|
||||
for key in parameters.keys():
|
||||
svgstr = svgstr.replace(key, str(parameters[key]))
|
||||
svgstr = svgstr.replace(key, xmlescape(str(parameters[key])))
|
||||
|
||||
svg = etree.fromstring(svgstr)
|
||||
|
||||
|
@ -208,7 +193,6 @@ def render(infile, outfile, sequence, parameters={}, workdir='artwork'):
|
|||
for el in svg.findall(".//svg:image[@xlink:href]", namespaces=namespaces):
|
||||
el.attrib['{http://www.w3.org/1999/xlink}href'] = 'file:///' + os.path.realpath(workdir) + '/' + el.attrib['{http://www.w3.org/1999/xlink}href']
|
||||
|
||||
|
||||
# frame-number counter
|
||||
frameNr = 0
|
||||
|
||||
|
@ -273,7 +257,7 @@ def events():
|
|||
|
||||
else:
|
||||
# download the schedule
|
||||
response = urllib2.urlopen('http://www.fossgis.de/konferenz/2014/programm/schedule.de.xml')
|
||||
response = urllib2.urlopen(scheduleUrl)
|
||||
|
||||
# read xml-source
|
||||
xml = response.read()
|
||||
|
@ -293,22 +277,22 @@ def events():
|
|||
personnames.append(person.text)
|
||||
|
||||
# yield a tupel with the event-id, event-title and person-names
|
||||
yield ( int(event.get('id')), event.find('title').text, ', '.join(personnames) )
|
||||
yield ( int(event.get('id')), event.find('title').text, event.find('subtitle').text or '', ', '.join(personnames) )
|
||||
|
||||
|
||||
# debug-mode selected by --debug switch
|
||||
if debug:
|
||||
print "!!! DEBUG MODE !!!"
|
||||
title = 'OpenJUMP - Überblick, Neuigkeiten, Zusammenarbeit/Schnittstellen mit proprietärer Software'
|
||||
|
||||
render(
|
||||
'vorspann.svg',
|
||||
os.path.join('..', str(667)+".dv"),
|
||||
'../intro.dv',
|
||||
vorspannFrames,
|
||||
{
|
||||
'$id': 667,
|
||||
'$title': vorspannTitle(title),
|
||||
'$personnames': 'Matthias Scholz'
|
||||
'$title': 'OpenJUMP - Überblick, Neuigkeiten, Zusammenarbeit/Schnittstellen mit proprietärer Software',
|
||||
'$subtitle': 'Even more news about OpenJUMP',
|
||||
'$personnames': 'Matthias S.'
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -330,10 +314,6 @@ if debug:
|
|||
# threaded task queue
|
||||
tasks = Queue()
|
||||
|
||||
titlemap = {
|
||||
708: "Neue WEB-Anwendungen des LGRB Baden-Württemberg im Überblick"
|
||||
}
|
||||
|
||||
# iterate over all events extracted from the schedule xml-export
|
||||
for (id, title, personnames) in events():
|
||||
if id in titlemap:
|
||||
|
@ -346,7 +326,8 @@ for (id, title, personnames) in events():
|
|||
vorspannFrames,
|
||||
{
|
||||
'$id': id,
|
||||
'$title': vorspannTitle(title),
|
||||
'$title': title,
|
||||
'$subtitle': subtitle,
|
||||
'$personnames': personnames
|
||||
}
|
||||
))
|
||||
|
|
Loading…
Add table
Reference in a new issue