Skip to content
Permalink
Browse files

Add composer svg export label unit tests

- Fix composer composition setup to near identical output of canvas->image (finally, expect for symbology, which still seems to be double-antialiased)
- Rebuild control images for composer->image output
  • Loading branch information
dakcarto committed Mar 14, 2014
1 parent b6b78ca commit fa157b0debf4c290448208b14c747b9bc00b9c02
Showing with 73 additions and 48 deletions.
  1. +60 −38 tests/src/python/test_qgspallabeling_composer.py
  2. +3 −1 tests/src/python/test_qgspallabeling_server.py
  3. +10 −9 tests/src/python/test_qgspallabeling_tests.py
  4. BIN ...s/testdata/control_images/expected_pal_composer/sp_img_background_rect/sp_img_background_rect.png
  5. BIN ..._images/expected_pal_composer/sp_img_background_rect_w_offset/sp_img_background_rect_w_offset.png
  6. BIN tests/testdata/control_images/expected_pal_composer/sp_img_background_svg/sp_img_background_svg.png
  7. BIN ...ol_images/expected_pal_composer/sp_img_background_svg_w_offset/sp_img_background_svg_w_offset.png
  8. BIN tests/testdata/control_images/expected_pal_composer/sp_img_default_label/sp_img_default_label.png
  9. BIN ..._images/expected_pal_composer/sp_img_partials_labels_disabled/sp_img_partials_labels_disabled.png
  10. BIN ...ol_images/expected_pal_composer/sp_img_partials_labels_enabled/sp_img_partials_labels_enabled.png
  11. BIN tests/testdata/control_images/expected_pal_composer/sp_img_text_color/sp_img_text_color.png
  12. BIN ...data/control_images/expected_pal_composer/sp_img_text_size_map_unit/sp_img_text_size_map_unit.png
  13. BIN ...s/testdata/control_images/expected_pal_composer/sp_svg_background_rect/sp_svg_background_rect.png
  14. BIN ..._images/expected_pal_composer/sp_svg_background_rect_w_offset/sp_svg_background_rect_w_offset.png
  15. BIN tests/testdata/control_images/expected_pal_composer/sp_svg_background_svg/sp_svg_background_svg.png
  16. BIN ...ol_images/expected_pal_composer/sp_svg_background_svg_w_offset/sp_svg_background_svg_w_offset.png
  17. BIN tests/testdata/control_images/expected_pal_composer/sp_svg_default_label/sp_svg_default_label.png
  18. BIN ..._images/expected_pal_composer/sp_svg_partials_labels_disabled/sp_svg_partials_labels_disabled.png
  19. BIN ...ol_images/expected_pal_composer/sp_svg_partials_labels_enabled/sp_svg_partials_labels_enabled.png
  20. BIN tests/testdata/control_images/expected_pal_composer/sp_svg_text_color/sp_svg_text_color.png
  21. BIN ...data/control_images/expected_pal_composer/sp_svg_text_size_map_unit/sp_svg_text_size_map_unit.png
@@ -94,44 +94,50 @@ def setUp(self):

def _set_up_composition(self, width, height, dpi):
# set up composition and add map
# TODO: how to keep embedded map from being anti-aliased twice?
# self._MapSettings.setFlag(QgsMapSettings.Antialiasing, False)
# self._MapSettings.setFlag(QgsMapSettings.UseAdvancedEffects, True)
self._TestMapSettings.setFlag(QgsMapSettings.Antialiasing, True)
self._TestMapSettings.setFlag(QgsMapSettings.UseAdvancedEffects, True)
self._TestMapSettings.setFlag(QgsMapSettings.ForceVectorOutput, True)
self._c = QgsComposition(self._TestMapSettings)
""":type: QgsComposition"""
# self._c.setUseAdvancedEffects(False)
self._c.setPrintResolution(dpi)
# 600 x 400 px = 211.67 x 141.11 mm @ 72 dpi
# TODO: figure out why this doesn't work and needs fudging
# probably need sets of fudgyness per dpi group (72, 150, 300)?
paperw = round((width * 25.4 / dpi) + 0.05, 0)
paperh = round((height * 25.4 / dpi) + 0.05, 1)
paperw = width * 25.4 / dpi
paperh = height * 25.4 / dpi
self._c.setPaperSize(paperw, paperh)
self._cmap = QgsComposerMap(
self._c, 0, 0, self._c.paperWidth(), self._c.paperHeight())
# NOTE: do not use QgsComposerMap(self._c, 0, 0, paperw, paperh) since
# it only takes integers as parameters and the composition will grow
# larger based upon union of item scene rectangles and a slight buffer
# see end of QgsComposition::compositionBounds()
# add map as small graphics item first, then set its scene QRectF later
self._cmap = QgsComposerMap(self._c, 10, 10, 10, 10)
""":type: QgsComposerMap"""
self._cmap.setPreviewMode(QgsComposerMap.Render)
self._cmap.setFrameEnabled(False)
self._cmap.setNewExtent(self.aoiExtent())
self._c.addComposerMap(self._cmap)
# now expand map to fill page and set its extent
self._cmap.setSceneRect(QRectF(0, 0, paperw, paperw))
self._cmap.setNewExtent(self.aoiExtent())
# self._cmap.updateCachedImage()
self._c.setPlotStyle(QgsComposition.Print)

