pillow-avif-plugin 1.4.4__tar.gz → 1.4.6__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.
Potentially problematic release.
This version of pillow-avif-plugin might be problematic. Click here for more details.
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/PKG-INFO +1 -1
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/src/pillow_avif/__init__.py +1 -1
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/src/pillow_avif_plugin.egg-info/PKG-INFO +1 -1
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/src/pillow_avif_plugin.egg-info/SOURCES.txt +0 -1
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/tests/test_file_avif.py +12 -0
- pillow-avif-plugin-1.4.4/src/pillow_avif/AvifImagePlugin.py.orig +0 -282
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/LICENSE +0 -0
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/MANIFEST.in +0 -0
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/README.md +0 -0
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/pyproject.toml +0 -0
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/setup.cfg +0 -0
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/setup.py +0 -0
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/src/pillow_avif/AvifImagePlugin.py +0 -0
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/src/pillow_avif/_avif.c +0 -0
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/src/pillow_avif_plugin.egg-info/dependency_links.txt +0 -0
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/src/pillow_avif_plugin.egg-info/top_level.txt +0 -0
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/src/pillow_avif_plugin.egg-info/zip-safe +0 -0
- {pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pillow-avif-plugin
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.6
|
|
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
|
{pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/src/pillow_avif_plugin.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pillow-avif-plugin
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.6
|
|
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
|
|
@@ -584,6 +584,18 @@ class TestFileAvif:
|
|
|
584
584
|
with Image.open("%s/tests/images/chimera-missing-pixi.avif" % CURR_DIR) as im:
|
|
585
585
|
assert im.size == (480, 270)
|
|
586
586
|
|
|
587
|
+
@skip_unless_avif_encoder("aom")
|
|
588
|
+
def test_aom_optimizations(self):
|
|
589
|
+
im = hopper("RGB")
|
|
590
|
+
buf = BytesIO()
|
|
591
|
+
im.save(buf, format="AVIF", codec="aom", speed=1)
|
|
592
|
+
|
|
593
|
+
@skip_unless_avif_encoder("svt")
|
|
594
|
+
def test_svt_optimizations(self):
|
|
595
|
+
im = hopper("RGB")
|
|
596
|
+
buf = BytesIO()
|
|
597
|
+
im.save(buf, format="AVIF", codec="svt", speed=1)
|
|
598
|
+
|
|
587
599
|
|
|
588
600
|
class TestAvifAnimation:
|
|
589
601
|
@contextmanager
|
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
from __future__ import division
|
|
2
|
-
|
|
3
|
-
from io import BytesIO
|
|
4
|
-
import sys
|
|
5
|
-
|
|
6
|
-
from PIL import ExifTags, Image, ImageFile
|
|
7
|
-
|
|
8
|
-
try:
|
|
9
|
-
from pillow_avif import _avif
|
|
10
|
-
|
|
11
|
-
SUPPORTED = True
|
|
12
|
-
except ImportError:
|
|
13
|
-
SUPPORTED = False
|
|
14
|
-
|
|
15
|
-
# Decoder options as module globals, until there is a way to pass parameters
|
|
16
|
-
# to Image.open (see https://github.com/python-pillow/Pillow/issues/569)
|
|
17
|
-
DECODE_CODEC_CHOICE = "auto"
|
|
18
|
-
CHROMA_UPSAMPLING = "auto"
|
|
19
|
-
<<<<<<< HEAD
|
|
20
|
-
DEFAULT_MAX_THREADS = 0
|
|
21
|
-
=======
|
|
22
|
-
DECODE_MAX_THREADS = 0
|
|
23
|
-
>>>>>>> 1e2fa65 (Let users pass max_threads manually as an argument)
|
|
24
|
-
|
|
25
|
-
_VALID_AVIF_MODES = {"RGB", "RGBA"}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if sys.version_info[0] == 2:
|
|
29
|
-
text_type = unicode # noqa
|
|
30
|
-
else:
|
|
31
|
-
text_type = str
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def _accept(prefix):
|
|
35
|
-
if prefix[4:8] != b"ftyp":
|
|
36
|
-
return
|
|
37
|
-
coding_brands = (b"avif", b"avis")
|
|
38
|
-
container_brands = (b"mif1", b"msf1")
|
|
39
|
-
major_brand = prefix[8:12]
|
|
40
|
-
if major_brand in coding_brands:
|
|
41
|
-
if not SUPPORTED:
|
|
42
|
-
return (
|
|
43
|
-
"image file could not be identified because AVIF "
|
|
44
|
-
"support not installed"
|
|
45
|
-
)
|
|
46
|
-
return True
|
|
47
|
-
if major_brand in container_brands:
|
|
48
|
-
# We accept files with AVIF container brands; we can't yet know if
|
|
49
|
-
# the ftyp box has the correct compatible brands, but if it doesn't
|
|
50
|
-
# then the plugin will raise a SyntaxError which Pillow will catch
|
|
51
|
-
# before moving on to the next plugin that accepts the file.
|
|
52
|
-
#
|
|
53
|
-
# Also, because this file might not actually be an AVIF file, we
|
|
54
|
-
# don't raise an error if AVIF support isn't properly compiled.
|
|
55
|
-
return True
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
class AvifImageFile(ImageFile.ImageFile):
|
|
59
|
-
format = "AVIF"
|
|
60
|
-
format_description = "AVIF image"
|
|
61
|
-
__loaded = -1
|
|
62
|
-
__frame = 0
|
|
63
|
-
|
|
64
|
-
def load_seek(self, pos):
|
|
65
|
-
pass
|
|
66
|
-
|
|
67
|
-
def _open(self):
|
|
68
|
-
self._decoder = _avif.AvifDecoder(
|
|
69
|
-
self.fp.read(), DECODE_CODEC_CHOICE, CHROMA_UPSAMPLING, DECODE_MAX_THREADS
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
# Get info from decoder
|
|
73
|
-
width, height, n_frames, mode, icc, exif, xmp = self._decoder.get_info()
|
|
74
|
-
self._size = width, height
|
|
75
|
-
self.n_frames = n_frames
|
|
76
|
-
self.is_animated = self.n_frames > 1
|
|
77
|
-
try:
|
|
78
|
-
self.mode = self.rawmode = mode
|
|
79
|
-
except AttributeError:
|
|
80
|
-
self._mode = self.rawmode = mode
|
|
81
|
-
self.tile = []
|
|
82
|
-
|
|
83
|
-
if icc:
|
|
84
|
-
self.info["icc_profile"] = icc
|
|
85
|
-
if exif:
|
|
86
|
-
self.info["exif"] = exif
|
|
87
|
-
if xmp:
|
|
88
|
-
self.info["xmp"] = xmp
|
|
89
|
-
|
|
90
|
-
def seek(self, frame):
|
|
91
|
-
if not self._seek_check(frame):
|
|
92
|
-
return
|
|
93
|
-
|
|
94
|
-
self.__frame = frame
|
|
95
|
-
|
|
96
|
-
def load(self):
|
|
97
|
-
if self.__loaded != self.__frame:
|
|
98
|
-
# We need to load the image data for this frame
|
|
99
|
-
data, timescale, tsp_in_ts, dur_in_ts = self._decoder.get_frame(
|
|
100
|
-
self.__frame
|
|
101
|
-
)
|
|
102
|
-
timestamp = round(1000 * (tsp_in_ts / timescale))
|
|
103
|
-
duration = round(1000 * (dur_in_ts / timescale))
|
|
104
|
-
self.info["timestamp"] = timestamp
|
|
105
|
-
self.info["duration"] = duration
|
|
106
|
-
self.__loaded = self.__frame
|
|
107
|
-
|
|
108
|
-
# Set tile
|
|
109
|
-
if self.fp and self._exclusive_fp:
|
|
110
|
-
self.fp.close()
|
|
111
|
-
self.fp = BytesIO(data)
|
|
112
|
-
self.tile = [("raw", (0, 0) + self.size, 0, self.rawmode)]
|
|
113
|
-
|
|
114
|
-
return super(AvifImageFile, self).load()
|
|
115
|
-
|
|
116
|
-
def tell(self):
|
|
117
|
-
return self.__frame
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def _save_all(im, fp, filename):
|
|
121
|
-
_save(im, fp, filename, save_all=True)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
def _save(im, fp, filename, save_all=False):
|
|
125
|
-
info = im.encoderinfo.copy()
|
|
126
|
-
if save_all:
|
|
127
|
-
append_images = list(info.get("append_images", []))
|
|
128
|
-
else:
|
|
129
|
-
append_images = []
|
|
130
|
-
|
|
131
|
-
total = 0
|
|
132
|
-
for ims in [im] + append_images:
|
|
133
|
-
total += getattr(ims, "n_frames", 1)
|
|
134
|
-
|
|
135
|
-
is_single_frame = total == 1
|
|
136
|
-
|
|
137
|
-
qmin = info.get("qmin", -1)
|
|
138
|
-
qmax = info.get("qmax", -1)
|
|
139
|
-
quality = info.get("quality", 75)
|
|
140
|
-
if not isinstance(quality, int) or quality < 0 or quality > 100:
|
|
141
|
-
raise ValueError("Invalid quality setting")
|
|
142
|
-
|
|
143
|
-
duration = info.get("duration", 0)
|
|
144
|
-
subsampling = info.get("subsampling", "4:2:0")
|
|
145
|
-
speed = info.get("speed", 6)
|
|
146
|
-
max_threads = info.get("max_threads", DEFAULT_MAX_THREADS)
|
|
147
|
-
codec = info.get("codec", "auto")
|
|
148
|
-
range_ = info.get("range", "full")
|
|
149
|
-
tile_rows_log2 = info.get("tile_rows", 0)
|
|
150
|
-
tile_cols_log2 = info.get("tile_cols", 0)
|
|
151
|
-
alpha_premultiplied = bool(info.get("alpha_premultiplied", False))
|
|
152
|
-
autotiling = bool(info.get("autotiling", tile_rows_log2 == tile_cols_log2 == 0))
|
|
153
|
-
|
|
154
|
-
icc_profile = info.get("icc_profile", im.info.get("icc_profile"))
|
|
155
|
-
exif = info.get("exif", im.info.get("exif"))
|
|
156
|
-
if isinstance(exif, Image.Exif):
|
|
157
|
-
exif = exif.tobytes()
|
|
158
|
-
|
|
159
|
-
exif_orientation = 0
|
|
160
|
-
if exif:
|
|
161
|
-
exif_data = Image.Exif()
|
|
162
|
-
try:
|
|
163
|
-
exif_data.load(exif)
|
|
164
|
-
except SyntaxError:
|
|
165
|
-
pass
|
|
166
|
-
else:
|
|
167
|
-
orientation_tag = next(
|
|
168
|
-
k for k, v in ExifTags.TAGS.items() if v == "Orientation"
|
|
169
|
-
)
|
|
170
|
-
exif_orientation = exif_data.get(orientation_tag) or 0
|
|
171
|
-
|
|
172
|
-
xmp = info.get("xmp", im.info.get("xmp") or im.info.get("XML:com.adobe.xmp"))
|
|
173
|
-
|
|
174
|
-
if isinstance(xmp, text_type):
|
|
175
|
-
xmp = xmp.encode("utf-8")
|
|
176
|
-
|
|
177
|
-
advanced = info.get("advanced")
|
|
178
|
-
if isinstance(advanced, dict):
|
|
179
|
-
advanced = tuple([k, v] for (k, v) in advanced.items())
|
|
180
|
-
if advanced is not None:
|
|
181
|
-
try:
|
|
182
|
-
advanced = tuple(advanced)
|
|
183
|
-
except TypeError:
|
|
184
|
-
invalid = True
|
|
185
|
-
else:
|
|
186
|
-
invalid = all(isinstance(v, tuple) and len(v) == 2 for v in advanced)
|
|
187
|
-
if invalid:
|
|
188
|
-
raise ValueError(
|
|
189
|
-
"advanced codec options must be a dict of key-value string "
|
|
190
|
-
"pairs or a series of key-value two-tuples"
|
|
191
|
-
)
|
|
192
|
-
advanced = tuple(
|
|
193
|
-
[(str(k).encode("utf-8"), str(v).encode("utf-8")) for k, v in advanced]
|
|
194
|
-
)
|
|
195
|
-
|
|
196
|
-
# Setup the AVIF encoder
|
|
197
|
-
enc = _avif.AvifEncoder(
|
|
198
|
-
im.size[0],
|
|
199
|
-
im.size[1],
|
|
200
|
-
subsampling,
|
|
201
|
-
qmin,
|
|
202
|
-
qmax,
|
|
203
|
-
quality,
|
|
204
|
-
speed,
|
|
205
|
-
max_threads,
|
|
206
|
-
codec,
|
|
207
|
-
range_,
|
|
208
|
-
tile_rows_log2,
|
|
209
|
-
tile_cols_log2,
|
|
210
|
-
alpha_premultiplied,
|
|
211
|
-
autotiling,
|
|
212
|
-
icc_profile or b"",
|
|
213
|
-
exif or b"",
|
|
214
|
-
exif_orientation,
|
|
215
|
-
xmp or b"",
|
|
216
|
-
advanced,
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
# Add each frame
|
|
220
|
-
frame_idx = 0
|
|
221
|
-
frame_dur = 0
|
|
222
|
-
cur_idx = im.tell()
|
|
223
|
-
try:
|
|
224
|
-
for ims in [im] + append_images:
|
|
225
|
-
# Get # of frames in this image
|
|
226
|
-
nfr = getattr(ims, "n_frames", 1)
|
|
227
|
-
|
|
228
|
-
for idx in range(nfr):
|
|
229
|
-
ims.seek(idx)
|
|
230
|
-
ims.load()
|
|
231
|
-
|
|
232
|
-
# Make sure image mode is supported
|
|
233
|
-
frame = ims
|
|
234
|
-
rawmode = ims.mode
|
|
235
|
-
if ims.mode not in _VALID_AVIF_MODES:
|
|
236
|
-
alpha = (
|
|
237
|
-
"A" in ims.mode
|
|
238
|
-
or "a" in ims.mode
|
|
239
|
-
or (ims.mode == "P" and "A" in ims.im.getpalettemode())
|
|
240
|
-
)
|
|
241
|
-
rawmode = "RGBA" if alpha else "RGB"
|
|
242
|
-
frame = ims.convert(rawmode)
|
|
243
|
-
|
|
244
|
-
# Update frame duration
|
|
245
|
-
if isinstance(duration, (list, tuple)):
|
|
246
|
-
frame_dur = duration[frame_idx]
|
|
247
|
-
else:
|
|
248
|
-
frame_dur = duration
|
|
249
|
-
|
|
250
|
-
# Append the frame to the animation encoder
|
|
251
|
-
enc.add(
|
|
252
|
-
frame.tobytes("raw", rawmode),
|
|
253
|
-
frame_dur,
|
|
254
|
-
frame.size[0],
|
|
255
|
-
frame.size[1],
|
|
256
|
-
rawmode,
|
|
257
|
-
is_single_frame,
|
|
258
|
-
)
|
|
259
|
-
|
|
260
|
-
# Update frame index
|
|
261
|
-
frame_idx += 1
|
|
262
|
-
|
|
263
|
-
if not save_all:
|
|
264
|
-
break
|
|
265
|
-
|
|
266
|
-
finally:
|
|
267
|
-
im.seek(cur_idx)
|
|
268
|
-
|
|
269
|
-
# Get the final output from the encoder
|
|
270
|
-
data = enc.finish()
|
|
271
|
-
if data is None:
|
|
272
|
-
raise OSError("cannot write file as AVIF (encoder returned None)")
|
|
273
|
-
|
|
274
|
-
fp.write(data)
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
Image.register_open(AvifImageFile.format, AvifImageFile, _accept)
|
|
278
|
-
if SUPPORTED:
|
|
279
|
-
Image.register_save(AvifImageFile.format, _save)
|
|
280
|
-
Image.register_save_all(AvifImageFile.format, _save_all)
|
|
281
|
-
Image.register_extensions(AvifImageFile.format, [".avif", ".avifs"])
|
|
282
|
-
Image.register_mime(AvifImageFile.format, "image/avif")
|
|
File without changes
|
|
File without changes
|
|
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.4 → pillow-avif-plugin-1.4.6}/src/pillow_avif_plugin.egg-info/top_level.txt
RENAMED
|
File without changes
|
{pillow-avif-plugin-1.4.4 → pillow-avif-plugin-1.4.6}/src/pillow_avif_plugin.egg-info/zip-safe
RENAMED
|
File without changes
|
|
File without changes
|