I am assisting in making a wiki for an old game, and we ripped the avatar GIFs from the games shop and want to have a catalog of them. What I need to do is to crop all the borders which are identical from 3,170 GIFs and maybe make background transparent.

I haven’t used python in years, but I managed to cobble up something that almost works as a single image test, only issue is that it crops and outputs only the first frame:

from PIL import Image

if __name__ == "__main__":
    input_loc = "AvatarShopImages/80001.gif"
    output_loc = "Output/80001.gif"
    im = Image.open(input_loc)
    im = im.crop((4, 4, 94, 94))
    im.save(output_loc)

If it looks weird, it is because I copy/pasted some code and edited a lot out of it.

  • @[email protected]
    link
    fedilink
    English
    1
    edit-2
    1 year ago

    As others have suggested, ffmpeg is a great cli tool. If you aren’t comfortable with the terminal you can do it via python like this:

    import os
    import sys
    import subprocess
    
    
    def crop_media(file_name: str, w: int, h: int, x: int, y: int, new_dir: str) -> None:
        try:
            subprocess.run(f'ffmpeg -i "{file_name}" -vf "crop={w}:{h}:{x}:{y}" temp.gif -y',
                               shell=True, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
            os.rename('temp.gif', os.path.join(new_dir, file_name))
        # Print the error and continue with other gifs, remove try block if you want a complete stop
        except subprocess.CalledProcessError as e:
            print(e)
        except KeyboardInterrupt:
            print('KeyboardInterrupt, cleaning up files...')
            os.remove('temp.gif')
            sys.exit(0)
    
    
    def crop_directory(directory: str, w: int, h: int, x: int, y: int, new_dir: str) -> None:
        for root, _, files in directory:
            for file in files:
                if not file.endswith('.gif'):
                    continue
                if os.path.isfile(os.path.join(new_dir, file)):
                    print(f'{file} already exists in {new_dir}, skipping...')
                    continue
    
                file_path = os.path.normpath(os.path.join(root, file))
                crop_media(file_path, w, h, x, y, new_dir)
    
    
    if __name__ == '__main__':
        width = 0
        height = 0
        x_offset = 0
        y_offset = 0
        gif_directory = ''
        new_directory = ''
        crop_directory(gif_directory, width, height, x_offset, y_offset, new_directory)
    

    This should go through every file in the directory and subdirectories and call the ffmpeg command on each .gif. With new_directory you can set a directory to store every cropped .gif. The ffmpeg command is based on johnpiers suggestion.

    The script assumes unique filenames for each gif and should work with spaces in the filenames. If they aren’t unique, you can just remove the new_directory part, but you will then lose the original gif that you cropped.