Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removed memset and ignoreAlpha #20

Merged
merged 12 commits into from
Feb 9, 2025
28 changes: 12 additions & 16 deletions src/PIL/AvifImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# 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)
DECODE_CODEC_CHOICE = "auto"
# Decoding is only affected by this for libavif **0.8.4** or greater.
DEFAULT_MAX_THREADS = 0


Expand Down Expand Up @@ -61,10 +62,7 @@ class AvifImageFile(ImageFile.ImageFile):

def _open(self) -> None:
if not SUPPORTED:
msg = (
"image file could not be identified because AVIF "
"support not installed"
)
msg = "image file could not be opened because AVIF support not installed"
raise SyntaxError(msg)

if DECODE_CODEC_CHOICE != "auto" and not _avif.decoder_codec_available(
Expand Down Expand Up @@ -116,11 +114,11 @@ def seek(self, frame: int) -> None:
def load(self) -> Image.core.PixelAccess | None:
if self.tile:
# We need to load the image data for this frame
data, timescale, tsp_in_ts, dur_in_ts = self._decoder.get_frame(
self.__frame
data, timescale, pts_in_timescales, dur_in_timescales = (
self._decoder.get_frame(self.__frame)
)
self.info["timestamp"] = round(1000 * (tsp_in_ts / timescale))
self.info["duration"] = round(1000 * (dur_in_ts / timescale))
self.info["timestamp"] = round(1000 * (pts_in_timescales / timescale))
self.info["duration"] = round(1000 * (dur_in_timescales / timescale))

# Set tile
if self.fp and self._exclusive_fp:
Expand Down Expand Up @@ -212,8 +210,7 @@ def _save(

# Setup the AVIF encoder
enc = _avif.AvifEncoder(
im.size[0],
im.size[1],
im.size,
subsampling,
quality,
speed,
Expand All @@ -233,7 +230,7 @@ def _save(

# Add each frame
frame_idx = 0
frame_dur = 0
frame_duration = 0
cur_idx = im.tell()
try:
for ims in [im] + append_images:
Expand All @@ -252,16 +249,15 @@ def _save(

# Update frame duration
if isinstance(duration, (list, tuple)):
frame_dur = duration[frame_idx]
frame_duration = duration[frame_idx]
else:
frame_dur = duration
frame_duration = duration

# Append the frame to the animation encoder
enc.add(
frame.tobytes("raw", rawmode),
frame_dur,
frame.size[0],
frame.size[1],
frame_duration,
frame.size,
rawmode,
is_single_frame,
)
Expand Down
48 changes: 18 additions & 30 deletions src/_avif.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
typedef struct {
PyObject_HEAD avifEncoder *encoder;
avifImage *image;
int frame_index;
int first_frame;
} AvifEncoderObject;

static PyTypeObject AvifEncoder_Type;
Expand All @@ -16,7 +16,6 @@ static PyTypeObject AvifEncoder_Type;
typedef struct {
PyObject_HEAD avifDecoder *decoder;
Py_buffer buffer;
char *mode;
} AvifDecoderObject;

static PyTypeObject AvifDecoder_Type;
Expand Down Expand Up @@ -154,7 +153,7 @@ exif_orientation_to_irot_imir(avifImage *image, int orientation) {
}

static int
_codec_available(const char *name, uint32_t flags) {
_codec_available(const char *name, avifCodecFlags flags) {
avifCodecChoice codec = avifCodecChoiceFromName(name);
if (codec == AVIF_CODEC_CHOICE_AUTO) {
return 0;
Expand Down Expand Up @@ -252,7 +251,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {

if (!PyArg_ParseTuple(
args,
"IIsiiissiiOOy*y*iy*O",
"(II)siiissiiOOy*y*iy*O",
&width,
&height,
&subsampling,
Expand Down Expand Up @@ -372,7 +371,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
avifEncoderDestroy(encoder);
return NULL;
}
self->frame_index = -1;
self->first_frame = 1;

avifResult result;
if (icc_buffer.len) {
Expand Down Expand Up @@ -466,10 +465,9 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {
unsigned int width;
unsigned int height;
char *mode;
PyObject *is_single_frame = NULL;
unsigned int is_single_frame;
PyObject *ret = Py_None;

int is_first_frame;
avifRGBImage rgb;
avifResult result;

Expand All @@ -479,7 +477,7 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {

if (!PyArg_ParseTuple(
args,
"z#IIIsO",
"y#I(II)sp",
(char **)&rgb_bytes,
&size,
&duration,
Expand All @@ -491,8 +489,6 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {
return NULL;
}

is_first_frame = self->frame_index == -1;

if (image->width != width || image->height != height) {
PyErr_Format(
PyExc_ValueError,
Expand All @@ -505,7 +501,7 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {
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
frame = image;
} else {
Expand Down Expand Up @@ -577,7 +573,7 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {
}

uint32_t addImageFlags = AVIF_ADD_IMAGE_FLAG_NONE;
if (PyObject_IsTrue(is_single_frame)) {
if (is_single_frame) {
addImageFlags |= AVIF_ADD_IMAGE_FLAG_SINGLE;
}

Expand All @@ -597,12 +593,12 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {

end:
avifRGBImageFreePixels(&rgb);
if (!is_first_frame) {
if (!self->first_frame) {
avifImageDestroy(frame);
}

if (ret == Py_None) {
self->frame_index++;
self->first_frame = 0;
Py_RETURN_NONE;
} else {
return ret;
Expand Down Expand Up @@ -708,12 +704,6 @@ AvifDecoderNew(PyObject *self_, PyObject *args) {
return NULL;
}

if (decoder->alphaPresent) {
self->mode = "RGBA";
} else {
self->mode = "RGB";
}

self->decoder = decoder;
self->buffer = buffer;

Expand Down Expand Up @@ -757,7 +747,7 @@ _decoder_get_info(AvifDecoderObject *self) {
image->width,
image->height,
decoder->imageCount,
self->mode,
decoder->alphaPresent == AVIF_TRUE ? "RGBA" : "RGB",
NULL == icc ? Py_None : icc,
NULL == exif ? Py_None : exif,
irot_imir_to_exif_orientation(image),
Expand Down Expand Up @@ -793,25 +783,19 @@ _decoder_get_frame(AvifDecoderObject *self, PyObject *args) {
PyErr_Format(
exc_type_for_avif_result(result),
"Failed to decode frame %u: %s",
decoder->imageIndex + 1,
frame_index,
avifResultToString(result)
);
return NULL;
}

image = decoder->image;

memset(&rgb, 0, sizeof(rgb));
avifRGBImageSetDefaults(&rgb, image);

rgb.depth = 8;

if (decoder->alphaPresent) {
rgb.format = AVIF_RGB_FORMAT_RGBA;
} else {
rgb.format = AVIF_RGB_FORMAT_RGB;
rgb.ignoreAlpha = AVIF_TRUE;
}
rgb.format =
decoder->alphaPresent == AVIF_TRUE ? AVIF_RGB_FORMAT_RGBA : AVIF_RGB_FORMAT_RGB;

result = avifRGBImageAllocatePixels(&rgb);
if (result != AVIF_RESULT_OK) {
Expand Down Expand Up @@ -940,5 +924,9 @@ PyInit__avif(void) {
return NULL;
}

#ifdef Py_GIL_DISABLED
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
#endif

return m;
}
Loading