-
Notifications
You must be signed in to change notification settings - Fork 228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix issue when comparing images with different sizes #292
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -88,12 +88,39 @@ def _clean(self): | |
shutil.rmtree(self._output) | ||
os.makedirs(self._output) | ||
|
||
def _draw_diff_outline(self, failure_file, diff, image_to_draw_on): | ||
draw = ImageDraw.Draw(image_to_draw_on) | ||
draw.rectangle(list(diff), outline=(255, 0, 0)) | ||
image_to_draw_on.save(failure_file) | ||
|
||
def _is_image_same(self, file1, file2, failure_file): | ||
with Image.open(file1) as im1, Image.open(file2) as im2: | ||
diff_image = ImageChops.difference(im1, im2) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So it turned out that This is definately not a bug in |
||
try: | ||
diff = diff_image.getbbox() | ||
if diff is None: | ||
if (im1.size != im2.size) or (im1.getbbox() != im2.getbbox()): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So in case there is no difference reported by If their size differ, but otherwise If one image is not a direct subset of the other |
||
# First image is longer than the second | ||
if im1.getbbox()[3] > im2.getbbox()[3]: | ||
diff = [(0, im2.getbbox()[3]), (im1.getbbox()[2]-1, im1.getbbox()[3] - 1)] | ||
self._draw_diff_outline(failure_file, diff, im1) | ||
|
||
# First image is shorter than the first | ||
if im1.getbbox()[3] < im2.getbbox()[3]: | ||
diff = [(0, im1.getbbox()[3]), (im2.getbbox()[2]-1, im2.getbbox()[3] - 1)] | ||
self._draw_diff_outline(failure_file, diff, im2) | ||
|
||
# First image is wider than the second | ||
if im1.getbbox()[2] > im2.getbbox()[2]: | ||
diff = [(im2.getbbox()[2], 0), (im1.getbbox()[2]-1, im1.getbbox()[3] - 1)] | ||
self._draw_diff_outline(failure_file, diff, im1) | ||
|
||
# First image is narrower than the first | ||
if im1.getbbox()[2] < im2.getbbox()[2]: | ||
diff = [(im1.getbbox()[2], 0), (im2.getbbox()[2]-1, im2.getbbox()[3] - 1)] | ||
self._draw_diff_outline(failure_file, diff, im2) | ||
|
||
return False | ||
return True | ||
else: | ||
if failure_file: | ||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -243,6 +243,221 @@ def test_verify_failure(self): | |||||||
self.assertEqual((0, 128, 0, 255), im.getpixel((1, 1))) | ||||||||
self.assertEqual((0, 128, 0, 255), im.getpixel((9, 1))) | ||||||||
|
||||||||
def test_verify_different_sizes_longer(self): | ||||||||
self.create_temp_image("foobar.png", (10, 10), "blue") | ||||||||
self.make_metadata( | ||||||||
# language=json | ||||||||
""" | ||||||||
[ | ||||||||
{ | ||||||||
"name": "foobar", | ||||||||
"tileWidth": 1, | ||||||||
"tileHeight": 1 | ||||||||
} | ||||||||
]""" | ||||||||
) | ||||||||
|
||||||||
self.recorder.record() | ||||||||
os.unlink(join(self.inputdir, "foobar.png")) | ||||||||
self.create_temp_image("foobar.png", (10, 20), "blue") | ||||||||
|
||||||||
try: | ||||||||
self.recorder.verify() | ||||||||
self.fail("expected exception") | ||||||||
except VerifyError: | ||||||||
pass # expected | ||||||||
|
||||||||
self.assertTrue(os.path.exists(join(self.failureDir, "foobar_actual.png"))) | ||||||||
self.assertTrue(os.path.exists(join(self.failureDir, "foobar_expected.png"))) | ||||||||
self.assertTrue(os.path.exists(join(self.failureDir, "foobar_diff.png"))) | ||||||||
|
||||||||
# check colored diff | ||||||||
with Image.open(join(self.failureDir, "foobar_diff.png")) as im: | ||||||||
(w, h) = im.size | ||||||||
self.assertEqual(10, w) | ||||||||
self.assertEqual(20, h) | ||||||||
|
||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((0, 0))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((9, 0))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((5, 0))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((0, 5))) | ||||||||
|
||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((0, 9))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((9, 9))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((5, 9))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((5, 5))) | ||||||||
|
||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((0, 10))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((9, 10))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((5, 10))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((0, 15))) | ||||||||
|
||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((0, 19))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((9, 19))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((5, 19))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((9, 15))) | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While debugging tests adding
Suggested change
It requires
Comment on lines
+280
to
+298
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of checking all pixels for the border I think we can get away with just checking the four corners (here and in the other tests) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You mean checking the corner pixels of the box? I recall that initially I had started with this approach, just checking the four corner pixels, but then during the implementation when I had made a mistake, and the rectange got wider, and lthe right side of the box where rendered ourside of the image, the test still had passed, as the top and bottom lines where still covering all four corner pixels. This is why I had decided to check the pixels in the middle of the lines as well, as this approach would catch that mistake. I would suggest to keep these checks to make sure this mistake is covered. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, makes sense. We just published a new version that partially addresses the issues this PR fixes, do you mind rebasing onto that? It seems like |
||||||||
|
||||||||
def test_verify_different_sizes_shorter(self): | ||||||||
self.create_temp_image("foobar.png", (10, 20), "blue") | ||||||||
self.make_metadata( | ||||||||
# language=json | ||||||||
""" | ||||||||
[ | ||||||||
{ | ||||||||
"name": "foobar", | ||||||||
"tileWidth": 1, | ||||||||
"tileHeight": 1 | ||||||||
} | ||||||||
]""" | ||||||||
) | ||||||||
|
||||||||
self.recorder.record() | ||||||||
os.unlink(join(self.inputdir, "foobar.png")) | ||||||||
self.create_temp_image("foobar.png", (10, 10), "blue") | ||||||||
|
||||||||
try: | ||||||||
self.recorder.verify() | ||||||||
self.fail("expected exception") | ||||||||
except VerifyError: | ||||||||
pass # expected | ||||||||
|
||||||||
self.assertTrue(os.path.exists(join(self.failureDir, "foobar_actual.png"))) | ||||||||
self.assertTrue(os.path.exists(join(self.failureDir, "foobar_expected.png"))) | ||||||||
self.assertTrue(os.path.exists(join(self.failureDir, "foobar_diff.png"))) | ||||||||
|
||||||||
# check colored diff | ||||||||
with Image.open(join(self.failureDir, "foobar_diff.png")) as im: | ||||||||
(w, h) = im.size | ||||||||
self.assertEqual(10, w) | ||||||||
self.assertEqual(20, h) | ||||||||
|
||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((0, 0))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((9, 0))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((5, 0))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((0, 5))) | ||||||||
|
||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((0, 9))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((9, 9))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((5, 9))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((5, 5))) | ||||||||
|
||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((0, 10))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((9, 10))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((5, 10))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((0, 15))) | ||||||||
|
||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((0, 19))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((9, 19))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((5, 19))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((9, 15))) | ||||||||
|
||||||||
def test_verify_different_sizes_wider(self): | ||||||||
self.create_temp_image("foobar.png", (10, 10), "blue") | ||||||||
self.make_metadata( | ||||||||
# language=json | ||||||||
""" | ||||||||
[ | ||||||||
{ | ||||||||
"name": "foobar", | ||||||||
"tileWidth": 1, | ||||||||
"tileHeight": 1 | ||||||||
} | ||||||||
]""" | ||||||||
) | ||||||||
|
||||||||
self.recorder.record() | ||||||||
os.unlink(join(self.inputdir, "foobar.png")) | ||||||||
self.create_temp_image("foobar.png", (20, 10), "blue") | ||||||||
|
||||||||
try: | ||||||||
self.recorder.verify() | ||||||||
self.fail("expected exception") | ||||||||
except VerifyError: | ||||||||
pass # expected | ||||||||
|
||||||||
self.assertTrue(os.path.exists(join(self.failureDir, "foobar_actual.png"))) | ||||||||
self.assertTrue(os.path.exists(join(self.failureDir, "foobar_expected.png"))) | ||||||||
self.assertTrue(os.path.exists(join(self.failureDir, "foobar_diff.png"))) | ||||||||
|
||||||||
# check colored diff | ||||||||
with Image.open(join(self.failureDir, "foobar_diff.png")) as im: | ||||||||
(w, h) = im.size | ||||||||
self.assertEqual(20, w) | ||||||||
self.assertEqual(10, h) | ||||||||
|
||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((0, 0))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((9, 0))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((5, 0))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((0, 5))) | ||||||||
|
||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((0, 0))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((9, 9))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((5, 9))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((5, 5))) | ||||||||
|
||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((10, 0))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((10, 9))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((10, 5))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((15, 0))) | ||||||||
|
||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((19, 0))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((19, 9))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((19, 5))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((15, 9))) | ||||||||
|
||||||||
def test_verify_different_sizes_narrower(self): | ||||||||
self.create_temp_image("foobar.png", (20, 10), "blue") | ||||||||
self.make_metadata( | ||||||||
# language=json | ||||||||
""" | ||||||||
[ | ||||||||
{ | ||||||||
"name": "foobar", | ||||||||
"tileWidth": 1, | ||||||||
"tileHeight": 1 | ||||||||
} | ||||||||
]""" | ||||||||
) | ||||||||
|
||||||||
self.recorder.record() | ||||||||
os.unlink(join(self.inputdir, "foobar.png")) | ||||||||
self.create_temp_image("foobar.png", (10, 10), "blue") | ||||||||
|
||||||||
try: | ||||||||
self.recorder.verify() | ||||||||
self.fail("expected exception") | ||||||||
except VerifyError: | ||||||||
pass # expected | ||||||||
|
||||||||
self.assertTrue(os.path.exists(join(self.failureDir, "foobar_actual.png"))) | ||||||||
self.assertTrue(os.path.exists(join(self.failureDir, "foobar_expected.png"))) | ||||||||
self.assertTrue(os.path.exists(join(self.failureDir, "foobar_diff.png"))) | ||||||||
|
||||||||
# check colored diff | ||||||||
with Image.open(join(self.failureDir, "foobar_diff.png")) as im: | ||||||||
(w, h) = im.size | ||||||||
self.assertEqual(20, w) | ||||||||
self.assertEqual(10, h) | ||||||||
|
||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((0, 0))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((9, 0))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((5, 0))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((0, 5))) | ||||||||
|
||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((0, 0))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((9, 9))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((5, 9))) | ||||||||
self.assertEqual((0, 0, 255, 255), im.getpixel((5, 5))) | ||||||||
|
||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((10, 0))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((10, 9))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((10, 5))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((15, 0))) | ||||||||
|
||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((19, 0))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((19, 9))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((19, 5))) | ||||||||
self.assertEqual((255, 0, 0, 255), im.getpixel((15, 9))) | ||||||||
|
||||||||
if __name__ == "__main__": | ||||||||
unittest.main() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Utility to highlight changed area on the larger screenshot