Skip to content

Commit ca01d2f

Browse files
committed
Fix Pillow typing
1 parent a11319c commit ca01d2f

2 files changed

Lines changed: 162 additions & 168 deletions

File tree

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ pip3 install wheel
2525
pip3 install rlottie-python
2626
```
2727

28+
Optionally, install `Pillow`:
29+
```
30+
pip3 install Pillow
31+
```
32+
2833
## Building from source
2934

3035
To build wheel, run the following:

rlottie_python/rlottie_wrapper.py

Lines changed: 157 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@
1010

1111
PILLOW_LOADED = True
1212
except ModuleNotFoundError:
13-
14-
class Image:
15-
pass
16-
1713
PILLOW_LOADED = False
1814
from .rlottiecommon import LOTLayerNode, LOTMarkerList
1915

@@ -659,173 +655,166 @@ def lottie_configure_model_cache_size(self, cache_size: int):
659655
self.rlottie_lib.lottie_configure_model_cache_size.restype = ctypes.c_void_p
660656
self.rlottie_lib.lottie_configure_model_cache_size(ctypes.c_size_t(cache_size))
661657

662-
def render_pillow_frame(
663-
self,
664-
frame_num: int = 0,
665-
buffer_size: Optional[int] = None,
666-
width: Optional[int] = None,
667-
height: Optional[int] = None,
668-
bytes_per_line: Optional[int] = None,
669-
) -> Image:
670-
"""
671-
Create Pillow Image at frame_num
672-
673-
:param int frame_num: the frame number needs to be rendered.
674-
Defaults to 0.
675-
:param Optional[int] buffer_size: size of surface buffer use for rendering
676-
:param Optional[int] width: width of the surface
677-
:param Optional[int] height: height of the surface
678-
:param Optional[int] bytes_per_line: stride of the surface in bytes.
679-
680-
:return: rendered Pillow Image
681-
:rtype: PIL.Image.Image
682-
"""
683-
if not PILLOW_LOADED:
684-
raise ModuleNotFoundError("Pillow is required for this function.")
685-
686-
if width == None or height == None:
687-
width, height = self.lottie_animation_get_size()
688-
689-
buffer = self.lottie_animation_render(
690-
frame_num=frame_num,
691-
buffer_size=buffer_size,
692-
width=width,
693-
height=height,
694-
bytes_per_line=bytes_per_line,
695-
)
696-
697-
im = Image.frombuffer("RGBA", (width, height), buffer, "raw", "BGRA")
698-
699-
return im
700-
701-
def save_frame(
702-
self,
703-
save_path: str,
704-
frame_num: int = 0,
705-
buffer_size: Optional[int] = None,
706-
width: Optional[int] = None,
707-
height: Optional[int] = None,
708-
bytes_per_line: Optional[int] = None,
709-
*args,
710-
**kwargs,
711-
) -> Image:
712-
"""
713-
Save Image at frame_num to save_path
714-
715-
:param str save_path: path to save the Pillow Image
716-
:param int frame_num: the frame number needs to be rendered.
717-
Defaults to 0.
718-
:param Optional[int] buffer_size: size of surface buffer use for rendering
719-
:param Optional[int] width: width of the surface
720-
:param Optional[int] height: height of the surface
721-
:param Optional[int] bytes_per_line: stride of the surface in bytes.
722-
:param *args: additional arguments passing to im.save()
723-
:param **kwargs: additional arguments passing to im.save()
724-
725-
:return: rendered Pillow Image
726-
:rtype: PIL.Image.Image
727-
"""
728-
if not PILLOW_LOADED:
729-
raise ModuleNotFoundError("Pillow is required for this function.")
730-
731-
im = self.render_pillow_frame(
732-
frame_num=frame_num,
733-
buffer_size=buffer_size,
734-
width=width,
735-
height=height,
736-
bytes_per_line=bytes_per_line,
737-
)
738-
im.save(save_path, *args, **kwargs)
739-
740-
def save_animation(
741-
self,
742-
save_path: str,
743-
fps: Optional[int] = None,
744-
frame_num_start: Optional[int] = None,
745-
frame_num_end: Optional[int] = None,
746-
buffer_size: Optional[int] = None,
747-
width: Optional[int] = None,
748-
height: Optional[int] = None,
749-
bytes_per_line: Optional[int] = None,
750-
*args,
751-
**kwargs,
752-
) -> Image:
753-
"""
754-
Save Image from frame_num_start to frame_num_end and save it to save_path.
755-
756-
It is possible to save animation as apng, gif or webp.
658+
if PILLOW_LOADED:
659+
660+
def render_pillow_frame(
661+
self,
662+
frame_num: int = 0,
663+
buffer_size: Optional[int] = None,
664+
width: Optional[int] = None,
665+
height: Optional[int] = None,
666+
bytes_per_line: Optional[int] = None,
667+
) -> Image.Image:
668+
"""
669+
Create Pillow Image at frame_num
670+
671+
:param int frame_num: the frame number needs to be rendered.
672+
Defaults to 0.
673+
:param Optional[int] buffer_size: size of surface buffer use for rendering
674+
:param Optional[int] width: width of the surface
675+
:param Optional[int] height: height of the surface
676+
:param Optional[int] bytes_per_line: stride of the surface in bytes.
677+
678+
:return: rendered Pillow Image
679+
:rtype: PIL.Image.Image
680+
"""
681+
if width == None or height == None:
682+
width, height = self.lottie_animation_get_size()
683+
684+
buffer = self.lottie_animation_render(
685+
frame_num=frame_num,
686+
buffer_size=buffer_size,
687+
width=width,
688+
height=height,
689+
bytes_per_line=bytes_per_line,
690+
)
757691

758-
For .gif, maximum framerate is capped at 50.
692+
im = Image.frombuffer("RGBA", (width, height), buffer, "raw", "BGRA")
759693

760-
Users may override this by specifying fps, at risk of breaking their gif.
694+
return im
761695

762-
:param str save_path: Path to save the Pillow Image
763-
:param Optional[int] fps: Set fps of output image.
764-
Will skip frames if lower than original.
765-
:param Optional[int] frame_num_start: the starting frame number
766-
needs to be rendered.
767-
:param Optional[int] frame_num_end: the ending frame number
768-
needs to be rendered.
769-
:param Optional[int] buffer_size: size of surface buffer use for rendering
770-
:param Optional[int] width: width of the surface
771-
:param Optional[int] height: height of the surface
772-
:param Optional[int] bytes_per_line: stride of the surface in bytes.
773-
:param *args: additional arguments passing to im.save()
774-
:param **kwargs: additional arguments passing to im.save()
775-
776-
:return: rendered Pillow Image
777-
:rtype: PIL.Image.Image
778-
"""
779-
if not PILLOW_LOADED:
780-
raise ModuleNotFoundError("Pillow is required for this function.")
781-
782-
fps_orig = self.lottie_animation_get_framerate()
783-
duration = self.lottie_animation_get_duration()
784-
785-
export_ext = os.path.splitext(save_path)[-1].lower()
786-
787-
if not fps:
788-
fps = fps_orig
789-
790-
# For .gif, maximum framerate is capped at 50
791-
# Users may override this by specifying fps, at risk of breaking their gif
792-
# Reference: https://wunkolo.github.io/post/2020/02/buttery-smooth-10fps/
793-
if export_ext == ".gif" and fps_orig > 50:
794-
fps = 50
795-
796-
if export_ext == ".gif" and kwargs.get("disposal") == None:
797-
kwargs["disposal"] = 2
798-
799-
if kwargs.get("loop") == None:
800-
kwargs["loop"] = 0
801-
802-
frames = int(duration * fps)
803-
frame_duration = 1000 / fps
804-
805-
if frame_num_start == None:
806-
frame_num_start = 0
807-
if frame_num_end == None:
808-
frame_num_end = frames
809-
810-
im_list = []
811-
for frame in range(frame_num_start, frame_num_end):
812-
pos = frame / frame_num_end
813-
frame_num = self.lottie_animation_get_frame_at_pos(pos)
814-
im_list.append(
815-
self.render_pillow_frame(
816-
frame_num=frame_num,
817-
buffer_size=buffer_size,
818-
width=width,
819-
height=height,
820-
bytes_per_line=bytes_per_line,
821-
).copy()
696+
def save_frame(
697+
self,
698+
save_path: str,
699+
frame_num: int = 0,
700+
buffer_size: Optional[int] = None,
701+
width: Optional[int] = None,
702+
height: Optional[int] = None,
703+
bytes_per_line: Optional[int] = None,
704+
*args,
705+
**kwargs,
706+
) -> Image.Image:
707+
"""
708+
Save Image at frame_num to save_path
709+
710+
:param str save_path: path to save the Pillow Image
711+
:param int frame_num: the frame number needs to be rendered.
712+
Defaults to 0.
713+
:param Optional[int] buffer_size: size of surface buffer use for rendering
714+
:param Optional[int] width: width of the surface
715+
:param Optional[int] height: height of the surface
716+
:param Optional[int] bytes_per_line: stride of the surface in bytes.
717+
:param *args: additional arguments passing to im.save()
718+
:param **kwargs: additional arguments passing to im.save()
719+
720+
:return: rendered Pillow Image
721+
:rtype: PIL.Image.Image
722+
"""
723+
im = self.render_pillow_frame(
724+
frame_num=frame_num,
725+
buffer_size=buffer_size,
726+
width=width,
727+
height=height,
728+
bytes_per_line=bytes_per_line,
822729
)
823-
824-
im_list[0].save(
825-
save_path,
826-
save_all=True,
827-
append_images=im_list[1:],
828-
duration=int(frame_duration),
730+
im.save(save_path, *args, **kwargs)
731+
732+
def save_animation(
733+
self,
734+
save_path: str,
735+
fps: Optional[int] = None,
736+
frame_num_start: Optional[int] = None,
737+
frame_num_end: Optional[int] = None,
738+
buffer_size: Optional[int] = None,
739+
width: Optional[int] = None,
740+
height: Optional[int] = None,
741+
bytes_per_line: Optional[int] = None,
829742
*args,
830743
**kwargs,
831-
)
744+
) -> Image.Image:
745+
"""
746+
Save Image from frame_num_start to frame_num_end and save it to save_path.
747+
748+
It is possible to save animation as apng, gif or webp.
749+
750+
For .gif, maximum framerate is capped at 50.
751+
752+
Users may override this by specifying fps, at risk of breaking their gif.
753+
754+
:param str save_path: Path to save the Pillow Image
755+
:param Optional[int] fps: Set fps of output image.
756+
Will skip frames if lower than original.
757+
:param Optional[int] frame_num_start: the starting frame number
758+
needs to be rendered.
759+
:param Optional[int] frame_num_end: the ending frame number
760+
needs to be rendered.
761+
:param Optional[int] buffer_size: size of surface buffer use for rendering
762+
:param Optional[int] width: width of the surface
763+
:param Optional[int] height: height of the surface
764+
:param Optional[int] bytes_per_line: stride of the surface in bytes.
765+
:param *args: additional arguments passing to im.save()
766+
:param **kwargs: additional arguments passing to im.save()
767+
768+
:return: rendered Pillow Image
769+
:rtype: PIL.Image.Image
770+
"""
771+
fps_orig = self.lottie_animation_get_framerate()
772+
duration = self.lottie_animation_get_duration()
773+
774+
export_ext = os.path.splitext(save_path)[-1].lower()
775+
776+
if not fps:
777+
fps = fps_orig
778+
779+
# For .gif, maximum framerate is capped at 50
780+
# Users may override this by specifying fps, at risk of breaking their gif
781+
# Reference: https://wunkolo.github.io/post/2020/02/buttery-smooth-10fps/
782+
if export_ext == ".gif" and fps_orig > 50:
783+
fps = 50
784+
785+
if export_ext == ".gif" and kwargs.get("disposal") == None:
786+
kwargs["disposal"] = 2
787+
788+
if kwargs.get("loop") == None:
789+
kwargs["loop"] = 0
790+
791+
frames = int(duration * fps)
792+
frame_duration = 1000 / fps
793+
794+
if frame_num_start == None:
795+
frame_num_start = 0
796+
if frame_num_end == None:
797+
frame_num_end = frames
798+
799+
im_list = []
800+
for frame in range(frame_num_start, frame_num_end):
801+
pos = frame / frame_num_end
802+
frame_num = self.lottie_animation_get_frame_at_pos(pos)
803+
im_list.append(
804+
self.render_pillow_frame(
805+
frame_num=frame_num,
806+
buffer_size=buffer_size,
807+
width=width,
808+
height=height,
809+
bytes_per_line=bytes_per_line,
810+
).copy()
811+
)
812+
813+
im_list[0].save(
814+
save_path,
815+
save_all=True,
816+
append_images=im_list[1:],
817+
duration=int(frame_duration),
818+
*args,
819+
**kwargs,
820+
)

0 commit comments

Comments
 (0)