1 package com.atlassian.selenium.visualcomparison.utils;
2
3 import java.awt.image.BufferedImage;
4 import java.io.IOException;
5 import java.util.ArrayList;
6 import java.util.List;
7
8 public class ScreenshotDiffer
9 {
10 public ScreenshotDiff diff(Screenshot oldScreen, Screenshot newScreen,
11 List<BoundingBox> ignoreAreas, boolean ignoreSingleLines) throws IOException
12 {
13 final BufferedImage thisImage = oldScreen.getImage();
14 final BufferedImage otherImage = newScreen.getImage();
15 final int thisWidth = thisImage.getWidth();
16 final int thisHeight = thisImage.getHeight();
17 final int otherWidth = otherImage.getWidth();
18 final int otherHeight = otherImage.getHeight();
19 final int maxWidth = Math.max(thisWidth, otherWidth);
20 final int maxHeight = Math.max(thisHeight, otherHeight);
21
22
23 BufferedImage diffImage = new BufferedImage(maxWidth, maxHeight, BufferedImage.TYPE_INT_RGB);
24 ArrayList<BoundingBox> boxes = new ArrayList<BoundingBox>();
25 for (int x = 0; x < maxWidth; x++)
26 {
27 for (int y = 0; y < maxHeight; y++)
28 {
29
30
31 if ((x < thisWidth) && (x < otherWidth) && (y < thisHeight) && (y < otherHeight))
32 {
33 int thisPixel = thisImage.getRGB(x, y);
34 int otherPixel = otherImage.getRGB(x, y);
35 if (shouldIgnorePixel (x, y, ignoreAreas) || thisPixel == otherPixel)
36 {
37
38 diffImage.setRGB(x, y, thisPixel);
39 }
40 else
41 {
42
43 diffImage.setRGB(x, y, 0xFF0000);
44
45
46 boolean foundBox = false;
47 for (BoundingBox box : boxes)
48 {
49 if (box.isNear(x, y))
50 {
51 box.merge(x, y);
52 foundBox = true;
53 }
54 }
55
56 if (!foundBox)
57 {
58 boxes.add(new BoundingBox(x, y));
59 }
60 }
61 }
62 else
63 {
64
65
66 diffImage.setRGB(x, y, 0x000000);
67 }
68 }
69 }
70 if (ignoreSingleLines)
71 {
72 BoundingBox.deleteSingleLineBoxes(boxes);
73 }
74
75 BoundingBox.mergeOverlappingBoxes(boxes);
76
77 thisImage.flush();
78 otherImage.flush();
79
80 return new ScreenshotDiff(oldScreen, newScreen, oldScreen.getId(), oldScreen.getResolution(), diffImage, boxes, ignoreAreas);
81 }
82
83 private boolean shouldIgnorePixel (int x, int y, List<BoundingBox> ignoreAreas)
84 {
85 if (ignoreAreas == null)
86 {
87 return false;
88 }
89 for (BoundingBox ignoreArea : ignoreAreas)
90 {
91 if (ignoreArea.contains (x,y))
92 {
93 return true;
94 }
95 }
96 return false;
97 }
98 }