Search code examples
pythonpython-imaging-library

Python Pillow: Make gradient for transparency


I have code which add gradient on image.

def st(path, gradient_magnitude=2.):
    im = Image.open(path)
    if im.mode != 'RGBA':
        im = im.convert('RGBA')
    width, height = im.size
    gradient = Image.new('L', (width, 1), color=0xFF)
    for x in range(width):
        gradient.putpixel((x, 0), int(255 * (1 - gradient_magnitude * float(x) / width)))
    alpha = gradient.resize(im.size)
    black_im = Image.new('RGBA', (width, height), color=0x000000)
    black_im.putalpha(alpha)
    gradient_im = Image.alpha_composite(im, black_im)
    gradient_im.save('out.jpg', 'JPEG')

After run I get this image enter image description here

How can I make gradient more transparency?


Solution

  • Try this. Initial opacity values of 0.9 or 0.95 should give you what you want. I also restructured the code a bit.

    from PIL import Image
    
    def apply_black_gradient(path_in, path_out='out.png',
                             gradient=1., initial_opacity=1.):
        """
        Applies a black gradient to the image, going from left to right.
    
        Arguments:
        ---------
            path_in: string
                path to image to apply gradient to
            path_out: string (default 'out.png')
                path to save result to
            gradient: float (default 1.)
                gradient of the gradient; should be non-negative;
                if gradient = 0., the image is black;
                if gradient = 1., the gradient smoothly varies over the full width;
                if gradient > 1., the gradient terminates before the end of the width;
            initial_opacity: float (default 1.)
                scales the initial opacity of the gradient (i.e. on the far left of the image);
                should be between 0. and 1.; values between 0.9-1. give good results
        """
    
        # get image to operate on
        input_im = Image.open(path_in)
        if input_im.mode != 'RGBA':
            input_im = input_im.convert('RGBA')
        width, height = input_im.size
    
        # create a gradient that
        # starts at full opacity * initial_value
        # decrements opacity by gradient * x / width
        alpha_gradient = Image.new('L', (width, 1), color=0xFF)
        for x in range(width):
            a = int((initial_opacity * 255.) * (1. - gradient * float(x)/width))
            if a > 0:
                alpha_gradient.putpixel((x, 0), a)
            else:
                alpha_gradient.putpixel((x, 0), 0)
            # print '{}, {:.2f}, {}'.format(x, float(x) / width, a)
        alpha = alpha_gradient.resize(input_im.size)
    
        # create black image, apply gradient
        black_im = Image.new('RGBA', (width, height), color=0) # i.e. black
        black_im.putalpha(alpha)
    
        # make composite with original image
        output_im = Image.alpha_composite(input_im, black_im)
        output_im.save(path_out, 'PNG')
    
        return