PaletteOptimiser

optimiser.py

98:e4db053e9a3b
2015-10-10 Paul Boddie Added tag snapshot-20151010 for changeset cd6bc22cd40b simpleimage-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 optimiserlib import *    24 from os.path import split, splitext    25 import EXIF    26 import PIL.Image    27 import sys    28     29 # Image operations.    30     31 def test():    32     33     "Generate slices of the colour cube."    34     35     size = 512    36     for r in (0, 63, 127, 191, 255):    37         im = PIL.Image.new("RGB", (size, size))    38         for g in range(0, size):    39             for b in range(0, size):    40                 value = get_value((r, (g * 256) / size, (b * 256 / size)))    41                 im.putpixel((g, b), value)    42         im.save("rgb%d.png" % r)    43     44 def test_flat(rgb):    45     46     "Generate a flat image for the colour 'rgb'."    47     48     size = 64    49     im = PIL.Image.new("RGB", (size, size))    50     for y in range(0, size):    51         for x in range(0, size):    52             im.putpixel((x, y), get_value(rgb))    53     im.save("rgb%02d%02d%02d.png" % rgb)    54     55 def rotate_and_scale(exif, im, width, height, rotate):    56     57     """    58     Using the given 'exif' information, rotate and scale image 'im' given the    59     indicated 'width' and 'height' constraints and any explicit 'rotate'    60     indication. The returned image will be within the given 'width' and    61     'height', filling either or both, and preserve its original aspect ratio.    62     """    63     64     if rotate or exif and exif["Image Orientation"].values == [6L]:    65         im = im.rotate(270)    66     67     w, h = im.size    68     if w > h:    69         height = (width * h) / w    70     else:    71         width = (height * w) / h    72     73     return im.resize((width, height))    74     75 def get_float(options, flag):    76     try:    77         i = options.index(flag)    78         if i+1 < len(options) and options[i+1].isdigit():    79             return float(options[i+1])    80         else:    81             return 1.0    82     except ValueError:    83         return 0.0    84     85 # Main program.    86     87 if __name__ == "__main__":    88     89     # Test options.    90     91     if "--test" in sys.argv:    92         test()    93         sys.exit(0)    94     elif "--test-flat" in sys.argv:    95         test_flat((120, 40, 60))    96         sys.exit(0)    97     elif "--help" in sys.argv:    98         print >>sys.stderr, """\    99 Usage: %s <input filename> <output filename> [ <options> ]   100    101 Options are...   102    103 -s - Saturate the input image (can be followed by a float, default 1.0)   104 -d - Desaturate the input image (can be followed by a float, default 1.0)   105 -D - Darken the input image (can be followed by a float, default 1.0)   106 -B - Brighten the input image (can be followed by a float, default 1.0)   107    108 -r - Rotate the input image clockwise   109 -p - Generate a separate preview image   110 -h - Make the preview image with half horizontal resolution (MODE 2)   111 -v - Verify the output image (loaded if -n is given)   112 -n - Generate no output image   113 """ % split(sys.argv[0])[1]   114         sys.exit(1)   115    116     width = 320   117     height = 256   118    119     input_filename, output_filename = sys.argv[1:3]   120     basename, ext = splitext(output_filename)   121     preview_filename = "".join([basename + "_preview", ext])   122    123     options = sys.argv[3:]   124    125     # Preprocessing options that can be repeated for extra effect.   126    127     saturate = get_float(options, "-s")   128     desaturate = get_float(options, "-d")   129     darken = get_float(options, "-D")   130     brighten = get_float(options, "-B")   131    132     # General output options.   133    134     rotate = "-r" in options   135     preview = "-p" in options   136     half_resolution_preview = "-h" in options   137     verify = "-v" in options   138     no_normal_output = "-n" in options   139     make_image = not no_normal_output   140    141     # Load the input image if requested.   142    143     if make_image or preview:   144         exif = EXIF.process_file(open(input_filename))   145         im = PIL.Image.open(input_filename).convert("RGB")   146         im = rotate_and_scale(exif, im, width, height, rotate)   147    148         sim = SimpleImage(list(im.getdata()), im.size)   149         process_image(sim, saturate, desaturate, darken, brighten)   150         im.putdata(sim.getdata())   151    152     # Generate a preview if requested.   153    154     if preview:   155         imp = im.copy()   156         sim = SimpleImage(list(im.getdata()), im.size)   157         simp = preview_image(sim, half_resolution_preview)   158         imp.putdata(simp.getdata())   159         imp.save(preview_filename)   160    161     # Generate an output image if requested.   162    163     if make_image:   164         sim = SimpleImage(list(im.getdata()), im.size)   165         convert_image(sim)   166         im.putdata(sim.getdata())   167         im.save(output_filename)   168    169     # Verify the output image (which may be loaded) if requested.   170    171     if verify:   172         if no_normal_output:   173             im = PIL.Image.open(output_filename).convert("RGB")   174    175         im = SimpleImage(list(im.getdata()), im.size)   176         result = count_colours(im, 4)   177         if result is not None:   178             y, colours = result   179             print "Image %s: row %d has the following colours: %s" % (output_filename, y, "; ".join([repr(c) for c in colours]))   180    181 # vim: tabstop=4 expandtab shiftwidth=4