1ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#! /usr/bin/env python
2ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh"""Test script for the imageop module.  This has the side
4ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh   effect of partially testing the imgfile module as well.
5ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh   Roger E. Masse
6ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh"""
7ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
8ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom test.test_support import verbose, unlink, import_module, run_unittest
9ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
10ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimageop = import_module('imageop', deprecated=True)
11ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport uu, os, unittest
12ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
13ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
14ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehSIZES = (1, 2, 3, 4)
15ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh_VALUES = (1, 2, 2**10, 2**15-1, 2**15, 2**15+1, 2**31-2, 2**31-1)
16ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehVALUES = tuple( -x for x in reversed(_VALUES) ) + (0,) + _VALUES
17ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehAAAAA = "A" * 1024
18ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehMAX_LEN = 2**20
19ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
20ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
21ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass InputValidationTests(unittest.TestCase):
22ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
23ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def _check(self, name, size=None, *extra):
24ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        func = getattr(imageop, name)
25ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for height in VALUES:
26ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for width in VALUES:
27ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                strlen = abs(width * height)
28ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if size:
29ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    strlen *= size
30ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if strlen < MAX_LEN:
31ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    data = "A" * strlen
32ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                else:
33ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    data = AAAAA
34ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if size:
35ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    arguments = (data, size, width, height) + extra
36ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                else:
37ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    arguments = (data, width, height) + extra
38ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                try:
39ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    func(*arguments)
40ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                except (ValueError, imageop.error):
41ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    pass
42ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
43ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def check_size(self, name, *extra):
44ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for size in SIZES:
45ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self._check(name, size, *extra)
46ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
47ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def check(self, name, *extra):
48ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self._check(name, None, *extra)
49ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
50ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_input_validation(self):
51ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.check_size("crop", 0, 0, 0, 0)
52ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.check_size("scale", 1, 0)
53ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.check_size("scale", -1, -1)
54ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.check_size("tovideo")
55ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.check("grey2mono", 128)
56ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.check("grey2grey4")
57ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.check("grey2grey2")
58ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.check("dither2mono")
59ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.check("dither2grey2")
60ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.check("mono2grey", 0, 0)
61ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.check("grey22grey")
62ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.check("rgb2rgb8") # nlen*4 == len
63ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.check("rgb82rgb")
64ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.check("rgb2grey")
65ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.check("grey2rgb")
66ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
67ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
68ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef test_main():
69ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
70ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    run_unittest(InputValidationTests)
71ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
72ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    try:
73ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        import imgfile
74ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    except ImportError:
75ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return
76ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
77ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Create binary test files
78ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    uu.decode(get_qualified_path('testrgb'+os.extsep+'uue'), 'test'+os.extsep+'rgb')
79ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
80ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    image, width, height = getimage('test'+os.extsep+'rgb')
81ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
82ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Return the selected part of image, which should by width by height
83ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # in size and consist of pixels of psize bytes.
84ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if verbose:
85ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print 'crop'
86ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    newimage = imageop.crop (image, 4, width, height, 0, 0, 1, 1)
87ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
88ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Return image scaled to size newwidth by newheight. No interpolation
89ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # is done, scaling is done by simple-minded pixel duplication or removal.
90ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Therefore, computer-generated images or dithered images will
91ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # not look nice after scaling.
92ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if verbose:
93ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print 'scale'
94ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    scaleimage = imageop.scale(image, 4, width, height, 1, 1)
95ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
96ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Run a vertical low-pass filter over an image. It does so by computing
97ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # each destination pixel as the average of two vertically-aligned source
98ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # pixels. The main use of this routine is to forestall excessive flicker
99ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # if the image two vertically-aligned source pixels,  hence the name.
100ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if verbose:
101ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print 'tovideo'
102ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    videoimage = imageop.tovideo (image, 4, width, height)
103ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
104ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Convert an rgb image to an 8 bit rgb
105ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if verbose:
106ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print 'rgb2rgb8'
107ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    greyimage = imageop.rgb2rgb8(image, width, height)
108ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
109ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Convert an 8 bit rgb image to a 24 bit rgb image
110ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if verbose:
111ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print 'rgb82rgb'
112ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    image = imageop.rgb82rgb(greyimage, width, height)
113ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
114ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Convert an rgb image to an 8 bit greyscale image
115ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if verbose:
116ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print 'rgb2grey'
117ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    greyimage = imageop.rgb2grey(image, width, height)
118ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
119ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Convert an 8 bit greyscale image to a 24 bit rgb image
120ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if verbose:
121ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print 'grey2rgb'
122ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    image = imageop.grey2rgb(greyimage, width, height)
123ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
124ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Convert a 8-bit deep greyscale image to a 1-bit deep image by
125ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # thresholding all the pixels. The resulting image is tightly packed
126ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # and is probably only useful as an argument to mono2grey.
127ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if verbose:
128ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print 'grey2mono'
129ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    monoimage = imageop.grey2mono (greyimage, width, height, 0)
130ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
131ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # monoimage, width, height = getimage('monotest.rgb')
132ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Convert a 1-bit monochrome image to an 8 bit greyscale or color image.
133ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # All pixels that are zero-valued on input get value p0 on output and
134ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # all one-value input pixels get value p1 on output. To convert a
135ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # monochrome  black-and-white image to greyscale pass the values 0 and
136ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # 255 respectively.
137ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if verbose:
138ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print 'mono2grey'
139ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    greyimage = imageop.mono2grey (monoimage, width, height, 0, 255)
140ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
141ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Convert an 8-bit greyscale image to a 1-bit monochrome image using a
142ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # (simple-minded) dithering algorithm.
143ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if verbose:
144ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print 'dither2mono'
145ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    monoimage = imageop.dither2mono (greyimage, width, height)
146ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
147ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Convert an 8-bit greyscale image to a 4-bit greyscale image without
148ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # dithering.
149ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if verbose:
150ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print 'grey2grey4'
151ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    grey4image = imageop.grey2grey4 (greyimage, width, height)
152ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
153ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Convert an 8-bit greyscale image to a 2-bit greyscale image without
154ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # dithering.
155ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if verbose:
156ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print 'grey2grey2'
157ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    grey2image = imageop.grey2grey2 (greyimage, width, height)
158ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
159ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Convert an 8-bit greyscale image to a 2-bit greyscale image with
160ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # dithering. As for dither2mono, the dithering algorithm is currently
161ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # very simple.
162ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if verbose:
163ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print 'dither2grey2'
164ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    grey2image = imageop.dither2grey2 (greyimage, width, height)
165ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
166ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Convert a 4-bit greyscale image to an 8-bit greyscale image.
167ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if verbose:
168ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print 'grey42grey'
169ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    greyimage = imageop.grey42grey (grey4image, width, height)
170ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
171ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Convert a 2-bit greyscale image to an 8-bit greyscale image.
172ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if verbose:
173ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print 'grey22grey'
174ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    image = imageop.grey22grey (grey2image, width, height)
175ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
176ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Cleanup
177ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    unlink('test'+os.extsep+'rgb')
178ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
179ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef getimage(name):
180ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """return a tuple consisting of
181ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh       image (in 'imgfile' format) width and height
182ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """
183ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    import imgfile
184ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    try:
185ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        sizes = imgfile.getsizes(name)
186ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    except imgfile.error:
187ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        name = get_qualified_path(name)
188ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        sizes = imgfile.getsizes(name)
189ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if verbose:
190ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print 'imgfile opening test image: %s, sizes: %s' % (name, str(sizes))
191ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
192ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    image = imgfile.read(name)
193ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    return (image, sizes[0], sizes[1])
194ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
195ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef get_qualified_path(name):
196ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """ return a more qualified path to name"""
197ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    import sys
198ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    import os
199ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    path = sys.path
200ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    try:
201ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        path = [os.path.dirname(__file__)] + path
202ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    except NameError:
203ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        pass
204ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    for dir in path:
205ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        fullname = os.path.join(dir, name)
206ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if os.path.exists(fullname):
207ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return fullname
208ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    return name
209ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
210ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehif __name__ == '__main__':
211ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    test_main()
212