# noinspection PyUnusedLocal
def _get_composer_image(self, width, height, dpi):
image = QImage(QSize(width, height), QImage.Format_ARGB32)
image.fill(QColor(152, 219, 249).rgb())
image.setDotsPerMeterX(dpi / 25.4 * 1000)
image.setDotsPerMeterY(dpi / 25.4 * 1000)

p = QPainter(image)
p.setRenderHint(QPainter.Antialiasing, True)
p.setRenderHint(QPainter.HighQualityAntialiasing, True)
self._c.renderPage(p, 0)
p.end()

# image = self._c.printPageAsRaster(0)
# """:type: QImage"""
# image = QImage(QSize(width, height), QImage.Format_ARGB32)
# image.fill(QColor(152, 219, 249).rgb())
# image.setDotsPerMeterX(dpi / 25.4 * 1000)
# image.setDotsPerMeterY(dpi / 25.4 * 1000)
#
# p = QPainter(image)
# p.setRenderHint(QPainter.Antialiasing, False)
# p.setRenderHint(QPainter.HighQualityAntialiasing, False)
# self._c.renderPage(p, 0)
# p.end()

image = self._c.printPageAsRaster(0)
""":type: QImage"""

if image.isNull():
# something went pear-shaped
return False, ''

filepath = getTempfilePath('png')
@@ -144,31 +150,23 @@ def _get_composer_image(self, width, height, dpi):

def _get_composer_svg_image(self, width, height, dpi):
# from qgscomposer.cpp, QgsComposer::on_mActionExportAsSVG_triggered,
# line 1909, near end of function
# near end of function
svgpath = getTempfilePath('svg')
temp_size = os.path.getsize(svgpath)

svg_g = QSvgGenerator()
# noinspection PyArgumentList
svg_g.setTitle(QgsProject.instance().title())
svg_g.setFileName(svgpath)
# width and height in pixels
# svg_w = int(self._c.paperWidth() * self._c.printResolution() / 25.4)
# svg_h = int(self._c.paperHeight() * self._c.printResolution() / 25.4)
svg_w = width
svg_h = height
svg_g.setSize(QSize(svg_w, svg_h))
svg_g.setViewBox(QRect(0, 0, svg_w, svg_h))
# because the rendering is done in mm, convert the dpi
# svg_g.setResolution(self._c.printResolution())
svg_g.setSize(QSize(width, height))
svg_g.setViewBox(QRect(0, 0, width, height))
svg_g.setResolution(dpi)

sp = QPainter(svg_g)
self._c.renderPage(sp, 0)
sp.end()

if temp_size == os.path.getsize(svgpath):
# something went pear-shaped
return False, ''

image = QImage(width, height, QImage.Format_ARGB32)
@@ -211,7 +209,6 @@ def _get_composer_pdf_image(self, width, height, dpi):
pdf_p.end()

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

filepath = getTempfilePath('png')
@@ -260,10 +257,11 @@ def get_composer_output(self, kind):
def checkTest(self, **kwargs):
self.lyr.writeToLayer(self.layer)
res_m, self._TestImage = self.get_composer_output(self._TestKind)
self.saveControlImage(self._TestImage)
self.assertTrue(res_m, 'Failed to retrieve/save output from composer')
self.saveControlImage(self._TestImage)
mismatch = self._Mismatch
if self._TestGroup in self._Mismatches:
if (self._TestGroup in self._Mismatches
and 'PAL_NO_MISMATCH' not in os.environ):
mismatch = self._Mismatches[self._TestGroup]
self.assertTrue(*self.renderCheck(mismatch=mismatch,
imgpath=self._TestImage))
@@ -295,15 +293,39 @@ def setUp(self):
self.configTest('pal_canvas', 'sp')


class TestComposerSvgPoint(TestComposerPointBase, TestPointBase):

def setUp(self):
"""Run before each test."""
super(TestComposerSvgPoint, self).setUp()
self._TestKind = OutputKind.Svg
self.configTest('pal_composer', 'sp_svg')


class TestComposerSvgVsComposerPoint(TestComposerPointBase, TestPointBase):
"""
Compare only to composer image, which is already compared to canvas point
"""
def setUp(self):
"""Run before each test."""
super(TestComposerSvgVsComposerPoint, self).setUp()
self._TestKind = OutputKind.Svg
self.configTest('pal_composer', 'sp_img')


