QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsmultirenderchecker.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmultirenderchecker.cpp
3  --------------------------------------
4  Date : 6.11.2014
5  Copyright : (C) 2014 Matthias Kuhn
6  Email : matthias at opengis dot ch
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsmultirenderchecker.h"
17 #include "qgslayout.h"
18 #include <QDebug>
19 
20 void QgsMultiRenderChecker::setControlName( const QString &name )
21 {
22  mControlName = name;
23 }
24 
25 void QgsMultiRenderChecker::setControlPathPrefix( const QString &prefix )
26 {
27  mControlPathPrefix = prefix;
28 }
29 
31 {
32  mMapSettings = mapSettings;
33 }
34 
35 bool QgsMultiRenderChecker::runTest( const QString &testName, unsigned int mismatchCount )
36 {
37  bool successful = false;
38 
39  const QString baseDir = controlImagePath();
40 
41  QStringList subDirs = QDir( baseDir ).entryList( QDir::Dirs | QDir::NoDotAndDotDot );
42 
43  if ( subDirs.isEmpty() )
44  {
45  subDirs << QString();
46  }
47 
48  QVector<QgsDartMeasurement> dartMeasurements;
49 
50  for ( const QString &suffix : qgis::as_const( subDirs ) )
51  {
52  if ( subDirs.count() > 1 )
53  {
54  qDebug() << "Checking subdir " << suffix;
55  }
56  bool result;
57  QgsRenderChecker checker;
58  checker.enableDashBuffering( true );
59  checker.setColorTolerance( mColorTolerance );
60  checker.setSizeTolerance( mMaxSizeDifferenceX, mMaxSizeDifferenceY );
61  checker.setControlPathPrefix( mControlPathPrefix );
62  checker.setControlPathSuffix( suffix );
63  checker.setControlName( mControlName );
64  checker.setMapSettings( mMapSettings );
65 
66  if ( !mRenderedImage.isNull() )
67  {
68  checker.setRenderedImage( mRenderedImage );
69  result = checker.compareImages( testName, mismatchCount, mRenderedImage );
70  }
71  else
72  {
73  result = checker.runTest( testName, mismatchCount );
74  mRenderedImage = checker.renderedImage();
75  }
76 
77  successful |= result;
78 
79  dartMeasurements << checker.dartMeasurements();
80 
81  mReport += checker.report();
82  }
83 
84  if ( !successful )
85  {
86  const auto constDartMeasurements = dartMeasurements;
87  for ( const QgsDartMeasurement &measurement : constDartMeasurements )
88  measurement.send();
89 
90  QgsDartMeasurement msg( QStringLiteral( "Image not accepted by test" ), QgsDartMeasurement::Text, "This may be caused because the test is supposed to fail or rendering inconsistencies."
91  "If this is a rendering inconsistency, please add another control image folder, add an anomaly image or increase the color tolerance." );
92  msg.send();
93  }
94 
95  return successful;
96 }
97 
99 {
100  QString myDataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt
101  QString myControlImageDir = myDataDir + QDir::separator() + "control_images" +
102  QDir::separator() + mControlPathPrefix + QDir::separator() + mControlName + QDir::separator();
103  return myControlImageDir;
104 }
105 
106 //
107 // QgsLayoutChecker
108 //
109 
111 
112 QgsLayoutChecker::QgsLayoutChecker( const QString &testName, QgsLayout *layout )
113  : mTestName( testName )
114  , mLayout( layout )
115  , mSize( 1122, 794 )
116  , mDotsPerMeter( 96 / 25.4 * 1000 )
117 {
118  // Qt has some slight render inconsistencies on the whole image sometimes
119  setColorTolerance( 5 );
120 }
121 
122 bool QgsLayoutChecker::testLayout( QString &checkedReport, int page, int pixelDiff, bool createReferenceImage )
123 {
124 #ifdef QT_NO_PRINTER
125  return false;
126 #else
127  if ( !mLayout )
128  {
129  return false;
130  }
131 
132  setControlName( "expected_" + mTestName );
133 
134 
135  if ( createReferenceImage )
136  {
137  //fake mode to generate expected image
138  //assume 96 dpi
139 
140 
141  QImage _outputImage( mSize, QImage::Format_RGB32 );
142  _outputImage.setDotsPerMeterX( 96 / 25.4 * 1000 );
143  _outputImage.setDotsPerMeterY( 96 / 25.4 * 1000 );
144  QPainter _p( &_outputImage );
145  QgsLayoutExporter _exporter( mLayout );
146  _exporter.renderPage( &_p, page );
147  _p.end();
148 
149  if ( ! QDir( controlImagePath() ).exists() )
150  {
151  QDir().mkdir( controlImagePath() );
152  }
153  _outputImage.save( controlImagePath() + QDir::separator() + "expected_" + mTestName + ".png", "PNG" );
154  qDebug( ) << "Reference image saved to : " + controlImagePath() + QDir::separator() + "expected_" + mTestName + ".png";
155 
156  }
157 
158  QImage outputImage( mSize, QImage::Format_RGB32 );
159  outputImage.setDotsPerMeterX( mDotsPerMeter );
160  outputImage.setDotsPerMeterY( mDotsPerMeter );
161  drawBackground( &outputImage );
162  QPainter p( &outputImage );
163  QgsLayoutExporter exporter( mLayout );
164  exporter.renderPage( &p, page );
165  p.end();
166 
167  QString renderedFilePath = QDir::tempPath() + '/' + QFileInfo( mTestName ).baseName() + "_rendered.png";
168  outputImage.save( renderedFilePath, "PNG" );
169 
170  setRenderedImage( renderedFilePath );
171 
172  bool testResult = runTest( mTestName, pixelDiff );
173 
174  checkedReport += report();
175 
176  return testResult;
177 #endif // QT_NO_PRINTER
178 }
179 
180 
181 
QgsRenderChecker::setMapSettings
void setMapSettings(const QgsMapSettings &mapSettings)
Definition: qgsrenderchecker.cpp:65
QgsRenderChecker::setControlPathSuffix
void setControlPathSuffix(const QString &name)
Definition: qgsrenderchecker.cpp:44
QgsMultiRenderChecker::setColorTolerance
void setColorTolerance(unsigned int colorTolerance)
Set tolerance for color components used by runTest() Default value is 0.
Definition: qgsmultirenderchecker.h:97
QgsRenderChecker::compareImages
bool compareImages(const QString &testName, unsigned int mismatchCount=0, const QString &renderedImageFile=QString())
Test using two arbitrary images (map renderer will not be used)
Definition: qgsrenderchecker.cpp:233
QgsDartMeasurement::Text
@ Text
Definition: qgsdartmeasurement.h:32
QgsRenderChecker::report
QString report()
Definition: qgsrenderchecker.h:49
QgsRenderChecker::setColorTolerance
void setColorTolerance(unsigned int colorTolerance)
Set tolerance for color components used by runTest() and compareImages().
Definition: qgsrenderchecker.h:100
QgsRenderChecker::renderedImage
QString renderedImage()
The path of the rendered image can be retrieved through that method.
Definition: qgsrenderchecker.h:88
QgsLayoutExporter
Handles rendering and exports of layouts to various formats.
Definition: qgslayoutexporter.h:45
QgsRenderChecker::setSizeTolerance
void setSizeTolerance(int xTolerance, int yTolerance)
Sets the largest allowable difference in size between the rendered and the expected image.
Definition: qgsrenderchecker.h:108
qgslayout.h
QgsMultiRenderChecker::runTest
bool runTest(const QString &testName, unsigned int mismatchCount=0)
Test using renderer to generate the image to be compared.
Definition: qgsmultirenderchecker.cpp:35
qgsmultirenderchecker.h
QgsDartMeasurement
Definition: qgsdartmeasurement.h:28
QgsLayout
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:50
QgsMultiRenderChecker::setControlName
void setControlName(const QString &name)
Base directory name for the control image (with control image path suffixed) the path to the image wi...
Definition: qgsmultirenderchecker.cpp:20
QgsRenderChecker::enableDashBuffering
void enableDashBuffering(bool enable)
Call this to enable internal buffering of dash messages.
Definition: qgsrenderchecker.h:165
QgsMultiRenderChecker::controlImagePath
QString controlImagePath() const
Returns the path to the control images.
Definition: qgsmultirenderchecker.cpp:98
QgsRenderChecker::setControlPathPrefix
void setControlPathPrefix(const QString &name)
Prefix where the control images are kept.
Definition: qgsrenderchecker.h:73
QgsRenderChecker::setRenderedImage
void setRenderedImage(const QString &imageFileName)
Definition: qgsrenderchecker.h:80
QgsMultiRenderChecker::setMapSettings
void setMapSettings(const QgsMapSettings &mapSettings)
Set the map settings to use to render the image.
Definition: qgsmultirenderchecker.cpp:30
QgsDartMeasurement::send
void send() const
Definition: qgsdartmeasurement.cpp:43
QgsRenderChecker
This is a helper class for unit tests that need to write an image and compare it to an expected resul...
Definition: qgsrenderchecker.h:39
QgsRenderChecker::runTest
bool runTest(const QString &testName, unsigned int mismatchCount=0)
Test using renderer to generate the image to be compared.
Definition: qgsrenderchecker.cpp:151
QgsMapSettings
The QgsMapSettings class contains configuration for rendering of the map.
Definition: qgsmapsettings.h:88
QgsMultiRenderChecker::setControlPathPrefix
void setControlPathPrefix(const QString &prefix)
Definition: qgsmultirenderchecker.cpp:25
QgsRenderChecker::dartMeasurements
QVector< QgsDartMeasurement > dartMeasurements() const
Gets access to buffered dash messages.
Definition: qgsrenderchecker.h:173
QgsRenderChecker::setControlName
void setControlName(const QString &name)
Base directory name for the control image (with control image path suffixed) the path to the image wi...
Definition: qgsrenderchecker.cpp:38