PaletteOptimiser

Changeset

104:abb04ac9cf8d
2015-10-11 Paul Boddie raw files shortlog changelog graph Combined the preview and conversion functions, added configuration of the number of chosen colours and the output image width. Fixed option descriptions.
optimiser.py (file)
     1.1 --- a/optimiser.py	Sat Oct 10 23:54:55 2015 +0200
     1.2 +++ b/optimiser.py	Sun Oct 11 15:19:18 2015 +0200
     1.3 @@ -294,26 +294,7 @@
     1.4                      rgb = amplify_rgb(rgb, brighten and 0.5 / brighten or 2 * darken)
     1.5                  im.putpixel((x, y), rgb)
     1.6  
     1.7 -def preview_image(im, half_resolution_preview=False):
     1.8 -
     1.9 -    "Return a preview copy of image 'im'."
    1.10 -
    1.11 -    width, height = im.size
    1.12 -
    1.13 -    imp = im.copy()
    1.14 -    step = half_resolution_preview and 2 or 1
    1.15 -
    1.16 -    for y in range(0, height):
    1.17 -        for x in range(0, width, step):
    1.18 -            rgb = imp.getpixel((x, y))
    1.19 -            value = get_value(rgb)
    1.20 -            imp.putpixel((x, y), value)
    1.21 -            if half_resolution_preview:
    1.22 -                imp.putpixel((x+1, y), value)
    1.23 -
    1.24 -    return imp
    1.25 -
    1.26 -def convert_image(im):
    1.27 +def convert_image(im, colours):
    1.28  
    1.29      "Convert image 'im' to an appropriate output representation."
    1.30  
    1.31 @@ -322,7 +303,7 @@
    1.32      for y in range(0, height):
    1.33          c = get_colours(im, y)
    1.34  
    1.35 -        for l in get_combinations(c, 4):
    1.36 +        for l in get_combinations(c, colours):
    1.37              most = [value for f, value in l]
    1.38              for x in range(0, width):
    1.39                  rgb = im.getpixel((x, y))
    1.40 @@ -332,7 +313,7 @@
    1.41              else:
    1.42                  break # use this combination
    1.43          else:
    1.44 -            most = [value for f, value in c[:4]] # use the first four
    1.45 +            most = [value for f, value in c[:colours]] # use the first colours
    1.46  
    1.47          for x in range(0, width):
    1.48              rgb = im.getpixel((x, y))
    1.49 @@ -357,15 +338,23 @@
    1.50                      )
    1.51                  im.putpixel((x, y+1), rgbn)
    1.52  
    1.53 -def get_float(options, flag):
    1.54 +def get_parameter(options, flag, conversion, default, missing):
    1.55 +
    1.56 +    """
    1.57 +    From 'options', return any parameter following the given 'flag', applying
    1.58 +    the 'conversion' which has the given 'default' if no valid parameter is
    1.59 +    found, or returning the given 'missing' value if the flag does not appear at
    1.60 +    all.
    1.61 +    """
    1.62 +
    1.63      try:
    1.64          i = options.index(flag)
    1.65          try:
    1.66 -            return float(options[i+1])
    1.67 +            return conversion(options[i+1])
    1.68          except (IndexError, ValueError):
    1.69 -            return 1.0
    1.70 +            return default
    1.71      except ValueError:
    1.72 -        return 0.0
    1.73 +        return missing
    1.74  
    1.75  # Main program.
    1.76  
    1.77 @@ -385,10 +374,13 @@
    1.78  
    1.79  Options are...
    1.80  
    1.81 --s - Saturate the input image (can be followed by a float, default 1.0)
    1.82 --d - Desaturate the input image (can be followed by a float, default 1.0)
    1.83 --D - Darken the input image (can be followed by a float, default 1.0)
    1.84 --B - Brighten the input image (can be followed by a float, default 1.0)
    1.85 +-W - Indicate the output width (default is 320)
    1.86 +-C - Number of colours per scanline (default is 4)
    1.87 +
    1.88 +-s - Saturate the input image (optional float, 1.0 if unspecified)
    1.89 +-d - Desaturate the input image (optional float, 1.0 if unspecified)
    1.90 +-D - Darken the input image (optional float, 1.0 if unspecified)
    1.91 +-B - Brighten the input image (optional float, 1.0 if unspecified)
    1.92  
    1.93  -r - Rotate the input image clockwise
    1.94  -p - Generate a separate preview image
    1.95 @@ -398,7 +390,7 @@
    1.96  """ % split(sys.argv[0])[1]
    1.97          sys.exit(1)
    1.98  
    1.99 -    width = 320
   1.100 +    base_width = 320
   1.101      height = 256
   1.102  
   1.103      input_filename, output_filename = sys.argv[1:3]
   1.104 @@ -407,12 +399,17 @@
   1.105  
   1.106      options = sys.argv[3:]
   1.107  
   1.108 -    # Preprocessing options that can be repeated for extra effect.
   1.109 +    # Basic image properties.
   1.110 +
   1.111 +    width = get_parameter(options, "-W", int, base_width, base_width)
   1.112 +    number_of_colours = get_parameter(options, "-C", int, 4, 4)
   1.113  
   1.114 -    saturate = get_float(options, "-s")
   1.115 -    desaturate = get_float(options, "-d")
   1.116 -    darken = get_float(options, "-D")
   1.117 -    brighten = get_float(options, "-B")
   1.118 +    # Preprocessing options that employ parameters.
   1.119 +
   1.120 +    saturate = get_parameter(options, "-s", float, 1.0, 0.0)
   1.121 +    desaturate = get_parameter(options, "-d", float, 1.0, 0.0)
   1.122 +    darken = get_parameter(options, "-D", float, 1.0, 0.0)
   1.123 +    brighten = get_parameter(options, "-B", float, 1.0, 0.0)
   1.124  
   1.125      # General output options.
   1.126  
   1.127 @@ -428,19 +425,30 @@
   1.128      if make_image or preview:
   1.129          exif = EXIF.process_file(open(input_filename))
   1.130          im = PIL.Image.open(input_filename).convert("RGB")
   1.131 -        im = rotate_and_scale(exif, im, width, height, rotate)
   1.132 +        im = rotate_and_scale(exif, im, base_width, height, rotate)
   1.133 +
   1.134 +        # Scale images to the appropriate width.
   1.135 +
   1.136 +        if width != base_width:
   1.137 +            im = im.resize((width, height))
   1.138  
   1.139          process_image(im, saturate, desaturate, darken, brighten)
   1.140  
   1.141      # Generate a preview if requested.
   1.142  
   1.143      if preview:
   1.144 -        preview_image(im, half_resolution_preview).save(preview_filename)
   1.145 +        imp = im.copy()
   1.146 +        if half_resolution_preview:
   1.147 +            imp = imp.resize((width / 2, height))
   1.148 +        convert_image(imp, 8)
   1.149 +        if half_resolution_preview:
   1.150 +            imp = imp.resize((width, height))
   1.151 +        imp.save(preview_filename)
   1.152  
   1.153      # Generate an output image if requested.
   1.154  
   1.155      if make_image:
   1.156 -        convert_image(im)
   1.157 +        convert_image(im, number_of_colours)
   1.158          im.save(output_filename)
   1.159  
   1.160      # Verify the output image (which may be loaded) if requested.
   1.161 @@ -449,7 +457,7 @@
   1.162          if no_normal_output:
   1.163              im = PIL.Image.open(output_filename).convert("RGB")
   1.164  
   1.165 -        result = count_colours(im, 4)
   1.166 +        result = count_colours(im, number_of_colours)
   1.167          if result is not None:
   1.168              y, colours = result
   1.169              print "Image %s: row %d has the following colours: %s" % (output_filename, y, "; ".join([repr(c) for c in colours]))