diff --git a/Tests/README.txt b/Tests/README.txt new file mode 100644 index 000000000..7622836b8 --- /dev/null +++ b/Tests/README.txt @@ -0,0 +1,4 @@ +Minimalistic PIL test framework. + +Test scripts are named "test_xxx" and are supposed to output "ok". +That's it. diff --git a/Tests/bench_get.py b/Tests/bench_get.py new file mode 100644 index 000000000..eca491600 --- /dev/null +++ b/Tests/bench_get.py @@ -0,0 +1,20 @@ +import sys +sys.path.insert(0, ".") + +import tester +import timeit + +def bench(mode): + im = tester.lena(mode) + get = im.im.getpixel + xy = 50, 50 # position shouldn't really matter + t0 = timeit.default_timer() + for i in range(1000000): + get(xy) + print(mode, timeit.default_timer() - t0, "us") + +bench("L") +bench("I") +bench("I;16") +bench("F") +bench("RGB") diff --git a/Tests/cms_test.py b/Tests/cms_test.py new file mode 100644 index 000000000..ba1c96527 --- /dev/null +++ b/Tests/cms_test.py @@ -0,0 +1,222 @@ +# PyCMSTests.py +# Examples of how to use pyCMS, as well as tests to verify it works properly +# By Kevin Cazabon (kevin@cazabon.com) + +# Imports +import os +from PIL import Image +from PIL import ImageCms + +# import PyCMSError separately so we can catch it +PyCMSError = ImageCms.PyCMSError + +####################################################################### +# Configuration: +####################################################################### +# set this to the image you want to test with +IMAGE = "c:\\temp\\test.tif" + +# set this to where you want to save the output images +OUTPUTDIR = "c:\\temp\\" + +# set these to two different ICC profiles, one for input, one for output +# set the corresponding mode to the proper PIL mode for that profile +INPUT_PROFILE = "c:\\temp\\profiles\\sRGB.icm" +INMODE = "RGB" + +OUTPUT_PROFILE = "c:\\temp\\profiles\\genericRGB.icm" +OUTMODE = "RGB" + +PROOF_PROFILE = "c:\\temp\\profiles\\monitor.icm" + +# set to True to show() images, False to save them into OUTPUT_DIRECTORY +SHOW = False + +# Tests you can enable/disable +TEST_error_catching = True +TEST_profileToProfile = True +TEST_profileToProfile_inPlace = True +TEST_buildTransform = True +TEST_buildTransformFromOpenProfiles = True +TEST_buildProofTransform = True +TEST_getProfileInfo = True +TEST_misc = False + +####################################################################### +# helper functions +####################################################################### +def outputImage(im, funcName = None): + # save or display the image, depending on value of SHOW_IMAGES + if SHOW == True: + im.show() + else: + im.save(os.path.join(OUTPUTDIR, "%s.tif" %funcName)) + + +####################################################################### +# The tests themselves +####################################################################### + +if TEST_error_catching == True: + im = Image.open(IMAGE) + try: + #neither of these proifles exists (unless you make them), so we should + # get an error + imOut = ImageCms.profileToProfile(im, "missingProfile.icm", "cmyk.icm") + + except PyCMSError as reason: + print("We caught a PyCMSError: %s\n\n" %reason) + + print("error catching test completed successfully (if you see the message \ + above that we caught the error).") + +if TEST_profileToProfile == True: + # open the image file using the standard PIL function Image.open() + im = Image.open(IMAGE) + + # send the image, input/output profiles, and rendering intent to + # ImageCms.profileToProfile() + imOut = ImageCms.profileToProfile(im, INPUT_PROFILE, OUTPUT_PROFILE, \ + outputMode = OUTMODE) + + # now that the image is converted, save or display it + outputImage(imOut, "profileToProfile") + + print("profileToProfile test completed successfully.") + +if TEST_profileToProfile_inPlace == True: + # we'll do the same test as profileToProfile, but modify im in place + # instead of getting a new image returned to us + im = Image.open(IMAGE) + + # send the image to ImageCms.profileToProfile(), specifying inPlace = True + result = ImageCms.profileToProfile(im, INPUT_PROFILE, OUTPUT_PROFILE, \ + outputMode = OUTMODE, inPlace = True) + + # now that the image is converted, save or display it + if result == None: + # this is the normal result when modifying in-place + outputImage(im, "profileToProfile_inPlace") + else: + # something failed... + print("profileToProfile in-place failed: %s" %result) + + print("profileToProfile in-place test completed successfully.") + +if TEST_buildTransform == True: + # make a transform using the input and output profile path strings + transform = ImageCms.buildTransform(INPUT_PROFILE, OUTPUT_PROFILE, INMODE, \ + OUTMODE) + + # now, use the trnsform to convert a couple images + im = Image.open(IMAGE) + + # transform im normally + im2 = ImageCms.applyTransform(im, transform) + outputImage(im2, "buildTransform") + + # then transform it again using the same transform, this time in-place. + result = ImageCms.applyTransform(im, transform, inPlace = True) + outputImage(im, "buildTransform_inPlace") + + print("buildTransform test completed successfully.") + + # and, to clean up a bit, delete the transform + # this should call the C destructor for the transform structure. + # Python should also do this automatically when it goes out of scope. + del(transform) + +if TEST_buildTransformFromOpenProfiles == True: + # we'll actually test a couple profile open/creation functions here too + + # first, get a handle to an input profile, in this case we'll create + # an sRGB profile on the fly: + inputProfile = ImageCms.createProfile("sRGB") + + # then, get a handle to the output profile + outputProfile = ImageCms.getOpenProfile(OUTPUT_PROFILE) + + # make a transform from these + transform = ImageCms.buildTransformFromOpenProfiles(inputProfile, \ + outputProfile, INMODE, OUTMODE) + + # now, use the trnsform to convert a couple images + im = Image.open(IMAGE) + + # transform im normally + im2 = ImageCms.applyTransform(im, transform) + outputImage(im2, "buildTransformFromOpenProfiles") + + # then do it again using the same transform, this time in-place. + result = ImageCms.applyTransform(im, transform, inPlace = True) + outputImage(im, "buildTransformFromOpenProfiles_inPlace") + + print("buildTransformFromOpenProfiles test completed successfully.") + + # and, to clean up a bit, delete the transform + # this should call the C destructor for the each item. + # Python should also do this automatically when it goes out of scope. + del(inputProfile) + del(outputProfile) + del(transform) + +if TEST_buildProofTransform == True: + # make a transform using the input and output and proof profile path + # strings + # images converted with this transform will simulate the appearance + # of the output device while actually being displayed/proofed on the + # proof device. This usually means a monitor, but can also mean + # other proof-printers like dye-sub, etc. + transform = ImageCms.buildProofTransform(INPUT_PROFILE, OUTPUT_PROFILE, \ + PROOF_PROFILE, INMODE, OUTMODE) + + # now, use the trnsform to convert a couple images + im = Image.open(IMAGE) + + # transform im normally + im2 = ImageCms.applyTransform(im, transform) + outputImage(im2, "buildProofTransform") + + # then transform it again using the same transform, this time in-place. + result = ImageCms.applyTransform(im, transform, inPlace = True) + outputImage(im, "buildProofTransform_inPlace") + + print("buildProofTransform test completed successfully.") + + # and, to clean up a bit, delete the transform + # this should call the C destructor for the transform structure. + # Python should also do this automatically when it goes out of scope. + del(transform) + +if TEST_getProfileInfo == True: + # get a profile handle + profile = ImageCms.getOpenProfile(INPUT_PROFILE) + + # lets print some info about our input profile: + print("Profile name (retrieved from profile string path name): %s" %ImageCms.getProfileName(INPUT_PROFILE)) + + # or, you could do the same thing using a profile handle as the arg + print("Profile name (retrieved from profile handle): %s" %ImageCms.getProfileName(profile)) + + # now lets get the embedded "info" tag contents + # once again, you can use a path to a profile, or a profile handle + print("Profile info (retrieved from profile handle): %s" %ImageCms.getProfileInfo(profile)) + + # and what's the default intent of this profile? + print("The default intent is (this will be an integer): %d" %(ImageCms.getDefaultIntent(profile))) + + # Hmmmm... but does this profile support INTENT_ABSOLUTE_COLORIMETRIC? + print("Does it support INTENT_ABSOLUTE_COLORIMETRIC?: (1 is yes, -1 is no): %s" \ + %ImageCms.isIntentSupported(profile, ImageCms.INTENT_ABSOLUTE_COLORIMETRIC, \ + ImageCms.DIRECTION_INPUT)) + + print("getProfileInfo test completed successfully.") + +if TEST_misc == True: + # test the versions, about, and copyright functions + print("Versions: %s" %str(ImageCms.versions())) + print("About:\n\n%s" %ImageCms.about()) + print("Copyright:\n\n%s" %ImageCms.copyright()) + + print("misc test completed successfully.") + diff --git a/Tests/crash_ttf_memory_error.py b/Tests/crash_ttf_memory_error.py new file mode 100644 index 000000000..881fc03a6 --- /dev/null +++ b/Tests/crash_ttf_memory_error.py @@ -0,0 +1,14 @@ +from PIL import Image, ImageFont, ImageDraw + +font = "../pil-archive/memory-error-2.ttf" + +s = "Test Text" +f = ImageFont.truetype(font, 64, index=0, encoding="unicode") +w, h = f.getsize(s) +i = Image.new("RGB", (500, h), "white") +d = ImageDraw.Draw(i) + +# this line causes a MemoryError +d.text((0,0), s, font=f, fill=0) + +i.show() diff --git a/Tests/fonts/helvO18.pcf b/Tests/fonts/helvO18.pcf new file mode 100644 index 000000000..f5e68ae9c Binary files /dev/null and b/Tests/fonts/helvO18.pcf differ diff --git a/Tests/icc/CMY.icm b/Tests/icc/CMY.icm new file mode 100644 index 000000000..acc71ddd9 Binary files /dev/null and b/Tests/icc/CMY.icm differ diff --git a/Tests/icc/YCC709.icm b/Tests/icc/YCC709.icm new file mode 100644 index 000000000..d9f5a5a5d Binary files /dev/null and b/Tests/icc/YCC709.icm differ diff --git a/Tests/icc/sRGB.icm b/Tests/icc/sRGB.icm new file mode 100644 index 000000000..7f9d18d09 Binary files /dev/null and b/Tests/icc/sRGB.icm differ diff --git a/Tests/images/broken.png b/Tests/images/broken.png new file mode 100644 index 000000000..7def38564 --- /dev/null +++ b/Tests/images/broken.png @@ -0,0 +1,5 @@ +PNG + +/}P̒>0jȂ&✉\@TLU +x/ +Z`w;9c \ No newline at end of file diff --git a/Tests/images/caption_6_33_22.png b/Tests/images/caption_6_33_22.png new file mode 100644 index 000000000..2aa0a50bf Binary files /dev/null and b/Tests/images/caption_6_33_22.png differ diff --git a/Tests/images/pil123p.png b/Tests/images/pil123p.png new file mode 100644 index 000000000..03960d493 Binary files /dev/null and b/Tests/images/pil123p.png differ diff --git a/Tests/images/pil123rgba.png b/Tests/images/pil123rgba.png new file mode 100644 index 000000000..c3d7b7d1b Binary files /dev/null and b/Tests/images/pil123rgba.png differ diff --git a/Tests/images/pil136.tiff b/Tests/images/pil136.tiff new file mode 100644 index 000000000..07d339e7c Binary files /dev/null and b/Tests/images/pil136.tiff differ diff --git a/Tests/images/pil168.tif b/Tests/images/pil168.tif new file mode 100644 index 000000000..621f03a2f Binary files /dev/null and b/Tests/images/pil168.tif differ diff --git a/Tests/images/pil184.pcx b/Tests/images/pil184.pcx new file mode 100644 index 000000000..bbd68be5c Binary files /dev/null and b/Tests/images/pil184.pcx differ diff --git a/Tests/images/pil_sample_cmyk.jpg b/Tests/images/pil_sample_cmyk.jpg new file mode 100644 index 000000000..0c11e70f2 Binary files /dev/null and b/Tests/images/pil_sample_cmyk.jpg differ diff --git a/Tests/images/pil_sample_rgb.jpg b/Tests/images/pil_sample_rgb.jpg new file mode 100644 index 000000000..956a86bae Binary files /dev/null and b/Tests/images/pil_sample_rgb.jpg differ diff --git a/Tests/images/rgb.jpg b/Tests/images/rgb.jpg new file mode 100644 index 000000000..fa9953844 Binary files /dev/null and b/Tests/images/rgb.jpg differ diff --git a/Tests/import_all.py b/Tests/import_all.py new file mode 100644 index 000000000..118bf69a7 --- /dev/null +++ b/Tests/import_all.py @@ -0,0 +1,13 @@ +import sys +sys.path.insert(0, ".") + +import glob, os +import traceback + +for file in glob.glob("PIL/*.py"): + module = os.path.basename(file)[:-3] + try: + exec("from PIL import " + module) + except (ImportError, SyntaxError): + print("===", "failed to import", module) + traceback.print_exc() diff --git a/Tests/make_hash.py b/Tests/make_hash.py new file mode 100644 index 000000000..7e1a1b2e1 --- /dev/null +++ b/Tests/make_hash.py @@ -0,0 +1,57 @@ +# brute-force search for access descriptor hash table + +import random + +modes = [ + "1", + "L", "LA", + "I", "I;16", "I;16L", "I;16B", "I;32L", "I;32B", + "F", + "P", "PA", + "RGB", "RGBA", "RGBa", "RGBX", + "CMYK", + "YCbCr", + ] + +def hash(s, i): + # djb2 hash: multiply by 33 and xor character + for c in s: + i = (((i<<5) + i) ^ ord(c)) & 0xffffffff + return i + +def check(size, i0): + h = [None] * size + for m in modes: + i = hash(m, i0) + i = i % size + if h[i]: + return 0 + h[i] = m + return h + +min_start = 0 + +# 1) find the smallest table size with no collisions +for min_size in range(len(modes), 16384): + if check(min_size, 0): + print(len(modes), "modes fit in", min_size, "slots") + break + +# 2) see if we can do better with a different initial value +for i0 in range(65556): + for size in range(1, min_size): + if check(size, i0): + if size < min_size: + print(len(modes), "modes fit in", size, "slots with start", i0) + min_size = size + min_start = i0 + +print() + +# print check(min_size, min_start) + +print("#define ACCESS_TABLE_SIZE", min_size) +print("#define ACCESS_TABLE_HASH", min_start) + +# for m in modes: +# print m, "=>", hash(m, min_start) % min_size diff --git a/Tests/run.py b/Tests/run.py new file mode 100644 index 000000000..27a7afa9f --- /dev/null +++ b/Tests/run.py @@ -0,0 +1,93 @@ +# minimal test runner + +import glob, os, sys + +try: + root = os.path.dirname(__file__) +except NameError: + root = os.path.dirname(sys.argv[0]) + +if not os.path.isfile("PIL/Image.py"): + print("***", "please run this script from the PIL development directory as") + print("***", "$ python Tests/run.py") + sys.exit(1) + +print("-"*68) + +python_options = [] +tester_options = [] + +if "--installed" not in sys.argv: + python_options.append("-S") + os.environ["PYTHONPATH"] = "." + +if "--coverage" in sys.argv: + tester_options.append("--coverage") + +if "--log" in sys.argv: + tester_options.append("--log") + +files = glob.glob(os.path.join(root, "test_*.py")) +files.sort() + +success = failure = 0 +include = [x for x in sys.argv[1:] if x[:2] != "--"] +skipped = [] + +python_options = " ".join(python_options) +tester_options = " ".join(tester_options) + +for file in files: + test, ext = os.path.splitext(os.path.basename(file)) + if include and test not in include: + continue + print("running", test, "...") + # 2>&1 works on unix and on modern windowses. we might care about + # very old Python versions, but not ancient microsoft products :-) + out = os.popen("%s %s -u %s %s 2>&1" % ( + sys.executable, python_options, file, tester_options + )) + result = out.read().strip() + if result == "ok": + result = None + elif result == "skip": + print("---", "skipped") # FIXME: driver should include a reason + skipped.append(test) + continue + elif not result: + result = "(no output)" + status = out.close() + if status or result: + if status: + print("=== error", status) + if result: + if result[-3:] == "\nok": + # if there's an ok at the end, it's not really ok + result = result[:-3] + print(result) + failure = failure + 1 + else: + success = success + 1 + +print("-"*68) + +tempfiles = glob.glob(os.path.join(root, "temp_*")) +if tempfiles: + print("===", "remaining temporary files") + for file in tempfiles: + print(file) + print("-"*68) + +def tests(n): + if n == 1: + return "1 test" + else: + return "%d tests" % n + +if skipped: + print("---", tests(len(skipped)), "skipped.") + print(skipped) +if failure: + print("***", tests(failure), "of", (success + failure), "failed.") +else: + print(tests(success), "passed.") diff --git a/Tests/show_icc.py b/Tests/show_icc.py new file mode 100644 index 000000000..e062747e7 --- /dev/null +++ b/Tests/show_icc.py @@ -0,0 +1,28 @@ +import sys +sys.path.insert(0, ".") + +from PIL import Image +from PIL import ImageCms + +try: + filename = sys.argv[1] +except IndexError: + filename = "../pil-archive/cmyk.jpg" + +i = Image.open(filename) + +print(i.format) +print(i.mode) +print(i.size) +print(i.tile) + +p = ImageCms.getMemoryProfile(i.info["icc_profile"]) + +print(repr(p.product_name)) +print(repr(p.product_info)) + +o = ImageCms.createProfile("sRGB") +t = ImageCms.buildTransformFromOpenProfiles(p, o, i.mode, "RGB") +i = ImageCms.applyTransform(i, t) + +i.show() diff --git a/Tests/show_mcidas.py b/Tests/show_mcidas.py new file mode 100644 index 000000000..db193b82a --- /dev/null +++ b/Tests/show_mcidas.py @@ -0,0 +1,26 @@ +import sys +sys.path.insert(0, ".") + +from PIL import Image +from PIL import ImageMath + +try: + filename = sys.argv[1] +except IndexError: + filename = "../pil-archive/goes12.2005.140.190925.BAND_01.mcidas" + # filename = "../pil-archive/goes12.2005.140.190925.BAND_01.im" + +im = Image.open(filename) + +print(im.format) +print(im.mode) +print(im.size) +print(im.tile) + +lo, hi = im.getextrema() + +print("map", lo, hi, "->", end=' ') +im = ImageMath.eval("convert(im*255/hi, 'L')", im=im, hi=hi) +print(im.getextrema()) + +im.show() diff --git a/Tests/test_000_sanity.py b/Tests/test_000_sanity.py new file mode 100644 index 000000000..cba99e4fe --- /dev/null +++ b/Tests/test_000_sanity.py @@ -0,0 +1,21 @@ +import PIL +import PIL.Image + +# Make sure we have the binary extension +im = PIL.Image.core.new("L", (100, 100)) + +assert PIL.Image.VERSION[:3] == '1.1' + +# Create an image and do stuff with it. +im = PIL.Image.new("1", (100, 100)) +assert (im.mode, im.size) == ('1', (100, 100)) +assert len(im.tobytes()) == 1300 + +# Create images in all remaining major modes. +im = PIL.Image.new("L", (100, 100)) +im = PIL.Image.new("P", (100, 100)) +im = PIL.Image.new("RGB", (100, 100)) +im = PIL.Image.new("I", (100, 100)) +im = PIL.Image.new("F", (100, 100)) + +print("ok") diff --git a/Tests/test_001_archive.py b/Tests/test_001_archive.py new file mode 100644 index 000000000..a914a6c4c --- /dev/null +++ b/Tests/test_001_archive.py @@ -0,0 +1,23 @@ +import PIL +import PIL.Image + +import glob, os + +for file in glob.glob("../pil-archive/*"): + f, e = os.path.splitext(file) + if e in [".txt", ".ttf", ".otf", ".zip"]: + continue + try: + im = PIL.Image.open(file) + im.load() + except IOError as v: + print("-", "failed to open", file, "-", v) + else: + print("+", file, im.mode, im.size, im.format) + if e == ".exif": + try: + info = im._getexif() + except KeyError as v: + print("-", "failed to get exif info from", file, "-", v) + +print("ok") diff --git a/Tests/test_contents.py b/Tests/test_contents.py new file mode 100644 index 000000000..0455ad89c --- /dev/null +++ b/Tests/test_contents.py @@ -0,0 +1,31 @@ +from tester import * + +import os, glob + +contents = {} +for file in open("CONTENTS"): + file = file.strip() + if file: + contents[os.path.normpath(file)] = None + +patterns = [ + "PIL/*.py", + "*.c", + "libImaging/*.c", + "libImaging/*.h", + ] + +def test_files(): + + for pattern in patterns: + for file in glob.glob(pattern): + file = os.path.normpath("Imaging/" + file) + assert_true(file in contents, "%r not in CONTENTS" % file) + +def test_contents(): + + for file in contents: + root, file = file.split(os.sep, 1) + if file == "MANIFEST": + continue # generated by distribution scripts + assert_true(os.path.isfile(file), "%r not found" % file) diff --git a/Tests/test_file_bmp.py b/Tests/test_file_bmp.py new file mode 100644 index 000000000..e0584641c --- /dev/null +++ b/Tests/test_file_bmp.py @@ -0,0 +1,27 @@ +from tester import * + +from PIL import Image + +def test_sanity(): + + file = tempfile("temp.bmp") + + lena().save(file) + + im = Image.open(file) + im.load() + assert_equal(im.mode, "RGB") + assert_equal(im.size, (128, 128)) + assert_equal(im.format, "BMP") + + lena("1").save(file) + im = Image.open(file) + + lena("L").save(file) + im = Image.open(file) + + lena("P").save(file) + im = Image.open(file) + + lena("RGB").save(file) + im = Image.open(file) diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py new file mode 100644 index 000000000..336aaba63 --- /dev/null +++ b/Tests/test_file_gif.py @@ -0,0 +1,28 @@ +from tester import * + +from PIL import Image + +codecs = dir(Image.core) + +if "gif_encoder" not in codecs or "gif_decoder" not in codecs: + skip("gif support not available") # can this happen? + +# sample gif stream +file = "Images/lena.gif" +data = open(file, "rb").read() + +def test_sanity(): + im = Image.open(file) + im.load() + assert_equal(im.mode, "P") + assert_equal(im.size, (128, 128)) + assert_equal(im.format, "GIF") + +def test_optimize(): + def test(optimize): + im = Image.new("L", (1, 1), 0) + file = BytesIO() + im.save(file, "GIF", optimize=optimize) + return len(file.getvalue()) + assert_equal(test(0), 800) + assert_equal(test(1), 32) diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py new file mode 100644 index 000000000..126c67237 --- /dev/null +++ b/Tests/test_file_jpeg.py @@ -0,0 +1,179 @@ +from tester import * + +from PIL import Image +from PIL import ImageFile + +codecs = dir(Image.core) + +if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs: + skip("jpeg support not available") + +# sample jpeg stream +file = "Images/lena.jpg" +data = open(file, "rb").read() + +def roundtrip(im, **options): + out = BytesIO() + im.save(out, "JPEG", **options) + bytes = out.tell() + out.seek(0) + im = Image.open(out) + im.bytes = bytes # for testing only + return im + +# -------------------------------------------------------------------- + +def test_sanity(): + + # internal version number + assert_match(Image.core.jpeglib_version, "\d+\.\d+$") + + im = Image.open(file) + im.load() + assert_equal(im.mode, "RGB") + assert_equal(im.size, (128, 128)) + assert_equal(im.format, "JPEG") + +# -------------------------------------------------------------------- + +def test_app(): + # Test APP/COM reader (@PIL135) + im = Image.open(file) + assert_equal(im.applist[0], + ("APP0", b"JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00")) + assert_equal(im.applist[1], ("COM", b"Python Imaging Library")) + assert_equal(len(im.applist), 2) + +def test_cmyk(): + # Test CMYK handling. Thanks to Tim and Charlie for test data, + # Michael for getting me to look one more time. + file = "Tests/images/pil_sample_cmyk.jpg" + im = Image.open(file) + # the source image has red pixels in the upper left corner. + c, m, y, k = [x / 255.0 for x in im.getpixel((0, 0))] + assert_true(c == 0.0 and m > 0.8 and y > 0.8 and k == 0.0) + # the opposite corner is black + c, m, y, k = [x / 255.0 for x in im.getpixel((im.size[0]-1, im.size[1]-1))] + assert_true(k > 0.9) + # roundtrip, and check again + im = roundtrip(im) + c, m, y, k = [x / 255.0 for x in im.getpixel((0, 0))] + assert_true(c == 0.0 and m > 0.8 and y > 0.8 and k == 0.0) + c, m, y, k = [x / 255.0 for x in im.getpixel((im.size[0]-1, im.size[1]-1))] + assert_true(k > 0.9) + +def test_dpi(): + def test(xdpi, ydpi=None): + im = Image.open(file) + im = roundtrip(im, dpi=(xdpi, ydpi or xdpi)) + return im.info.get("dpi") + assert_equal(test(72), (72, 72)) + assert_equal(test(300), (300, 300)) + assert_equal(test(100, 200), (100, 200)) + assert_equal(test(0), None) # square pixels + +def test_icc(): + # Test ICC support + im1 = Image.open("Tests/images/rgb.jpg") + icc_profile = im1.info["icc_profile"] + assert_equal(len(icc_profile), 3144) + # Roundtrip via physical file. + file = tempfile("temp.jpg") + im1.save(file, icc_profile=icc_profile) + im2 = Image.open(file) + assert_equal(im2.info.get("icc_profile"), icc_profile) + # Roundtrip via memory buffer. + im1 = roundtrip(lena()) + im2 = roundtrip(lena(), icc_profile=icc_profile) + assert_image_equal(im1, im2) + assert_false(im1.info.get("icc_profile")) + assert_true(im2.info.get("icc_profile")) + +def test_icc_big(): + # Make sure that the "extra" support handles large blocks + def test(n): + # The ICC APP marker can store 65519 bytes per marker, so + # using a 4-byte test code should allow us to detect out of + # order issues. + icc_profile = (b"Test"*int(n/4+1))[:n] + assert len(icc_profile) == n # sanity + im1 = roundtrip(lena(), icc_profile=icc_profile) + assert_equal(im1.info.get("icc_profile"), icc_profile or None) + test(0); test(1) + test(3); test(4); test(5) + test(65533-14) # full JPEG marker block + test(65533-14+1) # full block plus one byte + test(ImageFile.MAXBLOCK) # full buffer block + test(ImageFile.MAXBLOCK+1) # full buffer block plus one byte + test(ImageFile.MAXBLOCK*4+3) # large block + +def test_optimize(): + im1 = roundtrip(lena()) + im2 = roundtrip(lena(), optimize=1) + assert_image_equal(im1, im2) + assert_true(im1.bytes >= im2.bytes) + +def test_progressive(): + im1 = roundtrip(lena()) + im2 = roundtrip(lena(), progressive=1) + im3 = roundtrip(lena(), progression=1) # compatibility + assert_image_equal(im1, im2) + assert_image_equal(im1, im3) + assert_false(im1.info.get("progressive")) + assert_false(im1.info.get("progression")) + assert_true(im2.info.get("progressive")) + assert_true(im2.info.get("progression")) + assert_true(im3.info.get("progressive")) + assert_true(im3.info.get("progression")) + +def test_quality(): + im1 = roundtrip(lena()) + im2 = roundtrip(lena(), quality=50) + assert_image(im1, im2.mode, im2.size) + assert_true(im1.bytes >= im2.bytes) + +def test_smooth(): + im1 = roundtrip(lena()) + im2 = roundtrip(lena(), smooth=100) + assert_image(im1, im2.mode, im2.size) + +def test_subsampling(): + def getsampling(im): + layer = im.layer + return layer[0][1:3] + layer[1][1:3] + layer[2][1:3] + # experimental API + im = roundtrip(lena(), subsampling=-1) # default + assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1)) + im = roundtrip(lena(), subsampling=0) # 4:4:4 + assert_equal(getsampling(im), (1, 1, 1, 1, 1, 1)) + im = roundtrip(lena(), subsampling=1) # 4:2:2 + assert_equal(getsampling(im), (2, 1, 1, 1, 1, 1)) + im = roundtrip(lena(), subsampling=2) # 4:1:1 + assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1)) + im = roundtrip(lena(), subsampling=3) # default (undefined) + assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1)) + + im = roundtrip(lena(), subsampling="4:4:4") + assert_equal(getsampling(im), (1, 1, 1, 1, 1, 1)) + im = roundtrip(lena(), subsampling="4:2:2") + assert_equal(getsampling(im), (2, 1, 1, 1, 1, 1)) + im = roundtrip(lena(), subsampling="4:1:1") + assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1)) + + assert_exception(TypeError, lambda: roundtrip(lena(), subsampling="1:1:1")) + +def test_truncated_jpeg(): + def test(junk): + if junk: + # replace "junk" bytes at the end with junk + file = BytesIO(data[:-junk] + bytes(junk*[0])) + else: + file = BytesIO(data) + im = Image.open(file) + im.load() + assert_no_exception(lambda: test(0)) + assert_exception(IOError, lambda: test(1)) + assert_no_exception(lambda: test(2)) + assert_no_exception(lambda: test(4)) + assert_no_exception(lambda: test(8)) + assert_exception(IOError, lambda: test(10)) diff --git a/Tests/test_file_msp.py b/Tests/test_file_msp.py new file mode 100644 index 000000000..7ed200e43 --- /dev/null +++ b/Tests/test_file_msp.py @@ -0,0 +1,15 @@ +from tester import * + +from PIL import Image + +def test_sanity(): + + file = tempfile("temp.msp") + + lena("1").save(file) + + im = Image.open(file) + im.load() + assert_equal(im.mode, "1") + assert_equal(im.size, (128, 128)) + assert_equal(im.format, "MSP") diff --git a/Tests/test_file_pcx.py b/Tests/test_file_pcx.py new file mode 100644 index 000000000..73d358229 --- /dev/null +++ b/Tests/test_file_pcx.py @@ -0,0 +1,39 @@ +from tester import * + +from PIL import Image + +def test_sanity(): + + file = tempfile("temp.pcx") + + lena("1").save(file) + + im = Image.open(file) + im.load() + assert_equal(im.mode, "1") + assert_equal(im.size, (128, 128)) + assert_equal(im.format, "PCX") + + lena("1").save(file) + im = Image.open(file) + + lena("L").save(file) + im = Image.open(file) + + lena("P").save(file) + im = Image.open(file) + + lena("RGB").save(file) + im = Image.open(file) + +def test_pil184(): + # Check reading of files where xmin/xmax is not zero. + + file = "Tests/images/pil184.pcx" + im = Image.open(file) + + assert_equal(im.size, (447, 144)) + assert_equal(im.tile[0][1], (0, 0, 447, 144)) + + # Make sure all pixels are either 0 or 255. + assert_equal(im.histogram()[0] + im.histogram()[255], 447*144) diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py new file mode 100644 index 000000000..329598c9d --- /dev/null +++ b/Tests/test_file_png.py @@ -0,0 +1,170 @@ +from tester import * + +from PIL import Image +from PIL import PngImagePlugin + +codecs = dir(Image.core) + +if "zip_encoder" not in codecs or "zip_decoder" not in codecs: + skip("zip/deflate support not available") + +# sample png stream + +file = "Images/lena.png" +data = open(file, "rb").read() + +# stuff to create inline PNG images + +MAGIC = PngImagePlugin._MAGIC + +def chunk(cid, *data): + file = BytesIO() + PngImagePlugin.putchunk(*(file, cid) + data) + return file.getvalue() + +o32 = PngImagePlugin.o32 + +IHDR = chunk(b"IHDR", o32(1), o32(1), bytes((8,2)), bytes((0,0,0))) +IDAT = chunk(b"IDAT") +IEND = chunk(b"IEND") + +HEAD = MAGIC + IHDR +TAIL = IDAT + IEND + +def load(data): + return Image.open(BytesIO(data)) + +def roundtrip(im, **options): + out = BytesIO() + im.save(out, "PNG", **options) + out.seek(0) + return Image.open(out) + +# -------------------------------------------------------------------- + +def test_sanity(): + + # internal version number + assert_match(Image.core.zlib_version, "\d+\.\d+\.\d+(\.\d+)?$") + + file = tempfile("temp.png") + + lena("RGB").save(file) + + im = Image.open(file) + im.load() + assert_equal(im.mode, "RGB") + assert_equal(im.size, (128, 128)) + assert_equal(im.format, "PNG") + + lena("1").save(file) + im = Image.open(file) + + lena("L").save(file) + im = Image.open(file) + + lena("P").save(file) + im = Image.open(file) + + lena("RGB").save(file) + im = Image.open(file) + + lena("I").save(file) + im = Image.open(file) + +# -------------------------------------------------------------------- + +def test_broken(): + # Check reading of totally broken files. In this case, the test + # file was checked into Subversion as a text file. + + file = "Tests/images/broken.png" + assert_exception(IOError, lambda: Image.open(file)) + +def test_bad_text(): + # Make sure PIL can read malformed tEXt chunks (@PIL152) + + im = load(HEAD + chunk(b'tEXt') + TAIL) + assert_equal(im.info, {}) + + im = load(HEAD + chunk(b'tEXt', b'spam') + TAIL) + assert_equal(im.info, {b'spam': b''}) + + im = load(HEAD + chunk(b'tEXt', b'spam\0') + TAIL) + assert_equal(im.info, {b'spam': b''}) + + im = load(HEAD + chunk(b'tEXt', b'spam\0egg') + TAIL) + assert_equal(im.info, {b'spam': b'egg'}) + + im = load(HEAD + chunk(b'tEXt', b'spam\0egg\0') + TAIL) + assert_equal(im.info, {b'spam': b'egg\x00'}) + +def test_interlace(): + + file = "Tests/images/pil123p.png" + im = Image.open(file) + + assert_image(im, "P", (162, 150)) + assert_true(im.info.get("interlace")) + + assert_no_exception(lambda: im.load()) + + file = "Tests/images/pil123rgba.png" + im = Image.open(file) + + assert_image(im, "RGBA", (162, 150)) + assert_true(im.info.get("interlace")) + + assert_no_exception(lambda: im.load()) + +def test_load_verify(): + # Check open/load/verify exception (@PIL150) + + im = Image.open("Images/lena.png") + assert_no_exception(lambda: im.verify()) + + im = Image.open("Images/lena.png") + im.load() + assert_exception(RuntimeError, lambda: im.verify()) + +def test_roundtrip_dpi(): + # Check dpi roundtripping + + im = Image.open(file) + + im = roundtrip(im, dpi=(100, 100)) + assert_equal(im.info["dpi"], (100, 100)) + +def test_roundtrip_text(): + # Check text roundtripping + + im = Image.open(file) + + info = PngImagePlugin.PngInfo() + info.add_text(b"TXT", b"VALUE") + info.add_text(b"ZIP", b"VALUE", 1) + + im = roundtrip(im, pnginfo=info) + assert_equal(im.info, {b'TXT': b'VALUE', b'ZIP': b'VALUE'}) + assert_equal(im.text, {b'TXT': b'VALUE', b'ZIP': b'VALUE'}) + +def test_scary(): + # Check reading of evil PNG file. For information, see: + # http://scary.beasts.org/security/CESA-2004-001.txt + + import base64 + file = "Tests/images/pngtest_bad.png.base64" + data = base64.decodebytes(open(file, 'rb').read()) + file = BytesIO(data) + assert_exception(IOError, lambda: Image.open(file)) + +def test_trns_rgb(): + # Check writing and reading of tRNS chunks for RGB images. + # Independent file sample provided by Sebastian Spaeth. + + file = "Tests/images/caption_6_33_22.png" + im = Image.open(file) + assert_equal(im.info["transparency"], (248, 248, 248)) + + im = roundtrip(im, transparency=(0, 1, 2)) + assert_equal(im.info["transparency"], (0, 1, 2)) diff --git a/Tests/test_file_ppm.py b/Tests/test_file_ppm.py new file mode 100644 index 000000000..fccb94905 --- /dev/null +++ b/Tests/test_file_ppm.py @@ -0,0 +1,14 @@ +from tester import * + +from PIL import Image + +# sample ppm stream +file = "Images/lena.ppm" +data = open(file, "rb").read() + +def test_sanity(): + im = Image.open(file) + im.load() + assert_equal(im.mode, "RGB") + assert_equal(im.size, (128, 128)) + assert_equal(im.format, "PPM") diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py new file mode 100644 index 000000000..843e13d28 --- /dev/null +++ b/Tests/test_file_tiff.py @@ -0,0 +1,57 @@ +from tester import * + +from PIL import Image + +def test_sanity(): + + file = tempfile("temp.tif") + + lena("RGB").save(file) + + im = Image.open(file) + im.load() + assert_equal(im.mode, "RGB") + assert_equal(im.size, (128, 128)) + assert_equal(im.format, "TIFF") + + lena("1").save(file) + im = Image.open(file) + + lena("L").save(file) + im = Image.open(file) + + lena("P").save(file) + im = Image.open(file) + + lena("RGB").save(file) + im = Image.open(file) + + lena("I").save(file) + im = Image.open(file) + +def test_mac_tiff(): + # Read RGBa images from Mac OS X [@PIL136] + + file = "Tests/images/pil136.tiff" + im = Image.open(file) + + assert_equal(im.mode, "RGBA") + assert_equal(im.size, (55, 43)) + assert_equal(im.tile, [('raw', (0, 0, 55, 43), 8, ('RGBa', 0, 1))]) + assert_no_exception(lambda: im.load()) + +def test_gimp_tiff(): + # Read TIFF JPEG images from GIMP [@PIL168] + + file = "Tests/images/pil168.tif" + im = Image.open(file) + + assert_equal(im.mode, "RGB") + assert_equal(im.size, (256, 256)) + assert_equal(im.tile, [ + ('jpeg', (0, 0, 256, 64), 8, ('RGB', '')), + ('jpeg', (0, 64, 256, 128), 1215, ('RGB', '')), + ('jpeg', (0, 128, 256, 192), 2550, ('RGB', '')), + ('jpeg', (0, 192, 256, 256), 3890, ('RGB', '')), + ]) + assert_no_exception(lambda: im.load()) diff --git a/Tests/test_file_xbm.py b/Tests/test_file_xbm.py new file mode 100644 index 000000000..f27a3a349 --- /dev/null +++ b/Tests/test_file_xbm.py @@ -0,0 +1,34 @@ +from tester import * + +from PIL import Image + +PIL151 = b""" +#define basic_width 32 +#define basic_height 32 +static char basic_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x80, 0xff, 0xff, 0x01, 0x40, 0x00, 0x00, 0x02, +0x20, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x08, +0x10, 0x00, 0x00, 0x08, +0x10, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x08, +0x10, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x08, +0x20, 0x00, 0x00, 0x04, +0x20, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, 0x02, +0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +}; +""" + +def test_pil151(): + + im = Image.open(BytesIO(PIL151)) + + assert_no_exception(lambda: im.load()) + assert_equal(im.mode, '1') + assert_equal(im.size, (32, 32)) diff --git a/Tests/test_font_bdf.py b/Tests/test_font_bdf.py new file mode 100644 index 000000000..366bb4468 --- /dev/null +++ b/Tests/test_font_bdf.py @@ -0,0 +1,13 @@ +from tester import * + +from PIL import Image, FontFile, BdfFontFile + +filename = "Images/courB08.bdf" + +def test_sanity(): + + file = open(filename, "rb") + font = BdfFontFile.BdfFontFile(file) + + assert_true(isinstance(font, FontFile.FontFile)) + assert_equal(len([_f for _f in font.glyph if _f]), 190) diff --git a/Tests/test_font_pcf.py b/Tests/test_font_pcf.py new file mode 100644 index 000000000..958657eaa --- /dev/null +++ b/Tests/test_font_pcf.py @@ -0,0 +1,26 @@ +from tester import * + +from PIL import Image, FontFile, PcfFontFile +from PIL import ImageFont, ImageDraw + +fontname = "Tests/fonts/helvO18.pcf" +tempname = tempfile("temp.pil", "temp.pbm") + +message = "hello, world" + +def test_sanity(): + + file = open(fontname, "rb") + font = PcfFontFile.PcfFontFile(file) + assert_true(isinstance(font, FontFile.FontFile)) + assert_equal(len([_f for _f in font.glyph if _f]), 192) + + font.save(tempname) + +def test_draw(): + + font = ImageFont.load(tempname) + image = Image.new("L", font.getsize(message), "white") + draw = ImageDraw.Draw(image) + draw.text((0, 0), message, font=font) + # assert_signature(image, "7216c60f988dea43a46bb68321e3c1b03ec62aee") diff --git a/Tests/test_image.py b/Tests/test_image.py new file mode 100644 index 000000000..cb1de08d5 --- /dev/null +++ b/Tests/test_image.py @@ -0,0 +1,39 @@ +from tester import * + +from PIL import Image + +def test_sanity(): + + im = Image.new("L", (100, 100)) + assert_equal(repr(im)[:45], " 2**32: + assert_equal(put(sys.maxsize), (255, 255, 255, 255)) + else: + assert_equal(put(sys.maxsize), (255, 255, 255, 127)) diff --git a/Tests/test_image_putpalette.py b/Tests/test_image_putpalette.py new file mode 100644 index 000000000..b7ebb8853 --- /dev/null +++ b/Tests/test_image_putpalette.py @@ -0,0 +1,28 @@ +from tester import * + +from PIL import Image +from PIL import ImagePalette + +def test_putpalette(): + def palette(mode): + im = lena(mode).copy() + im.putpalette(list(range(256))*3) + p = im.getpalette() + if p: + return im.mode, p[:10] + return im.mode + assert_exception(ValueError, lambda: palette("1")) + assert_equal(palette("L"), ("P", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])) + assert_equal(palette("P"), ("P", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])) + assert_exception(ValueError, lambda: palette("I")) + assert_exception(ValueError, lambda: palette("F")) + assert_exception(ValueError, lambda: palette("RGB")) + assert_exception(ValueError, lambda: palette("RGBA")) + assert_exception(ValueError, lambda: palette("YCbCr")) + +def test_imagepalette(): + im = lena("P") + assert_no_exception(lambda: im.putpalette(ImagePalette.negative())) + assert_no_exception(lambda: im.putpalette(ImagePalette.random())) + assert_no_exception(lambda: im.putpalette(ImagePalette.sepia())) + assert_no_exception(lambda: im.putpalette(ImagePalette.wedge())) diff --git a/Tests/test_image_putpixel.py b/Tests/test_image_putpixel.py new file mode 100644 index 000000000..555a92f74 --- /dev/null +++ b/Tests/test_image_putpixel.py @@ -0,0 +1,43 @@ +from tester import * + +from PIL import Image + +def test_sanity(): + + im1 = lena() + im2 = Image.new(im1.mode, im1.size, 0) + + for y in range(im1.size[1]): + for x in range(im1.size[0]): + pos = x, y + im2.putpixel(pos, im1.getpixel(pos)) + + assert_image_equal(im1, im2) + + im2 = Image.new(im1.mode, im1.size, 0) + im2.readonly = 1 + + for y in range(im1.size[1]): + for x in range(im1.size[0]): + pos = x, y + im2.putpixel(pos, im1.getpixel(pos)) + + assert_false(im2.readonly) + assert_image_equal(im1, im2) + + im2 = Image.new(im1.mode, im1.size, 0) + + pix1 = im1.load() + pix2 = im2.load() + + for y in range(im1.size[1]): + for x in range(im1.size[0]): + pix2[x, y] = pix1[x, y] + + assert_image_equal(im1, im2) + + + + +# see test_image_getpixel for more tests + diff --git a/Tests/test_image_quantize.py b/Tests/test_image_quantize.py new file mode 100644 index 000000000..5dcbab7fe --- /dev/null +++ b/Tests/test_image_quantize.py @@ -0,0 +1,15 @@ +from tester import * + +from PIL import Image + +def test_sanity(): + + im = lena() + + im = im.quantize() + assert_image(im, "P", im.size) + + im = lena() + im = im.quantize(palette=lena("P")) + assert_image(im, "P", im.size) + diff --git a/Tests/test_image_resize.py b/Tests/test_image_resize.py new file mode 100644 index 000000000..4e228a396 --- /dev/null +++ b/Tests/test_image_resize.py @@ -0,0 +1,12 @@ +from tester import * + +from PIL import Image + +def test_resize(): + def resize(mode, size): + out = lena(mode).resize(size) + assert_equal(out.mode, mode) + assert_equal(out.size, size) + for mode in "1", "P", "L", "RGB", "I", "F": + yield_test(resize, mode, (100, 100)) + yield_test(resize, mode, (200, 200)) diff --git a/Tests/test_image_rotate.py b/Tests/test_image_rotate.py new file mode 100644 index 000000000..5e4782c87 --- /dev/null +++ b/Tests/test_image_rotate.py @@ -0,0 +1,15 @@ +from tester import * + +from PIL import Image + +def test_rotate(): + def rotate(mode): + im = lena(mode) + out = im.rotate(45) + assert_equal(out.mode, mode) + assert_equal(out.size, im.size) # default rotate clips output + out = im.rotate(45, expand=1) + assert_equal(out.mode, mode) + assert_true(out.size != im.size) + for mode in "1", "P", "L", "RGB", "I", "F": + yield_test(rotate, mode) diff --git a/Tests/test_image_save.py b/Tests/test_image_save.py new file mode 100644 index 000000000..7d4b6d9b3 --- /dev/null +++ b/Tests/test_image_save.py @@ -0,0 +1,5 @@ +from tester import * + +from PIL import Image + +success() diff --git a/Tests/test_image_seek.py b/Tests/test_image_seek.py new file mode 100644 index 000000000..7d4b6d9b3 --- /dev/null +++ b/Tests/test_image_seek.py @@ -0,0 +1,5 @@ +from tester import * + +from PIL import Image + +success() diff --git a/Tests/test_image_show.py b/Tests/test_image_show.py new file mode 100644 index 000000000..7d4b6d9b3 --- /dev/null +++ b/Tests/test_image_show.py @@ -0,0 +1,5 @@ +from tester import * + +from PIL import Image + +success() diff --git a/Tests/test_image_split.py b/Tests/test_image_split.py new file mode 100644 index 000000000..7fc70182b --- /dev/null +++ b/Tests/test_image_split.py @@ -0,0 +1,42 @@ +from tester import * + +from PIL import Image + +def test_split(): + def split(mode): + layers = lena(mode).split() + return [(i.mode, i.size[0], i.size[1]) for i in layers] + assert_equal(split("1"), [('1', 128, 128)]) + assert_equal(split("L"), [('L', 128, 128)]) + assert_equal(split("I"), [('I', 128, 128)]) + assert_equal(split("F"), [('F', 128, 128)]) + assert_equal(split("P"), [('P', 128, 128)]) + assert_equal(split("RGB"), [('L', 128, 128), ('L', 128, 128), ('L', 128, 128)]) + assert_equal(split("RGBA"), [('L', 128, 128), ('L', 128, 128), ('L', 128, 128), ('L', 128, 128)]) + assert_equal(split("CMYK"), [('L', 128, 128), ('L', 128, 128), ('L', 128, 128), ('L', 128, 128)]) + assert_equal(split("YCbCr"), [('L', 128, 128), ('L', 128, 128), ('L', 128, 128)]) + +def test_split_merge(): + def split_merge(mode): + return Image.merge(mode, lena(mode).split()) + assert_image_equal(lena("1"), split_merge("1")) + assert_image_equal(lena("L"), split_merge("L")) + assert_image_equal(lena("I"), split_merge("I")) + assert_image_equal(lena("F"), split_merge("F")) + assert_image_equal(lena("P"), split_merge("P")) + assert_image_equal(lena("RGB"), split_merge("RGB")) + assert_image_equal(lena("RGBA"), split_merge("RGBA")) + assert_image_equal(lena("CMYK"), split_merge("CMYK")) + assert_image_equal(lena("YCbCr"), split_merge("YCbCr")) + +def test_split_open(): + file = tempfile("temp.png") + def split_open(mode): + lena(mode).save(file) + im = Image.open(file) + return len(im.split()) + assert_equal(split_open("1"), 1) + assert_equal(split_open("L"), 1) + assert_equal(split_open("P"), 1) + assert_equal(split_open("RGB"), 3) + assert_equal(split_open("RGBA"), 4) diff --git a/Tests/test_image_tell.py b/Tests/test_image_tell.py new file mode 100644 index 000000000..7d4b6d9b3 --- /dev/null +++ b/Tests/test_image_tell.py @@ -0,0 +1,5 @@ +from tester import * + +from PIL import Image + +success() diff --git a/Tests/test_image_thumbnail.py b/Tests/test_image_thumbnail.py new file mode 100644 index 000000000..871dd1f54 --- /dev/null +++ b/Tests/test_image_thumbnail.py @@ -0,0 +1,36 @@ +from tester import * + +from PIL import Image + +def test_sanity(): + + im = lena() + im.thumbnail((100, 100)) + + assert_image(im, im.mode, (100, 100)) + +def test_aspect(): + + im = lena() + im.thumbnail((100, 100)) + assert_image(im, im.mode, (100, 100)) + + im = lena().resize((128, 256)) + im.thumbnail((100, 100)) + assert_image(im, im.mode, (50, 100)) + + im = lena().resize((128, 256)) + im.thumbnail((50, 100)) + assert_image(im, im.mode, (50, 100)) + + im = lena().resize((256, 128)) + im.thumbnail((100, 100)) + assert_image(im, im.mode, (100, 50)) + + im = lena().resize((256, 128)) + im.thumbnail((100, 50)) + assert_image(im, im.mode, (100, 50)) + + im = lena().resize((128, 128)) + im.thumbnail((100, 100)) + assert_image(im, im.mode, (100, 100)) diff --git a/Tests/test_image_tobitmap.py b/Tests/test_image_tobitmap.py new file mode 100644 index 000000000..f8186ae14 --- /dev/null +++ b/Tests/test_image_tobitmap.py @@ -0,0 +1,15 @@ +from tester import * + +from PIL import Image + +def test_sanity(): + + assert_exception(ValueError, lambda: lena().tobitmap()) + assert_no_exception(lambda: lena().convert("1").tobitmap()) + + im1 = lena().convert("1") + + bitmap = im1.tobitmap() + + assert_true(isinstance(bitmap, bytes)) + assert_image_equal(im1, fromstring(bitmap)) diff --git a/Tests/test_image_tostring.py b/Tests/test_image_tostring.py new file mode 100644 index 000000000..b992b63c6 --- /dev/null +++ b/Tests/test_image_tostring.py @@ -0,0 +1,8 @@ +from tester import * + +from PIL import Image + +def test_sanity(): + + data = lena().tobytes() + assert_true(isinstance(data, bytes)) diff --git a/Tests/test_image_transform.py b/Tests/test_image_transform.py new file mode 100644 index 000000000..7d4b6d9b3 --- /dev/null +++ b/Tests/test_image_transform.py @@ -0,0 +1,5 @@ +from tester import * + +from PIL import Image + +success() diff --git a/Tests/test_image_transpose.py b/Tests/test_image_transpose.py new file mode 100644 index 000000000..010478df4 --- /dev/null +++ b/Tests/test_image_transpose.py @@ -0,0 +1,34 @@ +from tester import * + +from PIL import Image + +FLIP_LEFT_RIGHT = Image.FLIP_LEFT_RIGHT +FLIP_TOP_BOTTOM = Image.FLIP_TOP_BOTTOM +ROTATE_90 = Image.ROTATE_90 +ROTATE_180 = Image.ROTATE_180 +ROTATE_270 = Image.ROTATE_270 + +def test_sanity(): + + im = lena() + + assert_no_exception(lambda: im.transpose(FLIP_LEFT_RIGHT)) + assert_no_exception(lambda: im.transpose(FLIP_TOP_BOTTOM)) + + assert_no_exception(lambda: im.transpose(ROTATE_90)) + assert_no_exception(lambda: im.transpose(ROTATE_180)) + assert_no_exception(lambda: im.transpose(ROTATE_270)) + +def test_roundtrip(): + + im = lena() + + def transpose(first, second): + return im.transpose(first).transpose(second) + + assert_image_equal(im, transpose(FLIP_LEFT_RIGHT, FLIP_LEFT_RIGHT)) + assert_image_equal(im, transpose(FLIP_TOP_BOTTOM, FLIP_TOP_BOTTOM)) + + assert_image_equal(im, transpose(ROTATE_90, ROTATE_270)) + assert_image_equal(im, transpose(ROTATE_180, ROTATE_180)) + diff --git a/Tests/test_image_verify.py b/Tests/test_image_verify.py new file mode 100644 index 000000000..7d4b6d9b3 --- /dev/null +++ b/Tests/test_image_verify.py @@ -0,0 +1,5 @@ +from tester import * + +from PIL import Image + +success() diff --git a/Tests/test_imagechops.py b/Tests/test_imagechops.py new file mode 100644 index 000000000..16eaaf55e --- /dev/null +++ b/Tests/test_imagechops.py @@ -0,0 +1,56 @@ +from tester import * + +from PIL import Image +from PIL import ImageChops + +def test_sanity(): + + im = lena("L") + + ImageChops.constant(im, 128) + ImageChops.duplicate(im) + ImageChops.invert(im) + ImageChops.lighter(im, im) + ImageChops.darker(im, im) + ImageChops.difference(im, im) + ImageChops.multiply(im, im) + ImageChops.screen(im, im) + + ImageChops.add(im, im) + ImageChops.add(im, im, 2.0) + ImageChops.add(im, im, 2.0, 128) + ImageChops.subtract(im, im) + ImageChops.subtract(im, im, 2.0) + ImageChops.subtract(im, im, 2.0, 128) + + ImageChops.add_modulo(im, im) + ImageChops.subtract_modulo(im, im) + + ImageChops.blend(im, im, 0.5) + ImageChops.composite(im, im, im) + + ImageChops.offset(im, 10) + ImageChops.offset(im, 10, 20) + +def test_logical(): + + def table(op, a, b): + out = [] + for x in (a, b): + imx = Image.new("1", (1, 1), x) + for y in (a, b): + imy = Image.new("1", (1, 1), y) + out.append(op(imx, imy).getpixel((0, 0))) + return tuple(out) + + assert_equal(table(ImageChops.logical_and, 0, 1), (0, 0, 0, 255)) + assert_equal(table(ImageChops.logical_or, 0, 1), (0, 255, 255, 255)) + assert_equal(table(ImageChops.logical_xor, 0, 1), (0, 255, 255, 0)) + + assert_equal(table(ImageChops.logical_and, 0, 128), (0, 0, 0, 255)) + assert_equal(table(ImageChops.logical_or, 0, 128), (0, 255, 255, 255)) + assert_equal(table(ImageChops.logical_xor, 0, 128), (0, 255, 255, 0)) + + assert_equal(table(ImageChops.logical_and, 0, 255), (0, 0, 0, 255)) + assert_equal(table(ImageChops.logical_or, 0, 255), (0, 255, 255, 255)) + assert_equal(table(ImageChops.logical_xor, 0, 255), (0, 255, 255, 0)) diff --git a/Tests/test_imagecms.py b/Tests/test_imagecms.py new file mode 100644 index 000000000..29e578192 --- /dev/null +++ b/Tests/test_imagecms.py @@ -0,0 +1,82 @@ +from tester import * + +from PIL import Image +try: + from PIL import ImageCms +except ImportError: + skip() + +SRGB = "Tests/icc/sRGB.icm" + +def test_sanity(): + + # basic smoke test. + # this mostly follows the cms_test outline. + + v = ImageCms.versions() # should return four strings + assert_equal(v[0], '0.1.0 pil') + assert_equal(list(map(type, v)), [str, str, str, str]) + + # internal version number + assert_match(ImageCms.core.littlecms_version, "\d+\.\d+$") + + i = ImageCms.profileToProfile(lena(), SRGB, SRGB) + assert_image(i, "RGB", (128, 128)) + + t = ImageCms.buildTransform(SRGB, SRGB, "RGB", "RGB") + i = ImageCms.applyTransform(lena(), t) + assert_image(i, "RGB", (128, 128)) + + p = ImageCms.createProfile("sRGB") + o = ImageCms.getOpenProfile(SRGB) + t = ImageCms.buildTransformFromOpenProfiles(p, o, "RGB", "RGB") + i = ImageCms.applyTransform(lena(), t) + assert_image(i, "RGB", (128, 128)) + + t = ImageCms.buildProofTransform(SRGB, SRGB, SRGB, "RGB", "RGB") + assert_equal(t.inputMode, "RGB") + assert_equal(t.outputMode, "RGB") + i = ImageCms.applyTransform(lena(), t) + assert_image(i, "RGB", (128, 128)) + + # get profile information for file + assert_equal(ImageCms.getProfileName(SRGB).strip(), + 'IEC 61966-2.1 Default RGB colour space - sRGB') + assert_equal(ImageCms.getProfileInfo(SRGB).splitlines(), + ['sRGB IEC61966-2.1', '', + 'Copyright (c) 1998 Hewlett-Packard Company', '', + 'WhitePoint : D65 (daylight)', '', + 'Tests/icc/sRGB.icm']) + assert_equal(ImageCms.getDefaultIntent(SRGB), 0) + assert_equal(ImageCms.isIntentSupported( + SRGB, ImageCms.INTENT_ABSOLUTE_COLORIMETRIC, + ImageCms.DIRECTION_INPUT), 1) + + # same, using profile object + p = ImageCms.createProfile("sRGB") + assert_equal(ImageCms.getProfileName(p).strip(), + 'sRGB built-in - (lcms internal)') + assert_equal(ImageCms.getProfileInfo(p).splitlines(), + ['sRGB built-in', '', 'WhitePoint : D65 (daylight)', '', '']) + assert_equal(ImageCms.getDefaultIntent(p), 0) + assert_equal(ImageCms.isIntentSupported( + p, ImageCms.INTENT_ABSOLUTE_COLORIMETRIC, + ImageCms.DIRECTION_INPUT), 1) + + # extensions + i = Image.open("Tests/images/rgb.jpg") + p = ImageCms.getOpenProfile(BytesIO(i.info["icc_profile"])) + assert_equal(ImageCms.getProfileName(p).strip(), + 'IEC 61966-2.1 Default RGB colour space - sRGB') + + # the procedural pyCMS API uses PyCMSError for all sorts of errors + assert_exception(ImageCms.PyCMSError, lambda: ImageCms.profileToProfile(lena(), "foo", "bar")) + assert_exception(ImageCms.PyCMSError, lambda: ImageCms.buildTransform("foo", "bar", "RGB", "RGB")) + assert_exception(ImageCms.PyCMSError, lambda: ImageCms.getProfileName(None)) + assert_exception(ImageCms.PyCMSError, lambda: ImageCms.isIntentSupported(SRGB, None, None)) + + # test PointTransform convenience API + im = lena().point(t) + + # try fetching the profile for the current display device + assert_no_exception(lambda: ImageCms.get_display_profile()) diff --git a/Tests/test_imagecolor.py b/Tests/test_imagecolor.py new file mode 100644 index 000000000..534005fe4 --- /dev/null +++ b/Tests/test_imagecolor.py @@ -0,0 +1,31 @@ +from tester import * + +from PIL import Image +from PIL import ImageColor + +# -------------------------------------------------------------------- +# sanity + +assert_equal((255, 0, 0), ImageColor.getrgb("#f00")) +assert_equal((255, 0, 0), ImageColor.getrgb("#ff0000")) +assert_equal((255, 0, 0), ImageColor.getrgb("rgb(255,0,0)")) +assert_equal((255, 0, 0), ImageColor.getrgb("rgb(100%,0%,0%)")) +assert_equal((255, 0, 0), ImageColor.getrgb("hsl(0, 100%, 50%)")) +assert_equal((255, 0, 0), ImageColor.getrgb("red")) + +# -------------------------------------------------------------------- +# look for rounding errors (based on code by Tim Hatch) + +for color in list(ImageColor.colormap.keys()): + expected = Image.new("RGB", (1, 1), color).convert("L").getpixel((0, 0)) + actual = Image.new("L", (1, 1), color).getpixel((0, 0)) + assert_equal(expected, actual) + +assert_equal((0, 0, 0), ImageColor.getcolor("black", "RGB")) +assert_equal((255, 255, 255), ImageColor.getcolor("white", "RGB")) + +assert_equal(0, ImageColor.getcolor("black", "L")) +assert_equal(255, ImageColor.getcolor("white", "L")) + +assert_equal(0, ImageColor.getcolor("black", "1")) +assert_equal(255, ImageColor.getcolor("white", "1")) diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py new file mode 100644 index 000000000..c6fd20f52 --- /dev/null +++ b/Tests/test_imagedraw.py @@ -0,0 +1,28 @@ +from tester import * + +from PIL import Image +from PIL import ImageDraw + +def test_sanity(): + + im = lena("RGB").copy() + + draw = ImageDraw.ImageDraw(im) + draw = ImageDraw.Draw(im) + + draw.ellipse(list(range(4))) + draw.line(list(range(10))) + draw.polygon(list(range(100))) + draw.rectangle(list(range(4))) + + success() + +def test_deprecated(): + + im = lena().copy() + + draw = ImageDraw.Draw(im) + + assert_warning(DeprecationWarning, lambda: draw.setink(0)) + assert_warning(DeprecationWarning, lambda: draw.setfill(0)) + diff --git a/Tests/test_imageenhance.py b/Tests/test_imageenhance.py new file mode 100644 index 000000000..04f16bfa5 --- /dev/null +++ b/Tests/test_imageenhance.py @@ -0,0 +1,19 @@ +from tester import * + +from PIL import Image +from PIL import ImageEnhance + +def test_sanity(): + + # FIXME: assert_image + assert_no_exception(lambda: ImageEnhance.Color(lena()).enhance(0.5)) + assert_no_exception(lambda: ImageEnhance.Contrast(lena()).enhance(0.5)) + assert_no_exception(lambda: ImageEnhance.Brightness(lena()).enhance(0.5)) + assert_no_exception(lambda: ImageEnhance.Sharpness(lena()).enhance(0.5)) + +def test_crash(): + + # crashes on small images + im = Image.new("RGB", (1, 1)) + assert_no_exception(lambda: ImageEnhance.Sharpness(im).enhance(0.5)) + diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py new file mode 100644 index 000000000..e260a24dd --- /dev/null +++ b/Tests/test_imagefile.py @@ -0,0 +1,61 @@ +from tester import * + +from PIL import Image +from PIL import ImageFile + +# save original block sizes +MAXBLOCK = ImageFile.MAXBLOCK +SAFEBLOCK = ImageFile.SAFEBLOCK + +def test_parser(): + + def roundtrip(format): + + im = lena("L").resize((1000, 1000)) + if format in ("MSP", "XBM"): + im = im.convert("1") + + file = BytesIO() + + im.save(file, format) + + data = file.getvalue() + + parser = ImageFile.Parser() + parser.feed(data) + imOut = parser.close() + + return im, imOut + + assert_image_equal(*roundtrip("BMP")) + assert_image_equal(*roundtrip("GIF")) + assert_image_equal(*roundtrip("IM")) + assert_image_equal(*roundtrip("MSP")) + try: + # force multiple blocks in PNG driver + ImageFile.MAXBLOCK = 8192 + assert_image_equal(*roundtrip("PNG")) + finally: + ImageFile.MAXBLOCK = MAXBLOCK + assert_image_equal(*roundtrip("PPM")) + assert_image_equal(*roundtrip("TIFF")) + assert_image_equal(*roundtrip("XBM")) + + im1, im2 = roundtrip("JPEG") # lossy compression + assert_image(im1, im2.mode, im2.size) + + assert_exception(IOError, lambda: roundtrip("PCX")) + assert_exception(IOError, lambda: roundtrip("PDF")) + + +def test_safeblock(): + + im1 = lena() + + try: + ImageFile.SAFEBLOCK = 1 + im2 = fromstring(tostring(im1, "PNG")) + finally: + ImageFile.SAFEBLOCK = SAFEBLOCK + + assert_image_equal(im1, im2) diff --git a/Tests/test_imagefileio.py b/Tests/test_imagefileio.py new file mode 100644 index 000000000..259c6fe1c --- /dev/null +++ b/Tests/test_imagefileio.py @@ -0,0 +1,24 @@ +from tester import * + +from PIL import Image +from PIL import ImageFileIO + +def test_fileio(): + + class DumbFile: + def __init__(self, data): + self.data = data + def read(self, bytes=None): + assert_equal(bytes, None) + return self.data + def close(self): + pass + + im1 = lena() + + io = ImageFileIO.ImageFileIO(DumbFile(tostring(im1, "PPM"))) + + im2 = Image.open(io) + assert_image_equal(im1, im2) + + diff --git a/Tests/test_imagefilter.py b/Tests/test_imagefilter.py new file mode 100644 index 000000000..214f88024 --- /dev/null +++ b/Tests/test_imagefilter.py @@ -0,0 +1,31 @@ +from tester import * + +from PIL import Image +from PIL import ImageFilter + +def test_sanity(): + # see test_image_filter for more tests + + assert_no_exception(lambda: ImageFilter.MaxFilter) + assert_no_exception(lambda: ImageFilter.MedianFilter) + assert_no_exception(lambda: ImageFilter.MinFilter) + assert_no_exception(lambda: ImageFilter.ModeFilter) + assert_no_exception(lambda: ImageFilter.Kernel((3, 3), list(range(9)))) + assert_no_exception(lambda: ImageFilter.GaussianBlur) + assert_no_exception(lambda: ImageFilter.GaussianBlur(5)) + assert_no_exception(lambda: ImageFilter.UnsharpMask) + assert_no_exception(lambda: ImageFilter.UnsharpMask(10)) + + assert_no_exception(lambda: ImageFilter.BLUR) + assert_no_exception(lambda: ImageFilter.CONTOUR) + assert_no_exception(lambda: ImageFilter.DETAIL) + assert_no_exception(lambda: ImageFilter.EDGE_ENHANCE) + assert_no_exception(lambda: ImageFilter.EDGE_ENHANCE_MORE) + assert_no_exception(lambda: ImageFilter.EMBOSS) + assert_no_exception(lambda: ImageFilter.FIND_EDGES) + assert_no_exception(lambda: ImageFilter.SMOOTH) + assert_no_exception(lambda: ImageFilter.SMOOTH_MORE) + assert_no_exception(lambda: ImageFilter.SHARPEN) + + + diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py new file mode 100644 index 000000000..3c4e1f1b8 --- /dev/null +++ b/Tests/test_imagefont.py @@ -0,0 +1,12 @@ +from tester import * + +from PIL import Image +try: + from PIL import ImageFont + ImageFont.core.getfont # check if freetype is available +except ImportError: + skip() + +def test_sanity(): + + assert_match(ImageFont.core.freetype2_version, "\d+\.\d+\.\d+$") diff --git a/Tests/test_imagegl.py b/Tests/test_imagegl.py new file mode 100644 index 000000000..87dd6aa2d --- /dev/null +++ b/Tests/test_imagegl.py @@ -0,0 +1,9 @@ +from tester import * + +from PIL import Image +try: + from PIL import ImageGL +except ImportError as v: + skip(v) + +success() diff --git a/Tests/test_imagegrab.py b/Tests/test_imagegrab.py new file mode 100644 index 000000000..67ff71960 --- /dev/null +++ b/Tests/test_imagegrab.py @@ -0,0 +1,13 @@ +from tester import * + +from PIL import Image +try: + from PIL import ImageGrab +except ImportError as v: + skip(v) + +def test_grab(): + im = ImageGrab.grab() + assert_image(im, im.mode, im.size) + + diff --git a/Tests/test_imagemath.py b/Tests/test_imagemath.py new file mode 100644 index 000000000..eaeb711ba --- /dev/null +++ b/Tests/test_imagemath.py @@ -0,0 +1,62 @@ +from tester import * + +from PIL import Image +from PIL import ImageMath + +def pixel(im): + if hasattr(im, "im"): + return "%s %r" % (im.mode, im.getpixel((0, 0))) + else: + if isinstance(im, type(0)): + return int(im) # hack to deal with booleans + print(im) + +A = Image.new("L", (1, 1), 1) +B = Image.new("L", (1, 1), 2) +F = Image.new("F", (1, 1), 3) +I = Image.new("I", (1, 1), 4) + +images = {"A": A, "B": B, "F": F, "I": I} + +def test_sanity(): + assert_equal(ImageMath.eval("1"), 1) + assert_equal(ImageMath.eval("1+A", A=2), 3) + assert_equal(pixel(ImageMath.eval("A+B", A=A, B=B)), "I 3") + assert_equal(pixel(ImageMath.eval("A+B", images)), "I 3") + assert_equal(pixel(ImageMath.eval("float(A)+B", images)), "F 3.0") + assert_equal(pixel(ImageMath.eval("int(float(A)+B)", images)), "I 3") + +def test_ops(): + + assert_equal(pixel(ImageMath.eval("-A", images)), "I -1") + assert_equal(pixel(ImageMath.eval("+B", images)), "L 2") + + assert_equal(pixel(ImageMath.eval("A+B", images)), "I 3") + assert_equal(pixel(ImageMath.eval("A-B", images)), "I -1") + assert_equal(pixel(ImageMath.eval("A*B", images)), "I 2") + assert_equal(pixel(ImageMath.eval("A/B", images)), "I 0") + assert_equal(pixel(ImageMath.eval("B**2", images)), "I 4") + assert_equal(pixel(ImageMath.eval("B**33", images)), "I 2147483647") + + assert_equal(pixel(ImageMath.eval("float(A)+B", images)), "F 3.0") + assert_equal(pixel(ImageMath.eval("float(A)-B", images)), "F -1.0") + assert_equal(pixel(ImageMath.eval("float(A)*B", images)), "F 2.0") + assert_equal(pixel(ImageMath.eval("float(A)/B", images)), "F 0.5") + assert_equal(pixel(ImageMath.eval("float(B)**2", images)), "F 4.0") + assert_equal(pixel(ImageMath.eval("float(B)**33", images)), "F 8589934592.0") + +def test_logical(): + assert_equal(pixel(ImageMath.eval("not A", images)), 0) + assert_equal(pixel(ImageMath.eval("A and B", images)), "L 2") + assert_equal(pixel(ImageMath.eval("A or B", images)), "L 1") + +def test_convert(): + assert_equal(pixel(ImageMath.eval("convert(A+B, 'L')", images)), "L 3") + assert_equal(pixel(ImageMath.eval("convert(A+B, '1')", images)), "1 0") + assert_equal(pixel(ImageMath.eval("convert(A+B, 'RGB')", images)), "RGB (3, 3, 3)") + +def test_compare(): + assert_equal(pixel(ImageMath.eval("min(A, B)", images)), "I 1") + assert_equal(pixel(ImageMath.eval("max(A, B)", images)), "I 2") + assert_equal(pixel(ImageMath.eval("A == 1", images)), "I 1") + assert_equal(pixel(ImageMath.eval("A == 2", images)), "I 0") diff --git a/Tests/test_imagemode.py b/Tests/test_imagemode.py new file mode 100644 index 000000000..54b04435f --- /dev/null +++ b/Tests/test_imagemode.py @@ -0,0 +1,23 @@ +from tester import * + +from PIL import Image +from PIL import ImageMode + +ImageMode.getmode("1") +ImageMode.getmode("L") +ImageMode.getmode("P") +ImageMode.getmode("RGB") +ImageMode.getmode("I") +ImageMode.getmode("F") + +m = ImageMode.getmode("1") +assert_equal(m.mode, "1") +assert_equal(m.bands, ("1",)) +assert_equal(m.basemode, "L") +assert_equal(m.basetype, "L") + +m = ImageMode.getmode("RGB") +assert_equal(m.mode, "RGB") +assert_equal(m.bands, ("R", "G", "B")) +assert_equal(m.basemode, "RGB") +assert_equal(m.basetype, "L") diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py new file mode 100644 index 000000000..362937e81 --- /dev/null +++ b/Tests/test_imageops.py @@ -0,0 +1,70 @@ +from tester import * + +from PIL import Image +from PIL import ImageOps + +class Deformer: + def getmesh(self, im): + x, y = im.size + return [((0, 0, x, y), (0, 0, x, 0, x, y, y, 0))] + +deformer = Deformer() + +def test_sanity(): + + ImageOps.autocontrast(lena("L")) + ImageOps.autocontrast(lena("RGB")) + + ImageOps.autocontrast(lena("L"), cutoff=10) + ImageOps.autocontrast(lena("L"), ignore=[0, 255]) + + ImageOps.colorize(lena("L"), (0, 0, 0), (255, 255, 255)) + ImageOps.colorize(lena("L"), "black", "white") + + ImageOps.crop(lena("L"), 1) + ImageOps.crop(lena("RGB"), 1) + + ImageOps.deform(lena("L"), deformer) + ImageOps.deform(lena("RGB"), deformer) + + ImageOps.equalize(lena("L")) + ImageOps.equalize(lena("RGB")) + + ImageOps.expand(lena("L"), 1) + ImageOps.expand(lena("RGB"), 1) + ImageOps.expand(lena("L"), 2, "blue") + ImageOps.expand(lena("RGB"), 2, "blue") + + ImageOps.fit(lena("L"), (128, 128)) + ImageOps.fit(lena("RGB"), (128, 128)) + + ImageOps.flip(lena("L")) + ImageOps.flip(lena("RGB")) + + ImageOps.grayscale(lena("L")) + ImageOps.grayscale(lena("RGB")) + + ImageOps.invert(lena("L")) + ImageOps.invert(lena("RGB")) + + ImageOps.mirror(lena("L")) + ImageOps.mirror(lena("RGB")) + + ImageOps.posterize(lena("L"), 4) + ImageOps.posterize(lena("RGB"), 4) + + ImageOps.solarize(lena("L")) + ImageOps.solarize(lena("RGB")) + + success() + +def test_pil163(): + # Division by zero in equalize if < 255 pixels in image (@PIL163) + + i = lena("RGB").resize((15, 16)) + + ImageOps.equalize(i.convert("L")) + ImageOps.equalize(i.convert("P")) + ImageOps.equalize(i.convert("RGB")) + + success() diff --git a/Tests/test_imageops_usm.py b/Tests/test_imageops_usm.py new file mode 100644 index 000000000..83a93b8e0 --- /dev/null +++ b/Tests/test_imageops_usm.py @@ -0,0 +1,55 @@ +from tester import * + +from PIL import Image +from PIL import ImageOps +from PIL import ImageFilter + +im = Image.open("Images/lena.ppm") + +def test_ops_api(): + + i = ImageOps.gaussian_blur(im, 2.0) + assert_equal(i.mode, "RGB") + assert_equal(i.size, (128, 128)) + # i.save("blur.bmp") + + i = ImageOps.usm(im, 2.0, 125, 8) + assert_equal(i.mode, "RGB") + assert_equal(i.size, (128, 128)) + # i.save("usm.bmp") + +def test_filter_api(): + + filter = ImageFilter.GaussianBlur(2.0) + i = im.filter(filter) + assert_equal(i.mode, "RGB") + assert_equal(i.size, (128, 128)) + + filter = ImageFilter.UnsharpMask(2.0, 125, 8) + i = im.filter(filter) + assert_equal(i.mode, "RGB") + assert_equal(i.size, (128, 128)) + +def test_usm(): + + usm = ImageOps.unsharp_mask + assert_exception(ValueError, lambda: usm(im.convert("1"))) + assert_no_exception(lambda: usm(im.convert("L"))) + assert_exception(ValueError, lambda: usm(im.convert("I"))) + assert_exception(ValueError, lambda: usm(im.convert("F"))) + assert_no_exception(lambda: usm(im.convert("RGB"))) + assert_no_exception(lambda: usm(im.convert("RGBA"))) + assert_no_exception(lambda: usm(im.convert("CMYK"))) + assert_exception(ValueError, lambda: usm(im.convert("YCbCr"))) + +def test_blur(): + + blur = ImageOps.gaussian_blur + assert_exception(ValueError, lambda: blur(im.convert("1"))) + assert_no_exception(lambda: blur(im.convert("L"))) + assert_exception(ValueError, lambda: blur(im.convert("I"))) + assert_exception(ValueError, lambda: blur(im.convert("F"))) + assert_no_exception(lambda: blur(im.convert("RGB"))) + assert_no_exception(lambda: blur(im.convert("RGBA"))) + assert_no_exception(lambda: blur(im.convert("CMYK"))) + assert_exception(ValueError, lambda: blur(im.convert("YCbCr"))) diff --git a/Tests/test_imagepalette.py b/Tests/test_imagepalette.py new file mode 100644 index 000000000..573c706b1 --- /dev/null +++ b/Tests/test_imagepalette.py @@ -0,0 +1,44 @@ +from tester import * + +from PIL import Image +from PIL import ImagePalette + +ImagePalette = ImagePalette.ImagePalette + +def test_sanity(): + + assert_no_exception(lambda: ImagePalette("RGB", list(range(256))*3)) + assert_exception(ValueError, lambda: ImagePalette("RGB", list(range(256))*2)) + +def test_getcolor(): + + palette = ImagePalette() + + map = {} + for i in range(256): + map[palette.getcolor((i, i, i))] = i + + assert_equal(len(map), 256) + assert_exception(ValueError, lambda: palette.getcolor((1, 2, 3))) + +def test_file(): + + palette = ImagePalette() + + file = tempfile("temp.lut") + + palette.save(file) + + from PIL.ImagePalette import load, raw + + p = load(file) + + # load returns raw palette information + assert_equal(len(p[0]), 768) + assert_equal(p[1], "RGB") + + p = raw(p[1], p[0]) + assert_true(isinstance(p, ImagePalette)) + + + diff --git a/Tests/test_imagepath.py b/Tests/test_imagepath.py new file mode 100644 index 000000000..beadff10e --- /dev/null +++ b/Tests/test_imagepath.py @@ -0,0 +1,49 @@ +from tester import * + +from PIL import Image +from PIL import ImagePath + +import array + +def test_path(): + + p = ImagePath.Path(list(range(10))) + + # sequence interface + assert_equal(len(p), 5) + assert_equal(p[0], (0.0, 1.0)) + assert_equal(p[-1], (8.0, 9.0)) + assert_equal(list(p[:1]), [(0.0, 1.0)]) + assert_equal(list(p), [(0.0, 1.0), (2.0, 3.0), (4.0, 5.0), (6.0, 7.0), (8.0, 9.0)]) + + # method sanity check + assert_equal(p.tolist(), [(0.0, 1.0), (2.0, 3.0), (4.0, 5.0), (6.0, 7.0), (8.0, 9.0)]) + assert_equal(p.tolist(1), [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]) + + assert_equal(p.getbbox(), (0.0, 1.0, 8.0, 9.0)) + + assert_equal(p.compact(5), 2) + assert_equal(list(p), [(0.0, 1.0), (4.0, 5.0), (8.0, 9.0)]) + + p.transform((1,0,1,0,1,1)) + assert_equal(list(p), [(1.0, 2.0), (5.0, 6.0), (9.0, 10.0)]) + + # alternative constructors + p = ImagePath.Path([0, 1]) + assert_equal(list(p), [(0.0, 1.0)]) + p = ImagePath.Path([0.0, 1.0]) + assert_equal(list(p), [(0.0, 1.0)]) + p = ImagePath.Path([0, 1]) + assert_equal(list(p), [(0.0, 1.0)]) + p = ImagePath.Path([(0, 1)]) + assert_equal(list(p), [(0.0, 1.0)]) + p = ImagePath.Path(p) + assert_equal(list(p), [(0.0, 1.0)]) + p = ImagePath.Path(p.tolist(0)) + assert_equal(list(p), [(0.0, 1.0)]) + p = ImagePath.Path(p.tolist(1)) + assert_equal(list(p), [(0.0, 1.0)]) + p = ImagePath.Path(array.array("f", [0, 1])) + assert_equal(list(p), [(0.0, 1.0)]) + p = ImagePath.Path(array.array("f", [0, 1]).tostring()) + assert_equal(list(p), [(0.0, 1.0)]) diff --git a/Tests/test_imageqt.py b/Tests/test_imageqt.py new file mode 100644 index 000000000..8d6ac9f3c --- /dev/null +++ b/Tests/test_imageqt.py @@ -0,0 +1,9 @@ +from tester import * + +from PIL import Image +try: + from PIL import ImageQt +except ImportError as v: + skip(v) + +success() diff --git a/Tests/test_imagesequence.py b/Tests/test_imagesequence.py new file mode 100644 index 000000000..0b244d88c --- /dev/null +++ b/Tests/test_imagesequence.py @@ -0,0 +1,22 @@ +from tester import * + +from PIL import Image +from PIL import ImageSequence + +def test_sanity(): + + file = tempfile("temp.im") + + im = lena("RGB") + im.save(file) + + seq = ImageSequence.Iterator(im) + + index = 0 + for frame in seq: + assert_image_equal(im, frame) + assert_equal(im.tell(), index) + index = index + 1 + + assert_equal(index, 1) + diff --git a/Tests/test_imageshow.py b/Tests/test_imageshow.py new file mode 100644 index 000000000..99ec005c8 --- /dev/null +++ b/Tests/test_imageshow.py @@ -0,0 +1,6 @@ +from tester import * + +from PIL import Image +from PIL import ImageShow + +success() diff --git a/Tests/test_imagestat.py b/Tests/test_imagestat.py new file mode 100644 index 000000000..02a461e22 --- /dev/null +++ b/Tests/test_imagestat.py @@ -0,0 +1,52 @@ +from tester import * + +from PIL import Image +from PIL import ImageStat + +def test_sanity(): + + im = lena() + + st = ImageStat.Stat(im) + st = ImageStat.Stat(im.histogram()) + st = ImageStat.Stat(im, Image.new("1", im.size, 1)) + + assert_no_exception(lambda: st.extrema) + assert_no_exception(lambda: st.sum) + assert_no_exception(lambda: st.mean) + assert_no_exception(lambda: st.median) + assert_no_exception(lambda: st.rms) + assert_no_exception(lambda: st.sum2) + assert_no_exception(lambda: st.var) + assert_no_exception(lambda: st.stddev) + assert_exception(AttributeError, lambda: st.spam) + + assert_exception(TypeError, lambda: ImageStat.Stat(1)) + +def test_lena(): + + im = lena() + + st = ImageStat.Stat(im) + + # verify a few values + assert_equal(st.extrema[0], (61, 255)) + assert_equal(st.median[0], 197) + assert_equal(st.sum[0], 2954416) + assert_equal(st.sum[1], 2027250) + assert_equal(st.sum[2], 1727331) + +def test_constant(): + + im = Image.new("L", (128, 128), 128) + + st = ImageStat.Stat(im) + + assert_equal(st.extrema[0], (128, 128)) + assert_equal(st.sum[0], 128**3) + assert_equal(st.sum2[0], 128**4) + assert_equal(st.mean[0], 128) + assert_equal(st.median[0], 128) + assert_equal(st.rms[0], 128) + assert_equal(st.var[0], 0) + assert_equal(st.stddev[0], 0) diff --git a/Tests/test_imagetk.py b/Tests/test_imagetk.py new file mode 100644 index 000000000..5c39c9283 --- /dev/null +++ b/Tests/test_imagetk.py @@ -0,0 +1,9 @@ +from tester import * + +from PIL import Image +try: + from PIL import ImageTk +except ImportError as v: + skip(v) + +success() diff --git a/Tests/test_imagetransform.py b/Tests/test_imagetransform.py new file mode 100644 index 000000000..884e6bb1c --- /dev/null +++ b/Tests/test_imagetransform.py @@ -0,0 +1,18 @@ +from tester import * + +from PIL import Image +from PIL import ImageTransform + +im = Image.new("L", (100, 100)) + +seq = tuple(range(10)) + +def test_sanity(): + transform = ImageTransform.AffineTransform(seq[:6]) + assert_no_exception(lambda: im.transform((100, 100), transform)) + transform = ImageTransform.ExtentTransform(seq[:4]) + assert_no_exception(lambda: im.transform((100, 100), transform)) + transform = ImageTransform.QuadTransform(seq[:8]) + assert_no_exception(lambda: im.transform((100, 100), transform)) + transform = ImageTransform.MeshTransform([(seq[:4], seq[:8])]) + assert_no_exception(lambda: im.transform((100, 100), transform)) diff --git a/Tests/test_imagewin.py b/Tests/test_imagewin.py new file mode 100644 index 000000000..268a75b6f --- /dev/null +++ b/Tests/test_imagewin.py @@ -0,0 +1,6 @@ +from tester import * + +from PIL import Image +from PIL import ImageWin + +success() diff --git a/Tests/test_lib_image.py b/Tests/test_lib_image.py new file mode 100644 index 000000000..93aa694d8 --- /dev/null +++ b/Tests/test_lib_image.py @@ -0,0 +1,30 @@ +from tester import * + +from PIL import Image + +def test_setmode(): + + im = Image.new("L", (1, 1), 255) + im.im.setmode("1") + assert_equal(im.im.getpixel((0, 0)), 255) + im.im.setmode("L") + assert_equal(im.im.getpixel((0, 0)), 255) + + im = Image.new("1", (1, 1), 1) + im.im.setmode("L") + assert_equal(im.im.getpixel((0, 0)), 255) + im.im.setmode("1") + assert_equal(im.im.getpixel((0, 0)), 255) + + im = Image.new("RGB", (1, 1), (1, 2, 3)) + im.im.setmode("RGB") + assert_equal(im.im.getpixel((0, 0)), (1, 2, 3)) + im.im.setmode("RGBA") + assert_equal(im.im.getpixel((0, 0)), (1, 2, 3, 255)) + im.im.setmode("RGBX") + assert_equal(im.im.getpixel((0, 0)), (1, 2, 3, 255)) + im.im.setmode("RGB") + assert_equal(im.im.getpixel((0, 0)), (1, 2, 3)) + + assert_exception(ValueError, lambda: im.im.setmode("L")) + assert_exception(ValueError, lambda: im.im.setmode("RGBABCDE")) diff --git a/Tests/test_lib_pack.py b/Tests/test_lib_pack.py new file mode 100644 index 000000000..cd26a54ea --- /dev/null +++ b/Tests/test_lib_pack.py @@ -0,0 +1,110 @@ +from tester import * + +from PIL import Image + +def pack(): + pass # not yet + +def test_pack(): + + def pack(mode, rawmode): + if len(mode) == 1: + im = Image.new(mode, (1, 1), 1) + else: + im = Image.new(mode, (1, 1), (1, 2, 3, 4)[:len(mode)]) + return list(im.tobytes("raw", rawmode)) + + assert_equal(pack("1", "1"), [128]) + assert_equal(pack("1", "1;I"), [0]) + assert_equal(pack("1", "1;R"), [1]) + assert_equal(pack("1", "1;IR"), [0]) + + assert_equal(pack("L", "L"), [1]) + + assert_equal(pack("I", "I"), [1, 0, 0, 0]) + + assert_equal(pack("F", "F"), [0, 0, 128, 63]) + + assert_equal(pack("LA", "LA"), [1, 2]) + + assert_equal(pack("RGB", "RGB"), [1, 2, 3]) + assert_equal(pack("RGB", "RGB;L"), [1, 2, 3]) + assert_equal(pack("RGB", "BGR"), [3, 2, 1]) + assert_equal(pack("RGB", "RGBX"), [1, 2, 3, 255]) # 255? + assert_equal(pack("RGB", "BGRX"), [3, 2, 1, 0]) + assert_equal(pack("RGB", "XRGB"), [0, 1, 2, 3]) + assert_equal(pack("RGB", "XBGR"), [0, 3, 2, 1]) + + assert_equal(pack("RGBX", "RGBX"), [1, 2, 3, 4]) # 4->255? + + assert_equal(pack("RGBA", "RGBA"), [1, 2, 3, 4]) + + assert_equal(pack("CMYK", "CMYK"), [1, 2, 3, 4]) + assert_equal(pack("YCbCr", "YCbCr"), [1, 2, 3]) + +def test_unpack(): + + def unpack(mode, rawmode, bytes_): + data = bytes(range(1,bytes_+1)) + im = Image.frombytes(mode, (1, 1), data, "raw", rawmode, 0, 1) + return im.getpixel((0, 0)) + + def unpack_1(mode, rawmode, value): + assert mode == "1" + im = Image.frombytes(mode, (8, 1), bytes([value]), "raw", rawmode, 0, 1) + return tuple(im.getdata()) + + X = 255 + + assert_equal(unpack_1("1", "1", 1), (0,0,0,0,0,0,0,X)) + assert_equal(unpack_1("1", "1;I", 1), (X,X,X,X,X,X,X,0)) + assert_equal(unpack_1("1", "1;R", 1), (X,0,0,0,0,0,0,0)) + assert_equal(unpack_1("1", "1;IR", 1), (0,X,X,X,X,X,X,X)) + + assert_equal(unpack_1("1", "1", 170), (X,0,X,0,X,0,X,0)) + assert_equal(unpack_1("1", "1;I", 170), (0,X,0,X,0,X,0,X)) + assert_equal(unpack_1("1", "1;R", 170), (0,X,0,X,0,X,0,X)) + assert_equal(unpack_1("1", "1;IR", 170), (X,0,X,0,X,0,X,0)) + + assert_equal(unpack("L", "L;2", 1), 0) + assert_equal(unpack("L", "L;4", 1), 0) + assert_equal(unpack("L", "L", 1), 1) + assert_equal(unpack("L", "L;I", 1), 254) + assert_equal(unpack("L", "L;R", 1), 128) + assert_equal(unpack("L", "L;16", 2), 2) # little endian + assert_equal(unpack("L", "L;16B", 2), 1) # big endian + + assert_equal(unpack("LA", "LA", 2), (1, 2)) + assert_equal(unpack("LA", "LA;L", 2), (1, 2)) + + assert_equal(unpack("RGB", "RGB", 3), (1, 2, 3)) + assert_equal(unpack("RGB", "RGB;L", 3), (1, 2, 3)) + assert_equal(unpack("RGB", "RGB;R", 3), (128, 64, 192)) + assert_equal(unpack("RGB", "RGB;16B", 6), (1, 3, 5)) # ? + assert_equal(unpack("RGB", "BGR", 3), (3, 2, 1)) + assert_equal(unpack("RGB", "BGR;15", 2), (0, 131, 8)) + assert_equal(unpack("RGB", "BGR;16", 2), (0, 64, 8)) + + assert_equal(unpack("RGB", "RGBX", 4), (1, 2, 3)) + assert_equal(unpack("RGB", "BGRX", 4), (3, 2, 1)) + assert_equal(unpack("RGB", "XRGB", 4), (2, 3, 4)) + assert_equal(unpack("RGB", "XBGR", 4), (4, 3, 2)) + + assert_equal(unpack("RGBA", "RGBA", 4), (1, 2, 3, 4)) + assert_equal(unpack("RGBA", "BGRA", 4), (3, 2, 1, 4)) + assert_equal(unpack("RGBA", "ARGB", 4), (2, 3, 4, 1)) + assert_equal(unpack("RGBA", "ABGR", 4), (4, 3, 2, 1)) + + assert_equal(unpack("RGBX", "RGBX", 4), (1, 2, 3, 4)) # 4->255? + assert_equal(unpack("RGBX", "BGRX", 4), (3, 2, 1, 255)) + assert_equal(unpack("RGBX", "XRGB", 4), (2, 3, 4, 255)) + assert_equal(unpack("RGBX", "XBGR", 4), (4, 3, 2, 255)) + + assert_equal(unpack("CMYK", "CMYK", 4), (1, 2, 3, 4)) + assert_equal(unpack("CMYK", "CMYK;I", 4), (254, 253, 252, 251)) + + assert_exception(ValueError, lambda: unpack("L", "L", 0)) + assert_exception(ValueError, lambda: unpack("RGB", "RGB", 2)) + assert_exception(ValueError, lambda: unpack("CMYK", "CMYK", 2)) + +run() diff --git a/Tests/test_mode_i16.py b/Tests/test_mode_i16.py new file mode 100644 index 000000000..91042e6f1 --- /dev/null +++ b/Tests/test_mode_i16.py @@ -0,0 +1,103 @@ +from tester import * + +from PIL import Image + +def verify(im1): + im2 = lena("I") + assert_equal(im1.size, im2.size) + pix1 = im1.load() + pix2 = im2.load() + for y in range(im1.size[1]): + for x in range(im1.size[0]): + xy = x, y + if pix1[xy] != pix2[xy]: + failure( + "got %r from mode %s at %s, expected %r" % + (pix1[xy], im1.mode, xy, pix2[xy]) + ) + return + success() + +def test_basic(): + # PIL 1.1 has limited support for 16-bit image data. Check that + # create/copy/transform and save works as expected. + + def basic(mode): + + imIn = lena("I").convert(mode) + verify(imIn) + + w, h = imIn.size + + imOut = imIn.copy() + verify(imOut) # copy + + imOut = imIn.transform((w, h), Image.EXTENT, (0, 0, w, h)) + verify(imOut) # transform + + filename = tempfile("temp.im") + imIn.save(filename) + + imOut = Image.open(filename) + + verify(imIn) + verify(imOut) + + imOut = imIn.crop((0, 0, w, h)) + verify(imOut) + + imOut = Image.new(mode, (w, h), None) + imOut.paste(imIn.crop((0, 0, w//2, h)), (0, 0)) + imOut.paste(imIn.crop((w//2, 0, w, h)), (w//2, 0)) + + verify(imIn) + verify(imOut) + + imIn = Image.new(mode, (1, 1), 1) + assert_equal(imIn.getpixel((0, 0)), 1) + + imIn.putpixel((0, 0), 2) + assert_equal(imIn.getpixel((0, 0)), 2) + + if mode == "L": + max = 255 + else: + max = 32767 + + imIn = Image.new(mode, (1, 1), 256) + assert_equal(imIn.getpixel((0, 0)), min(256, max)) + + imIn.putpixel((0, 0), 512) + assert_equal(imIn.getpixel((0, 0)), min(512, max)) + + basic("L") + + basic("I;16") + basic("I;16B") + basic("I;16L") + + basic("I") + + +def test_tostring(): + + def tostring(mode): + return Image.new(mode, (1, 1), 1).tobytes() + + assert_equal(tostring("L"), b"\x01") + assert_equal(tostring("I;16"), b"\x01\x00") + assert_equal(tostring("I;16B"), b"\x00\x01") + assert_equal(tostring("I"), b"\x01\x00\x00\x00") + + +def test_convert(): + + im = lena("I") + + verify(im.convert("I;16")) + verify(im.convert("I;16").convert("L")) + verify(im.convert("I;16").convert("I")) + + verify(im.convert("I;16B")) + verify(im.convert("I;16B").convert("L")) + verify(im.convert("I;16B").convert("I")) diff --git a/Tests/test_numpy.py b/Tests/test_numpy.py new file mode 100644 index 000000000..ea154afb8 --- /dev/null +++ b/Tests/test_numpy.py @@ -0,0 +1,54 @@ +from tester import * + +from PIL import Image + +try: + import site + import numpy +except ImportError: + skip() + +def test_numpy_to_image(): + + def to_image(dtype, bands=1, bool=0): + if bands == 1: + if bool: + data = [0, 1] * 50 + else: + data = list(range(100)) + a = numpy.array(data, dtype=dtype) + a.shape = 10, 10 + i = Image.fromarray(a) + if list(i.getdata()) != data: + print("data mismatch for", dtype) + else: + data = list(range(100)) + a = numpy.array([[x]*bands for x in data], dtype=dtype) + a.shape = 10, 10, bands + i = Image.fromarray(a) + if list(i.split()[0].getdata()) != list(range(100)): + print("data mismatch for", dtype) + # print dtype, list(i.getdata()) + return i + + # assert_image(to_image(numpy.bool, bool=1), "1", (10, 10)) + # assert_image(to_image(numpy.bool8, bool=1), "1", (10, 10)) + + assert_exception(TypeError, lambda: to_image(numpy.uint)) + assert_image(to_image(numpy.uint8), "L", (10, 10)) + assert_exception(TypeError, lambda: to_image(numpy.uint16)) + assert_exception(TypeError, lambda: to_image(numpy.uint32)) + assert_exception(TypeError, lambda: to_image(numpy.uint64)) + + assert_image(to_image(numpy.int), "I", (10, 10)) + assert_image(to_image(numpy.int8), "I", (10, 10)) + assert_image(to_image(numpy.int16), "I;16", (10, 10)) + assert_image(to_image(numpy.int32), "I", (10, 10)) + assert_exception(TypeError, lambda: to_image(numpy.int64)) + + assert_image(to_image(numpy.float), "F", (10, 10)) + assert_image(to_image(numpy.float32), "F", (10, 10)) + assert_image(to_image(numpy.float64), "F", (10, 10)) + + assert_image(to_image(numpy.uint8, 3), "RGB", (10, 10)) + assert_image(to_image(numpy.uint8, 4), "RGBA", (10, 10)) diff --git a/Tests/tester.py b/Tests/tester.py new file mode 100644 index 000000000..3e9d9e689 --- /dev/null +++ b/Tests/tester.py @@ -0,0 +1,229 @@ +# some test helpers + +_target = None +_tempfiles = [] +_logfile = None + +def success(): + import sys + success.count += 1 + if _logfile: + print(sys.argv[0], success.count, failure.count, file=_logfile) + +def failure(msg=None, frame=None): + import sys, linecache + failure.count += 1 + if _target: + if frame is None: + frame = sys._getframe() + while frame.f_globals.get("__name__") != _target.__name__: + frame = frame.f_back + location = (frame.f_code.co_filename, frame.f_lineno) + prefix = "%s:%d: " % location + line = linecache.getline(*location) + print(prefix + line.strip() + " failed:") + if msg: + print("- " + msg) + if _logfile: + print(sys.argv[0], success.count, failure.count, file=_logfile) + +success.count = failure.count = 0 + +# predicates + +def assert_true(v, msg=None): + if v: + success() + else: + failure(msg or "got %r, expected true value" % v) + +def assert_false(v, msg=None): + if v: + failure(msg or "got %r, expected false value" % v) + else: + success() + +def assert_equal(a, b, msg=None): + if a == b: + success() + else: + failure(msg or "got %r, expected %r" % (a, b)) + +def assert_match(v, pattern, msg=None): + import re + if re.match(pattern, v): + success() + else: + failure(msg or "got %r, doesn't match pattern %r" % (v, pattern)) + +def assert_exception(exc_class, func): + import sys, traceback + try: + func() + except exc_class: + success() + except: + failure("expected %r exception, got %r" % ( + exc_class.__name__, sys.exc_info()[0].__name__)) + traceback.print_exc() + else: + failure("expected %r exception, got no exception" % exc_class.__name__) + +def assert_no_exception(func): + import sys, traceback + try: + func() + except: + failure("expected no exception, got %r" % sys.exc_info()[0].__name__) + traceback.print_exc() + else: + success() + +def assert_warning(warn_class, func): + # note: this assert calls func three times! + import warnings + def warn_error(message, category, **options): + raise category(message) + def warn_ignore(message, category, **options): + pass + warn = warnings.warn + result = None + try: + warnings.warn = warn_ignore + assert_no_exception(func) + result = func() + warnings.warn = warn_error + assert_exception(warn_class, func) + finally: + warnings.warn = warn # restore + return result + +# helpers + +from io import BytesIO + +def fromstring(data): + from PIL import Image + return Image.open(BytesIO(data)) + +def tostring(im, format, **options): + out = BytesIO() + im.save(out, format, **options) + return out.getvalue() + +def lena(mode="RGB", cache={}): + from PIL import Image + im = cache.get(mode) + if im is None: + if mode == "RGB": + im = Image.open("Images/lena.ppm") + elif mode == "F": + im = lena("L").convert(mode) + elif mode[:4] == "I;16": + im = lena("I").convert(mode) + else: + im = lena("RGB").convert(mode) + cache[mode] = im + return im + +def assert_image(im, mode, size, msg=None): + if mode is not None and im.mode != mode: + failure(msg or "got mode %r, expected %r" % (im.mode, mode)) + elif size is not None and im.size != size: + failure(msg or "got size %r, expected %r" % (im.size, size)) + else: + success() + +def assert_image_equal(a, b, msg=None): + if a.mode != b.mode: + failure(msg or "got mode %r, expected %r" % (a.mode, b.mode)) + elif a.size != b.size: + failure(msg or "got size %r, expected %r" % (a.size, b.size)) + elif a.tobytes() != b.tobytes(): + failure(msg or "got different content") + # generate better diff? + else: + success() + +def tempfile(template, *extra): + import os, sys + files = [] + for temp in (template,) + extra: + assert temp[:5] in ("temp.", "temp_") + root, name = os.path.split(sys.argv[0]) + name = temp[:4] + os.path.splitext(name)[0][4:] + name = name + "_%d" % len(_tempfiles) + temp[4:] + name = os.path.join(root, name) + files.append(name) + _tempfiles.extend(files) + return files[0] + +# test runner + +def run(): + global _target, _tests, run + import sys, traceback + _target = sys.modules["__main__"] + run = None # no need to run twice + tests = [] + for name, value in list(vars(_target).items()): + if name[:5] == "test_" and type(value) is type(success): + tests.append((value.__code__.co_firstlineno, name, value)) + tests.sort() # sort by line + for lineno, name, func in tests: + try: + _tests = [] + func() + for func, args in _tests: + func(*args) + except: + t, v, tb = sys.exc_info() + tb = tb.tb_next + if tb: + failure(frame=tb.tb_frame) + traceback.print_exception(t, v, tb) + else: + print("%s:%d: cannot call test function: %s" % ( + sys.argv[0], lineno, v)) + failure.count += 1 + +def yield_test(function, *args): + # collect delayed/generated tests + _tests.append((function, args)) + +def skip(msg=None): + import os + print("skip") + os._exit(0) # don't run exit handlers + +def _setup(): + global _logfile + def report(): + if run: + run() + if success.count and not failure.count: + print("ok") + # only clean out tempfiles if test passed + import os + for file in _tempfiles: + try: + os.remove(file) + except OSError: + pass # report? + if "--coverage" in sys.argv: + import coverage + coverage.stop() + # The coverage module messes up when used from inside an + # atexit handler. Do an explicit save to make sure that + # we actually flush the coverage cache. + coverage.the_coverage.save() + import atexit, sys + atexit.register(report) + if "--coverage" in sys.argv: + import coverage + coverage.start() + if "--log" in sys.argv: + _logfile = open("test.log", "a") + + +_setup() diff --git a/Tests/threaded_save.py b/Tests/threaded_save.py new file mode 100644 index 000000000..8162e713c --- /dev/null +++ b/Tests/threaded_save.py @@ -0,0 +1,56 @@ +from PIL import Image + +import sys, time +import io +import threading, queue + +try: + format = sys.argv[1] +except: + format = "PNG" + +im = Image.open("Images/lena.ppm") +im.load() + +queue = queue.Queue() + +result = [] + +class Worker(threading.Thread): + def run(self): + while 1: + im = queue.get() + if im is None: + queue.task_done() + sys.stdout.write("x") + break + f = io.BytesIO() + im.save(f, format, optimize=1) + data = f.getvalue() + result.append(len(data)) + im = Image.open(io.BytesIO(data)) + im.load() + sys.stdout.write(".") + queue.task_done() + +t0 = time.time() + +threads = 20 +jobs = 100 + +for i in range(threads): + w = Worker() + w.start() + +for i in range(jobs): + queue.put(im) + +for i in range(threads): + queue.put(None) + +queue.join() + +print() +print(time.time() - t0) +print(len(result), sum(result)) +print(result) diff --git a/Tests/versions.py b/Tests/versions.py new file mode 100644 index 000000000..a4e4a0bc2 --- /dev/null +++ b/Tests/versions.py @@ -0,0 +1,23 @@ +from PIL import Image + +def version(module, version): + v = getattr(module.core, version + "_version", None) + if v: + print(version, v) + +version(Image, "jpeglib") +version(Image, "zlib") + +try: + from PIL import ImageFont +except ImportError: + pass +else: + version(ImageFont, "freetype2") + +try: + from PIL import ImageCms +except ImportError: + pass +else: + version(ImageCms, "littlecms")