Skip to content

Commit 53cfa9e

Browse files
committedMar 6, 2014
Convert label unit tests to using only QgsMapSettings
- Rebuild all control images
1 parent bad1898 commit 53cfa9e

File tree

22 files changed

+176
-93
lines changed

22 files changed

+176
-93
lines changed
 

‎tests/src/python/test_qgspallabeling_base.py

Lines changed: 115 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,18 @@
2626
import shutil
2727
import StringIO
2828
import tempfile
29+
2930
from PyQt4.QtCore import *
3031
from PyQt4.QtGui import *
3132

3233
from qgis.core import (
33-
QGis,
3434
QgsCoordinateReferenceSystem,
3535
QgsDataSourceURI,
36-
QgsLabelingEngineInterface,
3736
QgsMapLayerRegistry,
3837
QgsMapRenderer,
3938
QgsMapSettings,
4039
QgsPalLabeling,
4140
QgsPalLayerSettings,
42-
QgsProject,
4341
QgsProviderRegistry,
4442
QgsVectorLayer,
4543
QgsRenderChecker
@@ -55,6 +53,7 @@
5553
openInBrowserTab
5654
)
5755

56+
5857
QGISAPP, CANVAS, IFACE, PARENT = getQgisTestApp()
5958
FONTSLOADED = loadTestFonts()
6059

@@ -78,8 +77,6 @@ class TestQgsPalLabeling(TestCase):
7877
""":type: QgsMapSettings"""
7978
_Canvas = None
8079
""":type: QgsMapCanvas"""
81-
_Map = None
82-
""":type: QgsMapCanvasMap"""
8380
_Pal = None
8481
""":type: QgsPalLabeling"""
8582
_PalEngine = None
@@ -106,29 +103,18 @@ def setUpClass(cls):
106103
cls._TestGroupAbbr = ''
107104
cls._TestGroupCanvasAbbr = ''
108105
cls._TestImage = ''
106+
cls._TestMapSettings = None
109107

110108
# initialize class MapRegistry, Canvas, MapRenderer, Map and PAL
111109
# noinspection PyArgumentList
112110
cls._MapRegistry = QgsMapLayerRegistry.instance()
113-
# set color to match render test comparisons background
114-
cls._Canvas.setCanvasColor(QColor(152, 219, 249))
115-
cls._Map = cls._Canvas.map()
116-
cls._Map.resize(QSize(600, 400)) # is this necessary now?
117111
cls._MapRenderer = cls._Canvas.mapRenderer()
118112

119-
cls._MapSettings = QgsMapSettings()
120-
cls._CRS = QgsCoordinateReferenceSystem()
121-
""":type: QgsCoordinateReferenceSystem"""
122-
# default for labeling test data sources: WGS 84 / UTM zone 13N
123-
cls._CRS.createFromSrid(32613)
124-
cls._MapSettings.setBackgroundColor(QColor(152, 219, 249))
125-
cls._MapSettings.setOutputSize(QSize(600, 400))
126-
cls._MapSettings.setOutputDpi(72)
127-
cls._MapSettings.setFlag(QgsMapSettings.Antialiasing)
128-
cls._MapSettings.setDestinationCrs(cls._CRS)
129-
cls._MapSettings.setCrsTransformEnabled(False)
130-
cls._MapSettings.setMapUnits(cls._CRS.mapUnits()) # meters
131-
cls._MapSettings.setExtent(cls.aoiExtent())
113+
cls._MapSettings = cls.getBaseMapSettings()
114+
osize = cls._MapSettings.outputSize()
115+
cls._Canvas.resize(QSize(osize.width(), osize.height())) # necessary?
116+
# set color to match render test comparisons background
117+
cls._Canvas.setCanvasColor(cls._MapSettings.backgroundColor())
132118

133119
cls.setDefaultEngineSettings()
134120
msg = ('\nCould not initialize PAL labeling engine, '
@@ -137,19 +123,19 @@ def setUpClass(cls):
137123

138124
cls._BaseSetup = True
139125

126+
@classmethod
127+
def tearDownClass(cls):
128+
"""Run after all tests"""
129+
pass
130+
# cls.removeAllLayers()
131+
140132
@classmethod
141133
def setDefaultEngineSettings(cls):
142134
"""Restore default settings for pal labelling"""
143135
cls._Pal = QgsPalLabeling()
144136
cls._MapRenderer.setLabelingEngine(cls._Pal)
145137
cls._PalEngine = cls._MapRenderer.labelingEngine()
146138

147-
@classmethod
148-
def tearDownClass(cls):
149-
"""Run after all tests"""
150-
pass
151-
# cls.removeAllLayers()
152-
153139
@classmethod
154140
def removeAllLayers(cls):
155141
cls._MapRegistry.removeAllMapLayers()
@@ -192,6 +178,44 @@ def aoiExtent(cls):
192178
aoilayer = QgsVectorLayer(uri.uri(), 'aoi', 'spatialite')
193179
return aoilayer.extent()
194180

181+
@classmethod
182+
def getBaseMapSettings(cls):
183+
"""
184+
:rtype: QgsMapSettings
185+
"""
186+
ms = QgsMapSettings()
187+
crs = QgsCoordinateReferenceSystem()
188+
""":type: QgsCoordinateReferenceSystem"""
189+
# default for labeling test data: WGS 84 / UTM zone 13N
190+
crs.createFromSrid(32613)
191+
ms.setBackgroundColor(QColor(152, 219, 249))
192+
ms.setOutputSize(QSize(600, 400))
193+
ms.setOutputDpi(72)
194+
ms.setFlag(QgsMapSettings.Antialiasing)
195+
ms.setDestinationCrs(crs)
196+
ms.setCrsTransformEnabled(False)
197+
ms.setMapUnits(crs.mapUnits()) # meters
198+
ms.setExtent(cls.aoiExtent())
199+
return ms
200+
201+
def cloneMapSettings(self, oms):
202+
"""
203+
:param oms: QgsMapSettings
204+
:rtype: QgsMapSettings
205+
"""
206+
ms = QgsMapSettings()
207+
ms.setBackgroundColor(oms.backgroundColor())
208+
ms.setOutputSize(oms.outputSize())
209+
ms.setOutputDpi(oms.outputDpi())
210+
ms.setFlags(oms.flags())
211+
ms.setDestinationCrs(oms.destinationCrs())
212+
ms.setCrsTransformEnabled(oms.hasCrsTransformEnabled())
213+
ms.setMapUnits(oms.mapUnits())
214+
ms.setExtent(oms.extent())
215+
216+
ms.setLayers(oms.layers())
217+
return ms
218+
195219
def configTest(self, prefix, abbr):
196220
"""Call in setUp() function of test subclass"""
197221
self._TestGroupPrefix = prefix
@@ -244,13 +268,14 @@ def controlImagePath(self, grpprefix=''):
244268
'expected_' + grpprefix,
245269
self._Test, self._Test + '.png')
246270

247-
def saveContolImage(self, tmpimg=''):
271+
def saveControlImage(self, tmpimg=''):
248272
# don't save control images for RenderVsOtherOutput (Vs) tests, since
249273
# those control images belong to a different test result
250274
if ('PAL_CONTROL_IMAGE' not in os.environ
251275
or 'Vs' in self._TestGroup):
252276
return
253277
imgpath = self.controlImagePath()
278+
# print "saveControlImage: {0}".format(imgpath)
254279
testdir = os.path.dirname(imgpath)
255280
if not os.path.exists(testdir):
256281
os.makedirs(testdir)
@@ -263,12 +288,68 @@ def saveContolImage(self, tmpimg=''):
263288
if tmpimg and os.path.exists(tmpimg):
264289
shutil.copyfile(tmpimg, imgpath)
265290
else:
266-
self._Map.render()
267-
self._Canvas.saveAsImage(imgpath)
291+
print '\nsaveControlImage.render(): entered'
292+
print '{0}.{1}'.format(self._TestGroup, self._TestFunction)
293+
294+
ms = self._MapSettings # class settings
295+
""":type: QgsMapSettings"""
296+
if self._TestMapSettings is not None:
297+
ms = self._TestMapSettings # per test settings
298+
print 'self._MapSettings...'
299+
print 'ms.layers(): {0}'.format(
300+
[self._MapRegistry.mapLayer(i).name() for i in ms.layers()]
301+
)
302+
print 'ms.outputSize(): {0} x {1}'.format(
303+
ms.outputSize().width(), ms.outputSize().height())
304+
print 'ms.outputDpi(): {0}'.format(ms.outputDpi())
305+
print 'ms.mapUnits(): {0}'.format(ms.mapUnits())
306+
print 'ms.extent(): {0}'.format(ms.extent().toString())
307+
print 'ms.hasCrsTransformEnabled(): {0}'.format(
308+
ms.hasCrsTransformEnabled())
309+
print 'ms.destinationCrs(): {0}'.format(
310+
ms.destinationCrs().authid())
311+
312+
# pal = QgsPalLabeling()
313+
pal = self._Pal.clone() # or custom settings are lost
314+
pal.init(ms)
315+
r = QgsMapRenderer()
316+
r.setLabelingEngine(pal)
317+
318+
# this seems too redundant
319+
r.setOutputSize(ms.outputSize(), ms.outputDpi())
320+
r.setMapUnits(ms.mapUnits())
321+
r.setExtent(ms.extent())
322+
r.setProjectionsEnabled(ms.hasCrsTransformEnabled())
323+
r.setDestinationCrs(ms.destinationCrs())
324+
r.setLayerSet(ms.layers())
325+
326+
ctx = r.rendererContext()
327+
ctx.setDrawEditingInformation(
328+
ms.testFlag(QgsMapSettings.DrawEditingInfo))
329+
ctx.setForceVectorOutput(
330+
ms.testFlag(QgsMapSettings.ForceVectorOutput))
331+
ctx.setUseAdvancedEffects(
332+
ms.testFlag(QgsMapSettings.UseAdvancedEffects))
333+
334+
image = QImage(ms.outputSize(), QImage.Format_ARGB32)
335+
image.fill(ms.backgroundColor().rgb())
336+
image.setDotsPerMeterX(ms.outputDpi() / 25.4 * 1000)
337+
image.setDotsPerMeterY(ms.outputDpi() / 25.4 * 1000)
338+
339+
p = QPainter(image)
340+
r.render(p)
341+
p.end()
342+
343+
if not image.save(imgpath, 'png'):
344+
os.unlink(imgpath)
345+
268346
# delete extraneous world file (always generated)
269-
wrld_file = imgbasepath + '.PNGw'
270-
if os.path.exists(wrld_file):
271-
os.remove(wrld_file)
347+
# wrld_file = imgbasepath + '.PNGw'
348+
# if os.path.exists(wrld_file):
349+
# os.remove(wrld_file)
350+
351+
if not os.path.exists(imgpath):
352+
raise OSError('Control image not created: {0}'.format(imgpath))
272353

273354
def renderCheck(self, mismatch=0, imgpath='', grpprefix=''):
274355
"""Check rendered map canvas or existing image against control image

‎tests/src/python/test_qgspallabeling_canvas.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def setUp(self):
6363

6464
def checkTest(self, **kwargs):
6565
self.lyr.writeToLayer(self.layer)
66-
self.saveContolImage()
66+
self.saveControlImage()
6767
self.assertTrue(*self.renderCheck())
6868

6969

‎tests/src/python/test_qgspallabeling_composer.py

Lines changed: 59 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,6 @@ def setUpClass(cls):
7777
cls._CheckMismatch = 0 # mismatch expected for crosscheck
7878
cls._TestImage = ''
7979
cls._TestKind = '' # img|svg|pdf
80-
cls._ImgW = 600
81-
cls._ImgH = 400
82-
cls._ImgDpi = 72
8380

8481
@classmethod
8582
def tearDownClass(cls):
@@ -93,21 +90,15 @@ def setUp(self):
9390
TestQgsPalLabeling.setDefaultEngineSettings()
9491
self.lyr = self.defaultLayerSettings()
9592
self._TestImage = ''
96-
97-
# noinspection PyUnusedLocal
98-
def checkTest(self, **kwargs):
99-
self.lyr.writeToLayer(self.layer)
100-
res_m, self._TestImage = self.get_composer_output(self._TestKind)
101-
self.saveContolImage(self._TestImage)
102-
self.assertTrue(res_m, 'Failed to retrieve/save output from composer')
103-
self.assertTrue(*self.renderCheck(mismatch=self._CheckMismatch,
104-
imgpath=self._TestImage))
93+
# ensure per test map settings stay encapsulated
94+
self._TestMapSettings = self.cloneMapSettings(self._MapSettings)
10595

10696
def _set_up_composition(self, width, height, dpi):
10797
# set up composition and add map
10898
# TODO: how to keep embedded map from being anti-aliased twice?
10999
# self._MapSettings.setFlag(QgsMapSettings.Antialiasing, False)
110-
self._c = QgsComposition(self._MapSettings)
100+
# self._MapSettings.setFlag(QgsMapSettings.UseAdvancedEffects, True)
101+
self._c = QgsComposition(self._TestMapSettings)
111102
""":type: QgsComposition"""
112103
self._c.setPrintResolution(dpi)
113104
# 600 x 400 px = 211.67 x 141.11 mm @ 72 dpi
@@ -120,34 +111,30 @@ def _set_up_composition(self, width, height, dpi):
120111
self._c, 0, 0, self._c.paperWidth(), self._c.paperHeight())
121112
""":type: QgsComposerMap"""
122113
self._cmap.setFrameEnabled(False)
123-
self._c.addComposerMap(self._cmap)
124114
self._cmap.setNewExtent(self.aoiExtent())
115+
self._c.addComposerMap(self._cmap)
125116
self._c.setPlotStyle(QgsComposition.Print)
126117

127118
# noinspection PyUnusedLocal
128119
def _get_composer_image(self, width, height, dpi):
129-
# dpi = self._c.printResolution() # why did I add this before?
130-
dpmm = dpi / 25.4
131-
img_width = int(dpmm * self._c.paperWidth())
132-
img_height = int(dpmm * self._c.paperHeight())
133-
134-
# create output image and initialize it
135-
image = QImage(QSize(img_width, img_height), QImage.Format_ARGB32)
136-
image.setDotsPerMeterX(dpmm * 1000)
137-
image.setDotsPerMeterY(dpmm * 1000)
120+
image = QImage(QSize(width, height), QImage.Format_ARGB32)
138121
image.fill(QColor(152, 219, 249).rgb())
122+
image.setDotsPerMeterX(dpi / 25.4 * 1000)
123+
image.setDotsPerMeterY(dpi / 25.4 * 1000)
139124

140-
# render the composition
141125
p = QPainter(image)
142-
p.setRenderHint(QPainter.HighQualityAntialiasing, False)
143-
p.setRenderHint(QPainter.SmoothPixmapTransform, False)
144-
p.setRenderHint(QPainter.Antialiasing, False)
145-
p.setRenderHint(QPainter.TextAntialiasing, False)
146-
src = QRectF(0, 0, self._c.paperWidth(), self._c.paperHeight())
147-
trgt = QRectF(0, 0, img_width, img_height)
148-
self._c.render(p, trgt, src)
126+
p.setRenderHint(QPainter.Antialiasing, True)
127+
p.setRenderHint(QPainter.HighQualityAntialiasing, True)
128+
self._c.renderPage(p, 0)
149129
p.end()
150130

131+
# image = self._c.printPageAsRaster(0)
132+
# """:type: QImage"""
133+
134+
if image.isNull():
135+
# something went pear-shaped
136+
return False, ''
137+
151138
filepath = getTempfilePath('png')
152139
res = image.save(filepath, 'png')
153140
if not res:
@@ -161,17 +148,21 @@ def _get_composer_svg_image(self, width, height, dpi):
161148
# line 1909, near end of function
162149
svgpath = getTempfilePath('svg')
163150
temp_size = os.path.getsize(svgpath)
151+
164152
svg_g = QSvgGenerator()
165153
# noinspection PyArgumentList
166154
svg_g.setTitle(QgsProject.instance().title())
167155
svg_g.setFileName(svgpath)
168156
# width and height in pixels
169-
svg_w = int(self._c.paperWidth() * self._c.printResolution() / 25.4)
170-
svg_h = int(self._c.paperHeight() * self._c.printResolution() / 25.4)
157+
# svg_w = int(self._c.paperWidth() * self._c.printResolution() / 25.4)
158+
# svg_h = int(self._c.paperHeight() * self._c.printResolution() / 25.4)
159+
svg_w = width
160+
svg_h = height
171161
svg_g.setSize(QSize(svg_w, svg_h))
172162
svg_g.setViewBox(QRect(0, 0, svg_w, svg_h))
173163
# because the rendering is done in mm, convert the dpi
174-
svg_g.setResolution(self._c.printResolution())
164+
# svg_g.setResolution(self._c.printResolution())
165+
svg_g.setResolution(dpi)
175166

176167
sp = QPainter(svg_g)
177168
self._c.renderPage(sp, 0)
@@ -181,11 +172,12 @@ def _get_composer_svg_image(self, width, height, dpi):
181172
# something went pear-shaped
182173
return False, ''
183174

184-
svgr = QSvgRenderer(svgpath)
185175
image = QImage(width, height, QImage.Format_ARGB32)
186176
image.fill(QColor(152, 219, 249).rgb())
187-
image.setDotsPerMeterX(dpi/25.4 * 1000)
188-
image.setDotsPerMeterY(dpi/25.4 * 1000)
177+
image.setDotsPerMeterX(dpi / 25.4 * 1000)
178+
image.setDotsPerMeterY(dpi / 25.4 * 1000)
179+
180+
svgr = QSvgRenderer(svgpath)
189181
p = QPainter(image)
190182
svgr.render(p)
191183
p.end()
@@ -202,6 +194,7 @@ def _get_composer_svg_image(self, width, height, dpi):
202194
def _get_composer_pdf_image(self, width, height, dpi):
203195
pdfpath = getTempfilePath('pdf')
204196
temp_size = os.path.getsize(pdfpath)
197+
205198
p = QPrinter()
206199
p.setOutputFormat(QPrinter.PdfFormat)
207200
p.setOutputFileName(pdfpath)
@@ -212,36 +205,34 @@ def _get_composer_pdf_image(self, width, height, dpi):
212205
p.setResolution(self._c.printResolution())
213206

214207
pdf_p = QPainter(p)
215-
page_mm = p.pageRect(QPrinter.Millimeter)
216-
page_px = p.pageRect(QPrinter.DevicePixel)
217-
self._c.render(pdf_p, page_px, page_mm)
208+
# page_mm = p.pageRect(QPrinter.Millimeter)
209+
# page_px = p.pageRect(QPrinter.DevicePixel)
210+
# self._c.render(pdf_p, page_px, page_mm)
211+
self._c.renderPage(pdf_p, 0)
218212
pdf_p.end()
219213

220214
if temp_size == os.path.getsize(pdfpath):
221215
# something went pear-shaped
222216
return False, ''
223217

224218
filepath = getTempfilePath('png')
225-
filebase = os.path.join(os.path.dirname(filepath),
226-
os.path.splitext(os.path.basename(filepath))[0])
227219
# pdftoppm -singlefile -r 72 -x 0 -y 0 -W 600 -H 400 -png in.pdf pngbase
228220
# mudraw -o out.png -r 72 -w 600 -h 400 -c rgb[a] in.pdf
229221
if PDFUTIL == 'pdftoppm':
222+
filebase = os.path.join(
223+
os.path.dirname(filepath),
224+
os.path.splitext(os.path.basename(filepath))[0]
225+
)
230226
call = [
231-
'pdftoppm', '-singlefile',
232-
'-r', str(dpi),
233-
'-x', str(0), '-y', str(0),
234-
'-W', str(width), '-H', str(height),
227+
'pdftoppm', '-singlefile', '-r', str(dpi),
228+
'-x', str(0), '-y', str(0), '-W', str(width), '-H', str(height),
235229
'-png', pdfpath, filebase
236230
]
237231
elif PDFUTIL == 'mudraw':
238232
call = [
239-
'mudraw'
240-
'-o', filepath,
241-
'-c', 'rgba',
242-
'-r', str(dpi),
243-
'-w', str(width), '-h', str(height),
244-
pdfpath
233+
'mudraw', '-c', 'rgba',
234+
'-r', str(dpi), '-w', str(width), '-h', str(height),
235+
'-o', filepath, pdfpath
245236
]
246237
else:
247238
return False, ''
@@ -255,25 +246,36 @@ def _get_composer_pdf_image(self, width, height, dpi):
255246
return res, filepath
256247

257248
def get_composer_output(self, kind):
258-
width, height, dpi = self._ImgW, self._ImgH, self._ImgDpi
249+
ms = self._TestMapSettings
250+
osize = ms.outputSize()
251+
width, height, dpi = osize.width(), osize.height(), ms.outputDpi()
259252
self._set_up_composition(width, height, dpi)
260253
if kind == OutputKind.Svg:
261254
return self._get_composer_svg_image(width, height, dpi)
262255
elif kind == OutputKind.Pdf:
263256
return self._get_composer_pdf_image(width, height, dpi)
264-
else: # 'img'
257+
else: # OutputKind.Img
265258
return self._get_composer_image(width, height, dpi)
266259

260+
# noinspection PyUnusedLocal
261+
def checkTest(self, **kwargs):
262+
self.lyr.writeToLayer(self.layer)
263+
res_m, self._TestImage = self.get_composer_output(self._TestKind)
264+
self.saveControlImage(self._TestImage)
265+
self.assertTrue(res_m, 'Failed to retrieve/save output from composer')
266+
self.assertTrue(*self.renderCheck(mismatch=self._CheckMismatch,
267+
imgpath=self._TestImage))
268+
267269

268-
class TestComposerPointBase(TestComposerBase, TestPointBase):
270+
class TestComposerPointBase(TestComposerBase):
269271

270272
@classmethod
271273
def setUpClass(cls):
272274
TestComposerBase.setUpClass()
273275
cls.layer = TestQgsPalLabeling.loadFeatureLayer('point')
274276

275277

276-
class TestComposerImagePoint(TestComposerPointBase):
278+
class TestComposerImagePoint(TestComposerPointBase, TestPointBase):
277279

278280
def setUp(self):
279281
"""Run before each test."""
@@ -284,7 +286,7 @@ def setUp(self):
284286
self._CheckMismatch = 2700 # comment to PAL_REPORT difference
285287

286288

287-
class TestComposerImageVsCanvasPoint(TestComposerPointBase):
289+
class TestComposerImageVsCanvasPoint(TestComposerPointBase, TestPointBase):
288290

289291
def setUp(self):
290292
"""Run before each test."""

‎tests/src/python/test_qgspallabeling_server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ def checkTest(self, **kwargs):
168168
# print self.params.__repr__()
169169
res_m, self._TestImage = MAPSERV.get_map(self.params, False)
170170
# print self._TestImage.__repr__()
171-
self.saveContolImage(self._TestImage)
171+
self.saveControlImage(self._TestImage)
172172
self.assertTrue(res_m, 'Failed to retrieve/save image from test server')
173173
self.assertTrue(*self.renderCheck(mismatch=self._CheckMismatch,
174174
imgpath=self._TestImage))
931 Bytes

Error rendering embedded code

Invalid image source.

927 Bytes

Error rendering embedded code

Invalid image source.

937 Bytes
Loading
938 Bytes

Error rendering embedded code

Invalid image source.

958 Bytes
Loading
338 Bytes

Error rendering embedded code

Invalid image source.

1019 Bytes

Error rendering embedded code

Invalid image source.

742 Bytes

Error rendering embedded code

Invalid image source.

925 Bytes

Error rendering embedded code

Invalid image source.

-105 Bytes
Loading

Error rendering embedded code

Invalid image source.

76 Bytes

Error rendering embedded code

Invalid image source.

127 Bytes

Error rendering embedded code

Invalid image source.

33 Bytes

Error rendering embedded code

Invalid image source.

Error rendering embedded code

Invalid image source.

Error rendering embedded code

Invalid image source.

112 Bytes

Error rendering embedded code

Invalid image source.

122 Bytes

Error rendering embedded code

Invalid image source.

0 commit comments

Comments
 (0)
Please sign in to comment.