Search code examples
pythonimagepython-imaging-library

Splitting an image in half, leaving one half transparent, keeping the same image dimensions


I have an image, I want to split it vertically. When I do this I want to maintain the same aspect ratio (1024x1024), but make the other half of each image transparent. (Imagine going into photoshop, and just deleting half of an image leaving the transparent mask.)

I used image slicer to easily slice in half vertically. Then PIL to paste a new image. I get the ValueError: images do not match, and so I was wondering if there is an easier way.

from image_slicer import slice

from PIL import Image

slice('stickfigure.png', 2)

img = Image.open("stickfigure_01_01.png")
img.show()

img2 = Image.open("stickfigure_01_02.png")
img2.show()


background = Image.open("emptycanvas.png")
foreground = Image.open("stickfigure_01_01.png")

final = Image.new("RGBA", background.size)
final = Image.alpha_composite(final, background)
final = Image.alpha_composite(final, foreground)

Emptycanvas is just a 1024x1024 blank transparent png.


Solution

  • You don't really actually want to split the image in half, since you want to retain the original dimensions. So you actually just want to make one half transparent - remember the alpha/transparency is just a layer in your image, so all you need is a new, alpha layer that is white where you want to see the original image and black where you don't.

    So, let's make a radial gradient, get its size, and make a new black alpha channel the same size. Then draw a white rectangle on the left half and push that into your image as the alpha/transparency channel:

    #!/usr/bin/env python3
    
    from PIL import Image, ImageDraw
    
    # Create radial gradient, and get its dimensions
    im = Image.radial_gradient('L')
    w, h = im.size
    im.save('DEBUG-initial.png')
    

    enter image description here

    # Create single channel alpha/transparency layer, same size, initially all black
    alpha = Image.new('L', (w,h))
    draw  = ImageDraw.Draw(alpha)
    
    # Fill left half with white
    draw.rectangle((0,0,int(w/2),h), fill='white')
    alpha.save('DEBUG-alpha.png')
    

    enter image description here

    # Push that alpha layer into gradient image
    im.putalpha(alpha)
    im.save('result.png')
    

    enter image description here


    Note that as you didn't supply any representative image, I don't know whether your image already had some transparency, and if it did, this simple method will replace it throughout the image. If that is the case, you should extract the existing transparency from the image and draw onto that, rather than assuming you can replace the transparency wholesale like I did. You can use either of the following approaches:

    R,G,B,A = im.split()    
    #
    # modify A here
    #
    result = Image.merge('RGBA', (R,G,B,A))
    

    or

    alpha = im.getchannel('A')
    #
    # modify alpha here
    # 
    im.putalpha(A)
    

    Although you didn't mention it in your question, it seems you not only want to make one half transparent, but also want to move the remaining visible part to the other side!

    You need to add this near the start to copy the right half:

    # Copy right half
    rhs = im.crop((int(w/2),0,w,h))
    

    and this near the end to paste the copied right half into the left half:

    im.paste(rhs, (0,0))