| Differences between
and this patch
- Tools/ChangeLog +19 lines
Lines 1-3 Tools/ChangeLog_sec1
1
2011-06-02  Leandro Pereira  <leandro@profusion.mobi>
2
3
        Reviewed by NOBODY (OOPS!).
4
5
        [EFL] Add ImageDiff implementation.
6
        Build system changes will be made as soon as the complete
7
        DumpRenderTree implementation is upstreamed.
8
9
        * DumpRenderTree/efl: Added.
10
        * DumpRenderTree/efl/ImageDiff.cpp: Added.
11
        (differenceImageFromDifferenceBuffer):
12
        (calculateDifference):
13
        (getTemporaryFile):
14
        (printImage):
15
        (printImageDifferences):
16
        (readImageFromStdin):
17
        (parseCommandLineOptions):
18
        (main):
19
1
2011-06-02  Dimitri Glazkov  <dglazkov@chromium.org>
20
2011-06-02  Dimitri Glazkov  <dglazkov@chromium.org>
2
21
3
        Unreviewed, rolling out r87926.
22
        Unreviewed, rolling out r87926.
- Tools/DumpRenderTree/efl/ImageDiff.cpp +337 lines
Line 0 Tools/DumpRenderTree/efl/ImageDiff.cpp_sec1
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 <Ecore.h>
33
#include <Ecore_Evas.h>
34
#include <Evas.h>
35
#include <algorithm>
36
#include <cmath>
37
#include <cstdio>
38
#include <cstring>
39
#include <getopt.h>
40
#include <sys/stat.h>
41
#include <sys/types.h>
42
#include <unistd.h>
43
44
using namespace std;
45
46
static double tolerance = 0;
47
48
Evas_Object* differenceImageFromDifferenceBuffer(Evas* evas, unsigned char* buffer, int width, int height)
49
{
50
    Evas_Object* image = evas_object_image_filled_add(evas);
51
    if (!image)
52
        return image;
53
54
    evas_object_image_size_set(image, width, height);
55
    evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888);
56
    unsigned char* diffPixels = static_cast<unsigned char*>(evas_object_image_data_get(image, EINA_TRUE));
57
    const int rowStride = evas_object_image_stride_get(image);
58
59
    for (int x = 0; x < width; x++) {
60
        for (int y = 0; y < height; y++) {
61
            unsigned char* diffPixel = diffPixels + (y * rowStride) + (x * 4);
62
            diffPixel[0] = diffPixel[1] = diffPixel[2] = *buffer++;
63
            diffPixel[3] = 0xff; // Alpha channel
64
        }
65
    }
66
67
    return image;
