This commit is contained in:
Manfred Stock 2023-01-01 00:45:56 +01:00 committed by GitHub
commit 629abfbbee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 28 additions and 31 deletions

View file

@ -56,6 +56,10 @@ parser.add_argument('--resvg', action="store_true", default=False, help='''
Render frames using resvg instead of Inkscape.
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:
parser.print_help()

View file

@ -11,6 +11,7 @@ from svgtemplate import SVGTemplate
from lxml import etree
from urllib.request import urlopen
from wand.image import Image
from tempfile import NamedTemporaryFile
# Frames per second. Increasing this renders more frames, the avconf-statements would still need modifications
fps = 25
@ -83,12 +84,16 @@ def ensureFilesRemoved(pattern):
for f in glob.glob(pattern):
os.unlink(f)
def renderFrame(infile, task, outfile):
def renderFrame(svg, task, outfile):
width = 1920
height = 1080
outfile = os.path.abspath(outfile)
if args.imagemagick:
# 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:
svgfile.write(svg.svgstr.encode('utf-8'))
svgfile.flush()
with Image(filename=svgfile.name) as img:
with img.convert('png') as converted:
converted.save(filename=outfile)
elif args.resvg:
@ -98,11 +103,10 @@ def renderFrame(infile, task, outfile):
if errorReturn != '':
print("resvg exited with error\n" + errorReturn)
# sys.exit(42)
else:
# 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))
errorReturn = subprocess.check_output(cmd, shell=True, universal_newlines=True, stderr=subprocess.STDOUT, cwd=task.workdir)
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, input=svg.svgstr, stderr=subprocess.STDOUT, cwd=task.workdir)
if errorReturn != '':
print("inkscape exited with error\n" + errorReturn)
# sys.exit(42)
@ -135,26 +139,20 @@ def cachedRenderFrame(frame, frameNr, task, cache):
elif not skip_rendering:
cache[frame] = frameNr
svgfile = '{0}/.frames/{1:04d}.svg'.format(task.workdir, frameNr)
with SVGTemplate(task, svgfile) as svg:
outfile = '{0}/.frames/{1:04d}.png'.format(task.workdir, frameNr)
with SVGTemplate(task) as svg:
svg.replacetext()
svg.transform(frame)
svg.write()
outfile = '{0}/.frames/{1:04d}.png'.format(task.workdir, frameNr)
renderFrame(svgfile, task, outfile)
renderFrame(svg, task, outfile)
# increment frame-number
frameNr += 1
def rendertask_image(task):
svgfile = '{0}/image.svg'.format(task.workdir)
with SVGTemplate(task, svgfile) as svg:
with SVGTemplate(task) as svg:
svg.replacetext()
svg.write()
renderFrame(svgfile, task, task.outfile)
renderFrame(svg, task, task.outfile)
def rendertask_video(task):
# iterate through the animation sequence frame by frame
@ -178,16 +176,18 @@ def rendertask_video(task):
cmd = 'cd {0} && '.format(task.workdir)
cmd += 'ffmpeg -f image2 -i .frames/%04d.png '
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:
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 '
if task.audiofile is None:
cmd += '-map 1:0 -map 2:0 '
audio_map = '-map {0}:0 '
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)
elif task.outfile.endswith('.mov'):
cmd = 'cd {0} && '.format(task.workdir)

View file

@ -12,21 +12,14 @@ cssutils.ser.prefs.lineSeparator = ' '
cssutils.log.setLevel(logging.FATAL)
class SVGTemplate:
def __init__(self, task, outfile):
def __init__(self, task):
self.task = task
self.outfile = outfile
def __enter__(self):
with builtins.open(os.path.join(self.task.workdir, self.task.infile), 'r') as fp:
self.svgstr = fp.read()
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):
for key in self.task.parameters.keys():
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'] == '':
# child = svg.findall(".//*[@id='subtitle']")[0]
# 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):
pass