QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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  const auto constSubDirs = subDirs;
51  for ( const QString &suffix : constSubDirs )
52  {
53  qDebug() << "Checking subdir " << suffix;
54  bool result;
55  QgsRenderChecker checker;
56  checker.enableDashBuffering( true );
57  checker.setColorTolerance( mColorTolerance );
58  checker.setSizeTolerance( mMaxSizeDifferenceX, mMaxSizeDifferenceY );
59  checker.setControlPathPrefix( mControlPathPrefix );
60  checker.setControlPathSuffix( suffix );
61  checker.setControlName( mControlName );
62  checker.setMapSettings( mMapSettings );
63 
64  if ( !mRenderedImage.isNull() )
65  {
66  checker.setRenderedImage( mRenderedImage );
67  result = checker.compareImages( testName, mismatchCount, mRenderedImage );
68  }
69  else
70  {
71  result = checker.runTest( testName, mismatchCount );
72  mRenderedImage = checker.renderedImage();
73  }
74 
75  successful |= result;
76 
77  dartMeasurements << checker.dartMeasurements();
78 
79  mReport += checker.report();
80  }
81 
82  if ( !successful )
83  {
84  const auto constDartMeasurements = dartMeasurements;
85  for ( const QgsDartMeasurement &measurement : constDartMeasurements )
86  measurement.send();
87 
88  QgsDartMeasurement msg( QStringLiteral( "Image not accepted by test" ), QgsDartMeasurement::Text, "This may be caused because the test is supposed to fail or rendering inconsistencies."
89  "If this is a rendering inconsistency, please add another control image folder, add an anomaly image or increase the color tolerance." );
90  msg.send();
91  }
92 
93  return successful;
94 }
95 
97 {
98  QString myDataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt
99  QString myControlImageDir = myDataDir + QDir::separator() + "control_images" +
100  QDir::separator() + mControlPathPrefix + QDir::separator() + mControlName + QDir::separator();
101  return myControlImageDir;
102 }
103 
104 //
105 // QgsLayoutChecker
106 //
107 
109 
110 QgsLayoutChecker::QgsLayoutChecker( const QString &testName, QgsLayout *layout )
111  : mTestName( testName )
112  , mLayout( layout )
113  , mSize( 1122, 794 )
114  , mDotsPerMeter( 96 / 25.4 * 1000 )
115 {
116  // Qt has some slight render inconsistencies on the whole image sometimes
117  setColorTolerance( 5 );
118 }
119 
120 bool QgsLayoutChecker::testLayout( QString &checkedReport, int page, int pixelDiff, bool createReferenceImage )
121 {
122  if ( !mLayout )
123  {
124  return false;
125  }
126 
127  setControlName( "expected_" + mTestName );
128 
129 
130  if ( createReferenceImage )
131  {
132  //fake mode to generate expected image
133  //assume 96 dpi
134 
135 
136  QImage _outputImage( mSize, QImage::Format_RGB32 );
137  _outputImage.setDotsPerMeterX( 96 / 25.4 * 1000 );
138  _outputImage.setDotsPerMeterY( 96 / 25.4 * 1000 );
139  QPainter _p( &_outputImage );
140  QgsLayoutExporter _exporter( mLayout );
141  _exporter.renderPage( &_p, page );
142  _p.end();
143 
144  if ( ! QDir( controlImagePath() ).exists() )
145  {
146  QDir().mkdir( controlImagePath() );
147  }
148  _outputImage.save( controlImagePath() + QDir::separator() + "expected_" + mTestName + ".png", "PNG" );
149  qDebug( ) << "Reference image saved to : " + controlImagePath() + QDir::separator() + "expected_" + mTestName + ".png";
150 
151  }
152 
153  QImage outputImage( mSize, QImage::Format_RGB32 );
154  outputImage.setDotsPerMeterX( mDotsPerMeter );
155  outputImage.setDotsPerMeterY( mDotsPerMeter );
156  drawBackground( &outputImage );
157  QPainter p( &outputImage );
158  QgsLayoutExporter exporter( mLayout );
159  exporter.renderPage( &p, page );
160  p.end();
161 
162  QString renderedFilePath = QDir::tempPath() + '/' + QFileInfo( mTestName ).baseName() + "_rendered.png";
163  outputImage.save( renderedFilePath, "PNG" );
164 
165  setRenderedImage( renderedFilePath );
166 
167  bool testResult = runTest( mTestName, pixelDiff );
168 
169  checkedReport += report();
170 
171  return testResult;
172 }
173 
174 
void setColorTolerance(unsigned int colorTolerance)
Set tolerance for color components used by runTest() Default value is 0.
void enableDashBuffering(bool enable)
Call this to enable internal buffering of dash messages.
void setRenderedImage(const QString &imageFileName)
QString report() const
Returns a report for this test.
QString renderedImage()
The path of the rendered image can be retrieved through that method.
This is a helper class for unit tests that need to write an image and compare it to an expected resul...
void setMapSettings(const QgsMapSettings &mapSettings)
void setSizeTolerance(int xTolerance, int yTolerance)
Sets the largest allowable difference in size between the rendered and the expected image...
The QgsMapSettings class contains configuration for rendering of the map.
void setControlName(const QString &name)
Base directory name for the control image (with control image path suffixed) the path to the image wi...
QString controlImagePath() const
Returns the path to the control images.
void setControlPathPrefix(const QString &name)
Prefix where the control images are kept.
void setMapSettings(const QgsMapSettings &mapSettings)
Set the map settings to use to render the image.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:49
void setControlPathPrefix(const QString &prefix)
bool runTest(const QString &testName, unsigned int mismatchCount=0)
Test using renderer to generate the image to be compared.
bool compareImages(const QString &testName, unsigned int mismatchCount=0, const QString &renderedImageFile=QString())
Test using two arbitrary images (map renderer will not be used)
Handles rendering and exports of layouts to various formats.
QVector< QgsDartMeasurement > dartMeasurements() const
Gets access to buffered dash messages.
bool runTest(const QString &testName, unsigned int mismatchCount=0)
Test using renderer to generate the image to be compared.
void setColorTolerance(unsigned int colorTolerance)
Set tolerance for color components used by runTest() and compareImages().
void setControlPathSuffix(const QString &name)
static void drawBackground(QImage *image)
Draws a checkboard pattern for image backgrounds, so that opacity is visible without requiring a tran...
void setRenderedImage(const QString &renderedImagePath)
Set the path to the rendered image.
void setControlName(const QString &name)
Base directory name for the control image (with control image path suffixed) the path to the image wi...
void renderPage(QPainter *painter, int page) const
Renders a full page to a destination painter.