Showing with 136 additions and 26 deletions.
  1. +9 −0 python/core/qgsrasterdataprovider.sip
  2. +6 −1 src/core/qgsrasterdataprovider.cpp
  3. +5 −1 src/core/raster/qgsrasterlayer.cpp
  4. +79 −3 tests/src/core/qgsrenderchecker.cpp
  5. +19 −2 tests/src/core/qgsrenderchecker.h
  6. +1 −3 tests/src/core/regression992.cpp
  7. +1 −3 tests/src/core/testqgsgeometry.cpp
  8. +1 −8 tests/src/core/testqgsmaprenderer.cpp
  9. +1 −3 tests/src/core/testqgsrasterlayer.cpp
  10. +1 −2 tests/src/core/testqgsrenderers.cpp
  11. BIN tests/testdata/{ → control_images/expected_continuous}/expected_continuous.png
  12. BIN tests/testdata/{ → control_images/expected_geometry_bufferCheck}/expected_geometry_bufferCheck.png
  13. BIN ...ata/{ → control_images/expected_geometry_differenceCheck1}/expected_geometry_differenceCheck1.png
  14. BIN ...ata/{ → control_images/expected_geometry_differenceCheck2}/expected_geometry_differenceCheck2.png
  15. BIN ...{ → control_images/expected_geometry_intersectionCheck1}/expected_geometry_intersectionCheck1.png
  16. BIN ...estdata/{ → control_images/expected_geometry_simplifyCheck1}/expected_geometry_simplifyCheck1.png
  17. BIN tests/testdata/{ → control_images/expected_geometry_unionCheck1}/expected_geometry_unionCheck1.png
  18. BIN tests/testdata/{ → control_images/expected_geometry_unionCheck2}/expected_geometry_unionCheck2.png
  19. BIN tests/testdata/{ → control_images/expected_graduated}/expected_graduated.png
  20. BIN tests/testdata/{ → control_images/expected_landsat_875}/expected_landsat_875.png
  21. BIN tests/testdata/{ → control_images/expected_landsat_basic}/expected_landsat_basic.png
  22. BIN tests/testdata/{ → control_images/expected_maprender}/expected_maprender.png
  23. BIN tests/testdata/{ → control_images/expected_raster}/expected_raster.png
  24. +13 −0 tests/testdata/control_images/expected_raster/expected_raster.png.aux.xml
  25. BIN tests/testdata/{ → control_images/expected_raster_pseudo}/expected_raster_pseudo.png
  26. BIN tests/testdata/{ → control_images/expected_rgbwcmyk01_YeGeo.jp2}/expected_rgbwcmyk01_YeGeo.jp2.png
  27. BIN tests/testdata/{ → control_images/expected_single}/expected_single.png
  28. BIN tests/testdata/{ → control_images/expected_uniquevalue}/expected_uniquevalue.png
9 changes: 9 additions & 0 deletions python/core/qgsrasterdataprovider.sip
Original file line number Diff line number Diff line change
Expand Up @@ -151,5 +151,14 @@ class QgsRasterDataProvider : QgsDataProvider
/**Sets the output device resolution.
@note: this method was added in version 1.2*/
void setDpi( int dpi );

/** read block of data using give extent and size */
/*virtual void readBlock( int bandNo,
QgsRectangle const & viewExtent,
int width, int height,
QgsCoordinateReferenceSystem theSrcCRS,
QgsCoordinateReferenceSystem theDestCRS,
void *data ); */

};

7 changes: 6 additions & 1 deletion src/core/qgsrasterdataprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@
#include <QMap>
#include <QByteArray>

void QgsRasterDataProvider::readBlock( int bandNo, QgsRectangle const & viewExtent, int width, int height, QgsCoordinateReferenceSystem theSrcCRS, QgsCoordinateReferenceSystem theDestCRS, void *data )
void QgsRasterDataProvider::readBlock( int bandNo, QgsRectangle
const & viewExtent, int width,
int height,
QgsCoordinateReferenceSystem theSrcCRS,
QgsCoordinateReferenceSystem theDestCRS,
void *data )
{
QgsDebugMsg( "Entered" );
QgsDebugMsg( "viewExtent = " + viewExtent.toString() );
Expand Down
6 changes: 5 additions & 1 deletion src/core/raster/qgsrasterlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4580,7 +4580,11 @@ void *QgsRasterLayer::readData( int bandNo, QgsRasterViewPort *viewPort )
viewPort->mDrawnExtent.xMaximum(),
viewPort->mDrawnExtent.yMaximum()
);
mDataProvider->readBlock( bandNo, partExtent, viewPort->drawableAreaXDim, viewPort->drawableAreaYDim, viewPort->mSrcCRS, viewPort->mDestCRS, data );
mDataProvider->readBlock( bandNo, partExtent,
viewPort->drawableAreaXDim,
viewPort->drawableAreaYDim,
viewPort->mSrcCRS,
viewPort->mDestCRS, data );
}
return data;
}
Expand Down
82 changes: 79 additions & 3 deletions tests/src/core/qgsrenderchecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
#include <QPainter>
#include <QImage>
#include <QTime>

#include <QCryptographicHash>
#include <QByteArray>

QgsRenderChecker::QgsRenderChecker( ) :
mReport( "" ),
Expand All @@ -34,6 +35,64 @@ QgsRenderChecker::QgsRenderChecker( ) :
{

}

QString QgsRenderChecker::controlImagePath() const
{
QString myDataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt
QString myControlImageDir = myDataDir + QDir::separator() + "control_images"
+ QDir::separator() ;
return myControlImageDir;
}

void QgsRenderChecker::setControlName(const QString theName)
{
mControlName = theName;
mExpectedImageFile = controlImagePath() + theName + QDir::separator()
+ theName + ".png";
}

bool QgsRenderChecker::isKnownAnomaly( QImage theDifferenceImage )
{
QString myControlImageDir = controlImagePath() + mControlName
+ QDir::separator();
QDir myDirectory = QDir(myControlImageDir);
QStringList myList;
QString myFilename = "*";
myList = myDirectory.entryList(QStringList(myFilename),
QDir::Files | QDir::NoSymLinks);
//remove the control file from teh list as the anomalies are
//all files except the control file
myList.removeAt(myList.indexOf(mExpectedImageFile));
//todo compare each hash to diff path
QByteArray myData((const char*)theDifferenceImage.bits(),
theDifferenceImage.numBytes());
QByteArray mySourceHash = QCryptographicHash::hash(
myData, QCryptographicHash::Md5);
for (int i = 0; i < myList.size(); ++i)
{
QString myFile = myList.at(i);
mReport += "<tr><td colspan=3>"
"Checking if " + myFile + " is a known anomaly.";
mReport += "</td></tr>";
QImage myAnomalyImage( myFile );
QByteArray myData((const char*)myAnomalyImage.bits(),
myAnomalyImage.numBytes());
QByteArray myAnomolyHash = QCryptographicHash::hash(
myData, QCryptographicHash::Md5);
if ( mySourceHash.toHex() == myAnomolyHash.toHex() )
{
mReport += "<tr><td colspan=3>"
"Anomaly found! " + myFile;
mReport += "</td></tr>";
return true;
}
}
mReport += "<tr><td colspan=3>"
"No anomaly found! ";
mReport += "</td></tr>";
return false;
}

bool QgsRenderChecker::runTest( QString theTestName,
unsigned int theMismatchCount )
{
Expand Down Expand Up @@ -111,6 +170,7 @@ bool QgsRenderChecker::compareImages( QString theTestName,
myExpectedImage.height(),
QImage::Format_RGB32 );
QString myResultDiffImage = QDir::tempPath() + QDir::separator() +
"control_images" + QDir::separator() +
theTestName + "_result_diff.png";
myDifferenceImage.fill( qRgb( 152, 219, 249 ) );

Expand Down Expand Up @@ -197,11 +257,27 @@ bool QgsRenderChecker::compareImages( QString theTestName,
mReport += "<tr><td colspan=3>" +
QString::number( mMismatchCount ) + "/" +
QString::number( mMatchTarget ) +
" pixels mismatched";
" pixels mismatched (allowed threshold: " +
QString::number( theMismatchCount ) + ")";
mReport += "</td></tr>";

bool myAnomalyMatchFlag = isKnownAnomaly( myDifferenceImage );

if ( myAnomalyMatchFlag )
{
mReport += "<tr><td colspan=3>"
"Difference image matched a known anomaly - passing test! "
"</td></tr>";
return true;
}
else
{
mReport += "<tr><td colspan=3>"
"Difference image did not match any known anomaly."
"</td></tr>";
}

if ( mMismatchCount <= theMismatchCount )
if ( mMismatchCount <= theMismatchCount)
{
mReport += "<tr><td colspan = 3>\n";
mReport += "Test image and result image for " + theTestName + " are matched<br>";
Expand Down
21 changes: 19 additions & 2 deletions tests/src/core/qgsrenderchecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

#include <QString>
#include <qgsmaprenderer.h>

class QImage;

/** \ingroup UnitTests
* This is a helper class for unit tests that need to
Expand All @@ -34,6 +34,8 @@ class QgsRenderChecker
//! Destructor
~QgsRenderChecker(){};

QString controlImagePath() const;

QString report() { return mReport; };
float matchPercent() { return static_cast<float>(mMismatchCount) /
static_cast<float>(mMatchTarget) * 100; };
Expand All @@ -42,7 +44,11 @@ class QgsRenderChecker
//only records time for actual render part
int elapsedTime() { return mElapsedTime; };
void setElapsedTimeTarget(int theTarget) { mElapsedTimeTarget = theTarget; };
void setExpectedImage (QString theImageFileName) { mExpectedImageFile = theImageFileName; };
/** Base directory name for the control image (with control image path
* suffixed) the path to the image will be constructed like this:
* controlImagePath + '/' + mControlName + '/' + mControlName + '.png'
*/
void setControlName(const QString theName);
void setRenderedImage (QString theImageFileName) { mRenderedImageFile = theImageFileName; };
void setMapRenderer ( QgsMapRenderer * thepMapRenderer) { mpMapRenderer = thepMapRenderer; };
/**
Expand All @@ -68,9 +74,20 @@ class QgsRenderChecker
* @note: make sure to call setExpectedImage and setRenderedImage first.
*/
bool compareImages( QString theTestName, unsigned int theMismatchCount=0 );
/** Get a list of all teh anomalies. An anomaly is a rendered difference
* file where there is some red pixel content (indicating a render check
* mismatch), but where the output was still acceptible. If the render
* diff matches one of these anomalies we will still consider it to be
* acceptible.
* @return a bool indicating if the diff matched one of the anomaly files
*/
bool isKnownAnomaly( QImage theDifferenceImage );

private:

QString mReport;
QString mExpectedImageFile;
QString mControlName;
QString mRenderedImageFile;
unsigned int mMismatchCount;
unsigned int mMatchTarget;
Expand Down
4 changes: 1 addition & 3 deletions tests/src/core/regression992.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,8 @@ void Regression992::regression992()
{
QVERIFY( mpRasterLayer->isValid() );
mpMapRenderer->setExtent( mpRasterLayer->extent() );
QString myDataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt
QString myTestDataDir = myDataDir + QDir::separator();
QgsRenderChecker myChecker;
myChecker.setExpectedImage( myTestDataDir + "expected_rgbwcmyk01_YeGeo.jp2.png" );
myChecker.setControlName( "expected_rgbwcmyk01_YeGeo.jp2" );
myChecker.setMapRenderer( mpMapRenderer );
// allow up to 300 mismatched pixels
bool myResultFlag = myChecker.runTest( "regression992", 300 );
Expand Down
4 changes: 1 addition & 3 deletions tests/src/core/testqgsgeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,11 +312,9 @@ bool TestQgsGeometry::renderCheck( QString theTestName, QString theComment )
mReport += "<h3>" + theComment + "</h3>\n";
QString myTmpDir = QDir::tempPath() + QDir::separator() ;
QString myFileName = myTmpDir + theTestName + ".png";
QString myDataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt
QString myTestDataDir = myDataDir + QDir::separator();
mImage.save( myFileName, "PNG" );
QgsRenderChecker myChecker;
myChecker.setExpectedImage( myTestDataDir + "expected_" + theTestName + ".png" );
myChecker.setControlName( "expected_" + theTestName );
myChecker.setRenderedImage( myFileName );
bool myResultFlag = myChecker.compareImages( theTestName );
mReport += myChecker.report();
Expand Down
9 changes: 1 addition & 8 deletions tests/src/core/testqgsmaprenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@ void TestQgsMapRenderer::initTestCase()
mReport += "<h1>Map Render Tests</h1>\n";
}


void TestQgsMapRenderer::cleanupTestCase()
{
QString myReportFile = QDir::tempPath() + QDir::separator() + "qgistest.html";
Expand All @@ -188,25 +187,19 @@ void TestQgsMapRenderer::cleanupTestCase()
myFile.close();
//QDesktopServices::openUrl( "file:///" + myReportFile );
}

}



void TestQgsMapRenderer::performanceTest()
{
mpMapRenderer->setExtent( mpPolysLayer->extent() );
QString myDataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt
QString myTestDataDir = myDataDir + QDir::separator();
QgsRenderChecker myChecker;
myChecker.setExpectedImage( myTestDataDir + "expected_maprender.png" );
myChecker.setControlName( "expected_maprender" );
myChecker.setMapRenderer( mpMapRenderer );
bool myResultFlag = myChecker.runTest( "maprender" );
mReport += myChecker.report();
QVERIFY( myResultFlag );
}


QTEST_MAIN( TestQgsMapRenderer )
#include "moc_testqgsmaprenderer.cxx"

Expand Down
4 changes: 1 addition & 3 deletions tests/src/core/testqgsrasterlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,10 +255,8 @@ void TestQgsRasterLayer::registry()
bool TestQgsRasterLayer::render( QString theTestType )
{
mReport += "<h2>" + theTestType + "</h2>\n";
QString myDataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt
QString myTestDataDir = myDataDir + QDir::separator();
QgsRenderChecker myChecker;
myChecker.setExpectedImage( myTestDataDir + "expected_" + theTestType + ".png" );
myChecker.setControlName( "expected_" + theTestType );
myChecker.setMapRenderer( mpMapRenderer );
bool myResultFlag = myChecker.runTest( theTestType );
mReport += "\n\n\n" + myChecker.report();
Expand Down
3 changes: 1 addition & 2 deletions tests/src/core/testqgsrenderers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,8 @@ bool TestQgsRenderers::imageCheck( QString theTestType )
//use the QgsRenderChecker test utility class to
//ensure the rendered output matches our control image
mpMapRenderer->setExtent( mpPointsLayer->extent() );
QString myExpectedImage = mTestDataDir + "expected_" + theTestType + ".png";
QgsRenderChecker myChecker;
myChecker.setExpectedImage( myExpectedImage );
myChecker.setControlName( "expected_" + theTestType );
myChecker.setMapRenderer( mpMapRenderer );
bool myResultFlag = myChecker.runTest( theTestType );
mReport += myChecker.report();
Expand Down
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<PAMDataset>
<Metadata domain="IMAGE_STRUCTURE">
<MDI key="INTERLEAVE">PIXEL</MDI>
</Metadata>
<PAMRasterBand band="1">
<Metadata>
<MDI key="STATISTICS_MINIMUM">0</MDI>
<MDI key="STATISTICS_MAXIMUM">255</MDI>
<MDI key="STATISTICS_MEAN">127.2</MDI>
<MDI key="STATISTICS_STDDEV">81.364365664583</MDI>
</Metadata>
</PAMRasterBand>
</PAMDataset>
File renamed without changes
File renamed without changes
File renamed without changes