mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-11 20:27:06 +03:00
Save in icns format to support all operating systems.
This commit is contained in:
parent
8c9100e267
commit
b685c18e95
|
@ -6,11 +6,13 @@
|
||||||
#
|
#
|
||||||
# history:
|
# history:
|
||||||
# 2004-10-09 fl Turned into a PIL plugin; removed 2.3 dependencies.
|
# 2004-10-09 fl Turned into a PIL plugin; removed 2.3 dependencies.
|
||||||
|
# 2020-04-04 Save in icns format to support all operating systems.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2004 by Bob Ippolito.
|
# Copyright (c) 2004 by Bob Ippolito.
|
||||||
# Copyright (c) 2004 by Secret Labs.
|
# Copyright (c) 2004 by Secret Labs.
|
||||||
# Copyright (c) 2004 by Fredrik Lundh.
|
# Copyright (c) 2004 by Fredrik Lundh.
|
||||||
# Copyright (c) 2014 by Alastair Houghton.
|
# Copyright (c) 2014 by Alastair Houghton.
|
||||||
|
# Copyright (c) 2020 by Pan Jing.
|
||||||
#
|
#
|
||||||
# See the README file for information on usage and redistribution.
|
# See the README file for information on usage and redistribution.
|
||||||
#
|
#
|
||||||
|
@ -130,7 +132,6 @@ def read_png_or_jpeg2000(fobj, start_length, size):
|
||||||
|
|
||||||
|
|
||||||
class IcnsFile:
|
class IcnsFile:
|
||||||
|
|
||||||
SIZES = {
|
SIZES = {
|
||||||
(512, 512, 2): [(b"ic10", read_png_or_jpeg2000)],
|
(512, 512, 2): [(b"ic10", read_png_or_jpeg2000)],
|
||||||
(512, 512, 1): [(b"ic09", read_png_or_jpeg2000)],
|
(512, 512, 1): [(b"ic09", read_png_or_jpeg2000)],
|
||||||
|
@ -302,65 +303,71 @@ class IcnsImageFile(ImageFile.ImageFile):
|
||||||
self.load_end()
|
self.load_end()
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
TOC = 'TOC '
|
||||||
|
|
||||||
|
|
||||||
def _save(im, fp, filename):
|
def _save(im, fp, filename):
|
||||||
"""
|
"""
|
||||||
Saves the image as a series of PNG files,
|
Saves the image as a series of PNG files,
|
||||||
that are then converted to a .icns file
|
that are then converted to a .icns file
|
||||||
using the macOS command line utility 'iconutil'.
|
|
||||||
|
|
||||||
macOS only.
|
Support for arbitrary systems
|
||||||
"""
|
"""
|
||||||
if hasattr(fp, "flush"):
|
if hasattr(fp, "flush"):
|
||||||
fp.flush()
|
fp.flush()
|
||||||
|
|
||||||
# create the temporary set of pngs
|
# size
|
||||||
with tempfile.TemporaryDirectory(".iconset") as iconset:
|
sizes = [128, 256, 512, 32, 64, 256, 512, 1024]
|
||||||
provided_images = {
|
size_str = ['ic07', 'ic08', 'ic09', 'ic11', 'ic12', 'ic13', 'ic14', 'ic10']
|
||||||
im.width: im for im in im.encoderinfo.get("append_images", [])
|
file_size = 0
|
||||||
}
|
entries = []
|
||||||
last_w = None
|
for index, s in enumerate(sizes):
|
||||||
second_path = None
|
temp = io.BytesIO()
|
||||||
for w in [16, 32, 128, 256, 512]:
|
nb = im.resize((s, s))
|
||||||
prefix = "icon_{}x{}".format(w, w)
|
nb.save(temp, 'png')
|
||||||
|
file_size += len(temp.getvalue())
|
||||||
|
entries.append({
|
||||||
|
'type': size_str[index],
|
||||||
|
'size': len(temp.getvalue()),
|
||||||
|
'stream': temp
|
||||||
|
})
|
||||||
|
|
||||||
first_path = os.path.join(iconset, prefix + ".png")
|
# Header
|
||||||
if last_w == w:
|
fp.write(struct.pack('i', MAGIC)[::-1])
|
||||||
shutil.copyfile(second_path, first_path)
|
fp.write(struct.pack('i', file_size)[::-1])
|
||||||
else:
|
|
||||||
im_w = provided_images.get(w, im.resize((w, w), Image.LANCZOS))
|
|
||||||
im_w.save(first_path)
|
|
||||||
|
|
||||||
second_path = os.path.join(iconset, prefix + "@2x.png")
|
# TOC
|
||||||
im_w2 = provided_images.get(w * 2, im.resize((w * 2, w * 2), Image.LANCZOS))
|
toc_size = HEADER_SIZE + (len(entries) * HEADER_SIZE)
|
||||||
im_w2.save(second_path)
|
fp.write(struct.pack('i', to_int(TOC))[::-1])
|
||||||
last_w = w * 2
|
fp.write(struct.pack('i', toc_size)[::-1])
|
||||||
|
for e in entries:
|
||||||
|
fp.write(struct.pack('i', to_int(e.get('type')))[::-1])
|
||||||
|
fp.write(struct.pack('i', HEADER_SIZE + e.get('size'))[::-1])
|
||||||
|
|
||||||
# iconutil -c icns -o {} {}
|
# Data
|
||||||
|
for index, e in enumerate(entries):
|
||||||
|
fp.write(struct.pack('i', to_int(e.get('type')))[::-1])
|
||||||
|
fp.write(struct.pack('i', HEADER_SIZE + e.get('size'))[::-1])
|
||||||
|
fp.write(e.get('stream').getvalue())
|
||||||
|
|
||||||
convert_cmd = ["iconutil", "-c", "icns", "-o", filename, iconset]
|
fp.flush()
|
||||||
convert_proc = subprocess.Popen(
|
|
||||||
convert_cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL
|
|
||||||
)
|
|
||||||
|
|
||||||
convert_proc.stdout.close()
|
|
||||||
|
|
||||||
retcode = convert_proc.wait()
|
|
||||||
|
|
||||||
if retcode:
|
|
||||||
raise subprocess.CalledProcessError(retcode, convert_cmd)
|
|
||||||
|
|
||||||
|
|
||||||
Image.register_open(IcnsImageFile.format, IcnsImageFile, lambda x: x[:4] == b"icns")
|
Image.register_open(IcnsImageFile.format, IcnsImageFile, lambda x: x[:4] == b"icns")
|
||||||
Image.register_extension(IcnsImageFile.format, ".icns")
|
Image.register_extension(IcnsImageFile.format, ".icns")
|
||||||
|
|
||||||
if sys.platform == "darwin":
|
# if sys.platform == "darwin":
|
||||||
Image.register_save(IcnsImageFile.format, _save)
|
Image.register_save(IcnsImageFile.format, _save)
|
||||||
|
Image.register_mime(IcnsImageFile.format, "image/icns")
|
||||||
Image.register_mime(IcnsImageFile.format, "image/icns")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
print("Syntax: python IcnsImagePlugin.py [file]")
|
print("Syntax: python IcnsImagePlugin.py [file]")
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user