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