if __name__ == '__main__':
# NOTE: unless PAL_SUITE env var is set all test class methods will be run
# SEE: test_qgspallabeling_tests.suiteTests() to define suite
st = suiteTests()
sp_i = ['TestComposerImagePoint.' + t for t in st['sp_suite']]
sp_ivs = ['TestComposerImageVsCanvasPoint.' + t for t in st['sp_vs_suite']]
sp_s = ['TestComposerSvgPoint.' + t for t in st['sp_suite']]
sp_svs = ['TestComposerSvgVsComposerPoint.' + t for t in st['sp_vs_suite']]
suite = []
# extended separately for finer control of PAL_SUITE (comment-out undesired)
suite.extend(sp_i)
suite.extend(sp_ivs)
suite.extend(sp_s)
suite.extend(sp_svs)
res = runSuite(sys.modules[__name__], suite)
sys.exit(not res.wasSuccessful())
@@ -82,7 +82,9 @@ def setUpClass(cls):
settings = QSettings()
# noinspection PyArgumentList
cls._CacheDir = settings.value(
"cache/directory", QgsApplication.qgisSettingsDirPath() + "cache")
"cache/directory",
os.path.join(QgsApplication.qgisSettingsDirPath(), "cache"),
type=unicode)

@classmethod
def tearDownClass(cls):
@@ -15,7 +15,6 @@
__revision__ = '$Format:%H$'

import os
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

@@ -44,9 +43,14 @@ def __init__(self):
# e.g. self._Mismatches['TestClassName'] = 300
self._Mismatches = dict()

# noinspection PyMethodMayBeStatic
def checkTest(self, **kwargs):
"""Intended to be overridden in subclasses"""
pass

def test_default_label(self):
# Default label placement, with text size in points
self._Mismatches['TestComposerImageVsCanvasPoint'] = 2034
self._Mismatches['TestComposerSvgVsComposerPoint'] = 500
self.checkTest()

def test_text_size_map_unit(self):
@@ -55,18 +59,17 @@ def test_text_size_map_unit(self):
font = QFont(self._TestFont)
font.setPointSizeF(460)
self.lyr.textFont = font
self._Mismatches['TestComposerImageVsCanvasPoint'] = 1877
self.checkTest()

def test_text_color(self):
# Label color change
self.lyr.textColor = Qt.blue
self._Mismatches['TestComposerImageVsCanvasPoint'] = 2034
self._Mismatches['TestComposerSvgVsComposerPoint'] = 500
self.checkTest()

def test_background_rect(self):
self.lyr.shapeDraw = True
self._Mismatches['TestComposerImageVsCanvasPoint'] = 2751
self._Mismatches['TestComposerSvgVsComposerPoint'] = 1100
self.checkTest()

def test_background_rect_w_offset(self):
@@ -82,7 +85,7 @@ def test_background_rect_w_offset(self):
self.lyr.shapeDraw = True
self.lyr.shapeOffsetUnits = QgsPalLayerSettings.MapUnits
self.lyr.shapeOffset = QPointF(-2900.0, -450.0)
self._Mismatches['TestComposerImageVsCanvasPoint'] = 2530
self._Mismatches['TestComposerSvgVsComposerPoint'] = 750
self.checkTest()

def test_background_svg(self):
@@ -100,7 +103,6 @@ def test_background_svg(self):
self.lyr.shapeSizeUnits = QgsPalLayerSettings.MapUnits
self.lyr.shapeSizeType = QgsPalLayerSettings.SizeBuffer
self.lyr.shapeSize = QPointF(100.0, 0.0)
self._Mismatches['TestComposerImageVsCanvasPoint'] = 2882
self.checkTest()

def test_background_svg_w_offset(self):
@@ -121,7 +123,6 @@ def test_background_svg_w_offset(self):

self.lyr.shapeOffsetUnits = QgsPalLayerSettings.MapUnits
self.lyr.shapeOffset = QPointF(-2850.0, 500.0)
self._Mismatches['TestComposerImageVsCanvasPoint'] = 2901
self.checkTest()

def test_partials_labels_enabled(self):
@@ -132,7 +133,7 @@ def test_partials_labels_enabled(self):
# Enable partials labels
self._Pal.setShowingPartialsLabels(True)
self._Pal.saveEngineSettings()
self._Mismatches['TestComposerImageVsCanvasPoint'] = 2250
self._Mismatches['TestComposerSvgVsComposerPoint'] = 600
self.checkTest()

def test_partials_labels_disabled(self):
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 comments on commit fa157b0

Please sign in to comment.
You can’t perform that action at this time.