Removed memset and ignoreAlpha (#20)

This commit is contained in:
Andrew Murray 2025-02-09 11:48:25 +11:00 committed by GitHub
parent 7de1212c18
commit e1509ee88b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 30 additions and 46 deletions

View File

@ -16,6 +16,7 @@ except ImportError:
# Decoder options as module globals, until there is a way to pass parameters # Decoder options as module globals, until there is a way to pass parameters
# to Image.open (see https://github.com/python-pillow/Pillow/issues/569) # to Image.open (see https://github.com/python-pillow/Pillow/issues/569)
DECODE_CODEC_CHOICE = "auto" DECODE_CODEC_CHOICE = "auto"
# Decoding is only affected by this for libavif **0.8.4** or greater.
DEFAULT_MAX_THREADS = 0 DEFAULT_MAX_THREADS = 0
@ -61,10 +62,7 @@ class AvifImageFile(ImageFile.ImageFile):
def _open(self) -> None: def _open(self) -> None:
if not SUPPORTED: if not SUPPORTED:
msg = ( msg = "image file could not be opened because AVIF support not installed"
"image file could not be identified because AVIF "
"support not installed"
)
raise SyntaxError(msg) raise SyntaxError(msg)
if DECODE_CODEC_CHOICE != "auto" and not _avif.decoder_codec_available( if DECODE_CODEC_CHOICE != "auto" and not _avif.decoder_codec_available(
@ -116,11 +114,11 @@ class AvifImageFile(ImageFile.ImageFile):
def load(self) -> Image.core.PixelAccess | None: def load(self) -> Image.core.PixelAccess | None:
if self.tile: if self.tile:
# We need to load the image data for this frame # We need to load the image data for this frame
data, timescale, tsp_in_ts, dur_in_ts = self._decoder.get_frame( data, timescale, pts_in_timescales, dur_in_timescales = (
self.__frame self._decoder.get_frame(self.__frame)
) )
self.info["timestamp"] = round(1000 * (tsp_in_ts / timescale)) self.info["timestamp"] = round(1000 * (pts_in_timescales / timescale))
self.info["duration"] = round(1000 * (dur_in_ts / timescale)) self.info["duration"] = round(1000 * (dur_in_timescales / timescale))
# Set tile # Set tile
if self.fp and self._exclusive_fp: if self.fp and self._exclusive_fp:
@ -212,8 +210,7 @@ def _save(
# Setup the AVIF encoder # Setup the AVIF encoder
enc = _avif.AvifEncoder( enc = _avif.AvifEncoder(
im.size[0], im.size,
im.size[1],
subsampling, subsampling,
quality, quality,
speed, speed,
@ -233,7 +230,7 @@ def _save(
# Add each frame # Add each frame
frame_idx = 0 frame_idx = 0
frame_dur = 0 frame_duration = 0
cur_idx = im.tell() cur_idx = im.tell()
try: try:
for ims in [im] + append_images: for ims in [im] + append_images:
@ -252,16 +249,15 @@ def _save(
# Update frame duration # Update frame duration
if isinstance(duration, (list, tuple)): if isinstance(duration, (list, tuple)):
frame_dur = duration[frame_idx] frame_duration = duration[frame_idx]
else: else:
frame_dur = duration frame_duration = duration
# Append the frame to the animation encoder # Append the frame to the animation encoder
enc.add( enc.add(
frame.tobytes("raw", rawmode), frame.tobytes("raw", rawmode),
frame_dur, frame_duration,
frame.size[0], frame.size,
frame.size[1],
rawmode, rawmode,
is_single_frame, is_single_frame,
) )

View File

@ -7,7 +7,7 @@
typedef struct { typedef struct {
PyObject_HEAD avifEncoder *encoder; PyObject_HEAD avifEncoder *encoder;
avifImage *image; avifImage *image;
int frame_index; int first_frame;
} AvifEncoderObject; } AvifEncoderObject;
static PyTypeObject AvifEncoder_Type; static PyTypeObject AvifEncoder_Type;
@ -16,7 +16,6 @@ static PyTypeObject AvifEncoder_Type;
typedef struct { typedef struct {
PyObject_HEAD avifDecoder *decoder; PyObject_HEAD avifDecoder *decoder;
Py_buffer buffer; Py_buffer buffer;
char *mode;
} AvifDecoderObject; } AvifDecoderObject;
static PyTypeObject AvifDecoder_Type; static PyTypeObject AvifDecoder_Type;
@ -154,7 +153,7 @@ exif_orientation_to_irot_imir(avifImage *image, int orientation) {
} }
static int static int
_codec_available(const char *name, uint32_t flags) { _codec_available(const char *name, avifCodecFlags flags) {
avifCodecChoice codec = avifCodecChoiceFromName(name); avifCodecChoice codec = avifCodecChoiceFromName(name);
if (codec == AVIF_CODEC_CHOICE_AUTO) { if (codec == AVIF_CODEC_CHOICE_AUTO) {
return 0; return 0;
@ -252,7 +251,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
if (!PyArg_ParseTuple( if (!PyArg_ParseTuple(
args, args,
"IIsiiissiiOOy*y*iy*O", "(II)siiissiiOOy*y*iy*O",
&width, &width,
&height, &height,
&subsampling, &subsampling,
@ -372,7 +371,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
avifEncoderDestroy(encoder); avifEncoderDestroy(encoder);
return NULL; return NULL;
} }
self->frame_index = -1; self->first_frame = 1;
avifResult result; avifResult result;
if (icc_buffer.len) { if (icc_buffer.len) {
@ -466,10 +465,9 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {
unsigned int width; unsigned int width;
unsigned int height; unsigned int height;
char *mode; char *mode;
PyObject *is_single_frame = NULL; unsigned int is_single_frame;
PyObject *ret = Py_None; PyObject *ret = Py_None;
int is_first_frame;
avifRGBImage rgb; avifRGBImage rgb;
avifResult result; avifResult result;
@ -479,7 +477,7 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {
if (!PyArg_ParseTuple( if (!PyArg_ParseTuple(
args, args,
"z#IIIsO", "y#I(II)sp",
(char **)&rgb_bytes, (char **)&rgb_bytes,
&size, &size,
&duration, &duration,
@ -491,8 +489,6 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {
return NULL; return NULL;
} }
is_first_frame = self->frame_index == -1;
if (image->width != width || image->height != height) { if (image->width != width || image->height != height) {
PyErr_Format( PyErr_Format(
PyExc_ValueError, PyExc_ValueError,
@ -505,7 +501,7 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {
return NULL; return NULL;
} }
if (is_first_frame) { if (self->first_frame) {
// If we don't have an image populated with yuv planes, this is the first frame // If we don't have an image populated with yuv planes, this is the first frame
frame = image; frame = image;
} else { } else {
@ -577,7 +573,7 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {
} }
uint32_t addImageFlags = AVIF_ADD_IMAGE_FLAG_NONE; uint32_t addImageFlags = AVIF_ADD_IMAGE_FLAG_NONE;
if (PyObject_IsTrue(is_single_frame)) { if (is_single_frame) {
addImageFlags |= AVIF_ADD_IMAGE_FLAG_SINGLE; addImageFlags |= AVIF_ADD_IMAGE_FLAG_SINGLE;
} }
@ -597,12 +593,12 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {
end: end:
avifRGBImageFreePixels(&rgb); avifRGBImageFreePixels(&rgb);
if (!is_first_frame) { if (!self->first_frame) {
avifImageDestroy(frame); avifImageDestroy(frame);
} }
if (ret == Py_None) { if (ret == Py_None) {
self->frame_index++; self->first_frame = 0;
Py_RETURN_NONE; Py_RETURN_NONE;
} else { } else {
return ret; return ret;
@ -708,12 +704,6 @@ AvifDecoderNew(PyObject *self_, PyObject *args) {
return NULL; return NULL;
} }
if (decoder->alphaPresent) {
self->mode = "RGBA";
} else {
self->mode = "RGB";
}
self->decoder = decoder; self->decoder = decoder;
self->buffer = buffer; self->buffer = buffer;
@ -757,7 +747,7 @@ _decoder_get_info(AvifDecoderObject *self) {
image->width, image->width,
image->height, image->height,
decoder->imageCount, decoder->imageCount,
self->mode, decoder->alphaPresent == AVIF_TRUE ? "RGBA" : "RGB",
NULL == icc ? Py_None : icc, NULL == icc ? Py_None : icc,
NULL == exif ? Py_None : exif, NULL == exif ? Py_None : exif,
irot_imir_to_exif_orientation(image), irot_imir_to_exif_orientation(image),
@ -793,7 +783,7 @@ _decoder_get_frame(AvifDecoderObject *self, PyObject *args) {
PyErr_Format( PyErr_Format(
exc_type_for_avif_result(result), exc_type_for_avif_result(result),
"Failed to decode frame %u: %s", "Failed to decode frame %u: %s",
decoder->imageIndex + 1, frame_index,
avifResultToString(result) avifResultToString(result)
); );
return NULL; return NULL;
@ -801,17 +791,11 @@ _decoder_get_frame(AvifDecoderObject *self, PyObject *args) {
image = decoder->image; image = decoder->image;
memset(&rgb, 0, sizeof(rgb));
avifRGBImageSetDefaults(&rgb, image); avifRGBImageSetDefaults(&rgb, image);
rgb.depth = 8; rgb.depth = 8;
rgb.format =
if (decoder->alphaPresent) { decoder->alphaPresent == AVIF_TRUE ? AVIF_RGB_FORMAT_RGBA : AVIF_RGB_FORMAT_RGB;
rgb.format = AVIF_RGB_FORMAT_RGBA;
} else {
rgb.format = AVIF_RGB_FORMAT_RGB;
rgb.ignoreAlpha = AVIF_TRUE;
}
result = avifRGBImageAllocatePixels(&rgb); result = avifRGBImageAllocatePixels(&rgb);
if (result != AVIF_RESULT_OK) { if (result != AVIF_RESULT_OK) {
@ -940,5 +924,9 @@ PyInit__avif(void) {
return NULL; return NULL;
} }
#ifdef Py_GIL_DISABLED
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
#endif
return m; return m;
} }