0

I'm trying to convert some transparent PNGs to one animated GIF, but there is a trimming issue. Except for the first image, all other images' outermost space with only black colour are cropped and become transparent.

e.g. the red part of the PNG will be cut away in the generated GIF: example pic for trimming issue of animated GIF

Below is my code. Sorry if it is a bit messy cause I am still learning Python.

from PIL import Image
import glob

# https://stackoverflow.com/questions/46850318/transparent-background-in-gif-using-python-imageio
def gen_frame(path):
    im = Image.open(path)
    
    alpha = im.getchannel('A')

    # Convert the image into P mode but only use 255 colors in the palette out of 256
    im = im.convert('RGB').convert('P', palette=Image.Palette.ADAPTIVE, colors=255)

    # Set all pixel values below 128 to 255 , and the rest to 0
    mask = Image.eval(alpha, lambda a: 255 if a <=0 else 0)

    # Paste the color of index 255 and use alpha as a mask
    im.paste(255, mask)

    # The transparency index is 255
    im.info['transparency'] = 255

    return im

def resize4Twitter(img):
    TWITTER_MAX_WIDTH, TWITTER_MAX_HEIGHT = 1280, 1080
    if img.width < TWITTER_MAX_WIDTH and img.height < TWITTER_MAX_HEIGHT:
        return img
    elif img.width/img.height > TWITTER_MAX_WIDTH/TWITTER_MAX_HEIGHT:
        x, y = TWITTER_MAX_WIDTH, (img.height / img.width * TWITTER_MAX_WIDTH)
    else:
        x, y = (img.width / img.height * TWITTER_MAX_HEIGHT), TWITTER_MAX_HEIGHT
    return img.resize((int(x),int(y)))


### User Input

imagePath, gifName, fpsStr, forTwitter = '', '', '', ''
fps = 0

imagePath = input("Enter PNG path:")
gifName = input("Enter GIF name:")
while fps == 0:
    fpsStr = input("Enter FPS [1-50]:")
    if fpsStr.isdigit():
        if int(fpsStr) >= 1 and int(fpsStr) <= 50:
            fps = int(fpsStr)
        else:
            print("Invalid. Please enter an integer from 1 to 50.")
    else:
        print("Invalid. Please enter an integer from 1 to 50.")
while forTwitter!= "Y" and forTwitter != "N":
    forTwitter = input("Resize for Twitter? [Y/N]: ")


### filepaths

fp_in = imagePath + "\\" + gifName + "_*.png"
details = "_fps" + str(fps)
if forTwitter == "Y":
    details = details + "_twitterSize"
fp_out = imagePath + "\\" + gifName + details + ".gif"


### Process Images
# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif
# https://legacy.imagemagick.org/script/command-line-options.php?#dispose

imgpaths = sorted(glob.glob(fp_in))
imgs = []

for imgpath in imgpaths:
    img = gen_frame(imgpath)
    if forTwitter == "Y":
        img = resize4Twitter(img)
    imgs.append(img)
    print("Image loaded:\t" + imgpath)

imgs = iter(imgs) # I tried .show() here, the PNGs are still normal
dur = 1000/fps

img = next(imgs)  # extract first image from iterator
img.save(fp_out, save_all=True, append_images=imgs,
         optimize=False, duration=dur, loop=0, disposal=2) # use diposal to clear prev. frame
print("Animated GIF produced at: " + fp_out)
hlamai
  • 1
  • can you put a link to example images (2-3 frames) you trying to convert, and what is that you are getting? I can't quite undestand what the problem is from the text description. – jsbueno Oct 09 '22 at 15:30
  • Hi @jsbueno thanks for your reply! You can check the 3-frame GIF here: [link](https://imgur.com/a/Pfmuk59). All 3 frames use the same image [link](https://imgur.com/a/a9eZ05E) but just rotated a bit. You can see for frame 2&3, only the square containing orange colour remains, the black outline and light ray are gone. – hlamai Oct 11 '22 at 04:04

0 Answers0