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
		Add a link
		
	
		Reference in a new issue