mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-08-09 06:44:45 +03:00
ICNS save
This commit is contained in:
parent
d46441b789
commit
2d53be5a47
|
@ -17,7 +17,17 @@
|
|||
|
||||
from PIL import Image, ImageFile, PngImagePlugin, _binary
|
||||
import io
|
||||
import sys
|
||||
import os
|
||||
import struct
|
||||
import tempfile
|
||||
import subprocess
|
||||
import shutil
|
||||
|
||||
try:
|
||||
import warnings
|
||||
except ImportError:
|
||||
warnings = None
|
||||
|
||||
enable_jpeg2k = hasattr(Image.core, 'jp2klib_version')
|
||||
if enable_jpeg2k:
|
||||
|
@ -28,6 +38,49 @@ i8 = _binary.i8
|
|||
HEADERSIZE = 8
|
||||
|
||||
|
||||
def _save(im, fp, filename):
|
||||
if sys.platform == 'darwin':
|
||||
tmp_icons_dir = tempfile.mkdtemp(suffix='.iconset')
|
||||
tmp_targe_handle, tmp_targe_path = tempfile.mkstemp(suffix='.icns')
|
||||
tmp_targe_file = None
|
||||
os.close(tmp_targe_handle)
|
||||
try:
|
||||
sizes = im.encoderinfo.get("sizes",
|
||||
[(16, 16, 1), (16, 16, 2),
|
||||
(32, 32, 1), (32, 32, 2),
|
||||
(128, 128, 1), (128, 128, 2),
|
||||
(256, 256, 1), (256, 256, 2),
|
||||
(512, 512, 1), (512, 512, 2)])
|
||||
for size in sizes:
|
||||
width, height, scale = size
|
||||
size_name = '%sx%s%s' % (width, height,
|
||||
'' if scale == 1 else
|
||||
('@%sx' % scale))
|
||||
if im.size[0] < width*scale or im.size[1] < height*scale:
|
||||
if warnings:
|
||||
warnings.warn(('Skip %s because original image ' +
|
||||
'size(%sx%s) is too small') %
|
||||
(size_name, im.size[0], im.size[1]))
|
||||
continue
|
||||
png_path = os.path.join(tmp_icons_dir,
|
||||
'icon_%s.png' % size_name)
|
||||
with open(png_path, 'wb') as png_file:
|
||||
tmp = im.copy()
|
||||
tmp.thumbnail((width*scale, height*scale), Image.LANCZOS)
|
||||
tmp.save(png_file, "png")
|
||||
subprocess.call(['iconutil', '--convert', 'icns', '--output',
|
||||
tmp_targe_path, tmp_icons_dir])
|
||||
with open(tmp_targe_path, 'rb') as tmp_targe_file:
|
||||
fp.write(tmp_targe_file.read())
|
||||
finally:
|
||||
if tmp_targe_file:
|
||||
tmp_targe_file.close()
|
||||
os.remove(tmp_targe_path)
|
||||
shutil.rmtree(tmp_icons_dir)
|
||||
else:
|
||||
raise RuntimeError("Unsupported in non-darwin platform")
|
||||
|
||||
|
||||
def nextheader(fobj):
|
||||
return struct.unpack('>4sI', fobj.read(HEADERSIZE))
|
||||
|
||||
|
@ -294,8 +347,10 @@ class IcnsImageFile(ImageFile.ImageFile):
|
|||
self.load_end()
|
||||
|
||||
Image.register_open("ICNS", IcnsImageFile, lambda x: x[:4] == b'icns')
|
||||
Image.register_save("ICNS", _save)
|
||||
Image.register_extension("ICNS", '.icns')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import os
|
||||
import sys
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from helper import unittest, PillowTestCase, hopper
|
||||
|
||||
import io
|
||||
from PIL import Image
|
||||
|
||||
# sample icon file
|
||||
|
@ -67,6 +68,27 @@ class TestFileIcns(PillowTestCase):
|
|||
self.assertEqual(im2.mode, 'RGBA')
|
||||
self.assertEqual(im2.size, (wr, hr))
|
||||
|
||||
def test_save_to_bytes(self):
|
||||
output = io.BytesIO()
|
||||
im = hopper()
|
||||
sizes = [(16, 16, 1), (16, 16, 2),
|
||||
(32, 32, 1), (32, 32, 2),
|
||||
(128, 128, 1)]
|
||||
im.save(output, "icns", sizes=sizes)
|
||||
output.seek(0)
|
||||
reloaded = Image.open(output)
|
||||
self.assertEqual(reloaded.mode, "RGBA")
|
||||
self.assertEqual(reloaded.format, "ICNS")
|
||||
self.assertEqual(set(reloaded.info['sizes']), set(sizes))
|
||||
for w, h, r in reloaded.info['sizes']:
|
||||
wr = w * r
|
||||
hr = h * r
|
||||
im2 = Image.open(file)
|
||||
im2.size = (w, h, r)
|
||||
im2.load()
|
||||
self.assertEqual(im2.mode, 'RGBA')
|
||||
self.assertEqual(im2.size, (wr, hr))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
Loading…
Reference in New Issue
Block a user