pillow-avif-plugin 1.4.1__tar.gz → 1.4.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/PKG-INFO +1 -1
- {pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/setup.py +14 -1
- {pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/src/pillow_avif/AvifImagePlugin.py +19 -1
- {pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/src/pillow_avif/__init__.py +1 -1
- {pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/src/pillow_avif/_avif.c +121 -2
- {pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/src/pillow_avif_plugin.egg-info/PKG-INFO +1 -1
- {pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/src/pillow_avif_plugin.egg-info/SOURCES.txt +2 -2
- {pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/LICENSE +0 -0
- {pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/MANIFEST.in +0 -0
- {pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/README.md +0 -0
- {pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/pyproject.toml +0 -0
- {pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/setup.cfg +0 -0
- {pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/src/pillow_avif_plugin.egg-info/dependency_links.txt +0 -0
- /pillow-avif-plugin-1.4.1/src/pillow_avif_plugin.egg-info/zip-safe → /pillow-avif-plugin-1.4.3/src/pillow_avif_plugin.egg-info/not-zip-safe +0 -0
- {pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/src/pillow_avif_plugin.egg-info/top_level.txt +0 -0
- {pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/tox.ini +0 -0
|
@@ -28,6 +28,19 @@ def readme():
|
|
|
28
28
|
IS_DEBUG = hasattr(sys, "gettotalrefcount")
|
|
29
29
|
PLATFORM_MINGW = os.name == "nt" and "GCC" in sys.version
|
|
30
30
|
|
|
31
|
+
libraries = ["avif"]
|
|
32
|
+
if sys.platform == "win32":
|
|
33
|
+
libraries.extend(
|
|
34
|
+
[
|
|
35
|
+
"advapi32",
|
|
36
|
+
"bcrypt",
|
|
37
|
+
"ntdll",
|
|
38
|
+
"userenv",
|
|
39
|
+
"ws2_32",
|
|
40
|
+
"kernel32",
|
|
41
|
+
]
|
|
42
|
+
)
|
|
43
|
+
|
|
31
44
|
setup(
|
|
32
45
|
name="pillow-avif-plugin",
|
|
33
46
|
description="A pillow plugin that adds avif support via libavif",
|
|
@@ -39,7 +52,7 @@ setup(
|
|
|
39
52
|
"pillow_avif._avif",
|
|
40
53
|
["src/pillow_avif/_avif.c"],
|
|
41
54
|
depends=["avif/avif.h"],
|
|
42
|
-
libraries=
|
|
55
|
+
libraries=libraries,
|
|
43
56
|
),
|
|
44
57
|
],
|
|
45
58
|
package_data={"": ["README.rst"]},
|
|
@@ -3,7 +3,7 @@ from __future__ import division
|
|
|
3
3
|
from io import BytesIO
|
|
4
4
|
import sys
|
|
5
5
|
|
|
6
|
-
from PIL import Image, ImageFile
|
|
6
|
+
from PIL import ExifTags, Image, ImageFile
|
|
7
7
|
|
|
8
8
|
try:
|
|
9
9
|
from pillow_avif import _avif
|
|
@@ -56,6 +56,9 @@ class AvifImageFile(ImageFile.ImageFile):
|
|
|
56
56
|
__loaded = -1
|
|
57
57
|
__frame = 0
|
|
58
58
|
|
|
59
|
+
def load_seek(self, pos):
|
|
60
|
+
pass
|
|
61
|
+
|
|
59
62
|
def _open(self):
|
|
60
63
|
self._decoder = _avif.AvifDecoder(
|
|
61
64
|
self.fp.read(), DECODE_CODEC_CHOICE, CHROMA_UPSAMPLING
|
|
@@ -146,6 +149,20 @@ def _save(im, fp, filename, save_all=False):
|
|
|
146
149
|
exif = info.get("exif", im.info.get("exif"))
|
|
147
150
|
if isinstance(exif, Image.Exif):
|
|
148
151
|
exif = exif.tobytes()
|
|
152
|
+
|
|
153
|
+
exif_orientation = 0
|
|
154
|
+
if exif:
|
|
155
|
+
exif_data = Image.Exif()
|
|
156
|
+
try:
|
|
157
|
+
exif_data.load(exif)
|
|
158
|
+
except SyntaxError:
|
|
159
|
+
pass
|
|
160
|
+
else:
|
|
161
|
+
orientation_tag = next(
|
|
162
|
+
k for k, v in ExifTags.TAGS.items() if v == "Orientation"
|
|
163
|
+
)
|
|
164
|
+
exif_orientation = exif_data.get(orientation_tag) or 0
|
|
165
|
+
|
|
149
166
|
xmp = info.get("xmp", im.info.get("xmp") or im.info.get("XML:com.adobe.xmp"))
|
|
150
167
|
|
|
151
168
|
if isinstance(xmp, text_type):
|
|
@@ -187,6 +204,7 @@ def _save(im, fp, filename, save_all=False):
|
|
|
187
204
|
autotiling,
|
|
188
205
|
icc_profile or b"",
|
|
189
206
|
exif or b"",
|
|
207
|
+
exif_orientation,
|
|
190
208
|
xmp or b"",
|
|
191
209
|
advanced,
|
|
192
210
|
)
|
|
@@ -139,6 +139,118 @@ exc_type_for_avif_result(avifResult result) {
|
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
+
static void
|
|
143
|
+
exif_orientation_to_irot_imir(avifImage *image, int orientation) {
|
|
144
|
+
const avifTransformFlags otherFlags =
|
|
145
|
+
image->transformFlags & ~(AVIF_TRANSFORM_IROT | AVIF_TRANSFORM_IMIR);
|
|
146
|
+
|
|
147
|
+
//
|
|
148
|
+
// Mapping from Exif orientation as defined in JEITA CP-3451C section 4.6.4.A
|
|
149
|
+
// Orientation to irot and imir boxes as defined in HEIF ISO/IEC 28002-12:2021
|
|
150
|
+
// sections 6.5.10 and 6.5.12.
|
|
151
|
+
switch (orientation) {
|
|
152
|
+
case 1: // The 0th row is at the visual top of the image, and the 0th column is
|
|
153
|
+
// the visual left-hand side.
|
|
154
|
+
image->transformFlags = otherFlags;
|
|
155
|
+
image->irot.angle = 0; // ignored
|
|
156
|
+
#if AVIF_VERSION_MAJOR >= 1
|
|
157
|
+
image->imir.axis = 0; // ignored
|
|
158
|
+
#else
|
|
159
|
+
image->imir.mode = 0; // ignored
|
|
160
|
+
#endif
|
|
161
|
+
return;
|
|
162
|
+
case 2: // The 0th row is at the visual top of the image, and the 0th column is
|
|
163
|
+
// the visual right-hand side.
|
|
164
|
+
image->transformFlags = otherFlags | AVIF_TRANSFORM_IMIR;
|
|
165
|
+
image->irot.angle = 0; // ignored
|
|
166
|
+
#if AVIF_VERSION_MAJOR >= 1
|
|
167
|
+
image->imir.axis = 1;
|
|
168
|
+
#else
|
|
169
|
+
image->imir.mode = 1;
|
|
170
|
+
#endif
|
|
171
|
+
return;
|
|
172
|
+
case 3: // The 0th row is at the visual bottom of the image, and the 0th column
|
|
173
|
+
// is the visual right-hand side.
|
|
174
|
+
image->transformFlags = otherFlags | AVIF_TRANSFORM_IROT;
|
|
175
|
+
image->irot.angle = 2;
|
|
176
|
+
#if AVIF_VERSION_MAJOR >= 1
|
|
177
|
+
image->imir.axis = 0; // ignored
|
|
178
|
+
#else
|
|
179
|
+
image->imir.mode = 0; // ignored
|
|
180
|
+
#endif
|
|
181
|
+
return;
|
|
182
|
+
case 4: // The 0th row is at the visual bottom of the image, and the 0th column
|
|
183
|
+
// is the visual left-hand side.
|
|
184
|
+
image->transformFlags = otherFlags | AVIF_TRANSFORM_IMIR;
|
|
185
|
+
image->irot.angle = 0; // ignored
|
|
186
|
+
#if AVIF_VERSION_MAJOR >= 1
|
|
187
|
+
image->imir.axis = 0;
|
|
188
|
+
#else
|
|
189
|
+
image->imir.mode = 0;
|
|
190
|
+
#endif
|
|
191
|
+
return;
|
|
192
|
+
case 5: // The 0th row is the visual left-hand side of the image, and the 0th
|
|
193
|
+
// column is the visual top.
|
|
194
|
+
image->transformFlags =
|
|
195
|
+
otherFlags | AVIF_TRANSFORM_IROT | AVIF_TRANSFORM_IMIR;
|
|
196
|
+
image->irot.angle = 1; // applied before imir according to MIAF spec
|
|
197
|
+
// ISO/IEC 28002-12:2021 - section 7.3.6.7
|
|
198
|
+
#if AVIF_VERSION_MAJOR >= 1
|
|
199
|
+
image->imir.axis = 0;
|
|
200
|
+
#else
|
|
201
|
+
image->imir.mode = 0;
|
|
202
|
+
#endif
|
|
203
|
+
return;
|
|
204
|
+
case 6: // The 0th row is the visual right-hand side of the image, and the 0th
|
|
205
|
+
// column is the visual top.
|
|
206
|
+
image->transformFlags = otherFlags | AVIF_TRANSFORM_IROT;
|
|
207
|
+
image->irot.angle = 3;
|
|
208
|
+
#if AVIF_VERSION_MAJOR >= 1
|
|
209
|
+
image->imir.axis = 0; // ignored
|
|
210
|
+
#else
|
|
211
|
+
image->imir.mode = 0; // ignored
|
|
212
|
+
#endif
|
|
213
|
+
return;
|
|
214
|
+
case 7: // The 0th row is the visual right-hand side of the image, and the 0th
|
|
215
|
+
// column is the visual bottom.
|
|
216
|
+
image->transformFlags =
|
|
217
|
+
otherFlags | AVIF_TRANSFORM_IROT | AVIF_TRANSFORM_IMIR;
|
|
218
|
+
image->irot.angle = 3; // applied before imir according to MIAF spec
|
|
219
|
+
// ISO/IEC 28002-12:2021 - section 7.3.6.7
|
|
220
|
+
#if AVIF_VERSION_MAJOR >= 1
|
|
221
|
+
image->imir.axis = 0;
|
|
222
|
+
#else
|
|
223
|
+
image->imir.mode = 0;
|
|
224
|
+
#endif
|
|
225
|
+
return;
|
|
226
|
+
case 8: // The 0th row is the visual left-hand side of the image, and the 0th
|
|
227
|
+
// column is the visual bottom.
|
|
228
|
+
image->transformFlags = otherFlags | AVIF_TRANSFORM_IROT;
|
|
229
|
+
image->irot.angle = 1;
|
|
230
|
+
#if AVIF_VERSION_MAJOR >= 1
|
|
231
|
+
image->imir.axis = 0; // ignored
|
|
232
|
+
#else
|
|
233
|
+
image->imir.mode = 0; // ignored
|
|
234
|
+
#endif
|
|
235
|
+
return;
|
|
236
|
+
default: // reserved
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// The orientation tag is not mandatory (only recommended) according to JEITA
|
|
241
|
+
// CP-3451C section 4.6.8.A. The default value is 1 if the orientation tag is
|
|
242
|
+
// missing, meaning:
|
|
243
|
+
// The 0th row is at the visual top of the image, and the 0th column is the visual
|
|
244
|
+
// left-hand side.
|
|
245
|
+
image->transformFlags = otherFlags;
|
|
246
|
+
image->irot.angle = 0; // ignored
|
|
247
|
+
#if AVIF_VERSION_MAJOR >= 1
|
|
248
|
+
image->imir.axis = 0; // ignored
|
|
249
|
+
#else
|
|
250
|
+
image->imir.mode = 0; // ignored
|
|
251
|
+
#endif
|
|
252
|
+
}
|
|
253
|
+
|
|
142
254
|
static int
|
|
143
255
|
_codec_available(const char *name, uint32_t flags) {
|
|
144
256
|
avifCodecChoice codec = avifCodecChoiceFromName(name);
|
|
@@ -208,6 +320,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
|
|
|
208
320
|
int qmax = 10; // "High Quality", but not lossless
|
|
209
321
|
int quality = 75;
|
|
210
322
|
int speed = 8;
|
|
323
|
+
int exif_orientation = 0;
|
|
211
324
|
PyObject *icc_bytes;
|
|
212
325
|
PyObject *exif_bytes;
|
|
213
326
|
PyObject *xmp_bytes;
|
|
@@ -223,7 +336,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
|
|
|
223
336
|
|
|
224
337
|
if (!PyArg_ParseTuple(
|
|
225
338
|
args,
|
|
226
|
-
"
|
|
339
|
+
"IIsiiiissiiOOSSiSO",
|
|
227
340
|
&width,
|
|
228
341
|
&height,
|
|
229
342
|
&subsampling,
|
|
@@ -239,6 +352,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
|
|
|
239
352
|
&autotiling,
|
|
240
353
|
&icc_bytes,
|
|
241
354
|
&exif_bytes,
|
|
355
|
+
&exif_orientation,
|
|
242
356
|
&xmp_bytes,
|
|
243
357
|
&advanced)) {
|
|
244
358
|
return NULL;
|
|
@@ -334,7 +448,11 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
|
|
|
334
448
|
init_max_threads();
|
|
335
449
|
}
|
|
336
450
|
|
|
337
|
-
|
|
451
|
+
int is_aom_encode = strcmp(codec, "aom") == 0 ||
|
|
452
|
+
(strcmp(codec, "auto") == 0 &&
|
|
453
|
+
_codec_available("aom", AVIF_CODEC_FLAG_CAN_ENCODE));
|
|
454
|
+
|
|
455
|
+
encoder->maxThreads = is_aom_encode && max_threads > 64 ? 64 : max_threads;
|
|
338
456
|
#if AVIF_VERSION >= 1000000
|
|
339
457
|
if (enc_options.qmin != -1 && enc_options.qmax != -1) {
|
|
340
458
|
encoder->minQuantizer = enc_options.qmin;
|
|
@@ -404,6 +522,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
|
|
|
404
522
|
(uint8_t *)PyBytes_AS_STRING(xmp_bytes),
|
|
405
523
|
PyBytes_GET_SIZE(xmp_bytes));
|
|
406
524
|
}
|
|
525
|
+
exif_orientation_to_irot_imir(image, exif_orientation);
|
|
407
526
|
|
|
408
527
|
self->image = image;
|
|
409
528
|
self->frame_index = -1;
|
{pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/src/pillow_avif_plugin.egg-info/SOURCES.txt
RENAMED
|
@@ -11,5 +11,5 @@ src/pillow_avif/_avif.c
|
|
|
11
11
|
src/pillow_avif_plugin.egg-info/PKG-INFO
|
|
12
12
|
src/pillow_avif_plugin.egg-info/SOURCES.txt
|
|
13
13
|
src/pillow_avif_plugin.egg-info/dependency_links.txt
|
|
14
|
-
src/pillow_avif_plugin.egg-info/
|
|
15
|
-
src/pillow_avif_plugin.egg-info/
|
|
14
|
+
src/pillow_avif_plugin.egg-info/not-zip-safe
|
|
15
|
+
src/pillow_avif_plugin.egg-info/top_level.txt
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pillow-avif-plugin-1.4.1 → pillow-avif-plugin-1.4.3}/src/pillow_avif_plugin.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|