1 package com.atlassian.selenium.visualcomparison.utils;
2
3 import com.atlassian.selenium.visualcomparison.VisualComparableClient;
4
5 import javax.imageio.ImageIO;
6 import java.awt.image.BufferedImage;
7 import java.io.File;
8 import java.io.IOException;
9 import java.util.ArrayList;
10 import java.util.List;
11
12 public class Screenshot implements Comparable<Screenshot>
13 {
14 private ScreenResolution resolution;
15 private String id;
16 private File file;
17
18 public Screenshot(VisualComparableClient client, String id, String imageDir, ScreenResolution resolution) throws IOException
19 {
20 final String filePath = imageDir + "/" + id + "." + resolution + ".png";
21 client.captureEntirePageScreenshot(filePath);
22 init(filePath, id, resolution);
23 }
24
25 public Screenshot(File file) throws IOException
26 {
27 String[] fileNameParts = file.getName().split("\\.");
28 if (fileNameParts.length != 3)
29 {
30 throw new IOException("Invalid screenshot name - " + file.getName());
31 }
32 init(file.getAbsolutePath(), fileNameParts[0], new ScreenResolution(fileNameParts[1]));
33 }
34
35 public static String generateFileName(String id, ScreenResolution resolution)
36 {
37 return id.replace('.', '-') + "." + resolution + ".png";
38 }
39
40 private void init(String filePath, String id, ScreenResolution resolution) throws IOException
41 {
42 this.id = id;
43 this.resolution = resolution;
44 this.file = new File(filePath);
45 }
46
47 public String getFileName()
48 {
49 return file.getName();
50 }
51
52 public BufferedImage getImage() throws IOException
53 {
54 return ImageIO.read(file);
55 }
56
57 public int compareTo(Screenshot other)
58 {
59 int result = this.id.compareTo(other.id);
60 if (result != 0) {
61 return result;
62 }
63 return this.resolution.compareTo(other.resolution);
64 }
65
66 public ScreenshotDiff getDiff(Screenshot other) throws IOException
67 {
68 return getDiff (other, null, false);
69 }
70
71 public ScreenshotDiff getDiff(Screenshot other, List<BoundingBox> ignoreAreas, boolean ignoreSingleLines) throws IOException
72 {
73 final BufferedImage thisImage = getImage();
74 final BufferedImage otherImage = other.getImage();
75 final int thisWidth = thisImage.getWidth();
76 final int thisHeight = thisImage.getHeight();
77 final int otherWidth = otherImage.getWidth();
78 final int otherHeight = otherImage.getHeight();
79 final int maxWidth = Math.max(thisWidth, otherWidth);
80 final int maxHeight = Math.max(thisHeight, otherHeight);
81
82
83 BufferedImage diffImage = new BufferedImage(maxWidth, maxHeight, BufferedImage.TYPE_INT_RGB);
84 ArrayList<BoundingBox> boxes = new ArrayList<BoundingBox>();
85 for (int x = 0; x < maxWidth; x++)
86 {
87 for (int y = 0; y < maxHeight; y++)
88 {
89
90
91 if ((x < thisWidth) && (x < otherWidth) && (y < thisHeight) && (y < otherHeight))
92 {
93 int thisPixel = thisImage.getRGB(x, y);
94 int otherPixel = otherImage.getRGB(x, y);
95 if (shouldIgnorePixel (x, y, ignoreAreas) || thisPixel == otherPixel)
96 {
97
98 diffImage.setRGB(x, y, thisPixel);
99 }
100 else
101 {
102
103 diffImage.setRGB(x, y, 0xFF0000);
104
105
106 boolean foundBox = false;
107 for (BoundingBox box : boxes)
108 {
109 if (box.isNear(x, y))
110 {
111 box.merge(x, y);
112 foundBox = true;
113 }
114 }
115
116 if (!foundBox)
117 {
118 boxes.add(new BoundingBox(x, y));
119 }
120 }
121 }
122 else
123 {
124
125
126 diffImage.setRGB(x, y, 0x000000);
127 }
128 }
129 }
130 if (ignoreSingleLines)
131 {
132 BoundingBox.deleteSingleLineBoxes(boxes);
133 }
134
135 BoundingBox.mergeOverlappingBoxes(boxes);
136
137 thisImage.flush();
138 otherImage.flush();
139
140 return new ScreenshotDiff(this, other, this.id, this.resolution, diffImage, boxes, ignoreAreas);
141 }
142
143 private boolean shouldIgnorePixel (int x, int y, List<BoundingBox> ignoreAreas)
144 {
145 if (ignoreAreas == null)
146 {
147 return false;
148 }
149 for (BoundingBox ignoreArea : ignoreAreas)
150 {
151 if (ignoreArea.contains (x,y))
152 {
153 return true;
154 }
155 }
156 return false;
157 }
158 }