(PYTHON, PILLOW) How to make RGBA image conversion to RGB faster?

Question:

I’m making fade effect by merging .png image with .jpg, but the conversion process takes too long. Is there a way how I could speed up this process?

for f in range(101):
    print(str((200 + f) /3) + "%")
    if f == 0:
        im_rgba = img1.copy()
        im_rgba.putalpha(255)
        im_rgba = im_rgba.convert('RGB')
        im_rgba.save(crnt_dir + '/frames/img201.jpg', quality=5)
    elif f > 0:
        mask_im = img1.copy()
        mask_im.putalpha(int(255 - 255 / 100 * f))
        mask_im.save('mask_rect3.png', quality=5)
        if f <= 9:
            im_rgba = img1.copy()
            im_rgba.paste(img2, (0,0), mask_im)
            im_rgba = im_rgba.convert('RGB')
            im_rgba.save(crnt_dir + '/frames/img20'+str(f)+'.jpg', quality=5)
        elif f > 9 and f <= 99:
            im_rgba = img1.copy()
            im_rgba.paste(img2, (0,0), mask_im)
            im_rgba = im_rgba.convert('RGB')
            im_rgba.save(crnt_dir + '/frames/img2'+str(f)+'.jpg', quality=5)
        elif f > 99 and f <= 999:
            im_rgba = img1.copy()
            im_rgba.paste(img2, (0,0), mask_im)
            im_rgba = im_rgba.convert('RGB')
            im_rgba.save(crnt_dir + '/frames/img'+str(200 + f)+'.jpg', quality=5)

Answers:

I’m guessing that 99% of your time is spent reading and writing images. The only way to be sure is to benchmark it, but that’s my guess. That means almost everything else you manage to improve will be negligible.

One thing you could do is eliminate the save of mask_im. I don’t know why you’d need it, and every iteration of the loop writes over the copy saved in the previous iteration. It’s easy to recreate if you need it again, so just eliminate the save and get back that wasted time.

Speaking of mask_im, you’re creating it the hard way. I don’t expect this to make a measurable difference, but here’s the easy way:

mask_im = PIL.Image.new('L', img1.size, int(255 - 255 / 100 * f))

One other observation unrelated to speed – your logic for breaking the output into different cases is over complicated and buggy. For example you’re writing two different files called img201.jpg and none called img200.jpg. Since f is explicitly in the range of 0 to 100, there’s no need to test that it’s less than 999. Just eliminate all the if statements and use the code from the last one in every case:

    im_rgba = img1.copy()
    im_rgba.paste(img2, (0,0), mask_im)
    im_rgba = im_rgba.convert('RGB')
    im_rgba.save(f'{crnt_dir}/frames/img{200 + f}.jpg', quality=5)

(I took the liberty of using an f-string to simplify the building of the file name)

Answered By: Mark Ransom