diff -r 4f2f89ce4247 -r 303757a437d3 WebKitTools/DumpRenderTree/cg/ImageDiffCG.cpp --- a/WebKitTools/DumpRenderTree/cg/ImageDiffCG.cpp Fri Sep 17 09:02:29 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,250 +0,0 @@ -/* - * Copyright (C) 2005, 2007 Apple Inc. All rights reserved. - * Copyright (C) 2005 Ben La Monica . All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define min min - -#include -#include -#include - -#if PLATFORM(WIN) -#include -#include -#include -#include -#include -#endif - -#include -#include -#include - -#if PLATFORM(MAC) -#include -#endif - -#ifndef CGFLOAT_DEFINED -#ifdef __LP64__ -typedef double CGFloat; -#else -typedef float CGFloat; -#endif -#define CGFLOAT_DEFINED 1 -#endif - -using namespace std; - -#if PLATFORM(WIN) -static inline float strtof(const char *nptr, char **endptr) -{ - return strtod(nptr, endptr); -} -static const CFStringRef kUTTypePNG = CFSTR("public.png"); -#endif - -static RetainPtr createImageFromStdin(int bytesRemaining) -{ - unsigned char buffer[2048]; - RetainPtr data(AdoptCF, CFDataCreateMutable(0, bytesRemaining)); - - while (bytesRemaining > 0) { - size_t bytesToRead = min(bytesRemaining, 2048); - size_t bytesRead = fread(buffer, 1, bytesToRead, stdin); - CFDataAppendBytes(data.get(), buffer, static_cast(bytesRead)); - bytesRemaining -= static_cast(bytesRead); - } - RetainPtr dataProvider(AdoptCF, CGDataProviderCreateWithCFData(data.get())); - return RetainPtr(AdoptCF, CGImageCreateWithPNGDataProvider(dataProvider.get(), 0, false, kCGRenderingIntentDefault)); -} - -static void releaseMallocBuffer(void* info, const void* data, size_t size) -{ - free((void*)data); -} - -static RetainPtr createDifferenceImage(CGImageRef baseImage, CGImageRef testImage, float& difference) -{ - size_t width = CGImageGetWidth(baseImage); - size_t height = CGImageGetHeight(baseImage); - size_t rowBytes = width * 4; - - // Draw base image in bitmap context - void* baseBuffer = calloc(height, rowBytes); - RetainPtr baseContext(AdoptCF, CGBitmapContextCreate(baseBuffer, width, height, 8, rowBytes, CGImageGetColorSpace(baseImage), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); - CGContextDrawImage(baseContext.get(), CGRectMake(0, 0, width, height), baseImage); - - // Draw test image in bitmap context - void* buffer = calloc(height, rowBytes); - RetainPtr context(AdoptCF, CGBitmapContextCreate(buffer, width, height, 8, rowBytes, CGImageGetColorSpace(testImage), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); - CGContextDrawImage(context.get(), CGRectMake(0, 0, width, height), testImage); - - // Compare the content of the 2 bitmaps - void* diffBuffer = malloc(width * height); - float count = 0.0f; - float sum = 0.0f; - float maxDistance = 0.0f; - unsigned char* basePixel = (unsigned char*)baseBuffer; - unsigned char* pixel = (unsigned char*)buffer; - unsigned char* diff = (unsigned char*)diffBuffer; - for (size_t y = 0; y < height; ++y) { - for (size_t x = 0; x < width; ++x) { - float red = (pixel[0] - basePixel[0]) / max(255 - basePixel[0], basePixel[0]); - float green = (pixel[1] - basePixel[1]) / max(255 - basePixel[1], basePixel[1]); - float blue = (pixel[2] - basePixel[2]) / max(255 - basePixel[2], basePixel[2]); - float alpha = (pixel[3] - basePixel[3]) / max(255 - basePixel[3], basePixel[3]); - float distance = sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0f; - - *diff++ = (unsigned char)(distance * 255.0f); - - if (distance >= 1.0f / 255.0f) { - count += 1.0f; - sum += distance; - if (distance > maxDistance) - maxDistance = distance; - } - - basePixel += 4; - pixel += 4; - } - } - - // Compute the difference as a percentage combining both the number of different pixels and their difference amount i.e. the average distance over the entire image - if (count > 0.0f) - difference = 100.0f * sum / (height * width); - else - difference = 0.0f; - - RetainPtr diffImage; - // Generate a normalized diff image if there is any difference - if (difference > 0.0f) { - if (maxDistance < 1.0f) { - diff = (unsigned char*)diffBuffer; - for(size_t p = 0; p < height * width; ++p) - diff[p] = diff[p] / maxDistance; - } - - static CGColorSpaceRef diffColorspace = CGColorSpaceCreateDeviceGray(); - RetainPtr provider(AdoptCF, CGDataProviderCreateWithData(0, diffBuffer, width * height, releaseMallocBuffer)); - diffImage.adoptCF(CGImageCreate(width, height, 8, 8, width, diffColorspace, 0, provider.get(), 0, false, kCGRenderingIntentDefault)); - } - else - free(diffBuffer); - - // Destroy drawing buffers - if (buffer) - free(buffer); - if (baseBuffer) - free(baseBuffer); - - return diffImage; -} - -static inline bool imageHasAlpha(CGImageRef image) -{ - CGImageAlphaInfo info = CGImageGetAlphaInfo(image); - - return (info >= kCGImageAlphaPremultipliedLast) && (info <= kCGImageAlphaFirst); -} - -int main(int argc, const char* argv[]) -{ -#if PLATFORM(WIN) - _setmode(0, _O_BINARY); - _setmode(1, _O_BINARY); -#endif - - float tolerance = 0.0f; - - for (int i = 1; i < argc; ++i) { - if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--tolerance")) { - if (i >= argc - 1) - exit(1); - tolerance = strtof(argv[i + 1], 0); - ++i; - continue; - } - } - - char buffer[2048]; - RetainPtr actualImage; - RetainPtr baselineImage; - - while (fgets(buffer, sizeof(buffer), stdin)) { - // remove the CR - char* newLineCharacter = strchr(buffer, '\n'); - if (newLineCharacter) - *newLineCharacter = '\0'; - - if (!strncmp("Content-Length: ", buffer, 16)) { - strtok(buffer, " "); - int imageSize = strtol(strtok(0, " "), 0, 10); - - if (imageSize > 0 && !actualImage) - actualImage = createImageFromStdin(imageSize); - else if (imageSize > 0 && !baselineImage) - baselineImage = createImageFromStdin(imageSize); - else - fputs("error, image size must be specified.\n", stdout); - } - - if (actualImage && baselineImage) { - RetainPtr diffImage; - float difference = 100.0f; - - if ((CGImageGetWidth(actualImage.get()) == CGImageGetWidth(baselineImage.get())) && (CGImageGetHeight(actualImage.get()) == CGImageGetHeight(baselineImage.get())) && (imageHasAlpha(actualImage.get()) == imageHasAlpha(baselineImage.get()))) { - diffImage = createDifferenceImage(actualImage.get(), baselineImage.get(), difference); // difference is passed by reference - if (difference <= tolerance) - difference = 0.0f; - else { - difference = roundf(difference * 100.0f) / 100.0f; - difference = max(difference, 0.01f); // round to 2 decimal places - } - } else - fputs("error, test and reference image have different properties.\n", stderr); - - if (difference > 0.0f) { - if (diffImage) { - RetainPtr imageData(AdoptCF, CFDataCreateMutable(0, 0)); - RetainPtr imageDest(AdoptCF, CGImageDestinationCreateWithData(imageData.get(), kUTTypePNG, 1, 0)); - CGImageDestinationAddImage(imageDest.get(), diffImage.get(), 0); - CGImageDestinationFinalize(imageDest.get()); - printf("Content-Length: %lu\n", CFDataGetLength(imageData.get())); - fwrite(CFDataGetBytePtr(imageData.get()), 1, CFDataGetLength(imageData.get()), stdout); - } - - fprintf(stdout, "diff: %01.2f%% failed\n", difference); - } else - fprintf(stdout, "diff: %01.2f%% passed\n", difference); - - actualImage = 0; - baselineImage = 0; - } - - fflush(stdout); - } - - return 0; -}