@@ -43,23 +43,36 @@ The engine to use for video files. It defaults to
4343GIFSICLE\_ PATH
4444~~~~~~~~~~~~~~
4545
46- The path to the gifsicle binary. It defaults to ``None ``, in which case it
47- looks for gifsicle in ``PATH ``. This is only used if ``GIF_ENGINE `` is set to
48- ``'thumbor_video_engines.engines.gif' ``. As of version 6.7.0, thumbor does not
49- support configuring this value.
46+ The path to the gifsicle binary. It defaults to ``None ``, in which case gifsicle
47+ is looked up on ``PATH ``. It is honored both by the FFmpeg engine's animated-gif
48+ optimization pass (when ``FFMPEG_USE_GIFSICLE_ENGINE `` is enabled) and by the gif
49+ engine for non-animated gifs (when ``GIF_ENGINE `` is set to
50+ ``'thumbor_video_engine.engines.gif' ``).
5051
5152GIFSICLE\_ ARGS
5253~~~~~~~~~~~~~~
5354
54- A list of additional args to pass to gifsicle. This is only used if
55- ``GIF_ENGINE `` is set to ``'thumbor_video_engines.engines.gif' ``.
55+ A list of additional args to pass to gifsicle (e.g. ``['--lossy=80'] ``). Honored
56+ by the FFmpeg engine's animated-gif optimization pass (when
57+ ``FFMPEG_USE_GIFSICLE_ENGINE `` is enabled), by the gifski pipeline's optional
58+ ``GIFSKI_GIFSICLE_PASS ``, and by the gif engine for non-animated gifs (when
59+ ``GIF_ENGINE `` is ``'thumbor_video_engine.engines.gif' ``).
5660
5761FFMPEG\_ USE\_ GIFSICLE\_ ENGINE
5862~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5963
6064Equivalent to USE\_ GIFSICLE\_ ENGINE, but for the FFmpeg engine. It defaults to
61- ``False ``. If ``True ``, it will perform any image operations on animated gifs
62- (e.g. cropping and resizing) using gifsicle (by way of ``GIF_ENGINE ``).
65+ ``False ``. If ``True ``, gifsicle runs as a final ``-O3 `` optimization pass
66+ (plus ``GIFSICLE_ARGS ``) over the gif produced by ffmpeg, reducing file size.
67+ All geometry (cropping, resizing) is applied by ffmpeg at the target size, so
68+ the gifsicle pass performs no resizing of its own and runs file-to-file on
69+ disk — the full animation is never buffered in the Python heap.
70+
71+ This pass invokes ``gifsicle `` directly rather than routing through
72+ ``GIF_ENGINE ``, so a custom ``GIF_ENGINE `` does not participate in animated-gif
73+ transcodes (it is still used for non-animated gifs). To customize the
74+ animated-gif optimization step, subclass the FFmpeg engine (``FFMPEG_ENGINE ``)
75+ and override ``_gif_legacy `` or ``_gifsicle_optimize_file ``.
6376
6477FFMPEG\_ HANDLE\_ ANIMATED\_ GIF
6578~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -88,6 +101,86 @@ Specifies whether H265 format should be used automatically if the
88101source image is an animated gif and the request accepts it (via
89102``Accept: video/* ``). It defaults to ``False ``.
90103
104+ FFMPEG\_ GIF\_ PIPELINE
105+ ~~~~~~~~~~~~~~~~~~~~~
106+
107+ Selects the gif-to-gif transcode pipeline. It defaults to ``'legacy' ``.
108+
109+ ``'legacy' ``
110+ The ``palettegen ``/``paletteuse `` pipeline. ffmpeg applies all geometry
111+ (crop, resize) at the **target ** size, writes intermediates to disk, and
112+ — when ``FFMPEG_USE_GIFSICLE_ENGINE `` is enabled — runs a final
113+ geometry-free ``gifsicle -O3 `` optimization pass. Only the final output
114+ bytes ever enter the Python heap, so memory stays bounded regardless of
115+ the source animation's resolution or frame count.
116+
117+ ``'gifski' ``
118+ Streams frames from ffmpeg directly into the `gifski `__ encoder at the
119+ target size, producing noticeably higher-quality gifs much faster. Inputs
120+ that gifski cannot represent are routed back to the ``legacy `` path
121+ automatically:
122+
123+ - **variable per-frame delays ** (gifski emits a constant frame rate),
124+ - **target sizes above ** ``GIFSKI_MAX_TARGET_PIXELS ``,
125+ - and any request when the ``gifski `` binary is not available.
126+
127+ Visibly-transparent gifs are decoded to PNG frames first (gifski
128+ preserves alpha from PNG input); opaque gifs and video sources stream
129+ through a ``yuv4mpegpipe ``.
130+
131+ .. note ::
132+ gifski is licensed under the `AGPL-3.0 `__. thumbor-video-engine
133+ invokes it as an unmodified subprocess (aggregation, not linking) and
134+ never declares it as a dependency. You must install the ``gifski ``
135+ binary yourself to use this pipeline, and your deployment is
136+ responsible for AGPL compliance.
137+
138+ .. __ : https://gif.ski/
139+ .. __ : https://www.gnu.org/licenses/agpl-3.0.html
140+
141+ GIFSKI\_ PATH
142+ ~~~~~~~~~~~~
143+
144+ Path to the gifski binary. It defaults to ``None ``, in which case gifski is
145+ looked up on ``PATH ``. Only used when ``FFMPEG_GIF_PIPELINE `` is ``'gifski' ``.
146+
147+ GIFSKI\_ QUALITY
148+ ~~~~~~~~~~~~~~~
149+
150+ Quality (1–100) passed to gifski (``--quality ``). Defaults to ``90 ``.
151+
152+ GIFSKI\_ MAX\_ TARGET\_ PIXELS
153+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
154+
155+ Above this output size (target ``width * height ``), the gifski pipeline routes
156+ through the legacy path instead. gifski's quantizer working set grows with
157+ output dimensions, while the legacy path's memory stays bounded — this trades
158+ a bit of wall time for bounded subprocess memory on large outputs. Defaults to
159+ ``1440000 `` (1600×900). A value of ``0 `` disables the switch.
160+
161+ GIFSKI\_ GIFSICLE\_ PASS
162+ ~~~~~~~~~~~~~~~~~~~~~~
163+
164+ If ``True ``, run a final geometry-free ``gifsicle -O3 `` pass (plus
165+ ``GIFSICLE_ARGS ``, e.g. ``--lossy ``) over gifski's output to further reduce
166+ file size. Defaults to ``False ``.
167+
168+ MAX\_ ANIMATED\_ GIF\_ PIXELS
169+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
170+
171+ Maximum total pixels (``width * height * frame_count ``) for an animated **gif
172+ source that is being transcoded to gif **. Sources over this limit fail with a
173+ ``400 `` response. thumbor's ``MAX_PIXELS `` is per-frame and does not bound frame
174+ count, so a high-frame-count gif can still be expensive; this gate, evaluated
175+ cheaply at load time from a single-pass header parse (no frame decoding), bounds
176+ the total.
177+
178+ Only the gif→gif path is gated. Converting a GIF source to video/webp/avif
179+ (including the automatic conversions from ``FFMPEG_GIF_AUTO_H264 `` /
180+ ``FFMPEG_GIF_AUTO_H265 `` / ``FFMPEG_GIF_AUTO_WEBP ``) streams through ffmpeg with
181+ bounded memory and is the efficient way to serve a large animated gif, so those
182+ are not affected. Defaults to ``0 ``, which disables the check.
183+
91184FFPROBE\_ PATH
92185~~~~~~~~~~~~~
93186
0 commit comments