Skip to content

Commit f29d44e

Browse files
committed
Add PDF composer output labeling tests setup
- Only support for Poppler with Cairo (pdftocairo), since without Cairo a PDF's vectors are not always rendered properly
1 parent db4401f commit f29d44e

File tree

11 files changed

+66
-20
lines changed

11 files changed

+66
-20
lines changed

tests/src/python/test_qgspallabeling_composer.py

Lines changed: 64 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030
from qgis.core import *
3131

3232
from utilities import (
33-
unittest,
34-
expectedFailure,
3533
getTempfilePath,
3634
getExecutablePath,
3735
)
@@ -42,18 +40,23 @@
4240
suiteTests
4341
)
4442

45-
# look for Poppler, then muPDF PDF-to-image utility
46-
for util in ['pdftoppm', 'mudraw']:
43+
# PDF-to-image utility
44+
# look for Poppler w/ Cairo, then muPDF
45+
# * Poppler w/ Cairo renders correctly
46+
# * Poppler w/o Cairo does not always correctly render vectors in PDF to image
47+
# * muPDF renders correctly, but sightly shifts colors
48+
for util in [
49+
'pdftocairo',
50+
# 'mudraw',
51+
]:
4752
PDFUTIL = getExecutablePath(util)
4853
if PDFUTIL:
4954
break
5055

51-
52-
def skip_if_not_pdf_util(): # skip test class decorator
53-
if PDFUTIL:
54-
return lambda func: func
55-
return unittest.skip('\nPDF-to-image utility not found on PATH\n'
56-
'Install Poppler or muPDF utilities\n\n')
56+
# noinspection PyUnboundLocalVariable
57+
if not PDFUTIL:
58+
raise Exception('PDF-to-image utility not found on PATH: '
59+
'install Poppler (with Cairo)')
5760

5861

5962
# output kind enum
@@ -214,28 +217,40 @@ def _get_composer_pdf_image(self, width, height, dpi):
214217
return False, ''
215218

216219
filepath = getTempfilePath('png')
217-
# pdftoppm -singlefile -r 72 -x 0 -y 0 -W 600 -H 400 -png in.pdf pngbase
218-
# mudraw -o out.png -r 72 -w 600 -h 400 -c rgb[a] in.pdf
219-
if PDFUTIL == 'pdftoppm':
220+
# Poppler (pdftocairo or pdftoppm):
221+
# PDFUTIL -png -singlefile -r 72 -x 0 -y 0 -W 420 -H 280 in.pdf pngbase
222+
# muPDF (mudraw):
223+
# PDFUTIL -c rgb[a] -r 72 -w 420 -h 280 -o out.png in.pdf
224+
if PDFUTIL.strip().endswith('pdftocairo'):
220225
filebase = os.path.join(
221226
os.path.dirname(filepath),
222227
os.path.splitext(os.path.basename(filepath))[0]
223228
)
224229
call = [
225-
'pdftoppm', '-singlefile', '-r', str(dpi),
226-
'-x', str(0), '-y', str(0), '-W', str(width), '-H', str(height),
227-
'-png', pdfpath, filebase
230+
PDFUTIL, '-png', '-singlefile', '-r', str(dpi),
231+
'-x', '0', '-y', '0', '-W', str(width), '-H', str(height),
232+
pdfpath, filebase
228233
]
229-
elif PDFUTIL == 'mudraw':
234+
elif PDFUTIL.strip().endswith('mudraw'):
230235
call = [
231-
'mudraw', '-c', 'rgba',
236+
PDFUTIL, '-c', 'rgba',
232237
'-r', str(dpi), '-w', str(width), '-h', str(height),
238+
# '-b', '8',
233239
'-o', filepath, pdfpath
234240
]
235241
else:
236242
return False, ''
237243

238-
res = subprocess.check_call(call)
244+
qDebug("_get_composer_pdf_image call: {0}".format(' '.join(call)))
245+
res = False
246+
try:
247+
subprocess.check_call(call)
248+
res = True
249+
except subprocess.CalledProcessError as e:
250+
qDebug("_get_composer_pdf_image failed!\n"
251+
"cmd: {0}\n"
252+
"returncode: {1}\n"
253+
"message: {2}".format(e.cmd, e.returncode, e.message))
239254

240255
if not res:
241256
os.unlink(filepath)
@@ -269,6 +284,7 @@ def checkTest(self, **kwargs):
269284
mismatch = self._Mismatches[self._TestGroup]
270285
colortol = 0
271286
if 'PAL_NO_COLORTOL' not in os.environ:
287+
colortol = self._ColorTol if self._ColorTol else 0
272288
if self._TestGroup in self._ColorTols:
273289
colortol = self._ColorTols[self._TestGroup]
274290
self.assertTrue(*self.renderCheck(mismatch=mismatch,
@@ -320,7 +336,29 @@ def setUp(self):
320336
super(TestComposerSvgVsComposerPoint, self).setUp()
321337
self._TestKind = OutputKind.Svg
322338
self.configTest('pal_composer', 'sp_img')
323-
self._Mismatch = 350
339+
self._ColorTol = 4
340+
341+
342+
class TestComposerPdfPoint(TestComposerPointBase, TestPointBase):
343+
344+
def setUp(self):
345+
"""Run before each test."""
346+
super(TestComposerPdfPoint, self).setUp()
347+
self._TestKind = OutputKind.Pdf
348+
self.configTest('pal_composer', 'sp_pdf')
349+
350+
351+
class TestComposerPdfVsComposerPoint(TestComposerPointBase, TestPointBase):
352+
"""
353+
Compare only to composer image, which is already compared to canvas point
354+
"""
355+
def setUp(self):
356+
"""Run before each test."""
357+
super(TestComposerPdfVsComposerPoint, self).setUp()
358+
self._TestKind = OutputKind.Pdf
359+
self.configTest('pal_composer', 'sp_img')
360+
self._Mismatch = 50
361+
self._ColorTol = 18
324362

325363

326364
if __name__ == '__main__':
@@ -331,11 +369,17 @@ def setUp(self):
331369
sp_ivs = ['TestComposerImageVsCanvasPoint.' + t for t in st['sp_vs_suite']]
332370
sp_s = ['TestComposerSvgPoint.' + t for t in st['sp_suite']]
333371
sp_svs = ['TestComposerSvgVsComposerPoint.' + t for t in st['sp_vs_suite']]
372+
sp_p = ['TestComposerPdfPoint.' + t for t in st['sp_suite']]
373+
sp_pvs = ['TestComposerPdfVsComposerPoint.' + t for t in st['sp_vs_suite']]
334374
suite = []
375+
335376
# extended separately for finer control of PAL_SUITE (comment-out undesired)
336377
suite.extend(sp_i)
337378
suite.extend(sp_ivs)
338379
suite.extend(sp_s)
339380
suite.extend(sp_svs)
381+
suite.extend(sp_p)
382+
suite.extend(sp_pvs)
383+
340384
res = runSuite(sys.modules[__name__], suite)
341385
sys.exit(not res.wasSuccessful())

tests/src/python/test_qgspallabeling_tests.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ def test_background_svg(self):
105105
self.lyr.shapeSizeUnits = QgsPalLayerSettings.MapUnits
106106
self.lyr.shapeSizeType = QgsPalLayerSettings.SizeBuffer
107107
self.lyr.shapeSize = QPointF(100.0, 0.0)
108+
self._Mismatches['TestComposerPdfVsComposerPoint'] = 580
108109
self.checkTest()
109110

110111
def test_background_svg_w_offset(self):
@@ -125,6 +126,7 @@ def test_background_svg_w_offset(self):
125126

126127
self.lyr.shapeOffsetUnits = QgsPalLayerSettings.MapUnits
127128
self.lyr.shapeOffset = QPointF(-2850.0, 500.0)
129+
self._Mismatches['TestComposerPdfVsComposerPoint'] = 760
128130
self.checkTest()
129131

130132
def test_partials_labels_enabled(self):
Loading

0 commit comments

Comments
 (0)