Merge branch 'master' of github.com:MaZderMind/c3voc-toolz

This commit is contained in:
MaZderMind 2014-04-24 13:25:27 +02:00
commit 3102e07ea3
3 changed files with 137 additions and 63 deletions

82
README.md Normal file
View 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).

View file

@ -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

View file

@ -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
}
))