From 689f28aae7c9cc3fddb73e7ec2a07f169b91d4ba Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 12 Apr 2015 12:58:46 +1000 Subject: [PATCH] Added icns save --- PIL/IcnsImagePlugin.py | 51 ++++++++++++++++++++++++++++++++++++++--- Tests/test_file_icns.py | 18 ++++++++++++++- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/PIL/IcnsImagePlugin.py b/PIL/IcnsImagePlugin.py index e88b84985..26735cc95 100644 --- a/PIL/IcnsImagePlugin.py +++ b/PIL/IcnsImagePlugin.py @@ -18,6 +18,7 @@ from PIL import Image, ImageFile, PngImagePlugin, _binary import io import struct +import tempfile, shutil, os, sys enable_jpeg2k = hasattr(Image.core, 'jp2klib_version') if enable_jpeg2k: @@ -293,12 +294,56 @@ class IcnsImageFile(ImageFile.ImageFile): self.tile = () self.load_end() +def _save(im, fp, filename): + try: + fp.flush() + except: + pass + + # create the temporary set of pngs + iconset = tempfile.mkdtemp('.iconset') + last_w = None + last_im = None + for w in [16,32,128,256,512]: + prefix = 'icon_{}x{}'.format(w,w) + + if last_w == w: + im_scaled = last_im + else: + im_scaled = im.resize((w,w), Image.LANCZOS) + im_scaled.save(os.path.join(iconset, prefix+'.png')) + + im_scaled = im.resize((w*2,w*2), Image.LANCZOS) + im_scaled.save(os.path.join(iconset, prefix+'@2x.png')) + last_im = im_scaled + + # iconutil -c icns -o {} {} + from subprocess import Popen, PIPE, CalledProcessError + + convert_cmd = ["iconutil","-c","icns","-o",filename,iconset] + stderr = tempfile.TemporaryFile() + convert_proc = Popen(convert_cmd, stdout=PIPE, stderr=stderr) + + convert_proc.stdout.close() + + retcode = convert_proc.wait() + + # remove the temporary files + shutil.rmtree(iconset) + + if retcode: + raise CalledProcessError(retcode, convert_cmd) + Image.register_open("ICNS", IcnsImageFile, lambda x: x[:4] == b'icns') Image.register_extension("ICNS", '.icns') +if sys.platform == 'darwin': + Image.register_save("ICNS", _save) + + Image.register_mime("ICNS", "image/icns") + + if __name__ == '__main__': - import os - import sys imf = IcnsImageFile(open(sys.argv[1], 'rb')) for size in imf.info['sizes']: imf.size = size @@ -308,4 +353,4 @@ if __name__ == '__main__': im = Image.open(open(sys.argv[1], "rb")) im.save("out.png") if sys.platform == 'windows': - os.startfile("out.png") + os.startfile("out.png") \ No newline at end of file diff --git a/Tests/test_file_icns.py b/Tests/test_file_icns.py index 99f6da9e3..ddbed3cd2 100644 --- a/Tests/test_file_icns.py +++ b/Tests/test_file_icns.py @@ -2,6 +2,8 @@ from helper import unittest, PillowTestCase from PIL import Image +import sys + # sample icon file file = "Tests/images/pillow.icns" data = open(file, "rb").read() @@ -20,6 +22,20 @@ class TestFileIcns(PillowTestCase): self.assertEqual(im.size, (1024, 1024)) self.assertEqual(im.format, "ICNS") + @unittest.skipIf(sys.platform != 'darwin', + "requires MacOS") + def test_save(self): + im = Image.open(file) + + test_file = self.tempfile("temp.icns") + im.save(test_file) + + reread = Image.open(test_file) + + self.assertEqual(reread.mode, "RGBA") + self.assertEqual(reread.size, (1024, 1024)) + self.assertEqual(reread.format, "ICNS") + def test_sizes(self): # Check that we can load all of the sizes, and that the final pixel # dimensions are as expected @@ -71,4 +87,4 @@ class TestFileIcns(PillowTestCase): if __name__ == '__main__': unittest.main() -# End of file +# End of file \ No newline at end of file