Custom Image Optimizers
An optimizer receives the bytes produced by the engine and may return an
optimized replacement. Add optimizer modules to OPTIMIZERS in execution
order:
OPTIMIZERS = [
"my_package.optimizer",
]
Each module must expose a class named Optimizer. Subclass
thumbor.optimizers.BaseOptimizer:
import shutil
from thumbor.optimizers import BaseOptimizer
class Optimizer(BaseOptimizer):
def should_run(self, image_extension, image_buffer):
return image_extension in {".jpg", ".jpeg"}
def optimize(self, image_buffer, input_file, output_file):
# input_file and output_file are paths. Replace the copy with the
# command that writes the optimized image to output_file.
shutil.copyfile(input_file, output_file)
The base run_optimizer() implementation checks should_run(), writes the
buffer to a temporary input file, calls optimize() with the input and output
file paths and returns the bytes written to the output file. The return value
of optimize() is ignored, so it must always write output_file: an empty
output file makes the request fail. Override
run_optimizer(image_extension, buffer) instead when the optimizer works in
memory or needs a different process lifecycle.
An overridden run_optimizer() should return the original buffer when
optimization is skipped or fails safely. A non-None return value becomes the
input to the next configured optimizer, so the order in OPTIMIZERS is
significant. Thumbor instantiates each optimizer with the request context,
available as self.context.
Optimizers run synchronously while the response is being produced. Bound
external-process execution time and avoid leaving child processes or temporary
files behind. See thumbor.optimizers.jpegtran.Optimizer for an in-memory
run_optimizer() implementation.