Merge af310d7e3e
into 6ec541d49a
This commit is contained in:
commit
629abfbbee
3 changed files with 28 additions and 31 deletions
4
make.py
4
make.py
|
@ -56,6 +56,10 @@ parser.add_argument('--resvg', action="store_true", default=False, help='''
|
||||||
Render frames using resvg instead of Inkscape.
|
Render frames using resvg instead of Inkscape.
|
||||||
Usage: ./make.py yourproject/ --resvg
|
Usage: ./make.py yourproject/ --resvg
|
||||||
''')
|
''')
|
||||||
|
parser.add_argument('--audio-streams', action="store", default=2, type=int, help='''
|
||||||
|
Number of audio streams to generate.
|
||||||
|
Usage: ./make.py yourproject/ --audio-streams 4
|
||||||
|
''')
|
||||||
|
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
|
|
44
renderlib.py
44
renderlib.py
|
@ -11,6 +11,7 @@ from svgtemplate import SVGTemplate
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from urllib.request import urlopen
|
from urllib.request import urlopen
|
||||||
from wand.image import Image
|
from wand.image import Image
|
||||||
|
from tempfile import NamedTemporaryFile
|
||||||
|
|
||||||
# Frames per second. Increasing this renders more frames, the avconf-statements would still need modifications
|
# Frames per second. Increasing this renders more frames, the avconf-statements would still need modifications
|
||||||
fps = 25
|
fps = 25
|
||||||
|
@ -83,14 +84,18 @@ def ensureFilesRemoved(pattern):
|
||||||
for f in glob.glob(pattern):
|
for f in glob.glob(pattern):
|
||||||
os.unlink(f)
|
os.unlink(f)
|
||||||
|
|
||||||
def renderFrame(infile, task, outfile):
|
def renderFrame(svg, task, outfile):
|
||||||
width = 1920
|
width = 1920
|
||||||
height = 1080
|
height = 1080
|
||||||
|
outfile = os.path.abspath(outfile)
|
||||||
if args.imagemagick:
|
if args.imagemagick:
|
||||||
# invoke imagemagick to convert the generated svg-file into a png inside the .frames-directory
|
# invoke imagemagick to convert the generated svg-file into a png inside the .frames-directory
|
||||||
with Image(filename=infile) as img:
|
with NamedTemporaryFile(dir=task.workdir, suffix='.svg') as svgfile:
|
||||||
with img.convert('png') as converted:
|
svgfile.write(svg.svgstr.encode('utf-8'))
|
||||||
converted.save(filename=outfile)
|
svgfile.flush()
|
||||||
|
with Image(filename=svgfile.name) as img:
|
||||||
|
with img.convert('png') as converted:
|
||||||
|
converted.save(filename=outfile)
|
||||||
elif args.resvg:
|
elif args.resvg:
|
||||||
# invoke inkscape to convert the generated svg-file into a png inside the .frames-directory
|
# invoke inkscape to convert the generated svg-file into a png inside the .frames-directory
|
||||||
cmd = 'resvg --background white --width={1} --height={2} "{4}" "{3}" 2>&1 >/dev/null'.format(task.workdir, width, height, outfile, infile)
|
cmd = 'resvg --background white --width={1} --height={2} "{4}" "{3}" 2>&1 >/dev/null'.format(task.workdir, width, height, outfile, infile)
|
||||||
|
@ -98,11 +103,10 @@ def renderFrame(infile, task, outfile):
|
||||||
if errorReturn != '':
|
if errorReturn != '':
|
||||||
print("resvg exited with error\n" + errorReturn)
|
print("resvg exited with error\n" + errorReturn)
|
||||||
# sys.exit(42)
|
# sys.exit(42)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# invoke inkscape to convert the generated svg-file into a png inside the .frames-directory
|
# invoke inkscape to convert the generated svg-file into a png inside the .frames-directory
|
||||||
cmd = 'inkscape --export-background=white --export-background-opacity=0 --export-width={1} --export-height={2} --export-filename="{3}" "{4}" --pipe 2>&1 >/dev/null'.format(task.workdir, width, height, os.path.abspath(outfile), os.path.abspath(infile))
|
cmd = 'inkscape --export-background=white --export-background-opacity=0 --export-width={1} --export-height={2} --export-filename="{3}" --pipe 2>&1 >/dev/null'.format(task.workdir, width, height, outfile)
|
||||||
errorReturn = subprocess.check_output(cmd, shell=True, universal_newlines=True, stderr=subprocess.STDOUT, cwd=task.workdir)
|
errorReturn = subprocess.check_output(cmd, shell=True, universal_newlines=True, input=svg.svgstr, stderr=subprocess.STDOUT, cwd=task.workdir)
|
||||||
if errorReturn != '':
|
if errorReturn != '':
|
||||||
print("inkscape exited with error\n" + errorReturn)
|
print("inkscape exited with error\n" + errorReturn)
|
||||||
# sys.exit(42)
|
# sys.exit(42)
|
||||||
|
@ -135,26 +139,20 @@ def cachedRenderFrame(frame, frameNr, task, cache):
|
||||||
elif not skip_rendering:
|
elif not skip_rendering:
|
||||||
cache[frame] = frameNr
|
cache[frame] = frameNr
|
||||||
|
|
||||||
svgfile = '{0}/.frames/{1:04d}.svg'.format(task.workdir, frameNr)
|
outfile = '{0}/.frames/{1:04d}.png'.format(task.workdir, frameNr)
|
||||||
|
with SVGTemplate(task) as svg:
|
||||||
with SVGTemplate(task, svgfile) as svg:
|
|
||||||
svg.replacetext()
|
svg.replacetext()
|
||||||
svg.transform(frame)
|
svg.transform(frame)
|
||||||
svg.write()
|
renderFrame(svg, task, outfile)
|
||||||
|
|
||||||
outfile = '{0}/.frames/{1:04d}.png'.format(task.workdir, frameNr)
|
|
||||||
renderFrame(svgfile, task, outfile)
|
|
||||||
|
|
||||||
# increment frame-number
|
# increment frame-number
|
||||||
frameNr += 1
|
frameNr += 1
|
||||||
|
|
||||||
|
|
||||||
def rendertask_image(task):
|
def rendertask_image(task):
|
||||||
svgfile = '{0}/image.svg'.format(task.workdir)
|
with SVGTemplate(task) as svg:
|
||||||
with SVGTemplate(task, svgfile) as svg:
|
|
||||||
svg.replacetext()
|
svg.replacetext()
|
||||||
svg.write()
|
renderFrame(svg, task, task.outfile)
|
||||||
renderFrame(svgfile, task, task.outfile)
|
|
||||||
|
|
||||||
def rendertask_video(task):
|
def rendertask_video(task):
|
||||||
# iterate through the animation sequence frame by frame
|
# iterate through the animation sequence frame by frame
|
||||||
|
@ -178,16 +176,18 @@ def rendertask_video(task):
|
||||||
cmd = 'cd {0} && '.format(task.workdir)
|
cmd = 'cd {0} && '.format(task.workdir)
|
||||||
cmd += 'ffmpeg -f image2 -i .frames/%04d.png '
|
cmd += 'ffmpeg -f image2 -i .frames/%04d.png '
|
||||||
if task.audiofile is None:
|
if task.audiofile is None:
|
||||||
cmd += '-ar 48000 -ac 1 -f s16le -i /dev/zero -ar 48000 -ac 1 -f s16le -i /dev/zero '
|
audio_input = '-ar 48000 -ac 1 -f s16le -i /dev/zero '
|
||||||
else:
|
else:
|
||||||
cmd += '-i {0} -i {0} '.format(task.audiofile)
|
audio_input = '-i {0} '.format(task.audiofile)
|
||||||
|
cmd += audio_input * args.audio_streams
|
||||||
|
|
||||||
cmd += '-map 0:0 -c:v mpeg2video -q:v 2 -aspect 16:9 '
|
cmd += '-map 0:0 -c:v mpeg2video -q:v 2 -aspect 16:9 '
|
||||||
|
|
||||||
if task.audiofile is None:
|
if task.audiofile is None:
|
||||||
cmd += '-map 1:0 -map 2:0 '
|
audio_map = '-map {0}:0 '
|
||||||
else:
|
else:
|
||||||
cmd += '-map 1:0 -c:a copy -map 2:0 -c:a copy '
|
audio_map = '-map {0}:0 -c:a copy '
|
||||||
|
cmd += ''.join(audio_map.format(index + 1) for index in range(args.audio_streams))
|
||||||
cmd += '-shortest -f mpegts "{0}"'.format(task.outfile)
|
cmd += '-shortest -f mpegts "{0}"'.format(task.outfile)
|
||||||
elif task.outfile.endswith('.mov'):
|
elif task.outfile.endswith('.mov'):
|
||||||
cmd = 'cd {0} && '.format(task.workdir)
|
cmd = 'cd {0} && '.format(task.workdir)
|
||||||
|
|
|
@ -12,21 +12,14 @@ cssutils.ser.prefs.lineSeparator = ' '
|
||||||
cssutils.log.setLevel(logging.FATAL)
|
cssutils.log.setLevel(logging.FATAL)
|
||||||
|
|
||||||
class SVGTemplate:
|
class SVGTemplate:
|
||||||
def __init__(self, task, outfile):
|
def __init__(self, task):
|
||||||
self.task = task
|
self.task = task
|
||||||
self.outfile = outfile
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
with builtins.open(os.path.join(self.task.workdir, self.task.infile), 'r') as fp:
|
with builtins.open(os.path.join(self.task.workdir, self.task.infile), 'r') as fp:
|
||||||
self.svgstr = fp.read()
|
self.svgstr = fp.read()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def write(self):
|
|
||||||
# open the output-file (named ".gen.svg" in the workdir)
|
|
||||||
with builtins.open(self.outfile, 'w') as fp:
|
|
||||||
# write the generated svg-text into the output-file
|
|
||||||
fp.write(self.svgstr)
|
|
||||||
|
|
||||||
def replacetext(self):
|
def replacetext(self):
|
||||||
for key in self.task.parameters.keys():
|
for key in self.task.parameters.keys():
|
||||||
self.svgstr = self.svgstr.replace(key, xmlescape(str(self.task.parameters[key])))
|
self.svgstr = self.svgstr.replace(key, xmlescape(str(self.task.parameters[key])))
|
||||||
|
@ -49,7 +42,7 @@ class SVGTemplate:
|
||||||
# if '$subtitle' in task.parameters and task.parameters['$subtitle'] == '':
|
# if '$subtitle' in task.parameters and task.parameters['$subtitle'] == '':
|
||||||
# child = svg.findall(".//*[@id='subtitle']")[0]
|
# child = svg.findall(".//*[@id='subtitle']")[0]
|
||||||
# child.getparent().remove(child)
|
# child.getparent().remove(child)
|
||||||
self.svgstr = etree.tostring(svg, encoding='unicode')
|
self.svgstr = etree.tostring(svg).decode('UTF-8')
|
||||||
|
|
||||||
def __exit__(self, exception_type, exception_value, traceback):
|
def __exit__(self, exception_type, exception_value, traceback):
|
||||||
pass
|
pass
|
||||||
|
|
Loading…
Add table
Reference in a new issue