a cli-based image converter, in python

download

source:

  from PIL import Image
  import pillow_avif
  import os
  import sys
  import threading
  import time
  
  MAX_THREADS = 25
  
  def file_convert(img_dir, file_name, convert_from, convert_to):
      tmp = Image.open(img_dir + "/" + file_name)
      tmp.save(img_dir + "/" + file_name[:-len(convert_from)] + convert_to)
      os.remove(file_name)
  
  #run in interactive mode if called without arguments
  if (len(sys.argv) == 1):
      while(True):
          #prompt for a directory path to search for images
          print("Enter the directory to search for .webp files or enter 'cwd' to use the currect directory")
          img_dir = input("Path to search: ")
          if(img_dir == "cwd" or img_dir == "CWD"):
              img_dir = os.getcwd()
              break
          
          #if path supplied is not valid, loop and prompt again
          img_dir = os.path.expanduser(img_dir)
          if(not os.path.isdir(img_dir)):
              print("'" + img_dir + "' is not a valid directory.")
  
          else:
              break
  
      img_from = ".webp"
      img_to = ".png"
  
  #arguments are supplied, don't prompt for input
  else:
      img_dir = sys.argv[1]
      img_dir = os.path.expanduser(img_dir)
      #check if first argument is a valid file path or an indicator to use the current directory
      if(img_dir == "cwd" or img_dir == "CWD"):
              img_dir = os.getcwd()
      elif(not os.path.isdir(img_dir)):
              print("'" + img_dir + "' is not a valid directory.")
              sys.exit()
  
      if(len(sys.argv) == 4):
          img_from = sys.argv[2]
          img_to = sys.argv[3]
      else:
          img_from = ".webp"
          img_to = ".png"
  
      
  #cd into supplied directory
  os.chdir(img_dir)
  dir_contents = os.listdir(img_dir)
  dir_files = []
  
  #compile list of files in folder
  for x in dir_contents:
      if (os.path.isfile(x)):
          dir_files.append(x)
  
  #display files in folder to user to confirm directory is correct
  print("\nFiles in " + img_dir + ":")
  for x in dir_files:
      print(" > " + x)
  
  #if in interactive mode, prompt for confirmation
  if(len(sys.argv) == 1):
      confirm = input("\nConvert all .webp to .png? (y/n):\n")
  else:
      confirm = "y"
  
  #convert files from webp to png and list progress
  if (confirm in ["y", "Y"]):
      queue = []
      threads = []
      print("Queuing files for conversion")
      for x in dir_files:
          if (x[-len(img_from):] == img_from):
              print("Queued: " + x)
              queue.append(x)
      
      conversions = len(queue)
      iterations = 0
      start = time.perf_counter()
  
      while(len(queue) > 0):
          threads = threading.enumerate()
  
          #removing this print statement adds ~15 seconds to execution time
          #why? who the fuck knows
          print("Waiting for queued threads to finish", end="\r")
  
          # MAX_THREADS + 1 because threading.enumerate returns all threads including the main thread (this one)
          if(len(threads) < MAX_THREADS + 1):
              tmp = threading.Thread(target=file_convert, args=(img_dir, queue.pop(), img_from, img_to))
              tmp.start()
              threads.append(tmp)
  
      end = time.perf_counter()
  
      print(f"Converted {conversions} images in {(end - start):.2f} seconds.")
  
  
  #if user does not confirm, exit
  else:
      print("No operations performed. Exiting...")