diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index a12de82e2c0..7bb846b2a3e 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -200,12 +200,16 @@ attributes before loading the file:: ICNS ^^^^ -Pillow reads and (macOS only) writes macOS ``.icns`` files. By default, the +Pillow reads and writes macOS ``.icns`` files. By default, the largest available icon is read, though you can override this by setting the :py:attr:`~PIL.Image.Image.size` property before calling :py:meth:`~PIL.Image.Image.load`. The :py:meth:`~PIL.Image.Image.open` method sets the following :py:attr:`~PIL.Image.Image.info` property: +.. note:: + + Prior to version 7.2.0, Pillow could only write ICNS files on macOS. + **sizes** A list of supported sizes found in this icon file; these are a 3-tuple, ``(width, height, scale)``, where ``scale`` is 2 for a retina diff --git a/src/PIL/IcnsImagePlugin.py b/src/PIL/IcnsImagePlugin.py index 660de2b9250..cf9b5dcf5e8 100644 --- a/src/PIL/IcnsImagePlugin.py +++ b/src/PIL/IcnsImagePlugin.py @@ -300,13 +300,12 @@ def load(self): self.load_end() -def to_int(s): +def _to_int(s): b = s.encode("ascii") return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3] -MAGIC = to_int("icns") -HEADER_SIZE = 8 +MAGIC = _to_int("icns") TOC = "TOC " @@ -326,32 +325,34 @@ def _save(im, fp, filename): file_size = 0 entries = [] provided_images = {im.width: im for im in im.encoderinfo.get("append_images", [])} - for index, s in enumerate(sizes): - temp = io.BytesIO() + temp_sizes = {s: io.BytesIO() for s in set(sizes)} + for s, temp in temp_sizes.items(): nb = provided_images[s] if s in provided_images else im.resize((s, s)) nb.save(temp, "png") + for index, s in enumerate(sizes): + temp = temp_sizes[s] file_size += len(temp.getvalue()) entries.append( {"type": size_str[index], "size": len(temp.getvalue()), "stream": temp} ) # Header - fp.write(struct.pack("i", MAGIC)[::-1]) - fp.write(struct.pack("i", file_size)[::-1]) + fp.write(struct.pack("