1
0
mirror of synced 2025-02-16 10:52:34 +01:00

Exit early if we're done rendering the main animation, allow background color override.

This commit is contained in:
Jennifer Taylor 2021-04-21 01:06:48 +00:00
parent 47525837cd
commit f209bcbe54
2 changed files with 46 additions and 8 deletions

View File

@ -118,7 +118,7 @@ class AFPRenderer(VerboseOutput):
data.parse() data.parse()
self.swfs[name] = data self.swfs[name] = data
def render_path(self, path: str, verbose: bool = False) -> Tuple[int, List[Image.Image]]: def render_path(self, path: str, background_color: Optional[Color] = None, verbose: bool = False) -> Tuple[int, List[Image.Image]]:
# Given a path to a SWF root animation or an exported animation inside a SWF, # Given a path to a SWF root animation or an exported animation inside a SWF,
# attempt to render it to a list of frames, one per image. # attempt to render it to a list of frames, one per image.
components = path.split(".") components = path.split(".")
@ -130,6 +130,7 @@ class AFPRenderer(VerboseOutput):
if swf.exported_name == components[0]: if swf.exported_name == components[0]:
# This is the SWF we care about. # This is the SWF we care about.
with self.debugging(verbose): with self.debugging(verbose):
swf.color = background_color or swf.color
return self.__render(swf, components[1] if len(components) > 1 else None) return self.__render(swf, components[1] if len(components) > 1 else None)
raise Exception(f'{path} not found in registered SWFs!') raise Exception(f'{path} not found in registered SWFs!')
@ -598,7 +599,21 @@ class AFPRenderer(VerboseOutput):
frameno += 1 frameno += 1
# Garbage collect any clips that we're finished with. # Garbage collect any clips that we're finished with.
removed_referenced_tag = False
for c in self.__clips:
if c.finished:
if self.__visible_tag == c.tag_id:
removed_referenced_tag = True
self.vprint(f" Removing clip based on Tag ID {clip.tag_id} because it is finished playing.")
self.__clips = [c for c in self.__clips if not c.finished] self.__clips = [c for c in self.__clips if not c.finished]
# Exit early if we removed all tags we would be rendering.
if removed_referenced_tag and self.__clips:
if not any(c.tag_id == self.__visible_tag for c in self.__clips):
self.vprint("Finishing early because the tag we are rendering has deconstructed.")
break
except KeyboardInterrupt: except KeyboardInterrupt:
# Allow ctrl-c to end early and render a partial animation. # Allow ctrl-c to end early and render a partial animation.
print(f"WARNING: Interrupted early, will render only {len(frames)} of animation!") print(f"WARNING: Interrupted early, will render only {len(frames)} of animation!")

View File

@ -9,7 +9,7 @@ import textwrap
from PIL import Image, ImageDraw # type: ignore from PIL import Image, ImageDraw # type: ignore
from typing import Any, Dict from typing import Any, Dict
from bemani.format.afp import TXP2File, Shape, SWF, AFPRenderer from bemani.format.afp import TXP2File, Shape, SWF, AFPRenderer, Color
from bemani.format import IFS from bemani.format import IFS
@ -167,6 +167,12 @@ def main() -> int:
action="store_true", action="store_true",
help="Display verbuse debugging output", help="Display verbuse debugging output",
) )
render_parser.add_argument(
"--background-color",
type=str,
default=None,
help="Set the background color of the animation, overriding a default if present in the SWF.",
)
list_parser = subparsers.add_parser('list', help='List out the possible paths to render from a series of SWFs') list_parser = subparsers.add_parser('list', help='List out the possible paths to render from a series of SWFs')
list_parser.add_argument( list_parser.add_argument(
@ -558,12 +564,7 @@ def main() -> int:
continue continue
if args.action == "render": if args.action == "render":
# Render the gif/webp frames. # Verify the correct params.
duration, images = renderer.render_path(args.path, verbose=args.verbose)
if len(images) == 0:
raise Exception("Did not render any frames!")
# Write them out to a new file.
if args.output.lower().endswith(".gif"): if args.output.lower().endswith(".gif"):
fmt = "GIF" fmt = "GIF"
elif args.output.lower().endswith(".webp"): elif args.output.lower().endswith(".webp"):
@ -573,6 +574,28 @@ def main() -> int:
else: else:
raise Exception("Unrecognized file extension for output!") raise Exception("Unrecognized file extension for output!")
# Allow overriding background color.
if args.background_color:
colorvals = args.background_color.split(",")
if len(colorvals) not in [3, 4]:
raise Exception("Invalid color, specify a color as a comma-separated RGB or RGBA value!")
if len(colorvals) == 3:
colorvals.append("255")
colorints = [int(c.strip()) for c in colorvals]
for c in colorints:
if c < 0 or c > 255:
raise Exception("Color values should be between 0 and 255!")
color = Color(*[c / 255.0 for c in colorints])
else:
color = None
# Render the gif/webp frames.
duration, images = renderer.render_path(args.path, verbose=args.verbose, background_color=color)
if len(images) == 0:
raise Exception("Did not render any frames!")
if fmt in ["GIF", "WEBP"]: if fmt in ["GIF", "WEBP"]:
# Write all the frames out in one file. # Write all the frames out in one file.
with open(args.output, "wb") as bfp: with open(args.output, "wb") as bfp: