gimp/libgimp/tests/pygimp/utils.py

154 lines
6.7 KiB
Python
Executable File

#!/usr/bin/env python3
import gi
from gi.repository import Babl, Gegl, Gimp, Gio
import inspect
import re
import os
import sys
import tempfile
import urllib.request
gimp_test_filename = ''
def gimp_assert(subtest_name, test, image=None, outpath=None, cmp_data_path=None):
'''
Please call me like this, for instance, if I were testing if gimp_image_new()
succeeded:
gimp_assert("gimp_image_new()", image is not None)
'''
if not test:
frames = inspect.getouterframes(inspect.currentframe())
sys.stderr.write("\n**** START FAILED SUBTEST *****\n")
sys.stderr.write("ERROR: {} - line {}: {}\n".format(gimp_test_filename,
frames[1].lineno,
subtest_name))
if image is not None and outpath is not None:
Gimp.file_save(Gimp.RunMode.NONINTERACTIVE, image,
Gio.file_new_for_path(outpath),
None)
sys.stderr.write(" Test file saved as: {}\n".format(outpath))
if outpath[-4:] == '.xcf':
data_path = outpath[:-4] + '.data'
Gimp.file_save(Gimp.RunMode.NONINTERACTIVE, image,
Gio.file_new_for_path(data_path),
None)
sys.stderr.write(" Render file saved as: {}\n".format(data_path))
if cmp_data_path is not None:
cmp_img = None
img_width = image.get_width()
img_height = image.get_height()
proc = Gimp.get_pdb().lookup_procedure('file-raw-load')
config = proc.create_config()
config.set_property('run-mode', Gimp.RunMode.NONINTERACTIVE)
config.set_property('width', img_width)
config.set_property('height', img_height)
config.set_property('pixel-format', 'rgba-8bpc')
cmp_data_uri = None
result = None
if os.path.isfile(cmp_data_path):
config.set_property('file', Gio.file_new_for_path(cmp_data_path))
result = proc.run(config)
else:
cmp_data_basename = os.path.basename(cmp_data_path)
cmp_data_uri = os.path.join('https://download.gimp.org/users/jehan/unit-tests/', cmp_data_basename)
# Unfortunately this doesn't work with a remote file directly.
# TODO.
#config.set_property('file', Gio.file_new_for_uri(cmp_data_uri))
try:
with urllib.request.urlopen(cmp_data_uri) as remote:
with tempfile.NamedTemporaryFile() as tmpfile:
tmpfile.write(remote.read())
config.set_property('file', Gio.file_new_for_path(tmpfile.name))
result = proc.run(config)
tmpfile.close()
except urllib.error.HTTPError:
pass
status = None
if result is not None:
status = result.index(0)
if status == Gimp.PDBStatusType.SUCCESS:
cmp_img = result.index(1)
elif os.path.isfile(cmp_data_path):
sys.stderr.write(" Failed to load for statistical comparison: {}\n".format(cmp_data_path))
if cmp_img is None:
sys.stderr.write(" To get statistical comparison, store reference data in: {}\n".format(cmp_data_path))
else:
layer = image.merge_visible_layers(Gimp.MergeType.CLIP_TO_IMAGE)
buffer = layer.get_buffer()
rect = buffer.get_extent()
data = buffer.get(rect, 1.0, "R'G'B'A u8", Gegl.AbyssPolicy.BLACK)
cmp_buffer = cmp_img.get_layers()[0].get_buffer()
cmp_data = cmp_buffer.get(rect, 1.0, "R'G'B'A u8", Gegl.AbyssPolicy.BLACK)
sys.stderr.write(" Comparison with {}:\n".format(cmp_data_path if cmp_data_uri is None else cmp_data_uri))
n_diff_pixels = 0
n_perceptually_identical = 0
n_one_off = 0
num_samples = 4
num_identical_samples = 4
num_one_off_samples = 4
for x in range(img_width):
for y in range(img_height):
pos = (x + y * img_width) * 4
r1 = data[pos]
r2 = cmp_data[pos]
g1 = data[pos + 1]
g2 = cmp_data[pos + 1]
b1 = data[pos + 2]
b2 = cmp_data[pos + 2]
a1 = data[pos + 3]
a2 = cmp_data[pos + 3]
if r1 != r2 or g1 != g2 or b1 != b2 or a1 != a2:
c1 = Gegl.Color.new("black")
c1.set_rgba_with_space(r1/255, g1/255, b1/255, a1/255, Babl.space("sRGB"))
c2 = Gegl.Color.new("black")
c2.set_rgba_with_space(r2/256, g2/255, b2/255, a2/255, Babl.space("sRGB"))
n_diff_pixels += 1
if Gimp.color_is_perceptually_identical(c1, c2):
if num_identical_samples > 0:
sys.stderr.write(" - Example of differing pixel (yet perceptually identical) at {}x{}: ({}, {}, {}, {}) vs. ({}, {}, {}, {})\n".format(x, y, r1, g1, b1, a1, r2, g2, b2, a2))
num_identical_samples -= 1
n_perceptually_identical += 1
elif abs(r1 - r2) < 2 and abs(g1 - g2) < 2 and abs(b1 - b2) < 2 and abs(a1 - a2) < 2:
if num_one_off_samples > 0:
sys.stderr.write(" - Example of differing pixel (off-by-one) at {}x{}: ({}, {}, {}, {}) vs. ({}, {}, {}, {})\n".format(x, y, r1, g1, b1, a1, r2, g2, b2, a2))
num_one_off_samples -= 1
n_one_off += 1
else:
if num_samples > 0:
sys.stderr.write(" - Example of differing pixel at {}x{}: ({}, {}, {}, {}) vs. ({}, {}, {}, {})\n".format(x, y, r1, g1, b1, a1, r2, g2, b2, a2))
num_samples -= 1
sys.stderr.write(" - {} pixels are different\n".format(n_diff_pixels))
sys.stderr.write(" - Among them {} different pixels are perceptually identical\n".format(n_perceptually_identical))
sys.stderr.write(" - Among them {} different pixels are off by one\n".format(n_one_off))
if n_diff_pixels == n_perceptually_identical + n_one_off:
sys.stderr.write(" - All different pixels are either perceptually identical or off by one\n")
cmp_img.delete()
if image is not None:
image.delete()
sys.stderr.write("***** END FAILED SUBTEST ******\n\n")
assert test
def gimp_c_assert(c_filename, error_msg, test):
'''
This is called by the platform only, and print out the GError message from the
C test plug-in.
'''
if not test:
sys.stderr.write("\n**** START FAILED SUBTEST *****\n")
sys.stderr.write("ERROR: {}: {}\n".format(c_filename, error_msg))
sys.stderr.write("***** END FAILED SUBTEST ******\n\n")
assert test