pillow-avif-plugin 1.4.6__cp312-cp312-musllinux_1_2_x86_64.whl → 1.5.1__cp312-cp312-musllinux_1_2_x86_64.whl
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.
Potentially problematic release.
This version of pillow-avif-plugin might be problematic. Click here for more details.
- pillow_avif/AvifImagePlugin.py +87 -49
- pillow_avif/__init__.py +1 -1
- pillow_avif/_avif.cpython-312-x86_64-linux-musl.so +0 -0
- {pillow_avif_plugin-1.4.6.dist-info → pillow_avif_plugin-1.5.1.dist-info}/METADATA +18 -7
- pillow_avif_plugin-1.5.1.dist-info/RECORD +9 -0
- {pillow_avif_plugin-1.4.6.dist-info → pillow_avif_plugin-1.5.1.dist-info}/WHEEL +1 -1
- pillow_avif_plugin-1.4.6.dist-info/RECORD +0 -10
- pillow_avif_plugin.libs/libgcc_s-a3a07607.so.1 +0 -0
- {pillow_avif_plugin-1.4.6.dist-info → pillow_avif_plugin-1.5.1.dist-info/licenses}/LICENSE +0 -0
- {pillow_avif_plugin-1.4.6.dist-info → pillow_avif_plugin-1.5.1.dist-info}/top_level.txt +0 -0
- {pillow_avif_plugin-1.4.6.dist-info → pillow_avif_plugin-1.5.1.dist-info}/zip-safe +0 -0
pillow_avif/AvifImagePlugin.py
CHANGED
|
@@ -16,11 +16,9 @@ except ImportError:
|
|
|
16
16
|
# to Image.open (see https://github.com/python-pillow/Pillow/issues/569)
|
|
17
17
|
DECODE_CODEC_CHOICE = "auto"
|
|
18
18
|
CHROMA_UPSAMPLING = "auto"
|
|
19
|
+
# Decoding is only affected by this for libavif **0.8.4** or greater.
|
|
19
20
|
DEFAULT_MAX_THREADS = 0
|
|
20
21
|
|
|
21
|
-
_VALID_AVIF_MODES = {"RGB", "RGBA"}
|
|
22
|
-
|
|
23
|
-
|
|
24
22
|
if sys.version_info[0] == 2:
|
|
25
23
|
text_type = unicode # noqa
|
|
26
24
|
else:
|
|
@@ -29,18 +27,12 @@ else:
|
|
|
29
27
|
|
|
30
28
|
def _accept(prefix):
|
|
31
29
|
if prefix[4:8] != b"ftyp":
|
|
32
|
-
return
|
|
33
|
-
coding_brands = (b"avif", b"avis")
|
|
34
|
-
container_brands = (b"mif1", b"msf1")
|
|
30
|
+
return False
|
|
35
31
|
major_brand = prefix[8:12]
|
|
36
|
-
if major_brand in
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"support not installed"
|
|
41
|
-
)
|
|
42
|
-
return True
|
|
43
|
-
if major_brand in container_brands:
|
|
32
|
+
if major_brand in (
|
|
33
|
+
# coding brands
|
|
34
|
+
b"avif",
|
|
35
|
+
b"avis",
|
|
44
36
|
# We accept files with AVIF container brands; we can't yet know if
|
|
45
37
|
# the ftyp box has the correct compatible brands, but if it doesn't
|
|
46
38
|
# then the plugin will raise a SyntaxError which Pillow will catch
|
|
@@ -48,67 +40,108 @@ def _accept(prefix):
|
|
|
48
40
|
#
|
|
49
41
|
# Also, because this file might not actually be an AVIF file, we
|
|
50
42
|
# don't raise an error if AVIF support isn't properly compiled.
|
|
43
|
+
b"mif1",
|
|
44
|
+
b"msf1",
|
|
45
|
+
):
|
|
46
|
+
if not SUPPORTED:
|
|
47
|
+
return (
|
|
48
|
+
"image file could not be identified because AVIF support not installed"
|
|
49
|
+
)
|
|
51
50
|
return True
|
|
51
|
+
return False
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
class AvifImageFile(ImageFile.ImageFile):
|
|
55
55
|
format = "AVIF"
|
|
56
56
|
format_description = "AVIF image"
|
|
57
|
-
|
|
58
|
-
__frame = 0
|
|
59
|
-
|
|
60
|
-
def load_seek(self, pos):
|
|
61
|
-
pass
|
|
57
|
+
__frame = -1
|
|
62
58
|
|
|
63
59
|
def _open(self):
|
|
60
|
+
if not SUPPORTED:
|
|
61
|
+
msg = "image file could not be opened because AVIF support not installed"
|
|
62
|
+
raise SyntaxError(msg)
|
|
63
|
+
|
|
64
|
+
if DECODE_CODEC_CHOICE != "auto" and not _avif.decoder_codec_available(
|
|
65
|
+
DECODE_CODEC_CHOICE
|
|
66
|
+
):
|
|
67
|
+
msg = "Invalid opening codec"
|
|
68
|
+
raise ValueError(msg)
|
|
64
69
|
self._decoder = _avif.AvifDecoder(
|
|
65
70
|
self.fp.read(), DECODE_CODEC_CHOICE, CHROMA_UPSAMPLING, DEFAULT_MAX_THREADS
|
|
66
71
|
)
|
|
67
72
|
|
|
68
73
|
# Get info from decoder
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
74
|
+
(
|
|
75
|
+
width,
|
|
76
|
+
height,
|
|
77
|
+
self.n_frames,
|
|
78
|
+
mode,
|
|
79
|
+
icc,
|
|
80
|
+
exif,
|
|
81
|
+
exif_orientation,
|
|
82
|
+
xmp,
|
|
83
|
+
) = self._decoder.get_info()
|
|
84
|
+
self._size = (width, height)
|
|
72
85
|
self.is_animated = self.n_frames > 1
|
|
73
86
|
try:
|
|
74
87
|
self.mode = self.rawmode = mode
|
|
75
88
|
except AttributeError:
|
|
76
89
|
self._mode = self.rawmode = mode
|
|
77
|
-
self.tile = []
|
|
78
90
|
|
|
79
91
|
if icc:
|
|
80
92
|
self.info["icc_profile"] = icc
|
|
81
|
-
if exif:
|
|
82
|
-
self.info["exif"] = exif
|
|
83
93
|
if xmp:
|
|
84
94
|
self.info["xmp"] = xmp
|
|
85
95
|
|
|
96
|
+
if exif_orientation != 1 or exif:
|
|
97
|
+
exif_data = Image.Exif()
|
|
98
|
+
orientation_tag = next(
|
|
99
|
+
k for k, v in ExifTags.TAGS.items() if v == "Orientation"
|
|
100
|
+
)
|
|
101
|
+
if exif:
|
|
102
|
+
exif_data.load(exif)
|
|
103
|
+
original_orientation = exif_data.get(orientation_tag, 1)
|
|
104
|
+
else:
|
|
105
|
+
original_orientation = 1
|
|
106
|
+
if exif_orientation != original_orientation:
|
|
107
|
+
exif_data[orientation_tag] = exif_orientation
|
|
108
|
+
exif = exif_data.tobytes()
|
|
109
|
+
if exif:
|
|
110
|
+
self.info["exif"] = exif
|
|
111
|
+
self.seek(0)
|
|
112
|
+
|
|
86
113
|
def seek(self, frame):
|
|
87
114
|
if not self._seek_check(frame):
|
|
88
115
|
return
|
|
89
116
|
|
|
117
|
+
# Set tile
|
|
90
118
|
self.__frame = frame
|
|
119
|
+
if hasattr(ImageFile, "_Tile"):
|
|
120
|
+
self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 0, self.mode)]
|
|
121
|
+
else:
|
|
122
|
+
self.tile = [("raw", (0, 0) + self.size, 0, self.mode)]
|
|
91
123
|
|
|
92
124
|
def load(self):
|
|
93
|
-
if self.
|
|
125
|
+
if self.tile:
|
|
94
126
|
# We need to load the image data for this frame
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
self.info["
|
|
102
|
-
self.
|
|
127
|
+
(
|
|
128
|
+
data,
|
|
129
|
+
timescale,
|
|
130
|
+
pts_in_timescales,
|
|
131
|
+
duration_in_timescales,
|
|
132
|
+
) = self._decoder.get_frame(self.__frame)
|
|
133
|
+
self.info["timestamp"] = round(1000 * (pts_in_timescales / timescale))
|
|
134
|
+
self.info["duration"] = round(1000 * (duration_in_timescales / timescale))
|
|
103
135
|
|
|
104
|
-
# Set tile
|
|
105
136
|
if self.fp and self._exclusive_fp:
|
|
106
137
|
self.fp.close()
|
|
107
138
|
self.fp = BytesIO(data)
|
|
108
|
-
self.tile = [("raw", (0, 0) + self.size, 0, self.rawmode)]
|
|
109
139
|
|
|
110
140
|
return super(AvifImageFile, self).load()
|
|
111
141
|
|
|
142
|
+
def load_seek(self, pos):
|
|
143
|
+
pass
|
|
144
|
+
|
|
112
145
|
def tell(self):
|
|
113
146
|
return self.__frame
|
|
114
147
|
|
|
@@ -128,19 +161,21 @@ def _save(im, fp, filename, save_all=False):
|
|
|
128
161
|
for ims in [im] + append_images:
|
|
129
162
|
total += getattr(ims, "n_frames", 1)
|
|
130
163
|
|
|
131
|
-
is_single_frame = total == 1
|
|
132
|
-
|
|
133
164
|
qmin = info.get("qmin", -1)
|
|
134
165
|
qmax = info.get("qmax", -1)
|
|
135
166
|
quality = info.get("quality", 75)
|
|
136
167
|
if not isinstance(quality, int) or quality < 0 or quality > 100:
|
|
137
|
-
|
|
168
|
+
msg = "Invalid quality setting"
|
|
169
|
+
raise ValueError(msg)
|
|
138
170
|
|
|
139
171
|
duration = info.get("duration", 0)
|
|
140
172
|
subsampling = info.get("subsampling", "4:2:0")
|
|
141
173
|
speed = info.get("speed", 6)
|
|
142
174
|
max_threads = info.get("max_threads", DEFAULT_MAX_THREADS)
|
|
143
175
|
codec = info.get("codec", "auto")
|
|
176
|
+
if codec != "auto" and not _avif.encoder_codec_available(codec):
|
|
177
|
+
msg = "Invalid saving codec"
|
|
178
|
+
raise ValueError(msg)
|
|
144
179
|
range_ = info.get("range", "full")
|
|
145
180
|
tile_rows_log2 = info.get("tile_rows", 0)
|
|
146
181
|
tile_cols_log2 = info.get("tile_cols", 0)
|
|
@@ -171,20 +206,21 @@ def _save(im, fp, filename, save_all=False):
|
|
|
171
206
|
xmp = xmp.encode("utf-8")
|
|
172
207
|
|
|
173
208
|
advanced = info.get("advanced")
|
|
174
|
-
if isinstance(advanced, dict):
|
|
175
|
-
advanced = tuple([k, v] for (k, v) in advanced.items())
|
|
176
209
|
if advanced is not None:
|
|
210
|
+
if isinstance(advanced, dict):
|
|
211
|
+
advanced = tuple(advanced.items())
|
|
177
212
|
try:
|
|
178
213
|
advanced = tuple(advanced)
|
|
179
214
|
except TypeError:
|
|
180
215
|
invalid = True
|
|
181
216
|
else:
|
|
182
|
-
invalid =
|
|
217
|
+
invalid = any(not isinstance(v, tuple) or len(v) != 2 for v in advanced)
|
|
183
218
|
if invalid:
|
|
184
|
-
|
|
219
|
+
msg = (
|
|
185
220
|
"advanced codec options must be a dict of key-value string "
|
|
186
221
|
"pairs or a series of key-value two-tuples"
|
|
187
222
|
)
|
|
223
|
+
raise ValueError(msg)
|
|
188
224
|
advanced = tuple(
|
|
189
225
|
[(str(k).encode("utf-8"), str(v).encode("utf-8")) for k, v in advanced]
|
|
190
226
|
)
|
|
@@ -214,8 +250,9 @@ def _save(im, fp, filename, save_all=False):
|
|
|
214
250
|
|
|
215
251
|
# Add each frame
|
|
216
252
|
frame_idx = 0
|
|
217
|
-
|
|
253
|
+
frame_duration = 0
|
|
218
254
|
cur_idx = im.tell()
|
|
255
|
+
is_single_frame = total == 1
|
|
219
256
|
try:
|
|
220
257
|
for ims in [im] + append_images:
|
|
221
258
|
# Get # of frames in this image
|
|
@@ -228,7 +265,7 @@ def _save(im, fp, filename, save_all=False):
|
|
|
228
265
|
# Make sure image mode is supported
|
|
229
266
|
frame = ims
|
|
230
267
|
rawmode = ims.mode
|
|
231
|
-
if ims.mode not in
|
|
268
|
+
if ims.mode not in {"RGB", "RGBA"}:
|
|
232
269
|
alpha = (
|
|
233
270
|
"A" in ims.mode
|
|
234
271
|
or "a" in ims.mode
|
|
@@ -243,14 +280,14 @@ def _save(im, fp, filename, save_all=False):
|
|
|
243
280
|
|
|
244
281
|
# Update frame duration
|
|
245
282
|
if isinstance(duration, (list, tuple)):
|
|
246
|
-
|
|
283
|
+
frame_duration = duration[frame_idx]
|
|
247
284
|
else:
|
|
248
|
-
|
|
285
|
+
frame_duration = duration
|
|
249
286
|
|
|
250
287
|
# Append the frame to the animation encoder
|
|
251
288
|
enc.add(
|
|
252
289
|
frame.tobytes("raw", rawmode),
|
|
253
|
-
|
|
290
|
+
int(frame_duration),
|
|
254
291
|
frame.size[0],
|
|
255
292
|
frame.size[1],
|
|
256
293
|
rawmode,
|
|
@@ -269,7 +306,8 @@ def _save(im, fp, filename, save_all=False):
|
|
|
269
306
|
# Get the final output from the encoder
|
|
270
307
|
data = enc.finish()
|
|
271
308
|
if data is None:
|
|
272
|
-
|
|
309
|
+
msg = "cannot write file as AVIF (encoder returned None)"
|
|
310
|
+
raise OSError(msg)
|
|
273
311
|
|
|
274
312
|
fp.write(data)
|
|
275
313
|
|
pillow_avif/__init__.py
CHANGED
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: pillow-avif-plugin
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.1
|
|
4
4
|
Summary: A pillow plugin that adds avif support via libavif
|
|
5
5
|
Home-page: https://github.com/fdintino/pillow-avif-plugin/
|
|
6
6
|
Download-URL: https://github.com/fdintino/pillow-avif-plugin/releases
|
|
@@ -29,11 +29,22 @@ Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
|
|
|
29
29
|
Description-Content-Type: text/markdown
|
|
30
30
|
License-File: LICENSE
|
|
31
31
|
Provides-Extra: tests
|
|
32
|
-
Requires-Dist: pytest
|
|
33
|
-
Requires-Dist: packaging
|
|
34
|
-
Requires-Dist: pytest-cov
|
|
35
|
-
Requires-Dist: test-image-results
|
|
36
|
-
Requires-Dist: pillow
|
|
32
|
+
Requires-Dist: pytest; extra == "tests"
|
|
33
|
+
Requires-Dist: packaging; extra == "tests"
|
|
34
|
+
Requires-Dist: pytest-cov; extra == "tests"
|
|
35
|
+
Requires-Dist: test-image-results; extra == "tests"
|
|
36
|
+
Requires-Dist: pillow; extra == "tests"
|
|
37
|
+
Dynamic: author
|
|
38
|
+
Dynamic: author-email
|
|
39
|
+
Dynamic: classifier
|
|
40
|
+
Dynamic: description
|
|
41
|
+
Dynamic: description-content-type
|
|
42
|
+
Dynamic: download-url
|
|
43
|
+
Dynamic: home-page
|
|
44
|
+
Dynamic: license
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
Dynamic: provides-extra
|
|
47
|
+
Dynamic: summary
|
|
37
48
|
|
|
38
49
|
# pillow-avif-plugin
|
|
39
50
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
pillow_avif/AvifImagePlugin.py,sha256=B0w7AVoU3R-O9tTIOSqhjJdNAAEMYzMFhUcKf8Lczm4,9756
|
|
2
|
+
pillow_avif/__init__.py,sha256=ha9bUuJLoEM5BeveIZE1JwPGl8W2AUYVfXRwgEVCiI8,84
|
|
3
|
+
pillow_avif/_avif.cpython-312-x86_64-linux-musl.so,sha256=oLY8UrqWBSpMk1PTKBlAWMovHFhsVs3_8hNwc8nnf3I,21032672
|
|
4
|
+
pillow_avif_plugin-1.5.1.dist-info/METADATA,sha256=KhLcAf5Uq7bjWY5w8N-HPCJK6i7pPzMkK4EvQ8hTAxs,2143
|
|
5
|
+
pillow_avif_plugin-1.5.1.dist-info/WHEEL,sha256=ENczIf-GYPIfQ0_PXY8w5mFbOCUfjnGClbW6hbN_vLc,112
|
|
6
|
+
pillow_avif_plugin-1.5.1.dist-info/top_level.txt,sha256=xrg4zRnqDyl_JEyEQh3oCcAU4BHneocD-DCFDzf4g9E,12
|
|
7
|
+
pillow_avif_plugin-1.5.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
8
|
+
pillow_avif_plugin-1.5.1.dist-info/RECORD,,
|
|
9
|
+
pillow_avif_plugin-1.5.1.dist-info/licenses/LICENSE,sha256=2l49eVdgaNy9JTEPbstz1GaaPKw02gFdtuThTNUi730,25213
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
pillow_avif/AvifImagePlugin.py,sha256=MfIVDuN7jVDceVl68b9R5lTHxzrHG6wpt6Ca-NbFdAw,8486
|
|
2
|
-
pillow_avif/_avif.cpython-312-x86_64-linux-musl.so,sha256=eCSQv5moQdtO1kHbaUqENRqXRxegZgsGuFog0NmTy2I,59214201
|
|
3
|
-
pillow_avif/__init__.py,sha256=qh2QBNJ1nd7wWVTqzyqnMpC5fVuC1799iGLWYCKq36g,84
|
|
4
|
-
pillow_avif_plugin-1.4.6.dist-info/top_level.txt,sha256=xrg4zRnqDyl_JEyEQh3oCcAU4BHneocD-DCFDzf4g9E,12
|
|
5
|
-
pillow_avif_plugin-1.4.6.dist-info/RECORD,,
|
|
6
|
-
pillow_avif_plugin-1.4.6.dist-info/LICENSE,sha256=2l49eVdgaNy9JTEPbstz1GaaPKw02gFdtuThTNUi730,25213
|
|
7
|
-
pillow_avif_plugin-1.4.6.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
8
|
-
pillow_avif_plugin-1.4.6.dist-info/METADATA,sha256=arZMb94_qIVuxjND8P2bT5YgPLH3Fk5hlBl4IJlWWms,1914
|
|
9
|
-
pillow_avif_plugin-1.4.6.dist-info/WHEEL,sha256=8O9ZXBwDJ5UGP_BOnM_Qb43ANokSejH80Ub58rDU9U0,112
|
|
10
|
-
pillow_avif_plugin.libs/libgcc_s-a3a07607.so.1,sha256=5ptIUeAzZweNZrFehN0_Bb5B0FcJgux7NbAFoU8vwwo,148041
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|