Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(397)

Side by Side Diff: Tools/ImageDiff/efl/ImageDiff.cpp

Issue 18145008: Remove Tools/ImageDiff folder which has only qt/gtk/efl implementations left. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | Tools/ImageDiff/gtk/ImageDiff.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com>
3 * Copyright (C) 2010 Igalia S.L.
4 * Copyright (C) 2011 ProFUSION Embedded Systems
5 * Copyright (C) 2011 Samsung Electronics
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "config.h"
33
34 #include <Ecore.h>
35 #include <Ecore_Evas.h>
36 #include <Evas.h>
37 #include <algorithm>
38 #include <cmath>
39 #include <cstdio>
40 #include <cstdlib>
41 #include <getopt.h>
42 #include <sys/stat.h>
43 #include <sys/types.h>
44 #include <unistd.h>
45 #include <wtf/OwnArrayPtr.h>
46 #include <wtf/OwnPtr.h>
47 #include <wtf/PassOwnPtr.h>
48 #include <wtf/PassRefPtr.h>
49 #include <wtf/efl/RefPtrEfl.h>
50
51 enum PixelComponent {
52 Red,
53 Green,
54 Blue,
55 Alpha
56 };
57
58 static OwnPtr<Ecore_Evas> gEcoreEvas;
59 static double gTolerance = 0;
60
61 static void abortWithErrorMessage(const char* errorMessage);
62
63 static unsigned char* pixelFromImageData(unsigned char* imageData, int rowStride , int x, int y)
64 {
65 return imageData + (y * rowStride) + (x << 2);
66 }
67
68 static Evas_Object* differenceImageFromDifferenceBuffer(Evas* evas, unsigned cha r* buffer, int width, int height)
69 {
70 Evas_Object* image = evas_object_image_filled_add(evas);
71 if (!image)
72 abortWithErrorMessage("could not create difference image");
73
74 evas_object_image_size_set(image, width, height);
75 evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888);
76
77 unsigned char* diffPixels = static_cast<unsigned char*>(evas_object_image_da ta_get(image, EINA_TRUE));
78 const int rowStride = evas_object_image_stride_get(image);
79 for (int x = 0; x < width; x++) {
80 for (int y = 0; y < height; y++) {
81 unsigned char* diffPixel = pixelFromImageData(diffPixels, rowStride, x, y);
82 diffPixel[Red] = diffPixel[Green] = diffPixel[Blue] = *buffer++;
83 diffPixel[Alpha] = 0xff;
84 }
85 }
86
87 evas_object_image_data_set(image, diffPixels);
88
89 return image;
90 }
91
92 static float computeDistanceBetweenPixelComponents(unsigned char actualComponent , unsigned char baseComponent)
93 {
94 return (actualComponent - baseComponent) / std::max<float>(255 - baseCompone nt, baseComponent);
95 }
96
97 static float computeDistanceBetweenPixelComponents(unsigned char* actualPixel, u nsigned char* basePixel, PixelComponent component)
98 {
99 return computeDistanceBetweenPixelComponents(actualPixel[component], basePix el[component]);
100 }
101
102 static float calculatePixelDifference(unsigned char* basePixel, unsigned char* a ctualPixel)
103 {
104 const float red = computeDistanceBetweenPixelComponents(actualPixel, basePix el, Red);
105 const float green = computeDistanceBetweenPixelComponents(actualPixel, baseP ixel, Green);
106 const float blue = computeDistanceBetweenPixelComponents(actualPixel, basePi xel, Blue);
107 const float alpha = computeDistanceBetweenPixelComponents(actualPixel, baseP ixel, Alpha);
108 return sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0f ;
109 }
110
111 static float calculateDifference(Evas_Object* baselineImage, Evas_Object* actual Image, RefPtr<Evas_Object>& differenceImage)
112 {
113 int width, height, baselineWidth, baselineHeight;
114 evas_object_image_size_get(actualImage, &width, &height);
115 evas_object_image_size_get(baselineImage, &baselineWidth, &baselineHeight);
116
117 if (width != baselineWidth || height != baselineHeight) {
118 printf("Error, test and reference image have different sizes.\n");
119 return 100; // Completely different.
120 }
121
122 OwnArrayPtr<unsigned char> diffBuffer = adoptArrayPtr(new unsigned char[widt h * height]);
123 if (!diffBuffer)
124 abortWithErrorMessage("could not create difference buffer");
125
126 const int actualRowStride = evas_object_image_stride_get(actualImage);
127 const int baseRowStride = evas_object_image_stride_get(baselineImage);
128 unsigned numberOfDifferentPixels = 0;
129 float totalDistance = 0;
130 float maxDistance = 0;
131 unsigned char* actualPixels = static_cast<unsigned char*>(evas_object_image_ data_get(actualImage, EINA_FALSE));
132 unsigned char* basePixels = static_cast<unsigned char*>(evas_object_image_da ta_get(baselineImage, EINA_FALSE));
133 unsigned char* currentDiffPixel = diffBuffer.get();
134
135 for (int x = 0; x < width; x++) {
136 for (int y = 0; y < height; y++) {
137 unsigned char* actualPixel = pixelFromImageData(actualPixels, actual RowStride, x, y);
138 unsigned char* basePixel = pixelFromImageData(basePixels, baseRowStr ide, x, y);
139
140 const float distance = calculatePixelDifference(basePixel, actualPix el);
141 *currentDiffPixel++ = static_cast<unsigned char>(distance * 255.0f);
142
143 if (distance >= 1.0f / 255.0f) {
144 ++numberOfDifferentPixels;
145 totalDistance += distance;
146 maxDistance = std::max<float>(maxDistance, distance);
147 }
148 }
149 }
150
151 // When using evas_object_image_data_get(), a complementary evas_object_data _set() must be
152 // issued to balance the reference count, even if the image hasn't been chan ged.
153 evas_object_image_data_set(baselineImage, basePixels);
154 evas_object_image_data_set(actualImage, actualPixels);
155
156 // Compute the difference as a percentage combining both the number of
157 // different pixels and their difference amount i.e. the average distance
158 // over the entire image
159 float difference = 0;
160 if (numberOfDifferentPixels)
161 difference = 100.0f * totalDistance / (height * width);
162 if (difference <= gTolerance)
163 difference = 0;
164 else {
165 difference = roundf(difference * 100.0f) / 100.0f;
166 difference = std::max(difference, 0.01f); // round to 2 decimal places
167
168 differenceImage = adoptRef(differenceImageFromDifferenceBuffer(evas_obje ct_evas_get(baselineImage), diffBuffer.get(), width, height));
169 }
170
171 return difference;
172 }
173
174 static int getTemporaryFile(char *fileName, size_t fileNameLength)
175 {
176 char* tempDirectory = getenv("TMPDIR");
177 if (!tempDirectory)
178 tempDirectory = getenv("TEMP");
179
180 if (tempDirectory)
181 snprintf(fileName, fileNameLength, "%s/ImageDiffXXXXXX.png", tempDirecto ry);
182 else {
183 #if __linux__
184 strcpy(fileName, "/dev/shm/ImageDiffXXXXXX.png");
185 const int fileDescriptor = mkstemps(fileName, sizeof(".png") - 1);
186 if (fileDescriptor >= 0)
187 return fileDescriptor;
188 #endif // __linux__
189
190 strcpy(fileName, "ImageDiffXXXXXX.png");
191 }
192
193 return mkstemps(fileName, sizeof(".png") - 1);
194 }
195
196 static void printImage(Evas_Object* image)
197 {
198 char fileName[PATH_MAX];
199
200 const int tempImageFd = getTemporaryFile(fileName, PATH_MAX);
201 if (tempImageFd == -1)
202 abortWithErrorMessage("could not create temporary file");
203
204 evas_render(evas_object_evas_get(image));
205
206 if (evas_object_image_save(image, fileName, 0, 0)) {
207 struct stat fileInfo;
208 if (!stat(fileName, &fileInfo)) {
209 printf("Content-Length: %ld\n", fileInfo.st_size);
210 fflush(stdout);
211
212 unsigned char buffer[2048];
213 ssize_t bytesRead;
214 while ((bytesRead = read(tempImageFd, buffer, sizeof(buffer))) > 0) {
215 ssize_t bytesWritten = 0;
216 ssize_t count;
217 do {
218 if ((count = write(1, buffer + bytesWritten, bytesRead - byt esWritten)) <= 0)
219 break;
220 bytesWritten += count;
221 } while (bytesWritten < bytesRead);
222 }
223 }
224 }
225 close(tempImageFd);
226 unlink(fileName);
227 }
228
229 static void printImageDifferences(Evas_Object* baselineImage, Evas_Object* actua lImage)
230 {
231 RefPtr<Evas_Object> differenceImage;
232 const float difference = calculateDifference(baselineImage, actualImage, dif ferenceImage);
233
234 if (difference > 0.0f) {
235 if (differenceImage)
236 printImage(differenceImage.get());
237
238 printf("diff: %01.2f%% failed\n", difference);
239 } else
240 printf("diff: %01.2f%% passed\n", difference);
241 }
242
243 static void resizeEcoreEvasIfNeeded(Evas_Object* image)
244 {
245 int newWidth, newHeight;
246 evas_object_image_size_get(image, &newWidth, &newHeight);
247
248 int currentWidth, currentHeight;
249 ecore_evas_screen_geometry_get(gEcoreEvas.get(), 0, 0, &currentWidth, &curre ntHeight);
250
251 if (newWidth > currentWidth)
252 currentWidth = newWidth;
253 if (newHeight > currentHeight)
254 currentHeight = newHeight;
255
256 ecore_evas_resize(gEcoreEvas.get(), currentWidth, currentHeight);
257 }
258
259 static PassRefPtr<Evas_Object> readImageFromStdin(Evas* evas, long imageSize)
260 {
261 OwnArrayPtr<unsigned char> imageBuffer = adoptArrayPtr(new unsigned char[ima geSize]);
262 if (!imageBuffer)
263 abortWithErrorMessage("cannot allocate image");
264
265 const size_t bytesRead = fread(imageBuffer.get(), 1, imageSize, stdin);
266 if (!bytesRead)
267 return PassRefPtr<Evas_Object>();
268
269 Evas_Object* image = evas_object_image_filled_add(evas);
270 evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888);
271 evas_object_image_memfile_set(image, imageBuffer.get(), bytesRead, 0, 0);
272
273 resizeEcoreEvasIfNeeded(image);
274
275 return adoptRef(image);
276 }
277
278 static bool parseCommandLineOptions(int argc, char** argv)
279 {
280 static const option options[] = {
281 { "tolerance", required_argument, 0, 't' },
282 { 0, 0, 0, 0 }
283 };
284 int option;
285
286 while ((option = getopt_long(argc, (char* const*)argv, "t:", options, 0)) != -1) {
287 switch (option) {
288 case 't':
289 gTolerance = atof(optarg);
290 break;
291 case '?':
292 case ':':
293 return false;
294 }
295 }
296
297 return true;
298 }
299
300 static void shutdownEfl()
301 {
302 ecore_evas_shutdown();
303 ecore_shutdown();
304 evas_shutdown();
305 }
306
307 static void abortWithErrorMessage(const char* errorMessage)
308 {
309 shutdownEfl();
310
311 printf("Error, %s.\n", errorMessage);
312 exit(EXIT_FAILURE);
313 }
314
315 static Evas* initEfl()
316 {
317 evas_init();
318 ecore_init();
319 ecore_evas_init();
320
321 gEcoreEvas = adoptPtr(ecore_evas_buffer_new(1, 1));
322 Evas* evas = ecore_evas_get(gEcoreEvas.get());
323 if (!evas)
324 abortWithErrorMessage("could not create Ecore_Evas buffer");
325
326 return evas;
327 }
328
329 int main(int argc, char* argv[])
330 {
331 if (!parseCommandLineOptions(argc, argv))
332 return EXIT_FAILURE;
333
334 Evas* evas = initEfl();
335
336 RefPtr<Evas_Object> actualImage;
337 RefPtr<Evas_Object> baselineImage;
338
339 char buffer[2048];
340 while (fgets(buffer, sizeof(buffer), stdin)) {
341 char* contentLengthStart = strstr(buffer, "Content-Length: ");
342 if (!contentLengthStart)
343 continue;
344 long imageSize;
345 if (sscanf(contentLengthStart, "Content-Length: %ld", &imageSize) == 1) {
346 if (imageSize <= 0)
347 abortWithErrorMessage("image size must be specified");
348
349 if (!actualImage)
350 actualImage = readImageFromStdin(evas, imageSize);
351 else if (!baselineImage) {
352 baselineImage = readImageFromStdin(evas, imageSize);
353
354 printImageDifferences(baselineImage.get(), actualImage.get());
355
356 actualImage.clear();
357 baselineImage.clear();
358 }
359 }
360
361 fflush(stdout);
362 }
363
364 gEcoreEvas.clear(); // Make sure ecore_evas_free is called before the EFL ar e shut down
365
366 shutdownEfl();
367 return EXIT_SUCCESS;
368 }
OLDNEW
« no previous file with comments | « no previous file | Tools/ImageDiff/gtk/ImageDiff.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698