From f209bcbe549e39b75dc2c44a217ae4e540c7f978 Mon Sep 17 00:00:00 2001 From: Jennifer Taylor Date: Wed, 21 Apr 2021 01:06:48 +0000 Subject: [PATCH] Exit early if we're done rendering the main animation, allow background color override. --- bemani/format/afp/render.py | 17 ++++++++++++++++- bemani/utils/afputils.py | 37 ++++++++++++++++++++++++++++++------- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/bemani/format/afp/render.py b/bemani/format/afp/render.py index e7f772f..c1f2e6c 100644 --- a/bemani/format/afp/render.py +++ b/bemani/format/afp/render.py @@ -118,7 +118,7 @@ class AFPRenderer(VerboseOutput): data.parse() 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, # attempt to render it to a list of frames, one per image. components = path.split(".") @@ -130,6 +130,7 @@ class AFPRenderer(VerboseOutput): if swf.exported_name == components[0]: # This is the SWF we care about. with self.debugging(verbose): + swf.color = background_color or swf.color return self.__render(swf, components[1] if len(components) > 1 else None) raise Exception(f'{path} not found in registered SWFs!') @@ -598,7 +599,21 @@ class AFPRenderer(VerboseOutput): frameno += 1 # 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] + + # 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: # Allow ctrl-c to end early and render a partial animation. print(f"WARNING: Interrupted early, will render only {len(frames)} of animation!") diff --git a/bemani/utils/afputils.py b/bemani/utils/afputils.py index 796f7b2..7185811 100644 --- a/bemani/utils/afputils.py +++ b/bemani/utils/afputils.py @@ -9,7 +9,7 @@ import textwrap from PIL import Image, ImageDraw # type: ignore 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 @@ -167,6 +167,12 @@ def main() -> int: action="store_true", 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.add_argument( @@ -558,12 +564,7 @@ def main() -> int: continue if args.action == "render": - # Render the gif/webp frames. - 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. + # Verify the correct params. if args.output.lower().endswith(".gif"): fmt = "GIF" elif args.output.lower().endswith(".webp"): @@ -573,6 +574,28 @@ def main() -> int: else: 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"]: # Write all the frames out in one file. with open(args.output, "wb") as bfp: