PaletteOptimiser

Changeset

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