68
}
69
70
float calculateDifference(Evas_Object* baselineImage, Evas_Object* actualImage, Evas_Object** differenceImage)
71
{
72
    int width, height, baselineWidth, baselineHeight;
73
    evas_object_image_size_get(actualImage, &width, &height);
74
    evas_object_image_size_get(baselineImage, &baselineWidth, &baselineHeight);
75
76
    if (width != baselineWidth
77
        || height != baselineHeight
78
        || evas_object_image_alpha_get(actualImage) != evas_object_image_alpha_get(baselineImage)) {
79
        printf("Error, test and reference image have different properties.\n");
80
        return 100; // Completely different.
81
    }
82
    evas_object_image_colorspace_set(actualImage, EVAS_COLORSPACE_ARGB8888);
83
    evas_object_image_colorspace_set(baselineImage, EVAS_COLORSPACE_ARGB8888);
84
85
    const int numberOfChannels = 4; // Alpha + R + G + B
86
    const int actualRowStride = evas_object_image_stride_get(actualImage);
87
    const int baseRowStride = evas_object_image_stride_get(baselineImage);
88
    float count = 0;
89
    float sum = 0;
90
    float maxDistance = 0;
91
    unsigned char* actualPixels = static_cast<unsigned char*>(evas_object_image_data_get(actualImage, EINA_FALSE));
92
    unsigned char* basePixels = static_cast<unsigned char*>(evas_object_image_data_get(baselineImage, EINA_FALSE));
93
    unsigned char* diffBuffer = static_cast<unsigned char*>(malloc(width * height));
94
    unsigned char* currentDiffPixel = diffBuffer;
95
96
    if (!diffBuffer) {
97
        printf("Error, couldn't allocate difference buffer.\n");
98
        return 100;
99
    }
100
101
    for (int x = 0; x < width; x++) {
102
        for (int y = 0; y < height; y++) {
103
            unsigned char* actualPixel = actualPixels + (y * actualRowStride) + (x * numberOfChannels);
104
            unsigned char* basePixel = basePixels + (y * baseRowStride) + (x * numberOfChannels);
105
106
            float red = (actualPixel[0] - basePixel[0]) / max<float>(255 - basePixel[0], basePixel[0]);
107
            float green = (actualPixel[1] - basePixel[1]) / max<float>(255 - basePixel[1], basePixel[1]);
108
            float blue = (actualPixel[2] - basePixel[2]) / max<float>(255 - basePixel[2], basePixel[2]);
109
            float alpha = (actualPixel[3] - basePixel[3]) / max<float>(255 - basePixel[3], basePixel[3]);
110
            float distance = sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0f;
111
112
            *currentDiffPixel++ = static_cast<unsigned char>(distance * 255.0f);
113
114
            if (distance >= 1.0f / 255.0f) {
115
                count += 1.0f;
116
                sum += distance;
117
                maxDistance = max<float>(maxDistance, distance);
118
            }
119
        }
120
    }
121
122
    // Compute the difference as a percentage combining both the number of
123
    // different pixels and their difference amount i.e. the average distance
124
    // over the entire image
125
    float difference = 0;
126
    if (count > 0.0f)
127
        difference = 100.0f * sum / (height * width);
128
    if (difference <= tolerance)
129
        difference = 0;
130
    else {
131
        difference = roundf(difference * 100.0f) / 100.0f;
132
        difference = max(difference, 0.01f); // round to 2 decimal places
133
        *differenceImage = differenceImageFromDifferenceBuffer(evas_object_evas_get(baselineImage), diffBuffer, width, height);
134
    }
135
136
    free(diffBuffer);
137
    return difference;
138
}
139
140
int getTemporaryFile(char *fileName, size_t fileNameLen)
141
{
142
    if (getenv("TMPDIR"))
143
        snprintf(fileName, fileNameLen, "%s/ImageDiffXXXXXX.png", getenv("TMPDIR"));
144
    else if (getenv("TEMP"))
145
        snprintf(fileName, fileNameLen, "%s/ImageDiffXXXXXX.png", getenv("TEMP"));
146
    else {
147
#if __linux__
148
        strcpy(fileName, "/dev/shm/ImageDiffXXXXXX.png");
149
        int fileDescriptor = mkstemps(fileName, sizeof(".png") - 1);
150
        if (fileDescriptor >= 0)
151
            return fileDescriptor;
152
#endif // __linux__
153
154
        strcpy(fileName, "/tmp/ImageDiffXXXXXX.png");
155
    }
156
157
    return mkstemps(fileName, sizeof(".png") - 1);
158
}
159
160
void printImage(Evas_Object* image)
161
{
162
    char* buffer;
163
    size_t bufferSize;
164
    char fileName[PATH_MAX];
165
    int tempImageFd;
166
167
    tempImageFd = getTemporaryFile(fileName, PATH_MAX);
168
    if (tempImageFd < 0)
169
        return;
170
171
    if (evas_object_image_save(image, fileName, 0, 0)) {
172
        struct stat fileInfo;
173
        if (!stat(fileName, &fileInfo)) {
174
            unsigned char buffer[2048];
175
            ssize_t bytesRead;
176
177
            printf("Content-Length: %ld\n", fileInfo.st_size);
178
            fflush(stdout);
179
            while ((bytesRead = read(tempImageFd, buffer, sizeof(buffer))) > 0)
180
                write(1, buffer, bytesRead);
181
        }
182
    }
183
    close(tempImageFd);
184
    unlink(fileName);
185
}
186
187
void printImageDifferences(Evas_Object* baselineImage, Evas_Object* actualImage)
188
{
189
    Evas_Object* differenceImage = 0;
190
    float difference = calculateDifference(baselineImage, actualImage, &differenceImage);
191
    if (difference > 0.0f) {
192
        if (differenceImage) {
193
            printImage(differenceImage);
194
            evas_object_del(differenceImage);
195
        }
196
        printf("diff: %01.2f%% failed\n", difference);
197
    } else
198
        printf("diff: %01.2f%% passed\n", difference);
199
}
200
201
Evas_Object* readImageFromStdin(Evas* evas, long imageSize, int *width, int *height)
202
{
203
    Evas_Object* image;
204
    unsigned char* imageBuffer;
205
206
    imageBuffer = static_cast<unsigned char *>(malloc(imageSize));
207
    if (!imageBuffer)
208
        return 0;
209
210
    image = evas_object_image_filled_add(evas);
211
    size_t bytesRead = fread(imageBuffer, 1, imageSize, stdin);
212
    if (bytesRead > 0)
213
        evas_object_image_memfile_set(image, imageBuffer, bytesRead, 0, 0);
214
    else {
215
        free(imageBuffer);
216
        evas_object_del(image);
217
        return 0;
218
    }
219
    free(imageBuffer);
220
221
    evas_object_image_size_get(image, width, height);
222
    return image;
223
}
224
225
bool parseCommandLineOptions(int argc, char** argv)
226
{
227
    static const option options[] = {
228
        { "tolerance", required_argument, 0, 't' },
229
        { 0, 0, 0, 0 }
230
    };
231
    int option;
232
233
    while ((option = getopt_long(argc, (char* const*)argv, "t:", options, 0)) != -1) {
234
        switch (option) {
235
        case 't':
236
            tolerance = atof(optarg);
237
            break;
238
        case '?':
239
        case ':':
240
            return false;
241
        }
242
    }
243
244
    return true;
245
}
246
247
int main(int argc, char* argv[])
248
{
249
    Evas_Object* actualImage = 0;
250
    Evas_Object* baselineImage = 0;
251
    Ecore_Evas* ecoreEvas = 0;
252
    Evas* evas = 0;
253
    char buffer[2048];
254
    int returnValue = 0;
255
    int bufferWidth = 1;
256
    int bufferHeight = 1;
257
258
    if (!parseCommandLineOptions(argc, argv))
259
        return 1;
260
261
    evas_init();
262
    ecore_init();
263
    ecore_evas_init();
264
    
265
    ecoreEvas = ecore_evas_buffer_new(bufferWidth, bufferHeight);
266
    evas = ecore_evas_get(ecoreEvas);
267
    if (!evas) {
268
        printf("Error, couldn't create ecore evas buffer.\n");
269
        returnValue = 1;
270
        goto shutdown;
271
    }
272
273
    while (fgets(buffer, sizeof(buffer), stdin)) {
274
        char* newLineCharacter = strchr(buffer, '\n');
275
        if (newLineCharacter)
276
            *newLineCharacter = '\0';
277
278
        if (!strncmp("Content-Length: ", buffer, 16)) {
279
            long imageSize;
280
            int width, height;
281
282
            if (sscanf(buffer, "Content-Length: %ld", &imageSize) != 1) {
283
                printf("Error, image size must be specified.\n");
284
                returnValue = 1;
285
                goto shutdown;
286
            }
287
            if (imageSize > 0) {
288
                if (!actualImage) {
289
                    if (!(actualImage = readImageFromStdin(evas, imageSize, &width, &height))) {
290
                        printf("Error, could not read actual image.\n");
291
                        returnValue = 1;
292
                        goto shutdown;
293
                    }
294
                    if (width > bufferWidth)
295
                        bufferWidth = width;
296
                    if (height > bufferHeight)
297
                        bufferWidth = width;
298
                    ecore_evas_resize(ecoreEvas, bufferWidth, bufferHeight);
299
                } else if (!baselineImage) {
300
                    if (!(baselineImage = readImageFromStdin(evas, imageSize, &width, &height))) {
301
                        printf("Error, could not read baseline image.\n");
302
                        returnValue = 1;
303
                        goto shutdown;
304
                    }
305
                    if (width > bufferWidth)
306
                        bufferWidth = width;
307
                    if (height > bufferHeight)
308
                        bufferWidth = width;
309
                    ecore_evas_resize(ecoreEvas, bufferWidth, bufferHeight);
310
                }
311
            } else {
312
                printf("Error, image size must be specified.\n");
313
                returnValue = 1;
314
                goto shutdown;
315
            }
316
        }
317
318
        if (actualImage && baselineImage) {
319
            printImageDifferences(baselineImage, actualImage);
320
            evas_object_del(actualImage);
321
            evas_object_del(baselineImage);
322
            actualImage = 0;
323
            baselineImage = 0;
324
        }
325
326
        fflush(stdout);
327
    }
328
329
shutdown:
330
    if (ecoreEvas)
331
        ecore_evas_free(ecoreEvas);
332
    ecore_evas_shutdown();
333
    ecore_shutdown();
334
    evas_shutdown();
335
336
    return returnValue;
337
}

Return to Bug 61942