#! /usr/bin/env python3

"""
make-ico.py

LICENSE: This program is put into the public domain by James Stroud, 2008.
"""

import sys
import os
import base64

win16map = """\
UDYKMTYgMQoyNTUKAAAAgAAAAP//AP8AwMDAAICA/wD//wAAgICAAACAgACA//////8AAIAAgIAA
AAD/
"""

def err(msg):
  sys.stderr.write("%s\n" % msg)

def usage(err_msg=None):
  if err_msg is not None:
    err("\n** ERROR **: %s\n" % err_msg)
  progname = os.path.basename(sys.argv[0])
  err("usage: python %s imagefile\n" % progname)
  sys.exit()


def main():
  try:
    png_file = sys.argv[1]
  except IndexError:
    usage('No image file given.')

  if not os.path.exists(png_file):
    usage('The image file given (%s) does not exist.' % png_file)

  png_base, extension = os.path.basename(png_file).rsplit('.', 1)


  to_delete = []

  sizes = [48, 32, 24, 16]
  depths = [4, 8, 24]

  # these commands are redundant at this point
  # however, if this is generalized, this will need to be done
  # to ensure the final .ico file is created correctly
  sizes.sort(reverse=True)
  depths.sort()

  to_map = {}
  for size in sizes:
    name_args = (png_base, size, size)
    resized_base = "%s-%02dx%02d" % name_args
    resized_name = "%s.png" % resized_base
    resize_args = (png_file, size, size, resized_name)
    command = 'convert %s -resize %dx%d %s' % resize_args
    err(command)
    os.system(command)
    to_map[size] = resized_base
    to_delete.append(resized_name)

  ico_parts = []
  for depth in depths:
    for size in sizes:
      resized_base = to_map[size]
      resized_name = "%s.png" % resized_base
      redepthed_base = "%s-%02d" % (resized_base, depth)
      redepthed_name = "%s.pnm" % redepthed_base
      # ppmtowinicon only supports palettes of up to 256 colors, so always
      # convert at 8 bits per channel regardless of the nominal icon depth.
      redepth_args = (resized_name, redepthed_name)
      if depth >= 8:
        command = "convert -depth 8 %s %s" % redepth_args
      else:
        command = "convert %s %s" % (resized_name, redepthed_name)
      err(command)
      os.system(command)
      to_delete.append(redepthed_name)
      map_base = "%s-%02d" % (resized_base, depth)
      map_name = "%s.pam" % map_base
      if depth >= 8:
        colors = 256
        map_args = (colors, redepthed_name, map_name)
        command = "pnmcolormap %d %s > %s" % map_args
        err(command)
        os.system(command)
      else:
        # for the < 8 bit images, we don't need to calculate the map
        open(map_name, 'wb').write(base64.decodebytes(win16map.encode('ascii')))
      to_delete.append(map_name)
      remapped_base = map_base
      remapped_name = "%s.ppm" % remapped_base
      remap_args = (map_name, redepthed_name, remapped_name)
      command = "pnmremap -mapfile=%s -fs %s > %s" % remap_args
      err(command)
      os.system(command)
      to_delete.append(remapped_name)
      ico_parts.append(remapped_name)


  icon_names = " ".join(ico_parts)
  icon_name = "%s.ico" % png_base
  icon_args = (icon_names, icon_name)

  command = 'ppmtowinicon %s --output %s' % icon_args
  err(command)
  os.system(command)

  err("rm %s" % " ".join(to_delete))
  for p in to_delete:
    os.remove(p)

if __name__ == "__main__":
  main()
