Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Saving a PNG file is slow #1211

Closed
bouncehead13 opened this issue May 4, 2015 · 8 comments
Closed

Saving a PNG file is slow #1211

bouncehead13 opened this issue May 4, 2015 · 8 comments

Comments

@bouncehead13
Copy link

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

@hugovk
Copy link
Member

hugovk commented May 4, 2015

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

@bouncehead13
Copy link
Author

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)
     ....

@homm
Copy link
Member

homm commented May 4, 2015

@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

@bouncehead13
Copy link
Author

@homm I did not know compress_level was an available option. What is default compression level?

@homm
Copy link
Member

homm commented May 4, 2015

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.

@hugovk
Copy link
Member

hugovk commented May 4, 2015

@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

@homm
Copy link
Member

homm commented May 4, 2015

@hugovk black and while is still only two colors and far from arbitrary image color distribution :)

@bouncehead13
Copy link
Author

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants