QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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  Q_FOREACH ( const QString &suffix, subDirs )
51  {
52  qDebug() << "Checking subdir " << suffix;
53  bool result;
54  QgsRenderChecker checker;
55  checker.enableDashBuffering( true );
56  checker.setColorTolerance( mColorTolerance );
57  checker.setSizeTolerance( mMaxSizeDifferenceX, mMaxSizeDifferenceY );
58  checker.setControlPathPrefix( mControlPathPrefix );
59  checker.setControlPathSuffix( suffix );
60  checker.setControlName( mControlName );
61  checker.setMapSettings( mMapSettings );
62 
63  if ( !mRenderedImage.isNull() )
64  {
65  checker.setRenderedImage( mRenderedImage );
66  result = checker.compareImages( testName, mismatchCount, mRenderedImage );
67  }
68  else
69  {
70  result = checker.runTest( testName, mismatchCount );
71  mRenderedImage = checker.renderedImage();
72  }
73 
74  successful |= result;
75 
76  dartMeasurements << checker.dartMeasurements();
77 
78  mReport += checker.report();
79  }
80 
81  if ( !successful )
82  {
83  Q_FOREACH ( const QgsDartMeasurement &measurement, dartMeasurements )
84  measurement.send();
85 
86  QgsDartMeasurement msg( QStringLiteral( "Image not accepted by test" ), QgsDartMeasurement::Text, "This may be caused because the test is supposed to fail or rendering inconsistencies."
87  "If this is a rendering inconsistency, please add another control image folder, add an anomaly image or increase the color tolerance." );
88  msg.send();
89  }
90 
91  return successful;
92 }
93 
95 {
96  QString myDataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt
97  QString myControlImageDir = myDataDir + QDir::separator() + "control_images" +
98  QDir::separator() + mControlPathPrefix + QDir::separator() + mControlName + QDir::separator();
99  return myControlImageDir;
100 }
101 
102 //
103 // QgsLayoutChecker
104 //
105 
107 
108 QgsLayoutChecker::QgsLayoutChecker( const QString &testName, QgsLayout *layout )
109  : mTestName( testName )
110  , mLayout( layout )
111  , mSize( 1122, 794 )
112  , mDotsPerMeter( 96 / 25.4 * 1000 )
113 {
114  // Qt has some slight render inconsistencies on the whole image sometimes
115  setColorTolerance( 5 );
116 }
117 
118 bool QgsLayoutChecker::testLayout( QString &checkedReport, int page, int pixelDiff, bool createReferenceImage )
119 {
120  if ( !mLayout )
121  {
122  return false;
123  }
124 
125  setControlName( "expected_" + mTestName );
126 
127 
128  if ( createReferenceImage )
129  {
130  //fake mode to generate expected image
131  //assume 96 dpi
132 
133 
134  QImage _outputImage( mSize, QImage::Format_RGB32 );
135  _outputImage.setDotsPerMeterX( 96 / 25.4 * 1000 );
136  _outputImage.setDotsPerMeterY( 96 / 25.4 * 1000 );
137  QPainter _p( &_outputImage );
138  QgsLayoutExporter _exporter( mLayout );
139  _exporter.renderPage( &_p, page );
140  _p.end();
141 
142  if ( ! QDir( controlImagePath() ).exists() )
143  {
144  QDir().mkdir( controlImagePath() );
145  }
146  _outputImage.save( controlImagePath() + QDir::separator() + "expected_" + mTestName + ".png", "PNG" );
147  qDebug( ) << "Reference image saved to : " + controlImagePath() + QDir::separator() + "expected_" + mTestName + ".png";
148 
149  }
150 
151  QImage outputImage( mSize, QImage::Format_RGB32 );
152  outputImage.setDotsPerMeterX( mDotsPerMeter );
153  outputImage.setDotsPerMeterY( mDotsPerMeter );
154  drawBackground( &outputImage );
155  QPainter p( &outputImage );
156  QgsLayoutExporter exporter( mLayout );
157  exporter.renderPage( &p, page );
158  p.end();
159 
160  QString renderedFilePath = QDir::tempPath() + '/' + QFileInfo( mTestName ).baseName() + "_rendered.png";
161  outputImage.save( renderedFilePath, "PNG" );
162 
163  setRenderedImage( renderedFilePath );
164 
165  bool testResult = runTest( mTestName, pixelDiff );
166 
167  checkedReport += report();
168 
169  return testResult;
170 }
171 
172 
void setColorTolerance(unsigned int colorTolerance)
Set tolerance for color components used by runTest() Default value is 0.
QVector< QgsDartMeasurement > dartMeasurements() const
Gets access to buffered dash messages.
void enableDashBuffering(bool enable)
Call this to enable internal buffering of dash messages.
void setRenderedImage(const QString &imageFileName)
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 report() const
Returns a report for this test.
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.
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 renderPage(QPainter *painter, int page) const
Renders a full page to a destination painter.
void setControlPathSuffix(const QString &name)
QString controlImagePath() const
Returns the path to the control images.
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...