10bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch/* 20bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) 30bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 40bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch This library is free software; you can redistribute it and/or 50bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch modify it under the terms of the GNU Library General Public 60bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch License as published by the Free Software Foundation; either 70bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch version 2 of the License, or (at your option) any later version. 80bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 90bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch This library is distributed in the hope that it will be useful, 100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch but WITHOUT ANY WARRANTY; without even the implied warranty of 110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch Library General Public License for more details. 130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch You should have received a copy of the GNU Library General Public License 150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch along with this library; see the file COPYING.LIB. If not, write to 160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch Boston, MA 02110-1301, USA. 180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch*/ 190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 206c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen#include <QtCore/qmath.h> 216c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <QApplication> 230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <QBuffer> 240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <QByteArray> 250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <QImage> 260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <QStringList> 270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <stdio.h> 290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochint main(int argc, char* argv[]) 310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{ 320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch QCoreApplication app(argc, argv); 330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch qreal tolerance = 0; 350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch QStringList args = app.arguments(); 370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch for (int i = 0; i < argc; ++i) 380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (args[i] == "-t" || args[i] == "--tolerance") 390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch tolerance = args[i + 1].toDouble(); 400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch char buffer[2048]; 420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch QImage actualImage; 430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch QImage baselineImage; 440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch while (fgets(buffer, sizeof(buffer), stdin)) { 460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch // remove the CR 470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch char* newLineCharacter = strchr(buffer, '\n'); 480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (newLineCharacter) 490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch *newLineCharacter = '\0'; 500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (!strncmp("Content-Length: ", buffer, 16)) { 520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch strtok(buffer, " "); 530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch int imageSize = strtol(strtok(0, " "), 0, 10); 540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (imageSize <= 0) { 560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch fputs("error, image size must be specified.\n", stdout); 570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } else { 580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch unsigned char buffer[2048]; 590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch QBuffer data; 600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch // Read all the incoming chunks 620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch data.open(QBuffer::WriteOnly); 630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch while (imageSize > 0) { 640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch size_t bytesToRead = qMin(imageSize, 2048); 650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch size_t bytesRead = fread(buffer, 1, bytesToRead, stdin); 660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch data.write(reinterpret_cast<const char*>(buffer), bytesRead); 670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch imageSize -= static_cast<int>(bytesRead); 680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch // Convert into QImage 710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch QImage decodedImage; 720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch decodedImage.loadFromData(data.data(), "PNG"); 730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch decodedImage.convertToFormat(QImage::Format_ARGB32); 740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch // Place it in the right place 760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (actualImage.isNull()) 770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch actualImage = decodedImage; 780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch else 790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch baselineImage = decodedImage; 800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (!actualImage.isNull() && !baselineImage.isNull()) { 840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (actualImage.size() != baselineImage.size()) { 860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch fprintf(stderr, "error, test and reference image have different properties.\n"); 870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch fflush(stderr); 880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } else { 890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch int w = actualImage.width(); 910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch int h = actualImage.height(); 920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch QImage diffImage(w, h, QImage::Format_ARGB32); 930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch int count = 0; 950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch qreal sum = 0; 960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch qreal maxDistance = 0; 970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch for (int x = 0; x < w; ++x) 990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch for (int y = 0; y < h; ++y) { 1000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch QRgb pixel = actualImage.pixel(x, y); 1010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch QRgb basePixel = baselineImage.pixel(x, y); 1020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch qreal red = (qRed(pixel) - qRed(basePixel)) / static_cast<float>(qMax(255 - qRed(basePixel), qRed(basePixel))); 1030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch qreal green = (qGreen(pixel) - qGreen(basePixel)) / static_cast<float>(qMax(255 - qGreen(basePixel), qGreen(basePixel))); 1040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch qreal blue = (qBlue(pixel) - qBlue(basePixel)) / static_cast<float>(qMax(255 - qBlue(basePixel), qBlue(basePixel))); 1050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch qreal alpha = (qAlpha(pixel) - qAlpha(basePixel)) / static_cast<float>(qMax(255 - qAlpha(basePixel), qAlpha(basePixel))); 1066c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen qreal distance = qSqrt(red * red + green * green + blue * blue + alpha * alpha) / 2.0f; 1070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch int gray = distance * qreal(255); 1080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch diffImage.setPixel(x, y, qRgb(gray, gray, gray)); 1090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (distance >= 1 / qreal(255)) { 1100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch count++; 1110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch sum += distance; 1120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch maxDistance = qMax(maxDistance, distance); 1130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 1140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 1150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 1160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch qreal difference = 0; 1170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (count) 1180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch difference = 100 * sum / static_cast<qreal>(w * h); 1190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (difference <= tolerance) { 1200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch difference = 0; 1210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } else { 1226c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen difference = qRound(difference * 100) / 100; 123231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block difference = qMax(difference, qreal(0.01)); 1240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 1250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 1260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (!count) { 1270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch fprintf(stdout, "diff: %01.2f%% passed\n", difference); 1280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } else { 1290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch QBuffer buffer; 1300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch buffer.open(QBuffer::WriteOnly); 1310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch diffImage.save(&buffer, "PNG"); 1320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch buffer.close(); 1330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch const QByteArray &data = buffer.data(); 1340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch printf("Content-Length: %lu\n", static_cast<unsigned long>(data.length())); 1355abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick 1365abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick // We have to use the return value of fwrite to avoid "ignoring return value" gcc warning 1375abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick // See https://bugs.webkit.org/show_bug.cgi?id=45384 for details. 1385abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick if (fwrite(data.constData(), 1, data.length(), stdout)) {} 1390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 1400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch fprintf(stdout, "diff: %01.2f%% failed\n", difference); 1410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 1420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 1430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch fflush(stdout); 1440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 14581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch actualImage = QImage(); 14681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch baselineImage = QImage(); 1470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 1480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 1490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 1500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch return 0; 1510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch} 152