Skip to content

Commit f7ef19e

Browse files
committedAug 9, 2012
Add python composition checker and composermap test
1 parent 6cfb060 commit f7ef19e

File tree

4 files changed

+206
-3
lines changed

4 files changed

+206
-3
lines changed
 

‎tests/src/python/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
INCLUDE(UsePythonTest)
22
ADD_PYTHON_TEST(PyQGisApp test_qgisapp.py)
3+
ADD_PYTHON_TEST(PyQgsComposerMap test_qgscomposermap.py)
34
ADD_PYTHON_TEST(PyQgsGeometry test_qgsgeometry.py)
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# -*- coding: utf-8 -*-
2+
'''
3+
qgscompositionchecker.py - check rendering of Qgscomposition against an expected image
4+
--------------------------------------
5+
Date : 31 Juli 2012
6+
Copyright : (C) 2012 by Dr. Horst Düster / Dr. Marco Hugentobler
7+
email : horst.duester@sourcepole.ch
8+
***************************************************************************
9+
* *
10+
* This program is free software; you can redistribute it and/or modify *
11+
* it under the terms of the GNU General Public License as published by *
12+
* the Free Software Foundation; either version 2 of the License, or *
13+
* (at your option) any later version. *
14+
* *
15+
***************************************************************************/
16+
'''
17+
from PyQt4.QtCore import *
18+
from PyQt4.QtGui import *
19+
from qgis.core import *
20+
21+
class QgsCompositionChecker:
22+
23+
def testComposition(self, mTestName, mComposition, mExpectedImageFile, page=0 ):
24+
if ( mComposition == None):
25+
return false
26+
27+
28+
#load expected image
29+
expectedImage = QImage( mExpectedImageFile )
30+
31+
#get width/height, create image and render the composition to it
32+
width = expectedImage.width();
33+
height = expectedImage.height();
34+
outputImage = QImage( QSize( width, height ), QImage.Format_ARGB32 )
35+
36+
mComposition.setPlotStyle( QgsComposition.Print )
37+
outputImage.setDotsPerMeterX( expectedImage.dotsPerMeterX() )
38+
outputImage.setDotsPerMeterY( expectedImage.dotsPerMeterX() )
39+
outputImage.fill( 0 )
40+
p = QPainter( outputImage )
41+
mComposition.renderPage( p, page )
42+
p.end()
43+
44+
renderedFilePath = QDir.tempPath() + QDir.separator() + QFileInfo( mExpectedImageFile ).baseName() + "_rendered_python.png"
45+
outputImage.save( renderedFilePath, "PNG" )
46+
47+
diffFilePath = QDir.tempPath() + QDir.separator() + QFileInfo( mExpectedImageFile ).baseName() + "_diff_python.png"
48+
testResult = self.compareImages( expectedImage, outputImage, diffFilePath )
49+
50+
# myDashMessage = "<DartMeasurementFile name=\"Rendered Image " + mTestName + "\"
51+
# " type=\"image/png\">" + renderedFilePath +
52+
# "</DartMeasurementFile>"
53+
# "<DartMeasurementFile name=\"Expected Image " + mTestName + "\" type=\"image/png\">" +
54+
# mExpectedImageFile + "</DartMeasurementFile>"
55+
# "<DartMeasurementFile name=\"Difference Image " + mTestName + "\" type=\"image/png\">" +
56+
# diffFilePath + "</DartMeasurementFile>"
57+
58+
return testResult
59+
60+
def compareImages( self, imgExpected, imgRendered, differenceImagePath ):
61+
62+
if ( imgExpected.width() != imgRendered.width() or imgExpected.height() != imgRendered.height() ):
63+
return false
64+
65+
imageWidth = imgExpected.width()
66+
imageHeight = imgExpected.height()
67+
mismatchCount = 0
68+
69+
differenceImage = QImage( imageWidth, imageHeight, QImage.Format_ARGB32_Premultiplied )
70+
differenceImage.fill( qRgb( 152, 219, 249 ) )
71+
72+
pixel1 = QColor().rgb()
73+
pixel2 = QColor().rgb()
74+
for i in range( imageHeight ):
75+
for j in range( imageWidth ):
76+
pixel1 = imgExpected.pixel( j, i )
77+
pixel2 = imgRendered.pixel( j, i )
78+
if ( pixel1 != pixel2 ):
79+
mismatchCount = mismatchCount + 1
80+
differenceImage.setPixel( j, i, qRgb( 255, 0, 0 ) )
81+
82+
if not differenceImagePath.isEmpty():
83+
differenceImage.save( differenceImagePath, "PNG" )
84+
85+
#allow pixel deviation of 1 percent
86+
pixelCount = imageWidth * imageHeight;
87+
# print "MismatchCount: "+str(mismatchCount)
88+
# print "PixelCount: "+str(pixelCount)
89+
return (float(mismatchCount) / float(pixelCount) ) < 0.01
90+
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# -*- coding: utf-8 -*-
2+
'''
3+
test_qgscomposermap.py
4+
--------------------------------------
5+
Date : 31 Juli 2012
6+
Copyright : (C) 2012 by Dr. Horst Düster / Dr. Marco Hugentobler
7+
email : horst.duester@sourcepole.ch
8+
***************************************************************************
9+
* *
10+
* This program is free software; you can redistribute it and/or modify *
11+
* it under the terms of the GNU General Public License as published by *
12+
* the Free Software Foundation; either version 2 of the License, or *
13+
* (at your option) any later version. *
14+
* *
15+
***************************************************************************/
16+
'''
17+
import unittest
18+
from utilities import *
19+
from PyQt4.QtCore import *
20+
from PyQt4.QtGui import *
21+
from PyQt4.QtXml import *
22+
from qgis.core import *
23+
from qgscompositionchecker import QgsCompositionChecker
24+
25+
QGISAPP, CANVAS, IFACE, PARENT = getQgisTestApp()
26+
27+
class TestQgsComposerMap(unittest.TestCase):
28+
29+
def testCase(self):
30+
TEST_DATA_DIR = unitTestDataPath()
31+
rasterFileInfo = QFileInfo(TEST_DATA_DIR+QDir().separator().toAscii()+"landsat.tif")
32+
mRasterLayer = QgsRasterLayer(rasterFileInfo.filePath(), rasterFileInfo.completeBaseName())
33+
rasterRenderer = QgsMultiBandColorRenderer( mRasterLayer.dataProvider(), 2, 3, 4 )
34+
mRasterLayer.setRenderer( rasterRenderer )
35+
QgsMapLayerRegistry.instance().addMapLayer( mRasterLayer )
36+
37+
# create composition with composer map
38+
mMapRenderer = QgsMapRenderer()
39+
layerStringList = QStringList()
40+
layerStringList.append( mRasterLayer.id() )
41+
mMapRenderer.setLayerSet( layerStringList )
42+
mMapRenderer.setProjectionsEnabled( False )
43+
mComposition = QgsComposition( mMapRenderer )
44+
mComposition.setPaperSize( 297, 210 )
45+
mComposerMap = QgsComposerMap( mComposition, 20, 20, 200, 100 )
46+
mComposition.addComposerMap( mComposerMap )
47+
self.grid(mComposerMap, mComposition, TEST_DATA_DIR)
48+
self.overviewMap(mComposerMap, mComposition, TEST_DATA_DIR)
49+
50+
def grid(self, mComposerMap, mComposition, TEST_DATA_DIR):
51+
mComposerMap.setNewExtent( QgsRectangle( 781662.375, 3339523.125, 793062.375, 3345223.125 ) )
52+
mComposerMap.setGridEnabled( True )
53+
mComposerMap.setGridIntervalX( 2000 )
54+
mComposerMap.setGridIntervalY( 2000 )
55+
mComposerMap.setShowGridAnnotation( True )
56+
mComposerMap.setGridPenWidth( 0.5 )
57+
mComposerMap.setGridAnnotationPrecision( 0 )
58+
mComposerMap.setGridAnnotationPosition( QgsComposerMap.Disabled, QgsComposerMap.Left )
59+
mComposerMap.setGridAnnotationPosition( QgsComposerMap.OutsideMapFrame, QgsComposerMap.Right )
60+
mComposerMap.setGridAnnotationPosition( QgsComposerMap.Disabled, QgsComposerMap.Top )
61+
mComposerMap.setGridAnnotationPosition( QgsComposerMap.OutsideMapFrame, QgsComposerMap.Bottom )
62+
mComposerMap.setGridAnnotationDirection( QgsComposerMap.Horizontal, QgsComposerMap.Right )
63+
mComposerMap.setGridAnnotationDirection( QgsComposerMap.Horizontal, QgsComposerMap.Bottom )
64+
checker = QgsCompositionChecker()
65+
testResult = checker.testComposition( "Composer map grid", mComposition, TEST_DATA_DIR + QDir().separator().toAscii() + "control_images" + QDir().separator().toAscii() + "expected_composermap" + QDir().separator().toAscii() + "composermap_landsat_grid.png" )
66+
mComposerMap.setGridEnabled( False )
67+
mComposerMap.setShowGridAnnotation( False )
68+
mTestName = "gaga"
69+
# myMessage = "<DartMeasurementFile name=\"Rendered Image " + mTestName + "\" type=\"image/png\">" + renderedFilePath + "</DartMeasurementFile> <DartMeasurementFile name=\"Expected Image " + mTestName + "\" type=\"image/png\">" + mExpectedImageFile + "</DartMeasurementFile> <DartMeasurementFile name=\"Difference Image " + mTestName + "\" type=\"image/png\">" + diffFilePath + "</DartMeasurementFile>"
70+
assert testResult == True #, myMessage
71+
72+
def overviewMap(self, mComposerMap, mComposition, TEST_DATA_DIR):
73+
overviewMap = QgsComposerMap( mComposition, 20, 130, 70, 70 )
74+
mComposition.addComposerMap( overviewMap )
75+
# zoom in
76+
mComposerMap.setNewExtent( QgsRectangle( 785462.375, 3341423.125, 789262.375, 3343323.125 ) )
77+
overviewMap.setNewExtent( QgsRectangle( 781662.375, 3339523.125, 793062.375, 3350923.125 ) )
78+
overviewMap.setOverviewFrameMap( mComposerMap.id() )
79+
checker = QgsCompositionChecker()
80+
testResult = checker.testComposition( "Composer map overview", mComposition, TEST_DATA_DIR + QDir().separator().toAscii() +"control_images" + QDir().separator().toAscii() + "expected_composermap" + QDir().separator().toAscii() + "composermap_landsat_overview.png" )
81+
mComposition.removeComposerItem( overviewMap )
82+
assert testResult == True
83+
84+
85+
# def uniqueId(self, mComposerMap, mComposition):
86+
# doc = QDomDocument()
87+
# documentElement = doc.createElement( "ComposerItemClipboard" )
88+
# mComposerMap.writeXML( documentElement, doc )
89+
# mComposition.addItemsFromXML( documentElement, doc, 0, false )
90+
#
91+
# #test if both composer maps have different ids
92+
# newMap = QgsComposerMap()
93+
# mapList = mComposition.composerMapItems()
94+
#
95+
# for mapIt in mapList:
96+
# if mapIt != mComposerMap:
97+
# newMap = mapIt
98+
# break
99+
#
100+
# oldId = mComposerMap.id()
101+
# newId = newMap.id()
102+
#
103+
# mComposition.removeComposerItem( newMap );
104+
# print "old: "+str(oldId)
105+
# print "new "+str(newId)
106+
# assert oldId != newId
107+
108+
if __name__ == '__main__':
109+
unittest.main()
110+

‎tests/src/python/utilities.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,14 @@ def unitTestDataPath(theSubdir=None):
106106
'hazard' or 'exposure'.
107107
"""
108108
myPath = __file__
109+
tmpPath = os.path.split(os.path.dirname(myPath))
110+
myPath = os.path.split(tmpPath[0])
109111
if theSubdir is not None:
110-
myPath = os.path.abspath(os.path.join(myPath,
111-
'unit_test_data',
112+
myPath = os.path.abspath(os.path.join(myPath[0],
113+
'testdata',
112114
theSubdir))
113115
else:
114-
myPath = os.path.abspath(os.path.join(myPath, 'unit_test_data'))
116+
myPath = os.path.abspath(os.path.join(myPath[0], 'testdata'))
115117
return myPath
116118

117119
def setCanvasCrs(theEpsgId, theOtfpFlag=False):

0 commit comments

Comments
 (0)
Please sign in to comment.