Search code examples
python-2.7python-imaging-libraryimage-conversion

Is there a fast way to convert a image into WEBP?


In my website i'm now converting my upload images into webp, because is smaller than the other formats, the users will load my pages more faster(Also mobile user). But it's take some time to converter a medium image.

import StringIO
import time

from PIL import Image as PilImage

img = PilImage.open('222.jpg')

originalThumbStr = StringIO.StringIO()

now = time.time()
img.convert('RGBA').save(originalThumbStr, 'webp', quality=75)
print(time.time() - now)

It's take 2,8 seconds to convert this follow image:

860kbytes, 1920 x 1080

My memory is 8gb ram, with a processor with 4 cores(Intel I5), without GPU.

I'm using Pillow==5.4.1.

Is there a faster way to convert a image into WEBB more faster. 2,8s it's seems to long to wait.

enter image description here


Solution

  • If you want them done fast, use vips. So, taking your 1920x1080 image and using vips in the Terminal:

    vips webpsave autumn.jpg autumn.webp --Q 70
    

    That takes 0.3s on my MacBook Pro, i.e. it is 10x faster than the 3s your PIL implementation achieves.

    If you want lots done really fast, use GNU Parallel and vips. So, I made 100 copies of your image and converted the whole lot to WEBP in parallel like this:

    parallel vips webpsave {} {#}.webp --Q 70 ::: *jpg
    

    That took 4.9s for 100 copies of your image, i.e. it is 50x faster than the 3s your PIL implementation achieves.


    You could also use the pyvips binding - I am no expert on this but this works and takes 0.3s too:

    #!/usr/bin/env python3
    
    import pyvips
    
    # VIPS
    img = pyvips.Image.new_from_file("autumn.jpg", access='sequential')
    img.write_to_file("autumn.webp")
    

    So, my best suggestion would be to take the 2 lines of code above and use a multiprocessing pool or multithreading approach to get a whole directory of images processed. That could look like this:

    #!/usr/bin/env python3
    
    import pyvips
    from glob import glob
    from pathlib import Path
    from multiprocessing import Pool
    
    def doOne(f):
       img = pyvips.Image.new_from_file(f, access='sequential')
       webpname = Path(f).stem + ".webp"
       img.write_to_file(webpname)
    
    if __name__ == '__main__':
        files = glob("*.jpg")
        with Pool(12) as pool:
            pool.map(doOne, files)
    

    That takes 3.3s to convert 100 copies of your image into WEBP equivalents on my 12-core MacBook Pro with NVME disk.