Here are three ways to do this bilinear interpolation. The first version performs all arithmetic in pure Python, the second uses PIL composition of the image, the third uses Numpy to perform arithmetic. As expected, pure Python is significantly slower than other approaches. The Numpy version (which was obtained from code written by Andras Deak ) is almost as fast as the PIL version for small images, but for large images, the PIL version is noticeably faster.
I also tried using the jadsq scaling technique in PIL, but the results were not good - I suspect the PIL interpolation code is a bit buggy.
If you want to create many of these bilinear gradient images of the same size, the PIL method has another advantage: after creating composition masks, you do not need to rebuild them for each image.
#!/usr/bin/env python3 ''' Simple bilinear interpolation Written by PM 2Ring 2016.09.14 ''' from PIL import Image from math import floor import numpy as np def color_square0(colors, size): tl, tr, bl, br = colors m = size - 1 r = range(size) def interp_2D(tl, tr, bl, br, x, y): u0, v0 = x / m, y / m u1, v1 = 1 - u0, 1 - v0 return floor(0.5 + u1*v1*tl + u0*v1*tr + u1*v0*bl + u0*v0*br) data = bytes(interp_2D(tl[i], tr[i], bl[i], br[i], x, y) for y in r for x in r for i in (0, 1, 2)) return Image.frombytes('RGB', (size, size), data)
Exit

Just for fun, here is a simple GUI program using Tkinter that can be used to generate these gradients.
#!/usr/bin/env python3 ''' Simple bilinear colour interpolation using PIL, in a Tkinter GUI Inspired by https://stackoverflow.com/q/39485178/4014959 Written by PM 2Ring 2016.09.15 ''' import tkinter as tk from tkinter.colorchooser import askcolor from tkinter.filedialog import asksaveasfilename from PIL import Image, ImageTk DEFCOLOR = '#d9d9d9' SIZE = 256