23 #include <QCryptographicHash>
30 mExpectedImageFile(
"" ),
31 mRenderedImageFile(
"" ),
35 mElapsedTimeTarget( 0 ),
36 mpMapRenderer( NULL ),
37 mControlPathPrefix(
"" )
44 QString myDataDir( TEST_DATA_DIR );
45 QString myControlImageDir = myDataDir + QDir::separator() +
"control_images" +
47 return myControlImageDir;
60 myImage.load( theImageFile );
61 QByteArray myByteArray;
62 QBuffer myBuffer( &myByteArray );
63 myImage.save( &myBuffer,
"PNG" );
64 QString myImageString = QString::fromUtf8( myByteArray.toBase64().data() );
65 QCryptographicHash myHash( QCryptographicHash::Md5 );
66 myHash.addData( myImageString.toUtf8() );
67 return myHash.result().toHex().constData();
74 QDir myDirectory = QDir( myControlImageDir );
76 QString myFilename =
"*";
77 myList = myDirectory.entryList( QStringList( myFilename ),
78 QDir::Files | QDir::NoSymLinks );
83 QString myImageHash =
imageToHash( theDiffImageFile );
86 for (
int i = 0; i < myList.size(); ++i )
88 QString myFile = myList.at( i );
90 "Checking if " + myFile +
" is a known anomaly.";
93 + QDir::separator() + myFile );
94 QString myHashMessage = QString(
95 "Checking if anomaly %1 (hash %2)" )
97 .arg( myAnomalyHash );
98 myHashMessage += QString(
" matches %1 (hash %2)" )
99 .arg( theDiffImageFile )
102 QString myMeasureMessage =
"<DartMeasurement name=\"Anomaly check"
103 "\" type=\"text/text\">" + myHashMessage +
104 "</DartMeasurement>";
105 qDebug() << myMeasureMessage;
106 mReport +=
"<tr><td colspan=3>" + myHashMessage +
"</td></tr>";
107 if ( myImageHash == myAnomalyHash )
109 mReport +=
"<tr><td colspan=3>"
110 "Anomaly found! " + myFile;
115 mReport +=
"<tr><td colspan=3>"
116 "No anomaly found! ";
122 unsigned int theMismatchCount )
126 qDebug(
"QgsRenderChecker::runTest failed - Expected Image File not set." );
128 "<tr><td>Test Result:</td><td>Expected Result:</td></tr>\n"
129 "<tr><td>Nothing rendered</td>\n<td>Failed because Expected "
130 "Image File not set.</td></tr></table>\n";
137 mMatchTarget = myExpectedImage.width() * myExpectedImage.height();
141 QImage myImage( myExpectedImage.width(),
142 myExpectedImage.height(),
143 QImage::Format_RGB32 );
144 myImage.setDotsPerMeterX( myExpectedImage.dotsPerMeterX() );
145 myImage.setDotsPerMeterY( myExpectedImage.dotsPerMeterY() );
146 myImage.fill( qRgb( 152, 219, 249 ) );
147 QPainter myPainter( &myImage );
148 myPainter.setRenderHint( QPainter::Antialiasing );
150 myExpectedImage.width(),
151 myExpectedImage.height() ),
152 myExpectedImage.logicalDpiX() );
163 theTestName +
"_result.png";
168 QFile wldFile( QDir::tempPath() + QDir::separator() + theTestName +
"_result.wld" );
169 if ( wldFile.open( QIODevice::WriteOnly ) )
173 QTextStream stream( &wldFile );
174 stream << QString(
"%1\r\n0 \r\n0 \r\n%2\r\n%3\r\n%4\r\n" )
186 unsigned int theMismatchCount,
187 QString theRenderedImageFile )
191 qDebug(
"QgsRenderChecker::runTest failed - Expected Image (control) File not set." );
193 "<tr><td>Test Result:</td><td>Expected Result:</td></tr>\n"
194 "<tr><td>Nothing rendered</td>\n<td>Failed because Expected "
195 "Image File not set.</td></tr></table>\n";
198 if ( ! theRenderedImageFile.isEmpty() )
204 qDebug(
"QgsRenderChecker::runTest failed - Rendered Image File not set." );
206 "<tr><td>Test Result:</td><td>Expected Result:</td></tr>\n"
207 "<tr><td>Nothing rendered</td>\n<td>Failed because Expected "
208 "Image File not set.</td></tr></table>\n";
216 QImage myDifferenceImage( myExpectedImage.width(),
217 myExpectedImage.height(),
218 QImage::Format_RGB32 );
219 QString myDiffImageFile = QDir::tempPath() + QDir::separator() +
221 theTestName +
"_result_diff.png";
222 myDifferenceImage.fill( qRgb( 152, 219, 249 ) );
227 mMatchTarget = myExpectedImage.width() * myExpectedImage.height();
228 unsigned int myPixelCount = myResultImage.width() * myResultImage.height();
233 mReport +=
"<tr><td colspan=2>";
234 mReport +=
"Test image and result image for " + theTestName +
"<br>"
235 "Expected size: " + QString::number( myExpectedImage.width() ).toLocal8Bit() +
"w x " +
236 QString::number( myExpectedImage.width() ).toLocal8Bit() +
"h (" +
237 QString::number(
mMatchTarget ).toLocal8Bit() +
" pixels)<br>"
238 "Actual size: " + QString::number( myResultImage.width() ).toLocal8Bit() +
"w x " +
239 QString::number( myResultImage.width() ).toLocal8Bit() +
"h (" +
240 QString::number( myPixelCount ).toLocal8Bit() +
" pixels)";
242 mReport +=
"<tr><td colspan = 2>\n";
244 "ms (0 indicates not specified)<br>";
246 QString myImagesString =
"</td></tr>"
247 "<tr><td>Test Result:</td><td>Expected Result:</td><td>Difference (all blue is good, any red is bad)</td></tr>\n"
248 "<tr><td><img src=\"file://" +
250 "\"></td>\n<td><img src=\"file://" +
252 "\"></td><td><img src=\"file://" +
254 "\"></td>\n</tr>\n</table>";
258 QString myDashMessage =
"<DartMeasurementFile name=\"Rendered Image " + theTestName +
"\""
260 "</DartMeasurementFile>\n"
261 "<DartMeasurementFile name=\"Expected Image " + theTestName +
"\" type=\"image/png\">" +
263 "<DartMeasurementFile name=\"Difference Image " + theTestName +
"\" type=\"image/png\">" +
264 myDiffImageFile +
"</DartMeasurementFile>\n";
265 qDebug( ) << myDashMessage;
271 qDebug(
"Expected size: %dw x %dh", myExpectedImage.width(), myExpectedImage.height() );
272 qDebug(
"Actual size: %dw x %dh", myResultImage.width(), myResultImage.height() );
276 qDebug(
"Test image and result image for %s are different - FAILING!", theTestName.toLocal8Bit().constData() );
277 mReport +=
"<tr><td colspan=3>";
278 mReport +=
"<font color=red>Expected image and result image for " + theTestName +
" are different dimensions - FAILING!</font>";
279 mReport +=
"</td></tr>";
280 mReport += myImagesString;
290 for (
int x = 0; x < myExpectedImage.width(); ++x )
292 for (
int y = 0; y < myExpectedImage.height(); ++y )
294 QRgb myExpectedPixel = myExpectedImage.pixel( x, y );
295 QRgb myActualPixel = myResultImage.pixel( x, y );
296 if ( myExpectedPixel != myActualPixel )
299 myDifferenceImage.setPixel( x, y, qRgb( 255, 0, 0 ) );
306 myDifferenceImage.save( myDiffImageFile );
316 mReport +=
"<tr><td colspan=3>" +
319 " pixels mismatched (allowed threshold: " +
320 QString::number( theMismatchCount ) +
")";
326 myDashMessage =
"<DartMeasurement name=\"Mismatch Count "
327 "\" type=\"numeric/integer\">" +
330 "</DartMeasurement>";
331 qDebug( ) << myDashMessage;
335 if ( myAnomalyMatchFlag )
337 mReport +=
"<tr><td colspan=3>"
338 "Difference image matched a known anomaly - passing test! "
344 QString myMessage =
"Difference image did not match any known anomaly.";
345 mReport +=
"<tr><td colspan=3>"
347 QString myMeasureMessage =
"<DartMeasurement name=\"No Anomalies Match"
348 "\" type=\"text/text\">" + myMessage +
349 " If you feel the difference image should be considered an anomaly "
350 "you can do something like this\n"
351 "cp " + myDiffImageFile +
" ../tests/testdata/control_images/" + theTestName +
352 "/<imagename>.{wld,png}"
353 "</DartMeasurement>";
354 qDebug() << myMeasureMessage;
359 mReport +=
"<tr><td colspan = 3>\n";
360 mReport +=
"Test image and result image for " + theTestName +
" are matched<br>";
365 qDebug(
"Test failed because render step took too long" );
366 mReport +=
"<tr><td colspan = 3>\n";
367 mReport +=
"<font color=red>Test failed because render step took too long</font>";
380 mReport +=
"<tr><td colspan = 3>\n";
381 mReport +=
"<font color=red>Test image and result image for " + theTestName +
" are mismatched</font><br>";
QgsMapRenderer * mpMapRenderer
A rectangle specified with double values.
void render(QPainter *painter, double *forceWidthScale=0)
starts rendering @ param forceWidthScale Force a specific scale factor for line widths and marker siz...
double yMaximum() const
Get the y maximum value (top side of rectangle)
QgsRectangle extent() const
returns current extent
QString qgsDoubleToString(const double &a)
bool runTest(QString theTestName, unsigned int theMismatchCount=0)
Test using renderer to generate the image to be compared.
unsigned int mMismatchCount
QString controlImagePath() const
double mapUnitsPerPixel() const
QString imageToHash(QString theImageFile)
Get an md5 hash that uniquely identifies an image.
unsigned int mMatchTarget
void setOutputSize(QSize size, int dpi)
QString mControlPathPrefix
QString mRenderedImageFile
bool isKnownAnomaly(QString theDiffImageFile)
Get a list of all the anomalies.
QString mExpectedImageFile
void setControlName(const QString theName)
Base directory name for the control image (with control image path suffixed) the path to the image wi...
bool compareImages(QString theTestName, unsigned int theMismatchCount=0, QString theRenderedImageFile="")
Test using two arbitary images (map renderer will not be used)
double xMinimum() const
Get the x minimum value (left side of rectangle)