PaletteOptimiser

Changeset

50:6adea19bfcc2
2015-10-06 Paul Boddie raw files shortlog changelog graph Added options for verifying the number of colours per row, half-resolution previews, not producing an output image. Fixed EXIF object usage (which used a nasty global variable). Simplified the get_colours function signature.
optimiser.py (file)
     1.1 --- a/optimiser.py	Tue Oct 06 17:33:36 2015 +0200
     1.2 +++ b/optimiser.py	Tue Oct 06 22:22:52 2015 +0200
     1.3 @@ -116,7 +116,8 @@
     1.4  def amplify_value(x, exp):
     1.5      return int(pow(x / 255.0, exp) * 255.0)
     1.6  
     1.7 -def get_colours(im, width, y):
     1.8 +def get_colours(im, y):
     1.9 +    width, height = im.size
    1.10      c = {}
    1.11      for x in range(0, width):
    1.12          rgb = im.getpixel((x, y))
    1.13 @@ -151,8 +152,8 @@
    1.14              im.putpixel((x, y), get_value(rgb))
    1.15      im.save("rgb%02d%02d%02d.png" % rgb)
    1.16  
    1.17 -def rotate_and_scale(im, width, height, rotate):
    1.18 -    if rotate or x and x["Image Orientation"].values == [6L]:
    1.19 +def rotate_and_scale(exif, im, width, height, rotate):
    1.20 +    if rotate or exif and exif["Image Orientation"].values == [6L]:
    1.21          im = im.rotate(270)
    1.22  
    1.23      w, h = im.size
    1.24 @@ -163,6 +164,16 @@
    1.25  
    1.26      return im.resize((width, height))
    1.27  
    1.28 +def count_colours(im, colours):
    1.29 +    width, height = im.size
    1.30 +    for y in range(0, height):
    1.31 +        l = set()
    1.32 +        for x in range(0, width):
    1.33 +            l.add(im.getpixel((x, y)))
    1.34 +        if len(l) > colours:
    1.35 +            return (y, l)
    1.36 +    return None
    1.37 +
    1.38  if __name__ == "__main__":
    1.39      if "--test" in sys.argv:
    1.40          test()
    1.41 @@ -178,57 +189,78 @@
    1.42      basename, ext = splitext(output_filename)
    1.43      preview_filename = "".join([basename + "_preview", ext])
    1.44  
    1.45 -    rotate = "-r" in sys.argv[3:]
    1.46 -    saturate = sys.argv[3:].count("-s")
    1.47 -    desaturate = sys.argv[3:].count("-d")
    1.48 -    darken = sys.argv[3:].count("-D")
    1.49 -    brighten = sys.argv[3:].count("-B")
    1.50 -    preview = "-p" in sys.argv[3:]
    1.51 -    square = "-2" in sys.argv[3:] and square or (lambda x: x)
    1.52 +    options = sys.argv[3:]
    1.53  
    1.54 -    x = EXIF.process_file(open(input_filename))
    1.55 -    im = PIL.Image.open(input_filename).convert("RGB")
    1.56 -    im = rotate_and_scale(im, width, height, rotate)
    1.57 +    rotate = "-r" in options
    1.58 +    saturate = options.count("-s")
    1.59 +    desaturate = options.count("-d")
    1.60 +    darken = options.count("-D")
    1.61 +    brighten = options.count("-B")
    1.62 +    square = "-2" in options and square or (lambda x: x)
    1.63 +    preview = "-p" in options
    1.64 +    half_resolution_preview = "-h" in options
    1.65 +    verify = "-v" in options
    1.66 +    no_normal_output = "-n" in options
    1.67 +    make_image = not no_normal_output
    1.68  
    1.69 -    width, height = im.size
    1.70 +    if make_image or preview:
    1.71 +        exif = EXIF.process_file(open(input_filename))
    1.72 +        im = PIL.Image.open(input_filename).convert("RGB")
    1.73 +        im = rotate_and_scale(exif, im, width, height, rotate)
    1.74 +
    1.75 +        width, height = im.size
    1.76  
    1.77 -    if saturate or desaturate or darken or brighten:
    1.78 -        for y in range(0, height):
    1.79 -            for x in range(0, width):
    1.80 -                if saturate or desaturate:
    1.81 -                    rgb = im.getpixel((x, y))
    1.82 -                    rgb = saturate_rgb(rgb, saturate and math.pow(0.5, saturate) or math.pow(2, desaturate))
    1.83 -                    im.putpixel((x, y), rgb)
    1.84 +        if saturate or desaturate or darken or brighten:
    1.85 +            for y in range(0, height):
    1.86 +                for x in range(0, width):
    1.87 +                    if saturate or desaturate:
    1.88 +                        rgb = im.getpixel((x, y))
    1.89 +                        rgb = saturate_rgb(rgb, saturate and math.pow(0.5, saturate) or math.pow(2, desaturate))
    1.90 +                        im.putpixel((x, y), rgb)
    1.91  
    1.92 -                if darken or brighten:
    1.93 -                    rgb = im.getpixel((x, y))
    1.94 -                    rgb = amplify_rgb(rgb, brighten and math.pow(0.5, brighten) or math.pow(2, darken))
    1.95 -                    im.putpixel((x, y), rgb)
    1.96 +                    if darken or brighten:
    1.97 +                        rgb = im.getpixel((x, y))
    1.98 +                        rgb = amplify_rgb(rgb, brighten and math.pow(0.5, brighten) or math.pow(2, darken))
    1.99 +                        im.putpixel((x, y), rgb)
   1.100  
   1.101      if preview:
   1.102          imp = im.copy()
   1.103 +        step = half_resolution_preview and 2 or 1
   1.104          for y in range(0, height):
   1.105 -            for x in range(0, width):
   1.106 +            for x in range(0, width, step):
   1.107                  rgb = imp.getpixel((x, y))
   1.108                  value = get_value(rgb)
   1.109                  imp.putpixel((x, y), value)
   1.110 +                if half_resolution_preview:
   1.111 +                    imp.putpixel((x+1, y), value)
   1.112 +
   1.113          imp.save(preview_filename)
   1.114  
   1.115 -    for y in range(0, height):
   1.116 -        c = get_colours(im, width, y)
   1.117 -        most = [value for n, value in c[:4]]
   1.118 -        least = [value for n, value in c[4:]]
   1.119 +    if make_image:
   1.120 +        for y in range(0, height):
   1.121 +            c = get_colours(im, y)
   1.122 +            most = [value for n, value in c[:4]]
   1.123 +            least = [value for n, value in c[4:]]
   1.124 +
   1.125 +            for x in range(0, width):
   1.126 +                rgb = im.getpixel((x, y))
   1.127 +                value = get_value(rgb, most)
   1.128 +                im.putpixel((x, y), value)
   1.129  
   1.130 -        for x in range(0, width):
   1.131 -            rgb = im.getpixel((x, y))
   1.132 -            value = get_value(rgb, most)
   1.133 -            im.putpixel((x, y), value)
   1.134 +                if y < height - 1:
   1.135 +                    rgbn = im.getpixel((x, y+1))
   1.136 +                    rgbn = tuple(map(lambda i: clip(i[0] + i[1] - i[2]), zip(rgbn, rgb, value)))
   1.137 +                    im.putpixel((x, y+1), rgbn)
   1.138 +
   1.139 +        im.save(output_filename)
   1.140  
   1.141 -            if y < height - 1:
   1.142 -                rgbn = im.getpixel((x, y+1))
   1.143 -                rgbn = tuple(map(lambda i: clip(i[0] + i[1] - i[2]), zip(rgbn, rgb, value)))
   1.144 -                im.putpixel((x, y+1), rgbn)
   1.145 +    if verify:
   1.146 +        if no_normal_output:
   1.147 +            im = PIL.Image.open(output_filename).convert("RGB")
   1.148  
   1.149 -    im.save(output_filename)
   1.150 +        result = count_colours(im, 4)
   1.151 +        if result is not None:
   1.152 +            y, colours = result
   1.153 +            print "Row %d has the following colours: %s" % (y, "; ".join([repr(c) for c in colours]))
   1.154  
   1.155  # vim: tabstop=4 expandtab shiftwidth=4