From 2f548c9a4df443948f2dfcde30a7211ce8b3adc2 Mon Sep 17 00:00:00 2001 From: Christoph Gohlke Date: Sat, 2 Sep 2023 22:41:40 -0700 Subject: [PATCH] Update imagecodecs/_avif.pyx --- imagecodecs/_avif.pyx | 60 +++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 28 deletions(-) Index: imagecodecs-2023.3.16/imagecodecs/_avif.pyx =================================================================== --- imagecodecs-2023.3.16.orig/imagecodecs/_avif.pyx +++ imagecodecs-2023.3.16/imagecodecs/_avif.pyx @@ -56,12 +56,14 @@ class AVIF: YUV422 = AVIF_PIXEL_FORMAT_YUV422 YUV420 = AVIF_PIXEL_FORMAT_YUV420 YUV400 = AVIF_PIXEL_FORMAT_YUV400 + COUNT = AVIF_PIXEL_FORMAT_COUNT - class QUANTIZER(enum.IntEnum): - """AVIF codec quantizers.""" - LOSSLESS = AVIF_QUANTIZER_LOSSLESS - BEST_QUALITY = AVIF_QUANTIZER_BEST_QUALITY - WORST_QUALITY = AVIF_QUANTIZER_WORST_QUALITY + class QUALITY(enum.IntEnum): + """AVIF codec quality.""" + DEFAULT = AVIF_QUALITY_DEFAULT # -1 + LOSSLESS = AVIF_QUALITY_LOSSLESS # 100 + WORST = AVIF_QUALITY_WORST # 0 + BEST = AVIF_QUALITY_BEST # 100 class SPEED(enum.IntEnum): """AVIF codec speeds.""" @@ -85,6 +87,7 @@ class AVIF: LIBGAV1 = AVIF_CODEC_CHOICE_LIBGAV1 RAV1E = AVIF_CODEC_CHOICE_RAV1E SVT = AVIF_CODEC_CHOICE_SVT + AVM = AVIF_CODEC_CHOICE_AVM class AvifError(RuntimeError): @@ -143,8 +146,8 @@ def avif_encode( const uint8_t[::1] dst # must be const to write to bytes ssize_t dstsize, size ssize_t itemsize = data.dtype.itemsize + int quality = AVIF_QUALITY_LOSSLESS int speed_ = AVIF_SPEED_DEFAULT - int quantizer = AVIF_QUANTIZER_LOSSLESS int tilerowslog2 = 0 int tilecolslog2 = 0 int duration = 1 @@ -172,10 +175,10 @@ def avif_encode( src.dtype in (numpy.uint8, numpy.uint16) # and numpy.PyArray_ISCONTIGUOUS(src) and src.ndim in (2, 3, 4) - and src.shape[0] < 2 ** 31 - and src.shape[1] < 2 ** 31 - and src.shape[src.ndim - 1] < 2 ** 31 - and src.shape[src.ndim - 2] < 2 ** 31 + and src.shape[0] <= 2147483647 + and src.shape[1] <= 2147483647 + and src.shape[src.ndim - 1] <= 2147483647 + and src.shape[src.ndim - 2] <= 2147483647 ): raise ValueError('invalid data shape, strides, or dtype') @@ -205,10 +208,6 @@ def avif_encode( monochrome = samples < 3 hasalpha = samples in (2, 4) - if monochrome: - raise NotImplementedError('cannot encode monochome images') - # TODO: check status of libavif/aom monochome support - if bitspersample is None: depth = itemsize * 8 else: @@ -223,11 +222,11 @@ def avif_encode( if 0 <= tilecolslog2 <= 6: raise ValueError('invalid tileColsLog2') - quantizer = _default_value( + quality = _default_value( level, - AVIF_QUANTIZER_LOSSLESS, - AVIF_QUANTIZER_BEST_QUALITY, - AVIF_QUANTIZER_WORST_QUALITY + AVIF_QUALITY_LOSSLESS, # 100 + AVIF_QUALITY_DEFAULT, # -1 + AVIF_QUALITY_BEST # 100 ) speed_ = _default_value( @@ -239,8 +238,8 @@ def avif_encode( if monochrome: yuvformat = AVIF_PIXEL_FORMAT_YUV400 - quantizer = AVIF_QUANTIZER_LOSSLESS - elif quantizer == AVIF_QUANTIZER_LOSSLESS: + quality = AVIF_QUALITY_LOSSLESS + elif quality == AVIF_QUALITY_LOSSLESS: yuvformat = AVIF_PIXEL_FORMAT_YUV444 elif pixelformat is not None: yuvformat = _avif_pixelformat(pixelformat) @@ -254,11 +253,9 @@ def avif_encode( if encoder == NULL: raise AvifError('avifEncoderCreate', 'NULL') + encoder.quality = quality + encoder.qualityAlpha = AVIF_QUALITY_LOSSLESS encoder.maxThreads = maxthreads - encoder.minQuantizer = quantizer - encoder.maxQuantizer = quantizer - encoder.minQuantizerAlpha = AVIF_QUANTIZER_LOSSLESS - encoder.maxQuantizerAlpha = AVIF_QUANTIZER_LOSSLESS encoder.tileRowsLog2 = tilerowslog2 encoder.tileColsLog2 = tilecolslog2 encoder.speed = speed_ @@ -269,7 +266,7 @@ def avif_encode( if image == NULL: raise AvifError('avifImageCreate', 'NULL') - if monochrome or quantizer == AVIF_QUANTIZER_LOSSLESS: + if monochrome or quality == AVIF_QUALITY_LOSSLESS: if codecchoice == AVIF_CODEC_CHOICE_AUTO: encoder.codecChoice = AVIF_CODEC_CHOICE_AOM else: @@ -287,7 +284,9 @@ def avif_encode( avifRGBImageSetDefaults(&rgb, image) if monochrome: - avifRGBImageAllocatePixels(&rgb) + res = avifRGBImageAllocatePixels(&rgb) + if res != AVIF_RESULT_OK: + raise AvifError('avifRGBImageAllocatePixels', res) if rgb.format != AVIF_RGB_FORMAT_RGBA: raise RuntimeError('rgb.format != AVIF_RGB_FORMAT_RGBA') srcptr = src.data @@ -419,7 +418,7 @@ def avif_encode( return _return_output(out, dstsize, rawsize, outgiven) -def avif_decode(data, index=None, out=None): +def avif_decode(data, index=None, numthreads=None, out=None): """Return decoded AVIF image.""" cdef: numpy.ndarray dst @@ -429,6 +428,7 @@ def avif_decode(data, index=None, out=No ssize_t samples, size, itemsize, i, j, k, dstindex, imagecount bint monochrome = 0 # must be initialized bint hasalpha = 0 + int maxthreads = _default_threads(numthreads) uint8_t* dstptr = NULL uint8_t* srcptr = NULL avifDecoder* decoder = NULL @@ -448,6 +448,8 @@ def avif_decode(data, index=None, out=No # required to read AVIF files created by ImageMagick decoder.strictFlags = AVIF_STRICT_DISABLED + decoder.maxThreads = maxthreads + res = avifDecoderSetSource(decoder, AVIF_DECODER_SOURCE_AUTO) if res != AVIF_RESULT_OK: raise AvifError('avifDecoderSetSource', res) @@ -632,10 +634,12 @@ cdef _avif_codecchoice(codec): AVIF_CODEC_CHOICE_LIBGAV1: AVIF_CODEC_CHOICE_LIBGAV1, AVIF_CODEC_CHOICE_RAV1E: AVIF_CODEC_CHOICE_RAV1E, AVIF_CODEC_CHOICE_SVT: AVIF_CODEC_CHOICE_SVT, + AVIF_CODEC_CHOICE_AVM: AVIF_CODEC_CHOICE_AVM, 'auto': AVIF_CODEC_CHOICE_AUTO, 'aom': AVIF_CODEC_CHOICE_AOM, 'dav1d': AVIF_CODEC_CHOICE_DAV1D, 'libgav1': AVIF_CODEC_CHOICE_LIBGAV1, 'rav1e': AVIF_CODEC_CHOICE_RAV1E, 'svt': AVIF_CODEC_CHOICE_SVT, + 'avm': AVIF_CODEC_CHOICE_AVM, }[codec]