more elegant solution to modify the svgs which keeps the svgs editable

This commit is contained in:
MaZderMind 2014-04-09 20:55:55 +02:00
parent b5dc82b054
commit 85dfd7043d
4 changed files with 106 additions and 87 deletions

View file

@ -148,14 +148,14 @@
id="g_background"
transform="translate(3.2142857,-29.821429)">
<image
xlink:href="file:///%workdir/foto-soft.jpg"
xlink:href="foto-soft.jpg"
y="313.82144"
x="-3.2142856"
id="image_background"
height="768"
width="1024" />
<image
xlink:href="file:///%workdir/logo_ohne_rand-332.png"
xlink:href="logo_ohne_rand-332.png"
y="537.82141"
x="28.785715"
id="image_logo"
@ -215,11 +215,12 @@
</g>
<image
style="opacity:%opacityLizenz"
style="opacity:1"
id="lizenz"
y="950"
x="890"
width="120"
height="42"
xlink:href="file:///%workdir/%lizenz.svg" />
xlink:href="by-sa.svg" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Before After
Before After

View file

@ -148,14 +148,14 @@
id="g_background"
transform="translate(3.2142857,-29.821429)">
<image
xlink:href="file:///%workdir/foto-soft.jpg"
xlink:href="foto-soft.jpg"
y="313.82144"
x="-3.2142856"
id="image_background"
height="768"
width="1024" />
<image
xlink:href="file:///%workdir/logo_ohne_rand-332.png"
xlink:href="logo_ohne_rand-332.png"
y="537.82141"
x="28.785715"
id="image_logo"
@ -174,8 +174,8 @@
id="rect_banderole_1" />
</g>
<g
style="opacity:%opacity1"
id="g3849">
style="opacity:1"
id="text1">
<text
sodipodi:linespacing="80.000001%"
id="text2992"
@ -218,8 +218,8 @@
</g>
<g
style="opacity:%opacity2"
id="g3849">
style="opacity:0"
id="text2">
<text
sodipodi:linespacing="80.000001%"
id="text2992-5"

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Before After
Before After

View file

@ -179,14 +179,14 @@
id="g_background"
transform="translate(3.2142857,-29.821429)">
<image
xlink:href="file:///%workdir/foto-soft.jpg"
xlink:href="foto-soft.jpg"
width="1024"
height="768"
id="image_background"
x="-3.2142856"
y="313.82144" />
<image
xlink:href="file:///%workdir/logo_ohne_rand-332.png"
xlink:href="logo_ohne_rand-332.png"
width="166"
height="166"
id="image_logo"
@ -194,8 +194,8 @@
y="537.82141" />
</g>
<g
style="opacity:%opacityBox"
id="g3091x">
style="opacity:1"
id="box">
<rect
style="fill:#ffffff;fill-opacity:0.50196078"
ry="0.0062701544"
@ -206,8 +206,8 @@
id="rect_banderole_1" />
</g>
<g
style="opacity:%opacity1"
id="g3091">
style="opacity:0"
id="text1">
<text
sodipodi:linespacing="80.000001%"
id="text2992"
@ -244,8 +244,8 @@
sodipodi:role="line">2014</tspan></text>
</g>
<g
style="opacity:%opacity2"
id="g3115"
style="opacity:1"
id="text2"
transform="translate(-70,202)">
<text
xml:space="preserve"
@ -257,8 +257,8 @@
sodipodi:role="line"
x="149.334"
y="625.30579"
id="tspan3002-1"
style="font-size:48px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:80.00000119%;fill:#7b9199;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans Bold">%personnames</tspan></text>
id="personnames"
style="font-size:48px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:80.00000119%;fill:#7b9199;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans Bold">$personnames</tspan></text>
<text
xml:space="preserve"
style="font-size:43px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:80.00000119%;fill:#f2f4f5;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans Bold"
@ -269,7 +269,7 @@
sodipodi:role="line"
x="150.58771"
y="696.31714"
id="tspan2998-1-5">%title</tspan></text>
id="title">$title</tspan></text>
</g>
<text
xml:space="preserve"
@ -281,7 +281,7 @@
sodipodi:role="line"
x="563.25279"
y="1042"
id="tspan3002-3-3-1"
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:80.00000119%;fill:#f2f4f5;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans Bold">fossgis.de/konferenz/2014/programm/events/%id.de.html</tspan></text>
id="url"
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:80.00000119%;fill:#f2f4f5;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans Bold">fossgis.de/konferenz/2014/programm/events/$id.de.html</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Before After
Before After

View file

