From f0621c72ada95f2828deee3363b98900c49a69b1 Mon Sep 17 00:00:00 2001 From: Frankie Dintino Date: Thu, 12 Oct 2023 13:57:31 -0400 Subject: [PATCH] fix: cannot access local variable 'quality' ... Moves the qmin/qmax conversion logic from AvifImagePlugin to _avif.c, where we know whether avif supports the quality encoder option. This allows users to continue to pass qmin/qmax to save(), even if they are using libavif >= 1.0.0 fixes #32 --- src/pillow_avif/AvifImagePlugin.py | 22 +++++----------------- src/pillow_avif/_avif.c | 21 ++++++++++++++++++--- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/pillow_avif/AvifImagePlugin.py b/src/pillow_avif/AvifImagePlugin.py index b8fda97..c0c2f03 100644 --- a/src/pillow_avif/AvifImagePlugin.py +++ b/src/pillow_avif/AvifImagePlugin.py @@ -126,23 +126,11 @@ def _save(im, fp, filename, save_all=False): is_single_frame = total == 1 - qmin = info.get("qmin") - qmax = info.get("qmax") - - if qmin is None and qmax is None: - # The min and max quantizer settings in libavif range from 0 (best quality) - # to 63 (worst quality). If neither are explicitly specified, we use a 0-100 - # quality scale (default 75) and calculate the qmin and qmax from that. - # - # - qmin is 0 for quality >= 64. Below that, qmin has an inverse linear - # relation to quality (i.e., quality 63 = qmin 1, quality 0 => qmin 63) - # - qmax is 0 for quality=100, then qmax increases linearly relative to - # quality decreasing, until it flattens out at quality=37. - quality = info.get("quality", 75) - if not isinstance(quality, int) or quality < 0 or quality > 100: - raise ValueError("Invalid quality setting") - qmin = max(0, min(64 - quality, 63)) - qmax = max(0, min(100 - quality, 63)) + qmin = info.get("qmin", -1) + qmax = info.get("qmax", -1) + quality = info.get("quality", 75) + if not isinstance(quality, int) or quality < 0 or quality > 100: + raise ValueError("Invalid quality setting") duration = info.get("duration", 0) subsampling = info.get("subsampling", "4:2:0") diff --git a/src/pillow_avif/_avif.c b/src/pillow_avif/_avif.c index 0728d06..c35b3bb 100644 --- a/src/pillow_avif/_avif.c +++ b/src/pillow_avif/_avif.c @@ -257,8 +257,18 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { return NULL; } - enc_options.qmin = normalize_quantize_value(qmin); - enc_options.qmax = normalize_quantize_value(qmax); + if (qmin == -1 || qmax == -1) { +#if AVIF_VERSION >= 1000000 + enc_options.qmin = -1; + enc_options.qmax = -1; +#else + enc_options.qmin = normalize_quantize_value(64 - quality); + enc_options.qmax = normalize_quantize_value(100 - quality); +#endif + } else { + enc_options.qmin = normalize_quantize_value(qmin); + enc_options.qmax = normalize_quantize_value(qmax); + } enc_options.quality = quality; if (speed < AVIF_SPEED_SLOWEST) { @@ -326,7 +336,12 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { encoder->maxThreads = max_threads; #if AVIF_VERSION >= 1000000 - encoder->quality = enc_options.quality; + if (enc_options.qmin != -1 && enc_options.qmax != -1) { + encoder->minQuantizer = enc_options.qmin; + encoder->maxQuantizer = enc_options.qmax; + } else { + encoder->quality = enc_options.quality; + } #else encoder->minQuantizer = enc_options.qmin; encoder->maxQuantizer = enc_options.qmax;