Skip to content

Commit

Permalink
Support loop_count when writing animations
Browse files Browse the repository at this point in the history
  • Loading branch information
anibali committed Jun 9, 2024
1 parent fd98c96 commit 2525817
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 1 deletion.
26 changes: 26 additions & 0 deletions tests/test_webp.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,32 @@ def test_anim_simple(self):
expected = np.asarray(img, dtype=np.uint8)
assert_array_equal(actual, expected)

def test_anim_loop_count(self):
imgs = []
width = 256
height = 64
for i in range(4):
img = Image.new('RGBA', (width, height))
draw = ImageDraw.Draw(img)
draw.rectangle((0, 0, width-1, height-1), fill=(0, 0, 255))
x = i * (width/4)
draw.rectangle((x, 0, x + (width/4-1), height-1), fill=(255, 0, 0))
imgs.append(img)

with TemporaryDirectory() as tmpdir:
file_name = os.path.join(tmpdir, 'anim.webp')

webp.save_images(imgs, file_name, fps=4, loop_count=2, lossless=True)

with open(file_name, 'rb') as f:
webp_data = webp.WebPData.from_buffer(f.read())
dec_opts = webp.WebPAnimDecoderOptions.new(
use_threads=True, color_mode=webp.WebPColorMode.RGBA)
dec = webp.WebPAnimDecoder.new(webp_data, dec_opts)
assert dec.anim_info.loop_count == 2
assert dec.anim_info.width == width
assert dec.anim_info.height == height

# WebP combines adjacent duplicate frames and adjusts timestamps
# accordingly, resulting in unevenly spaced frames. By specifying the fps
# while loading we can return evenly spaced frames.
Expand Down
22 changes: 21 additions & 1 deletion webp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,14 @@ class WebPAnimEncoderOptions:
def __init__(self, ptr: Any) -> None:
self.ptr = ptr

@property
def loop_count(self) -> int:
return self.ptr.anim_params.loop_count

@loop_count.setter
def loop_count(self, loop_count: int) -> None:
self.ptr.anim_params.loop_count = loop_count

@property
def minimize_size(self) -> bool:
return self.ptr.minimize_size != 0
Expand Down Expand Up @@ -475,6 +483,10 @@ def width(self) -> int:
def height(self) -> int:
return self.ptr.canvas_height

@property
def loop_count(self) -> int:
return self.ptr.loop_count

@staticmethod
def new() -> "WebPAnimInfo":
ptr = ffi.new('WebPAnimInfo*')
Expand Down Expand Up @@ -582,9 +594,12 @@ def _mimwrite_pics(
pics: List[WebPPicture],
*args: Any,
fps: float = 30.0,
loop_count: Optional[int] = None,
**kwargs: Any
) -> None:
enc_opts = WebPAnimEncoderOptions.new()
if loop_count is not None:
enc_opts.loop_count = loop_count
enc = WebPAnimEncoder.new(pics[0].ptr.width, pics[0].ptr.height, enc_opts)
config = WebPConfig.new(**kwargs)
for i, pic in enumerate(pics):
Expand All @@ -602,6 +617,7 @@ def mimwrite(
arrs: "List[np.ndarray[Any, np.dtype[np.uint8]]]",
*args: Any,
fps: float = 30.0,
loop_count: Optional[int] = None,
pilmode: Optional[str] = None,
**kwargs: Any) -> None:
"""Encode a sequence of PIL Images with WebP and save to file.
Expand All @@ -610,10 +626,14 @@ def mimwrite(
file_path (str): File to save to.
imgs (list of np.ndarray): Image data to save.
fps (float): Animation speed in frames per second.
loop_count (int, optional): Number of times to repeat the animation.
0 = infinite.
pilmode (str, optional): Image color mode (RGBA or RGB). Will be
inferred from the images if not specified.
kwargs: Keyword arguments for encoder settings (see `WebPConfig.new`).
"""
pics = [WebPPicture.from_numpy(arr, pilmode=pilmode) for arr in arrs]
_mimwrite_pics(file_path, pics, fps=fps, **kwargs)
_mimwrite_pics(file_path, pics, fps=fps, loop_count=loop_count, **kwargs)


def mimread(
Expand Down
7 changes: 7 additions & 0 deletions webp_build/cdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,14 @@ struct WebPMemoryWriter {
};
typedef struct WebPMemoryWriter WebPMemoryWriter;

struct WebPMuxAnimParams {
uint32_t bgcolor;
int loop_count;
};
typedef struct WebPMuxAnimParams WebPMuxAnimParams;

struct WebPAnimEncoderOptions {
WebPMuxAnimParams anim_params;
int minimize_size;
int kmin;
int kmax;
Expand Down

0 comments on commit 2525817

Please sign in to comment.