@ -9,7 +9,9 @@ import shutil
import errno
import unicodedata
import urllib2
import xml.etree.ElementTree as ET
#import xml.etree.ElementTree as etree
from lxml import etree
import cssutils
import textwrap
import tempfile
import threading
@ -67,6 +69,8 @@ def vorspannFilename(id, title):
def vorspannTitle(title):
return '</tspan><tspan x="150" dy="45">'.join(textwrap.wrap(title, 35))
def vorspannUrl(id):
return 'fossgis.de/konferenz/2014/programm/events/'+str(id)+'.de.html'
def abspannFrames():
@ -76,24 +80,24 @@ def abspannFrames():
frames = 2*fps
for i in range(0, frames):
yield {
'%opacity': easeOutCubic(i, 0, 1, frames),
'%opacityLizenz': 0
('banderole', 'opacity', "%.2f" % easeOutCubic(i, 0, 1, frames) ),
('license', 'opacity', 0)
}
# 2 Sekunde Fadein Lizenz-Logo
frames = 2*fps
for i in range(0, frames):
yield {
'%opacity': 1,
'%opacityLizenz': float(i)/frames
('banderole', 'opacity', 1),
('license', 'opacity', "%.2f" % (float(i)/frames))
}
# 1 Sekunde stehen bleiben
frames = 1*fps
for i in range(0, frames):
yield {
'%opacity': 1,
'%opacityLizenz': 1
('banderole', 'opacity', 1),
('license', 'opacity', 1)
}
def vorspannFrames():
@ -102,37 +106,37 @@ def vorspannFrames():
# 2 Sekunden Text 1
frames = 2*fps
for i in range(0, frames):
yield {
'%opacityBox': easeOutCubic(i, 0, 1, frames),
'%opacity1': easeOutCubic(i, 0, 1, frames),
'%opacity2': 0
}
yield (
('box', 'opacity', "%.2f" % easeOutCubic(i, 0, 1, frames)),
('text1', 'opacity', "%.2f" % easeOutCubic(i, 0, 1, frames)),
('text2', 'opacity', 0)
)
# 1 Sekunde Fadeout Text 1
frames = 1*fps
for i in range(0, frames):
yield {
'%opacityBox': 1,
'%opacity1': 1-(float(i)/frames),
'%opacity2': 0
('box', 'opacity', 1),
('text1', 'opacity', "%.2f" % (1-(float(i)/frames))),
('text2', 'opacity', 0)
}
# 2 Sekunden Text 2
frames = 2*fps
for i in range(0, frames):
yield {
'%opacityBox': 1,
'%opacity1': 0,
'%opacity2': easeOutCubic(i, 0, 1, frames)
('box', 'opacity', 1),
('text1', 'opacity', 0),
('text2', 'opacity', "%.2f" % easeOutCubic(i, 0, 1, frames))
}
# 2 Sekunden stehen bleiben
frames = 2*fps
for i in range(0, frames):
yield {
'%opacityBox': 1,
'%opacity1': 0,
'%opacity2': 1
('box', 'opacity', 1),
('text1', 'opacity', 0),
('text2', 'opacity', 1)
}
def pauseFrames():
@ -142,50 +146,51 @@ def pauseFrames():
frames = 2*fps
for i in range(0, frames):
yield {
'%opacity1': 1,
'%opacity2': 0
('text1', 'opacity', 1),
('text2', 'opacity', 0)
}
# 2 Sekunden Fadeout Text1
frames = 2*fps
for i in range(0, frames):
yield {
'%opacity1': 1-easeOutCubic(i, 0, 1, frames),
'%opacity2': 0
('text1', 'opacity', "%.2f" % (1-easeOutCubic(i, 0, 1, frames))),
('text2', 'opacity', 0)
}
# 2 Sekunden Fadein Text2
frames = 2*fps
for i in range(0, frames):
yield {
'%opacity1': 0,
'%opacity2': easeOutCubic(i, 0, 1, frames)
('text1', 'opacity', 0),
('text2', 'opacity', "%.2f" % easeOutCubic(i, 0, 1, frames))
}
# 2 Sekunden Text2 stehen
frames = 2*fps
for i in range(0, frames):
yield {
'%opacity1': 0,
'%opacity2': 1
('text1', 'opacity', 0),
('text2', 'opacity', 1)
}
# 2 Sekunden Fadeout Text2
frames = 2*fps
for i in range(0, frames):
yield {
'%opacity1': 0,
'%opacity2': 1-easeOutCubic(i, 0, 1, frames)
('text1', 'opacity', 0),
('text2', 'opacity', "%.2f" % (1-easeOutCubic(i, 0, 1, frames)))
}
# 2 Sekunden Fadein Text1
frames = 2*fps
for i in range(0, frames):
yield {
'%opacity1': easeOutCubic(i, 0, 1, frames),
'%opacity2': 0
('text1', 'opacity', "%.2f" % (easeOutCubic(i, 0, 1, frames))),
('text2', 'opacity', 0)
}
cssutils.ser.prefs.lineSeparator = ' '
def render(infile, outfile, sequence, parameters={}, workdir='artwork'):
# in debug mode we have no thread-worker which prints its progress
@ -197,33 +202,41 @@ def render(infile, outfile, sequence, parameters={}, workdir='artwork'):
# open and parse the input file
with open(os.path.join(workdir, infile), 'r') as fp:
svg = fp.read()
svgstr = fp.read()
for key in parameters.keys():
svgstr = svgstr.replace(key, str(parameters[key]))
svg = etree.fromstring(svgstr)
# find all images and force them to absolute file-urls
namespaces = {'xlink': 'http://www.w3.org/1999/xlink', 'svg': 'http://www.w3.org/2000/svg'}
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
# iterate through the animation seqence frame by frame
# frame is a dictionary with key/value-pairs ("replace-pairs"), where the key
# is searched for in the source svg-file and every occurence is replaced by
# its companion the value
# frame is a ... tbd
for frame in sequence():
# print a line for each and every frame generated
if debug:
print "frameNr {0:2d} => {1}".format(frameNr, frame)
# extend the frame-dictionary with additional replace-pairs from the arguments
frame.update(parameters)
# add some more useful replace-pairs
frame['%workdir'] = os.path.realpath(workdir)
# open the output-file (named ".gen.svg" in the workdir)
with open(os.path.join(workdir, '.gen.svg'), 'w') as fp:
# apply the replace-pairs to the input text, by replacing each key with its companion value
gen_svg = reduce(lambda x, y: x.replace(y, str(frame[y])), frame, svg)
# apply the replace-pairs to the input text, by finding the specified xml-elements by thier id and modify thier css-parameter the correct value
for replaceinfo in frame:
(id, key, value) = replaceinfo
for el in svg.findall(".//*[@id='"+id.replace("'", "\\'")+"']"):
style = cssutils.parseStyle( el.attrib['style'] )
style[key] = unicode(value)
el.attrib['style'] = style.cssText
# write the generated svg-text into the output-file
fp.write( gen_svg )
fp.write( etree.tostring(svg) )
# invoke rsvg to convert the generated svg-file into a png inside the .frames-directory
os.system('cd {0} && rsvg-convert .gen.svg > .frames/{1:04d}.png'.format(workdir, frameNr))
@ -236,7 +249,7 @@ def render(infile, outfile, sequence, parameters={}, workdir='artwork'):
# invoke avconv aka ffmpeg and renerate a lossles-dv from the frames
# if we're not in debug-mode, suppress all output
os.system('cd {0} && avconv -ar 48000 -ac 2 -f s16le -i /dev/zero -f image2 -i .frames/%04d.png -target pal-dv "{1}"'.format(workdir, outfile) + ('' if debug else '>/dev/null 2>&1'))
os.system('cd {0} && avconv -ar 48000 -ac 2 -f s16le -i /dev/zero -f image2 -i .frames/%04d.png -target pal-dv -shortest "{1}"'.format(workdir, outfile) + ('' if debug else '>/dev/null 2>&1'))
# as before, in non-debug-mode the thread-worker does all progress messages
if debug:
@ -257,7 +270,7 @@ def events():
# use --offline to skip networking
if offline:
# parse the offline-version
schedule = ET.parse('schedule.de.xml').getroot()
schedule = etree.parse('schedule.de.xml').getroot()
else:
# download the schedule
@ -267,7 +280,7 @@ def events():
xml = response.read()
# parse into ElementTree
schedule = ET.fromstring(xml)
schedule = etree.fromstring(xml)
# iterate all days
for day in schedule.iter('day'):
@ -291,16 +304,19 @@ if debug:
render(
'vorspann.svg',
os.path.join('..', vorspannFilename(667, title)),
os.path.join('..', str(667)+".dv"),
vorspannFrames,
{'%id': 664, '%title': vorspannTitle(title), '%personnames': 'Matthias Scholz' }
{
'$id': 667,
'$title': vorspannTitle(title),
'$personnames': 'Matthias Scholz'
}
)
render(
'abspann.svg',
'../abspann-by-sa.dv',
abspannFrames,
{'%lizenz': 'by-sa'}
'../outro.dv',
abspannFrames
)
render('pause.svg',
@ -327,19 +343,21 @@ for (id, title, personnames) in events():
# generate a task description and put them into the queue
tasks.put((
'vorspann.svg',
vorspannFilename(id, title),
str(id)+".dv",
vorspannFrames,
{'%id':id, '%title':vorspannTitle(title), '%personnames':personnames }
{
'$id': id,
'$title': vorspannTitle(title),
'$personnames': personnames
}
))
# iterate over the licences and place a task into the queue
for lizenz in ('by-sa', 'by-nc-sa', 'cc-zero'):
tasks.put((
'abspann.svg',
'abspann-{0}.dv'.format(lizenz),
abspannFrames,
{'%lizenz':lizenz}
))
# place a task for the outro into the queue
tasks.put((
'abspann.svg',
'outro.dv',
abspannFrames
))
# place the pause-sequence into the queue
tasks.put((