PaletteOptimiser

main.py

74:18b62cd6bdac
2015-10-10 Paul Boddie Re-expressed various things to try and help Shedskin even further. shedskin
     1 #!/usr/bin/env python     2      3 """     4 Convert and optimise images for display in an Acorn Electron MODE 1 variant     5 with four colours per line but eight colours available for selection on each     6 line.     7      8 Copyright (C) 2015 Paul Boddie <paul@boddie.org.uk>     9     10 This program is free software; you can redistribute it and/or modify it under    11 the terms of the GNU General Public License as published by the Free Software    12 Foundation; either version 3 of the License, or (at your option) any later    13 version.    14     15 This program is distributed in the hope that it will be useful, but WITHOUT ANY    16 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A    17 PARTICULAR PURPOSE.  See the GNU General Public License for more details.    18     19 You should have received a copy of the GNU General Public License along    20 with this program.  If not, see <http://www.gnu.org/licenses/>.    21 """    22     23 from optimiser import *    24 from os.path import split, splitext    25 import EXIF    26 import PIL.Image    27 import sys    28     29 def rotate_and_scale(exif, im, width, height, rotate):    30     31     """    32     Using the given 'exif' information, rotate and scale image 'im' given the    33     indicated 'width' and 'height' constraints and any explicit 'rotate'    34     indication. The returned image will be within the given 'width' and    35     'height', filling either or both, and preserve its original aspect ratio.    36     """    37     38     if rotate or exif and exif["Image Orientation"].values == [6L]:    39         im = im.rotate(270)    40     41     w, h = im.size    42     if w > h:    43         height = (width * h) / w    44     else:    45         width = (height * w) / h    46     47     return im.resize((width, height))    48     49 def test():    50     51     "Generate slices of the colour cube."    52     53     size = 64    54     for r in (0, 63, 127, 191, 255):    55         pim = PIL.Image.new("RGB", (size, size))    56         im = SimpleImage(list(pim.getdata()), pim.size)    57         test_slice(im, size, r)    58         pim.putdata(im.getdata())    59         pim.save("rgb%d.png" % r)    60     61 def test_flat(rgb):    62     63     "Generate a flat image for the colour 'rgb'."    64     65     size = 64    66     pim = PIL.Image.new("RGB", (size, size))    67     im = SimpleImage(list(pim.getdata()), pim.size)    68     test_flat_slice(im, size, rgb)    69     pim.putdata(im.getdata())    70     pim.save("rgb%02d%02d%02d.png" % rgb)    71     72 def get_float(options, flag):    73     try:    74         i = options.index(flag)    75         if i+1 < len(options) and options[i+1].isdigit():    76             return float(options[i+1])    77         else:    78             return 1.0    79     except ValueError:    80         return 0.0    81     82 # Main program.    83     84 if __name__ == "__main__":    85     86     # Test options.    87     88     if "--test" in sys.argv:    89         test()    90         sys.exit(0)    91     elif "--test-flat" in sys.argv:    92         test_flat((120, 40, 60))    93         sys.exit(0)    94     elif "--help" in sys.argv:    95         print >>sys.stderr, """\    96 Usage: %s <input filename> <output filename> [ <options> ]    97     98 Options are...    99    100 -s - Saturate the input image (can be followed by a float, default 1.0)   101 -d - Desaturate the input image (can be followed by a float, default 1.0)   102 -D - Darken the input image (can be followed by a float, default 1.0)   103 -B - Brighten the input image (can be followed by a float, default 1.0)   104    105 -r - Rotate the input image clockwise   106 -p - Generate a separate preview image   107 -h - Make the preview image with half horizontal resolution (MODE 2)   108 -v - Verify the output image (loaded if -n is given)   109 -n - Generate no output image   110 """ % split(sys.argv[0])[1]   111         sys.exit(1)   112    113     width = 320   114     height = 256   115    116     input_filename, output_filename = sys.argv[1:3]   117     basename, ext = splitext(output_filename)   118     preview_filename = "".join([basename + "_preview", ext])   119    120     options = sys.argv[3:]   121    122     # Preprocessing options that can be repeated for extra effect.   123    124     saturate = get_float(options, "-s")   125     desaturate = get_float(options, "-d")   126     darken = get_float(options, "-D")   127     brighten = get_float(options, "-B")   128    129     # General output options.   130    131     rotate = "-r" in options   132     preview = "-p" in options   133     half_resolution_preview = "-h" in options   134     verify = "-v" in options   135     no_normal_output = "-n" in options   136     make_image = not no_normal_output   137    138     # Load the input image if requested.   139    140     if make_image or preview:   141         exif = EXIF.process_file(open(input_filename))   142         pim = PIL.Image.open(input_filename).convert("RGB")   143         pim = rotate_and_scale(exif, pim, width, height, rotate)   144         im = SimpleImage(list(pim.getdata()), pim.size)   145         process_image(im, saturate, desaturate, darken, brighten)   146    147     # Generate a preview if requested.   148    149     if preview:   150         imp = preview_image(im, half_resolution_preview)   151         pimp = pim.copy()   152         pimp.putdata(imp.getdata())   153         pimp.save(preview_filename)   154    155     # Generate an output image if requested.   156    157     if make_image:   158         convert_image(im)   159         pim.putdata(im.getdata())   160         pim.save(output_filename)   161    162     # Verify the output image (which may be loaded) if requested.   163    164     if verify:   165         if no_normal_output:   166             pim = PIL.Image.open(output_filename).convert("RGB")   167             im = SimpleImage(list(pim.getdata()), pim.size)   168    169         try:   170             count_colours(im, 4)   171         except ValueError, exc:   172             y, colours = exc.args   173             print "Image %s: row %d has the following colours: %s" % (output_filename, y, "; ".join([repr(c) for c in colours]))   174    175 # vim: tabstop=4 expandtab shiftwidth=4