1e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke/* 2e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com> 3e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * Copyright (C) 2010 Igalia S.L. 4e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * 5e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * Redistribution and use in source and binary forms, with or without 6e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * modification, are permitted provided that the following conditions 7e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * are met: 8e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * 9e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * 1. Redistributions of source code must retain the above copyright 10e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * notice, this list of conditions and the following disclaimer. 11e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * 2. Redistributions in binary form must reproduce the above copyright 12e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * notice, this list of conditions and the following disclaimer in the 13e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * documentation and/or other materials provided with the distribution. 14e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * its contributors may be used to endorse or promote products derived 16e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * from this software without specific prior written permission. 17e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * 18e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke */ 29e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 30e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke#include <algorithm> 31e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke#include <cmath> 32e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke#include <cstdio> 33e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke#include <cstring> 34e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke#include <gdk/gdk.h> 35e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 36e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarkeusing namespace std; 37e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 38e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarkestatic double tolerance = 0; 39e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarkestatic GOptionEntry commandLineOptionEntries[] = 40e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke{ 41e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke { "tolerance", 0, 0, G_OPTION_ARG_DOUBLE, &tolerance, "Percentage difference between images before considering them different", "T" }, 42e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke { 0, 0, 0, G_OPTION_ARG_NONE, 0, 0, 0 }, 43e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke}; 44e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 45e458d70a0d18538346f41b503114c9ebe6b2ce12Leon ClarkeGdkPixbuf* readPixbufFromStdin(long imageSize) 46e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke{ 47e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke unsigned char imageBuffer[2048]; 48e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke GdkPixbufLoader* loader = gdk_pixbuf_loader_new_with_type("png", 0); 49e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke GError* error = 0; 50e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 51e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke while (imageSize > 0) { 52e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke size_t bytesToRead = min<int>(imageSize, 2048); 53e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke size_t bytesRead = fread(imageBuffer, 1, bytesToRead, stdin); 54e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 55e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (!gdk_pixbuf_loader_write(loader, reinterpret_cast<const guchar*>(imageBuffer), bytesRead, &error)) { 56e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke g_error_free(error); 57e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke gdk_pixbuf_loader_close(loader, 0); 58e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke g_object_unref(loader); 59e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return 0; 60e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 61e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 62e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke imageSize -= static_cast<int>(bytesRead); 63e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 64e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 65e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke gdk_pixbuf_loader_close(loader, 0); 66e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke GdkPixbuf* decodedImage = gdk_pixbuf_loader_get_pixbuf(loader); 67e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke g_object_ref(decodedImage); 68e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return decodedImage; 69e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke} 70e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 71e458d70a0d18538346f41b503114c9ebe6b2ce12Leon ClarkeGdkPixbuf* differenceImageFromDifferenceBuffer(unsigned char* buffer, int width, int height) 72e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke{ 73e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke GdkPixbuf* image = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height); 74e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (!image) 75e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return image; 76e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 77e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke int rowStride = gdk_pixbuf_get_rowstride(image); 78e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke unsigned char* diffPixels = gdk_pixbuf_get_pixels(image); 79e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke for (int x = 0; x < width; x++) { 80e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke for (int y = 0; y < height; y++) { 81e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke unsigned char* diffPixel = diffPixels + (y * rowStride) + (x * 3); 82e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke diffPixel[0] = diffPixel[1] = diffPixel[2] = *buffer++; 83e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 84e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 85e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 86e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return image; 87e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke} 88e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 89e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarkefloat calculateDifference(GdkPixbuf* baselineImage, GdkPixbuf* actualImage, GdkPixbuf** differenceImage) 90e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke{ 91e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke int width = gdk_pixbuf_get_width(actualImage); 92e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke int height = gdk_pixbuf_get_height(actualImage); 93e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke int numberOfChannels = gdk_pixbuf_get_n_channels(actualImage); 94e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if ((width != gdk_pixbuf_get_width(baselineImage)) 95e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke || (height != gdk_pixbuf_get_height(baselineImage)) 96e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke || (numberOfChannels != gdk_pixbuf_get_n_channels(baselineImage)) 97e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke || (gdk_pixbuf_get_has_alpha(actualImage) != gdk_pixbuf_get_has_alpha(baselineImage))) { 98e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke fprintf(stderr, "Error, test and reference image have different properties.\n"); 99e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return 100; // Completely different. 100e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 101e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 102e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke unsigned char* diffBuffer = static_cast<unsigned char*>(malloc(width * height)); 103e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke float count = 0; 104e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke float sum = 0; 105e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke float maxDistance = 0; 106e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke int actualRowStride = gdk_pixbuf_get_rowstride(actualImage); 107e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke int baseRowStride = gdk_pixbuf_get_rowstride(baselineImage); 108e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke unsigned char* actualPixels = gdk_pixbuf_get_pixels(actualImage); 109e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke unsigned char* basePixels = gdk_pixbuf_get_pixels(baselineImage); 110e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke unsigned char* currentDiffPixel = diffBuffer; 111e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke for (int x = 0; x < width; x++) { 112e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke for (int y = 0; y < height; y++) { 113e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke unsigned char* actualPixel = actualPixels + (y * actualRowStride) + (x * numberOfChannels); 114e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke unsigned char* basePixel = basePixels + (y * baseRowStride) + (x * numberOfChannels); 115e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 116e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke float red = (actualPixel[0] - basePixel[0]) / max<float>(255 - basePixel[0], basePixel[0]); 117e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke float green = (actualPixel[1] - basePixel[1]) / max<float>(255 - basePixel[1], basePixel[1]); 118e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke float blue = (actualPixel[2] - basePixel[2]) / max<float>(255 - basePixel[2], basePixel[2]); 119e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke float alpha = (actualPixel[3] - basePixel[3]) / max<float>(255 - basePixel[3], basePixel[3]); 120e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke float distance = sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0f; 121e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 122e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke *currentDiffPixel++ = (unsigned char)(distance * 255.0f); 123e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 124e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (distance >= 1.0f / 255.0f) { 125e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke count += 1.0f; 126e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke sum += distance; 127e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke maxDistance = max<float>(maxDistance, distance); 128e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 129e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 130e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 131e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 132e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke // Compute the difference as a percentage combining both the number of 133e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke // different pixels and their difference amount i.e. the average distance 134e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke // over the entire image 135e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke float difference = 0; 136e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (count > 0.0f) 137e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke difference = 100.0f * sum / (height * width); 138e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (difference <= tolerance) 139e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke difference = 0; 140e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke else { 141e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke difference = roundf(difference * 100.0f) / 100.0f; 142e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke difference = max(difference, 0.01f); // round to 2 decimal places 143e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke *differenceImage = differenceImageFromDifferenceBuffer(diffBuffer, width, height); 144e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 145e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 146e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke free(diffBuffer); 147e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return difference; 148e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke} 149e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 150e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarkevoid printImage(GdkPixbuf* image) 151e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke{ 152e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke char* buffer; 153e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke gsize bufferSize; 154e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke GError* error = 0; 155e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (!gdk_pixbuf_save_to_buffer(image, &buffer, &bufferSize, "png", &error, NULL)) { 156e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke g_error_free(error); 157e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return; // Don't bail out, as we can still use the percentage output. 158e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 159e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 160e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke printf("Content-Length: %"G_GSIZE_FORMAT"\n", bufferSize); 161e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke fwrite(buffer, 1, bufferSize, stdout); 162e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke} 163e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 164e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarkevoid printImageDifferences(GdkPixbuf* baselineImage, GdkPixbuf* actualImage) 165e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke{ 166e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke GdkPixbuf* differenceImage = 0; 167e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke float difference = calculateDifference(baselineImage, actualImage, &differenceImage); 168e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (difference > 0.0f) { 169e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (differenceImage) { 170e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke printImage(differenceImage); 171e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke g_object_unref(differenceImage); 172e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 173e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke printf("diff: %01.2f%% failed\n", difference); 174e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } else { 175e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke printf("diff: %01.2f%% passed\n", difference); 176e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 177e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke} 178e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 179e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarkeint main(int argc, char* argv[]) 180e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke{ 181e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke gdk_init(&argc, &argv); 182e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 183e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke GError* error = 0; 184e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke GOptionContext* context = g_option_context_new("- compare two image files, printing their percentage difference and the difference image to stdout"); 185e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke g_option_context_add_main_entries(context, commandLineOptionEntries, 0); 186e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (!g_option_context_parse(context, &argc, &argv, &error)) { 187e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke printf("Option parsing failed: %s\n", error->message); 188e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke g_error_free(error); 189e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return 1; 190e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 191e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 192e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke GdkPixbuf* actualImage = 0; 193e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke GdkPixbuf* baselineImage = 0; 194e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke char buffer[2048]; 195e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke while (fgets(buffer, sizeof(buffer), stdin)) { 196e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke // Convert the first newline into a NUL character so that strtok doesn't produce it. 197e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke char* newLineCharacter = strchr(buffer, '\n'); 198e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (newLineCharacter) 199e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke *newLineCharacter = '\0'; 200e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 201e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (!strncmp("Content-Length: ", buffer, 16)) { 2025abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick gchar** tokens = g_strsplit(buffer, " ", 0); 2035abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick if (!tokens[1]) { 2045abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick g_strfreev(tokens); 2055abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick printf("Error, image size must be specified..\n"); 2065abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick return 1; 2075abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick } 208e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 2095abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick long imageSize = strtol(tokens[1], 0, 10); 2105abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick g_strfreev(tokens); 211e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (imageSize > 0 && !actualImage) { 212e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (!(actualImage = readPixbufFromStdin(imageSize))) { 213e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke printf("Error, could not read actual image.\n"); 214e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return 1; 215e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 216e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } else if (imageSize > 0 && !baselineImage) { 217e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (!(baselineImage = readPixbufFromStdin(imageSize))) { 218e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke printf("Error, could not read baseline image.\n"); 219e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return 1; 220e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 221e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } else { 222e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke printf("Error, image size must be specified..\n"); 223e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return 1; 224e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 225e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 226e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 227e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (actualImage && baselineImage) { 228e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke printImageDifferences(baselineImage, actualImage); 229e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke g_object_unref(actualImage); 230e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke g_object_unref(baselineImage); 231e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke actualImage = 0; 232e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke baselineImage = 0; 233e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 234e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 235e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke fflush(stdout); 236e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 237e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 238e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return 0; 239e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke} 240