Hello,
I wan to create a PNG file from the data with dimensions 4928x3264. It takes roughly 9 seconds to save this data to a file. I am looking into improving this time for my work. Can you give a brief explanation to why this function takes a long time to complete? Also, is the saving process multi-threaded or does it happen using a single process.
Thanks!
Matt
I just tested this code:
from PIL import Image
im = Image.open("/tmp/hopper.png")
print(im.size)
im = im.resize((4928, 3264))
print(im.size)
im.save("/tmp/out.png")
Running it:
$ time python /tmp/test.py
(128, 128)
(4928, 3264)
real 0m1.371s
user 0m0.633s
sys 0m0.091s
Profiling it shows the call to save takes 0.518 seconds:
time python -m cProfile -s time /tmp/test.py
(128, 128)
(4928, 3264)
1718 function calls (1700 primitive calls) in 0.579 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
2 0.516 0.258 0.516 0.258 {method 'encode' of 'ImagingEncoder' objects}
1 0.043 0.043 0.043 0.043 {method 'resize' of 'ImagingCore' objects}
1 0.003 0.003 0.012 0.012 Image.py:27(<module>)
1 0.001 0.001 0.002 0.002 __init__.py:4(<module>)
1 0.001 0.001 0.002 0.002 io.py:34(<module>)
1 0.001 0.001 0.002 0.002 collections.py:1(<module>)
2 0.001 0.000 0.004 0.002 Image.py:342(preinit)
1 0.001 0.001 0.003 0.003 FixTk.py:1(<module>)
1 0.001 0.001 0.579 0.579 test.py:1(<module>)
1 0.001 0.001 0.001 0.001 heapq.py:31(<module>)
1 0.001 0.001 0.001 0.001 {method 'decode' of 'ImagingDecoder' objects}
1 0.001 0.001 0.001 0.001 BmpImagePlugin.py:27(<module>)
1 0.001 0.001 0.001 0.001 ImagePalette.py:19(<module>)
1 0.000 0.000 0.000 0.000 ffiplatform.py:1(<module>)
1 0.000 0.000 0.001 0.001 PngImagePlugin.py:34(<module>)
1 0.000 0.000 0.001 0.001 JpegImagePlugin.py:35(<module>)
13 0.000 0.000 0.000 0.000 {method 'write' of 'file' objects}
2 0.000 0.000 0.003 0.002 {__import__}
18 0.000 0.000 0.000 0.000 {PIL._imaging.crc32}
1 0.000 0.000 0.001 0.001 __init__.py:1(<module>)
1 0.000 0.000 0.000 0.000 GifImagePlugin.py:27(<module>)
10 0.000 0.000 0.001 0.000 abc.py:86(__new__)
11 0.000 0.000 0.000 0.000 {built-in method __new__ of type object at 0x10dc727e8}
1 0.000 0.000 0.000 0.000 api.py:1(<module>)
1 0.000 0.000 0.518 0.518 Image.py:1622(save)
38 0.000 0.000 0.000 0.000 _weakrefset.py:36(__init__)
279 0.000 0.000 0.000 0.000 {getattr}
2 0.000 0.000 0.000 0.000 {open}
1 0.000 0.000 0.000 0.000 TiffImagePlugin.py:42(<module>)
1 0.000 0.000 0.517 0.517 ImageFile.py:453(_save)
1 0.000 0.000 0.000 0.000 TiffImagePlugin.py:228(ImageFileDirectory)
12 0.000 0.000 0.000 0.000 abc.py:148(__subclasscheck__)
1 0.000 0.000 0.000 0.000 {method 'close' of 'file' objects}
3 0.000 0.000 0.000 0.000 __init__.py:78(CFUNCTYPE)
24 0.000 0.000 0.000 0.000 {method 'read' of 'file' objects}
1 0.000 0.000 0.000 0.000 _endian.py:4(<module>)
1 0.000 0.000 0.000 0.000 ascii.py:8(<module>)
3 0.000 0.000 0.000 0.000 __init__.py:493(PYFUNCTYPE)
1 0.000 0.000 0.517 0.517 PngImagePlugin.py:634(_save)
1 0.000 0.000 0.000 0.000 PpmImagePlugin.py:18(<module>)
1 0.000 0.000 0.000 0.000 {PIL._imaging.zip_encoder}
2 0.000 0.000 0.000 0.000 sre_parse.py:388(_parse)
14 0.000 0.000 0.000 0.000 __init__.py:147(_check_size)
1 0.000 0.000 0.000 0.000 _util.py:1(<module>)
2 0.000 0.000 0.000 0.000 {_ctypes.POINTER}
1 0.000 0.000 0.044 0.044 Image.py:1528(resize)
4 0.000 0.000 0.001 0.000 PngImagePlugin.py:612(putchunk)
51 0.000 0.000 0.000 0.000 abc.py:89(<genexpr>)
1 0.000 0.000 0.000 0.000 {PIL._imaging.new}
1 0.000 0.000 0.000 0.000 ImageFile.py:30(<module>)
1 0.000 0.000 0.001 0.001 ImageFile.py:130(load)
24 0.000 0.000 0.000 0.000 _weakrefset.py:58(__iter__)
4/2 0.000 0.000 0.000 0.000 sre_compile.py:64(_compile)
1 0.000 0.000 0.000 0.000 Image.py:507(_new)
1 0.000 0.000 0.001 0.001 numbers.py:6(<module>)
12 0.000 0.000 0.000 0.000 abc.py:105(register)
1 0.000 0.000 0.000 0.000 __init__.py:349(__init__)
1 0.000 0.000 0.000 0.000 ImageColor.py:20(<module>)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:485(_open)
42 0.000 0.000 0.000 0.000 {isinstance}
1 0.000 0.000 0.000 0.000 _binary.py:14(<module>)
1 0.000 0.000 0.000 0.000 __init__.py:265(_reset_cache)
2 0.000 0.000 0.000 0.000 {method 'sort' of 'list' objects}
6/4 0.000 0.000 0.000 0.000 sre_parse.py:149(getwidth)
1 0.000 0.000 0.000 0.000 lock.py:1(<module>)
1 0.000 0.000 0.005 0.005 Image.py:2224(open)
2 0.000 0.000 0.000 0.000 re.py:230(_compile)
5 0.000 0.000 0.000 0.000 sre_compile.py:256(_optimize_charset)
92 0.000 0.000 0.000 0.000 {method 'add' of 'set' objects}
14 0.000 0.000 0.000 0.000 {_struct.pack}
1 0.000 0.000 0.000 0.000 Image.py:481(Image)
1 0.000 0.000 0.000 0.000 {PIL._imaging.zip_decoder}
4 0.000 0.000 0.000 0.000 Image.py:750(load)
12 0.000 0.000 0.000 0.000 _weakrefset.py:26(__exit__)
5 0.000 0.000 0.000 0.000 PngImagePlugin.py:135(crc)
17 0.000 0.000 0.000 0.000 sre_parse.py:191(__next)
6 0.000 0.000 0.000 0.000 PngImagePlugin.py:128(call)
1 0.000 0.000 0.000 0.000 {method 'flush' of 'file' objects}
24 0.000 0.000 0.000 0.000 _weakrefset.py:83(add)
1 0.000 0.000 0.000 0.000 {posix.uname}
18 0.000 0.000 0.000 0.000 {_struct.calcsize}
2 0.000 0.000 0.000 0.000 Image.py:495(__init__)
6 0.000 0.000 0.000 0.000 PngImagePlugin.py:103(read)
1 0.000 0.000 0.000 0.000 JpegPresets.py:67(<module>)
2 0.000 0.000 0.000 0.000 locale.py:363(normalize)
1 0.000 0.000 0.000 0.000 collections.py:26(OrderedDict)
2 0.000 0.000 0.000 0.000 sre_compile.py:567(compile)
1 0.000 0.000 0.000 0.000 __future__.py:48(<module>)
89 0.000 0.000 0.000 0.000 {method 'append' of 'list' objects}
36/24 0.000 0.000 0.000 0.000 {issubclass}
5 0.000 0.000 0.000 0.000 sre_compile.py:228(_compile_charset)
16 0.000 0.000 0.000 0.000 _weakrefset.py:70(__contains__)
7 0.000 0.000 0.000 0.000 {method 'decode' of 'str' objects}
1 0.000 0.000 0.000 0.000 posixpath.py:336(normpath)
1 0.000 0.000 0.000 0.000 __init__.py:71(search_function)
37 0.000 0.000 0.000 0.000 abc.py:15(abstractmethod)
74/72 0.000 0.000 0.000 0.000 {len}
1 0.000 0.000 0.000 0.000 locale.py:493(getdefaultlocale)
1 0.000 0.000 0.000 0.000 numbers.py:34(Complex)
2 0.000 0.000 0.000 0.000 sre_parse.py:686(parse)
12 0.000 0.000 0.000 0.000 _weakrefset.py:20(__enter__)
2 0.000 0.000 0.000 0.000 sre_compile.py:433(_compile_info)
8 0.000 0.000 0.000 0.000 {hasattr}
6 0.000 0.000 0.000 0.000 Image.py:2396(register_open)
1 0.000 0.000 0.000 0.000 numbers.py:295(Integral)
29 0.000 0.000 0.000 0.000 {method 'upper' of 'str' objects}
13 0.000 0.000 0.000 0.000 {method 'items' of 'dict' objects}
2 0.000 0.000 0.000 0.000 {posix.stat}
3 0.000 0.000 0.000 0.000 {method 'seek' of 'file' objects}
1 0.000 0.000 0.000 0.000 genericpath.py:85(_splitext)
1 0.000 0.000 0.000 0.000 {method 'encode' of 'unicode' objects}
11 0.000 0.000 0.000 0.000 _binary.py:56(i32be)
21 0.000 0.000 0.000 0.000 {_struct.unpack}
6 0.000 0.000 0.000 0.000 _binary.py:73(o32be)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:368(chunk_pHYs)
1 0.000 0.000 0.000 0.000 keyword.py:11(<module>)
12 0.000 0.000 0.000 0.000 sre_parse.py:139(__getitem__)
6 0.000 0.000 0.000 0.000 {method 'match' of '_sre.SRE_Pattern' objects}
6 0.000 0.000 0.000 0.000 {method 'split' of 'str' objects}
15 0.000 0.000 0.000 0.000 sre_parse.py:210(get)
1 0.000 0.000 0.000 0.000 api.py:30(FFI)
2 0.000 0.000 0.000 0.000 sre_compile.py:552(_code)
1 0.000 0.000 0.000 0.000 numbers.py:169(Real)
1 0.000 0.000 0.000 0.000 ImageMode.py:17(<module>)
10 0.000 0.000 0.000 0.000 _binary.py:52(i16be)
12 0.000 0.000 0.000 0.000 Image.py:2433(register_extension)
1 0.000 0.000 0.000 0.000 posixpath.py:104(splitext)
2 0.000 0.000 0.000 0.000 sre_parse.py:310(_parse_sub)
1 0.000 0.000 0.000 0.000 ascii.py:41(getregentry)
2 0.000 0.000 0.000 0.000 genericpath.py:15(exists)
20 0.000 0.000 0.000 0.000 {method 'get' of 'dict' objects}
5 0.000 0.000 0.000 0.000 ImageFile.py:506(_safe_read)
2 0.000 0.000 0.000 0.000 posixpath.py:68(join)
1 0.000 0.000 0.000 0.000 Image.py:422(_getencoder)
1 0.000 0.000 0.000 0.000 ImageFile.py:78(__init__)
6 0.000 0.000 0.000 0.000 Image.py:2422(register_save)
12 0.000 0.000 0.000 0.000 _weakrefset.py:52(_commit_removals)
2 0.000 0.000 0.000 0.000 re.py:192(compile)
1 0.000 0.000 0.000 0.000 {method 'setimage' of 'ImagingEncoder' objects}
8 0.000 0.000 0.000 0.000 _binary.py:69(o16be)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:186(PngInfo)
4 0.000 0.000 0.000 0.000 _util.py:7(isPath)
3 0.000 0.000 0.000 0.000 {method 'pixel_access' of 'ImagingCore' objects}
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:309(chunk_IHDR)
1 0.000 0.000 0.000 0.000 io.py:69(IOBase)
2 0.000 0.000 0.001 0.000 PngImagePlugin.py:630(write)
3 0.000 0.000 0.000 0.000 Image.py:613(__getattr__)
2 0.000 0.000 0.000 0.000 {_sre.compile}
12 0.000 0.000 0.000 0.000 _weakrefset.py:16(__init__)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:554(load_read)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:361(chunk_gAMA)
1 0.000 0.000 0.000 0.000 locale.py:347(_replace_encoding)
3 0.000 0.000 0.000 0.000 UserDict.py:58(get)
1 0.000 0.000 0.000 0.000 collections.py:390(Counter)
1 0.000 0.000 0.000 0.000 codecs.py:77(__new__)
1 0.000 0.000 0.000 0.000 {_codecs.utf_8_decode}
5 0.000 0.000 0.000 0.000 {method 'find' of 'bytearray' objects}
2 0.000 0.000 0.000 0.000 sre_compile.py:428(_simple)
12 0.000 0.000 0.000 0.000 {method '__subclasses__' of 'type' objects}
1 0.000 0.000 0.000 0.000 {sorted}
7 0.000 0.000 0.000 0.000 {method 'join' of 'str' objects}
1 0.000 0.000 0.000 0.000 __init__.py:332(CDLL)
9 0.000 0.000 0.000 0.000 {min}
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:546(load_prepare)
1 0.000 0.000 0.000 0.000 Image.py:405(_getdecoder)
4 0.000 0.000 0.000 0.000 sre_compile.py:546(isstring)
2 0.000 0.000 0.000 0.000 locale.py:447(_parse_localename)
13 0.000 0.000 0.000 0.000 {method 'lower' of 'str' objects}
7 0.000 0.000 0.000 0.000 {method 'startswith' of 'str' objects}
7 0.000 0.000 0.000 0.000 __future__.py:75(__init__)
1 0.000 0.000 0.000 0.000 numbers.py:270(Rational)
2 0.000 0.000 0.000 0.000 {method 'rfind' of 'str' objects}
6 0.000 0.000 0.000 0.000 {method 'tell' of 'file' objects}
1 0.000 0.000 0.000 0.000 ImageFile.py:262(load_prepare)
1 0.000 0.000 0.000 0.000 {method 'setimage' of 'ImagingDecoder' objects}
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:580(load_end)
4 0.000 0.000 0.000 0.000 {method 'endswith' of 'str' objects}
1 0.000 0.000 0.000 0.000 locale.py:546(getlocale)
2 0.000 0.000 0.000 0.000 __init__.py:49(normalize_encoding)
2 0.000 0.000 0.000 0.000 sre_parse.py:187(__init__)
1 0.000 0.000 0.000 0.000 utf_8.py:15(decode)
4 0.000 0.000 0.000 0.000 sre_parse.py:90(__init__)
1 0.000 0.000 0.000 0.000 GifImagePlugin.py:52(GifImageFile)
5 0.000 0.000 0.000 0.000 _binary.py:17(i8)
1 0.000 0.000 0.000 0.000 ImageFile.py:284(StubImageFile)
9 0.000 0.000 0.000 0.000 sre_parse.py:147(append)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:324(chunk_IDAT)
4 0.000 0.000 0.000 0.000 sre_parse.py:204(match)
1 0.000 0.000 0.000 0.000 posixpath.py:365(abspath)
3 0.000 0.000 0.000 0.000 __init__.py:494(CFunctionType)
1 0.000 0.000 0.000 0.000 BmpImagePlugin.py:63(BmpImageFile)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:95(__init__)
2 0.000 0.000 0.000 0.000 sre_parse.py:67(__init__)
3 0.000 0.000 0.000 0.000 UserDict.py:70(__contains__)
1 0.000 0.000 0.000 0.000 {max}
1 0.000 0.000 0.000 0.000 {_locale.setlocale}
1 0.000 0.000 0.000 0.000 io.py:73(RawIOBase)
1 0.000 0.000 0.000 0.000 ImagePalette.py:24(ImagePalette)
12 0.000 0.000 0.000 0.000 {method 'remove' of 'set' objects}
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:626(__init__)
38 0.000 0.000 0.000 0.000 {_ctypes.sizeof}
1 0.000 0.000 0.000 0.000 {_ctypes.set_conversion_mode}
1 0.000 0.000 0.000 0.000 TiffImagePlugin.py:618(TiffImageFile)
1 0.000 0.000 0.000 0.000 Image.py:446(_E)
1 0.000 0.000 0.000 0.000 __init__.py:193(c_uint)
1 0.000 0.000 0.000 0.000 numbers.py:13(Number)
1 0.000 0.000 0.000 0.000 __init__.py:201(c_double)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:480(PngImageFile)
1 0.000 0.000 0.000 0.000 _util.py:22(deferred_error)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:623(_idat)
1 0.000 0.000 0.000 0.000 io.py:79(TextIOBase)
12 0.000 0.000 0.000 0.000 {method '__subclasshook__' of 'object' objects}
1 0.000 0.000 0.000 0.000 BmpImagePlugin.py:56(_accept)
1 0.000 0.000 0.000 0.000 JpegImagePlugin.py:281(JpegImageFile)
1 0.000 0.000 0.000 0.000 ascii.py:13(Codec)
1 0.000 0.000 0.000 0.000 io.py:76(BufferedIOBase)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:166(iTXt)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:121(close)
1 0.000 0.000 0.000 0.000 {_ctypes.dlopen}
2 0.000 0.000 0.000 0.000 {method 'clear' of 'dict' objects}
1 0.000 0.000 0.000 0.000 ImageFile.py:75(ImageFile)
4 0.000 0.000 0.000 0.000 {method 'translate' of 'str' objects}
1 0.000 0.000 0.000 0.000 __init__.py:197(c_float)
3 0.000 0.000 0.000 0.000 {method 'replace' of 'str' objects}
8 0.000 0.000 0.000 0.000 {ord}
1 0.000 0.000 0.000 0.000 _endian.py:49(BigEndianStructure)
1 0.000 0.000 0.000 0.000 __init__.py:205(c_longdouble)
1 0.000 0.000 0.000 0.000 __init__.py:243(c_char_p)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:263(PngStream)
1 0.000 0.000 0.000 0.000 __init__.py:180(c_ulong)
1 0.000 0.000 0.000 0.000 __init__.py:14(<module>)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:265(__init__)
1 0.000 0.000 0.000 0.000 Image.py:38(_imaging_not_installed)
1 0.000 0.000 0.000 0.000 ImageFile.py:314(Parser)
1 0.000 0.000 0.000 0.000 GifImagePlugin.py:44(_accept)
1 0.000 0.000 0.000 0.000 {method 'index' of 'str' objects}
1 0.000 0.000 0.000 0.000 {method 'cleanup' of 'ImagingDecoder' objects}
1 0.000 0.000 0.000 0.000 Image.py:1983(ImageTransformHandler)
1 0.000 0.000 0.000 0.000 {method 'copy' of 'dict' objects}
1 0.000 0.000 0.000 0.000 Image.py:1978(ImagePointHandler)
2 0.000 0.000 0.000 0.000 ImageFile.py:66(_tilesort)
1 0.000 0.000 0.000 0.000 posixpath.py:59(isabs)
1 0.000 0.000 0.000 0.000 __future__.py:74(_Feature)
1 0.000 0.000 0.000 0.000 PpmImagePlugin.py:59(PpmImageFile)
2 0.000 0.000 0.000 0.000 __init__.py:429(__init__)
1 0.000 0.000 0.000 0.000 ascii.py:34(StreamConverter)
1 0.000 0.000 0.000 0.000 Image.py:1942(_ImageCrop)
8 0.000 0.000 0.000 0.000 sre_parse.py:135(__len__)
1 0.000 0.000 0.000 0.000 __init__.py:233(c_byte)
1 0.000 0.000 0.000 0.000 _endian.py:26(_swapped_meta)
1 0.000 0.000 0.000 0.000 {method 'cleanup' of 'ImagingEncoder' objects}
1 0.000 0.000 0.000 0.000 Image.py:34(DecompressionBombWarning)
1 0.000 0.000 0.000 0.000 JpegImagePlugin.py:274(_accept)
4 0.000 0.000 0.000 0.000 Image.py:2411(register_mime)
3 0.000 0.000 0.000 0.000 __init__.py:104(CFunctionType)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:93(ChunkStream)
1 0.000 0.000 0.000 0.000 Image.py:2210(_decompression_bomb_check)
2 0.000 0.000 0.000 0.000 sre_parse.py:143(__setitem__)
1 0.000 0.000 0.000 0.000 __init__.py:428(LibraryLoader)
1 0.000 0.000 0.000 0.000 ffiplatform.py:4(VerificationError)
1 0.000 0.000 0.000 0.000 ascii.py:28(StreamWriter)
1 0.000 0.000 0.000 0.000 __init__.py:388(PyDLL)
6 0.000 0.000 0.000 0.000 {method 'pop' of 'dict' objects}
1 0.000 0.000 0.000 0.000 __init__.py:255(c_void_p)
4 0.000 0.000 0.000 0.000 sre_parse.py:266(_escape)
1 0.000 0.000 0.000 0.000 __init__.py:359(_FuncPtr)
1 0.000 0.000 0.000 0.000 __init__.py:294(c_wchar)
1 0.000 0.000 0.000 0.000 ffiplatform.py:8(VerificationMissing)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:473(_accept)
1 0.000 0.000 0.000 0.000 ascii.py:24(IncrementalDecoder)
1 0.000 0.000 0.000 0.000 __init__.py:291(c_wchar_p)
1 0.000 0.000 0.000 0.000 __init__.py:238(c_char)
1 0.000 0.000 0.000 0.000 __init__.py:260(c_bool)
1 0.000 0.000 0.000 0.000 __init__.py:172(c_ushort)
1 0.000 0.000 0.000 0.000 {method 'keys' of 'dict' objects}
1 0.000 0.000 0.000 0.000 PpmImagePlugin.py:52(_accept)
1 0.000 0.000 0.000 0.000 BmpImagePlugin.py:200(DibImageFile)
1 0.000 0.000 0.000 0.000 UserDict.py:18(__getitem__)
1 0.000 0.000 0.000 0.000 TiffImagePlugin.py:221(_accept)
1 0.000 0.000 0.000 0.000 __init__.py:176(c_long)
1 0.000 0.000 0.000 0.000 api.py:21(CDefError)
1 0.000 0.000 0.000 0.000 api.py:18(FFIError)
1 0.000 0.000 0.000 0.000 ascii.py:20(IncrementalEncoder)
1 0.000 0.000 0.000 0.000 __init__.py:168(c_short)
1 0.000 0.000 0.000 0.000 __init__.py:226(c_ubyte)
1 0.000 0.000 0.000 0.000 ImageMode.py:23(ModeDescriptor)
1 0.000 0.000 0.000 0.000 ascii.py:31(StreamReader)
1 0.000 0.000 0.000 0.000 __init__.py:189(c_int)
1 0.000 0.000 0.000 0.000 __init__.py:159(py_object)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
real 0m0.728s
user 0m0.632s
sys 0m0.091s
Running that same test on my machine, I get the same behavior. However, using an image of the original size and not being resized, the time taken increases. I should also add that in addition to the dimensions 4928x3264, the image is 20MB in size. Could multi-threading the encoding process improve this time?
time python -m cProfile -s time testDriver.py
(4928, 3264)
33042 function calls (33024 primitive calls) in 8.974 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
290 8.491 0.029 8.491 0.029 {method 'encode' of 'ImagingEncoder' objects}
1276 0.326 0.000 0.326 0.000 {method 'decode' of 'ImagingDecoder' objects}
877 0.055 0.000 0.055 0.000 {method 'write' of 'file' objects}
592 0.040 0.000 0.040 0.000 {PIL._imaging.crc32}
1 0.016 0.016 0.016 0.016 {method 'close' of 'file' objects}
3845 0.011 0.000 0.011 0.000 {method 'read' of 'file' objects}
1276 0.004 0.000 0.023 0.000 PngImagePlugin.py:416(load_read)
2 0.003 0.002 0.352 0.176 ImageFile.py:125(load)
1284 0.002 0.000 0.004 0.000 _binary.py:50(i32be)
1280 0.002 0.000 0.009 0.000 PngImagePlugin.py:88(read)
292 0.002 0.000 0.101 0.000 PngImagePlugin.py:474(putchunk)
1 0.002 0.002 8.595 8.595 ImageFile.py:435(_save)
1280 0.002 0.000 0.002 0.000 {method 'match' of '_sre.SRE_Pattern' objects}
1 0.002 0.002 0.006 0.006 Image.py:27(<module>)
1 0.001 0.001 0.002 0.002 __init__.py:4(<module>)
1 0.001 0.001 0.002 0.002 collections.py:1(<module>)
5157 0.001 0.000 0.002 0.000 _binary.py:15(i8)
....
@hugovk PNG compression time is very sensitive to input data. If you are compressing very small image (hopper.png) image resized with nearest filter (the default), it will be much faster than compressing arbitrary image without repeating colors.
In [1]: from PIL import Image
In [2]: im = Image.open('Tests/images/hopper.png').resize((4928, 3264))
In [3]: %time im.save('png.png')
CPU times: user 544 ms, sys: 8 ms, total: 552 ms
Wall time: 556 ms
In [4]: im = Image.open('Tests/images/hopper.png').resize((4928, 3264), Image.BICUBIC)
In [5]: %time im.save('png.png')
CPU times: user 3.39 s, sys: 92 ms, total: 3.48 s
Wall time: 3.49 s
@bouncehead13 PNG uses deflate algorithm for compression, which is asymmetrical (much slower compression than decompression). All you can do is reduce compression level (you can choose from 1 to 9, where 1 is lowest):
In [5]: %time im.save('png.png')
CPU times: user 3.39 s, sys: 92 ms, total: 3.48 s
Wall time: 3.49 s
In [6]: %time im.save('png.png', compress_level=1)
CPU times: user 1.3 s, sys: 132 ms, total: 1.43 s
Wall time: 1.43 s
@homm I did not know compress_level was an available option. What is default compression level?
From zlib docs:
Z_DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6).
Pillow doesn't change this level if compress_level is not specified.
@homm Ah, of course, the resized image has lots of repeated colours.
This creates an image with random black and white pixels:
from PIL import Image
size = (4928, 3264)
sigma = 128
im = Image.effect_noise(size, sigma)
print(im.size)
im.save("/tmp/out.png")
Running it creates a 15M image (compared to 120K before):
time python -m cProfile -s time /tmp/test.py
(4928, 3264)
5436 function calls (5418 primitive calls) in 2.323 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
...
1 0.000 0.000 1.218 1.218 Image.py:1622(save)
...
real 0m3.619s
user 0m1.796s
sys 0m0.154s
@hugovk black and while is still only two colors and far from arbitrary image color distribution :)
For the work I'm doing compression_level helps immensely. Knowing the default is 6, I've changed it to 3 with a loss of 0.9MB in compression. Thanks for the help, I appreciate it!
Most helpful comment
@hugovk PNG compression time is very sensitive to input data. If you are compressing very small image (hopper.png) image resized with nearest filter (the default), it will be much faster than compressing arbitrary image without repeating colors.
@bouncehead13 PNG uses deflate algorithm for compression, which is asymmetrical (much slower compression than decompression). All you can do is reduce compression level (you can choose from 1 to 9, where 1 is lowest):