def _get_composer_pdf_image(self, width, height, dpi): pdfpath = getTempfilePath('pdf') temp_size = os.path.getsize(pdfpath) p = QPrinter() p.setOutputFormat(QPrinter.PdfFormat) p.setOutputFileName(pdfpath) p.setPaperSize(QSizeF(self._c.paperWidth(), self._c.paperHeight()), QPrinter.Millimeter) p.setFullPage(True) p.setColorMode(QPrinter.Color) p.setResolution(self._c.printResolution()) pdf_p = QPainter(p) # page_mm = p.pageRect(QPrinter.Millimeter) # page_px = p.pageRect(QPrinter.DevicePixel) # self._c.render(pdf_p, page_px, page_mm) self._c.renderPage(pdf_p, 0) pdf_p.end() if temp_size == os.path.getsize(pdfpath): # something went pear-shaped return False, '' filepath = getTempfilePath('png') # pdftoppm -singlefile -r 72 -x 0 -y 0 -W 600 -H 400 -png in.pdf pngbase # mudraw -o out.png -r 72 -w 600 -h 400 -c rgb[a] in.pdf if PDFUTIL == 'pdftoppm': filebase = os.path.join( os.path.dirname(filepath), os.path.splitext(os.path.basename(filepath))[0] ) call = [ 'pdftoppm', '-singlefile', '-r', str(dpi), '-x', str(0), '-y', str(0), '-W', str(width), '-H', str(height), '-png', pdfpath, filebase ] elif PDFUTIL == 'mudraw': call = [ 'mudraw', '-c', 'rgba', '-r', str(dpi), '-w', str(width), '-h', str(height), '-o', filepath, pdfpath ] else: return False, '' res = subprocess.check_call(call) if not res: os.unlink(filepath) filepath = '' return res, filepath
def checkTest(self, **kwargs): self.lyr.writeToLayer(self.layer) ms = self._MapSettings # class settings settings_type = "Class" if self._TestMapSettings is not None: ms = self._TestMapSettings # per test settings settings_type = "Test" if "PAL_VERBOSE" in os.environ: qDebug("MapSettings type: {0}".format(settings_type)) qDebug(mapSettingsString(ms)) img = renderMapToImage(ms, parallel=False) self._TestImage = getTempfilePath("png") if not img.save(self._TestImage, "png"): os.unlink(self._TestImage) raise OSError("Failed to save output from map render job") self.saveControlImage(self._TestImage) mismatch = 0 if "PAL_NO_MISMATCH" not in os.environ: # some mismatch expected mismatch = self._Mismatch if self._Mismatch else 0 if self._TestGroup in self._Mismatches: mismatch = self._Mismatches[self._TestGroup] colortol = 0 if "PAL_NO_COLORTOL" not in os.environ: colortol = self._ColorTol if self._ColorTol else 0 if self._TestGroup in self._ColorTols: colortol = self._ColorTols[self._TestGroup] self.assertTrue(*self.renderCheck(mismatch=mismatch, colortol=colortol, imgpath=self._TestImage))
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, False) # p.setRenderHint(QPainter.HighQualityAntialiasing, False) # self._c.renderPage(p, 0) # p.end() image = self._c.printPageAsRaster(0) """:type: QImage""" if image.isNull(): return False, '' filepath = getTempfilePath('png') res = image.save(filepath, 'png') if not res: os.unlink(filepath) filepath = '' return res, filepath
def runSuite(module, tests): """This allows for a list of test names to be selectively run. Also, ensures unittest verbose output comes at end, after debug output""" loader = unittest.defaultTestLoader if 'PAL_SUITE' in os.environ: if tests: suite = loader.loadTestsFromNames(tests, module) else: raise Exception( "\n\n####__ 'PAL_SUITE' set, but no tests specified __####\n") else: suite = loader.loadTestsFromModule(module) verb = 2 if 'PAL_VERBOSE' in os.environ else 0 res = unittest.TextTestRunner(verbosity=verb).run(suite) if PALREPORTS: teststamp = 'PAL Test Report: ' + \ datetime.datetime.now().strftime('%Y-%m-%d %X') report = '<html><head><title>{0}</title></head><body>'.format(teststamp) report += '\n<h2>Failed Tests: {0}</h2>'.format(len(PALREPORTS)) for k, v in list(PALREPORTS.items()): report += '\n<h3>{0}</h3>\n{1}'.format(k, v) report += '</body></html>' tmp_name = getTempfilePath('html') with open(tmp_name, 'wt') as report_file: report_file.write(report) openInBrowserTab('file://' + tmp_name) return res
def checkTest(self, **kwargs): self.layer.setLabeling(QgsVectorLayerSimpleLabeling(self.lyr)) ms = self._MapSettings # class settings settings_type = 'Class' if self._TestMapSettings is not None: ms = self._TestMapSettings # per test settings settings_type = 'Test' if 'PAL_VERBOSE' in os.environ: qDebug('MapSettings type: {0}'.format(settings_type)) qDebug(mapSettingsString(ms)) img = renderMapToImage(ms, parallel=False) self._TestImage = getTempfilePath('png') if not img.save(self._TestImage, 'png'): os.unlink(self._TestImage) raise OSError('Failed to save output from map render job') self.saveControlImage(self._TestImage) mismatch = 0 if 'PAL_NO_MISMATCH' not in os.environ: # some mismatch expected mismatch = self._Mismatch if self._Mismatch else 0 if self._TestGroup in self._Mismatches: mismatch = self._Mismatches[self._TestGroup] colortol = 0 if 'PAL_NO_COLORTOL' not in os.environ: colortol = self._ColorTol if self._ColorTol else 0 if self._TestGroup in self._ColorTols: colortol = self._ColorTols[self._TestGroup] self.assertTrue(*self.renderCheck(mismatch=mismatch, colortol=colortol, imgpath=self._TestImage))
def run_suite(module, tests): """This allows for a list of test names to be selectively run. Also, ensures unittest verbose output comes at end, after debug output""" loader = unittest.defaultTestLoader if 'QGIS_TEST_SUITE' in os.environ and tests: suite = loader.loadTestsFromNames(tests, module) else: suite = loader.loadTestsFromModule(module) verb = 2 if 'QGIS_TEST_VERBOSE' in os.environ else 0 res = unittest.TextTestRunner(verbosity=verb).run(suite) if QGIS_TEST_REPORT and len(TESTREPORTS) > 0: teststamp = 'Local Server Test Report: ' + \ datetime.datetime.now().strftime('%Y-%m-%d %X') report = '<html><head><title>{0}</title></head><body>'.format(teststamp) report += '\n<h2>Failed Image Tests: {0}</h2>'.format(len(TESTREPORTS)) for k, v in list(TESTREPORTS.items()): report += '\n<h3>{0}</h3>\n{1}'.format(k, v) report += '</body></html>' tmp_name = getTempfilePath("html") with open(tmp_name, 'wb') as temp_file: temp_file.write(report) openInBrowserTab('file://' + tmp_name) return res
def _get_composer_image(self, width, height, dpi): image = QImage(QSize(width, height), self._TestMapSettings.outputImageFormat()) 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, self._TestMapSettings.testFlag(QgsMapSettings.Antialiasing) ) self._c.renderPage(p, 0) p.end() # image = self._c.printPageAsRaster(0) # """:type: QImage""" if image.isNull(): return False, '' filepath = getTempfilePath('png') res = image.save(filepath, 'png') if not res: os.unlink(filepath) filepath = '' return res, filepath
def _get_composer_svg_image(self, width, height, dpi): # from qgscomposer.cpp, QgsComposer::on_mActionExportAsSVG_triggered, # line 1909, 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.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) image.fill(QColor(152, 219, 249).rgb()) image.setDotsPerMeterX(dpi / 25.4 * 1000) image.setDotsPerMeterY(dpi / 25.4 * 1000) svgr = QSvgRenderer(svgpath) p = QPainter(image) svgr.render(p) p.end() filepath = getTempfilePath('png') res = image.save(filepath, 'png') if not res: os.unlink(filepath) filepath = '' # TODO: remove .svg file as well? return res, filepath
def _get_composer_svg_image(self, width, height, dpi): # from qgscomposer.cpp, QgsComposer::on_mActionExportAsSVG_triggered, # 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) 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): return False, '' image = QImage(width, height, self._TestMapSettings.outputImageFormat()) image.fill(QColor(152, 219, 249).rgb()) image.setDotsPerMeterX(dpi / 25.4 * 1000) image.setDotsPerMeterY(dpi / 25.4 * 1000) svgr = QSvgRenderer(svgpath) p = QPainter(image) p.setRenderHint( QPainter.Antialiasing, self._TestMapSettings.testFlag(QgsMapSettings.Antialiasing) ) p.setRenderHint(QPainter.TextAntialiasing) svgr.render(p) p.end() filepath = getTempfilePath('png') res = image.save(filepath, 'png') if not res: os.unlink(filepath) filepath = '' # TODO: remove .svg file as well? return res, filepath
def saveControlImage(self, tmpimg=''): # don't save control images for RenderVsOtherOutput (Vs) tests, since # those control images belong to a different test result if ('PAL_CONTROL_IMAGE' not in os.environ or 'Vs' in self._TestGroup): return imgpath = self.controlImagePath() testdir = os.path.dirname(imgpath) if not os.path.exists(testdir): os.makedirs(testdir) imgbasepath = \ os.path.join(testdir, os.path.splitext(os.path.basename(imgpath))[0]) # remove any existing control images for f in glob.glob(imgbasepath + '.*'): if os.path.exists(f): os.remove(f) qDebug('Control image for {0}.{1}'.format(self._TestGroup, self._TestFunction)) if not tmpimg: # TODO: this can be deprecated, when per-base-test-class rendering # in checkTest() is verified OK for all classes qDebug('Rendering control to: {0}'.format(imgpath)) ms = self._MapSettings # class settings """:type: QgsMapSettings""" settings_type = 'Class' if self._TestMapSettings is not None: ms = self._TestMapSettings # per test settings settings_type = 'Test' qDebug('MapSettings type: {0}'.format(settings_type)) img = renderMapToImage(ms, parallel=False) """:type: QImage""" tmpimg = getTempfilePath('png') if not img.save(tmpimg, 'png'): os.unlink(tmpimg) raise OSError('Control not created for: {0}'.format(imgpath)) if tmpimg and os.path.exists(tmpimg): qDebug('Copying control to: {0}'.format(imgpath)) shutil.copyfile(tmpimg, imgpath) else: raise OSError('Control not copied to: {0}'.format(imgpath))
def get_capabilities(self, params, browser=False): assert self.processes_running(), "Server processes not running" params = self._params_to_upper(params) if ("REQUEST" in params and params["REQUEST"] != "GetCapabilities") or "REQUEST" not in params: params["REQUEST"] = "GetCapabilities" url = self._fcgi_url + "?" + self.process_params(params) res = urllib.request.urlopen(url) xml = res.read().decode("utf-8") if browser: tmp_name = getTempfilePath("html") with open(tmp_name, "wt") as temp_html: temp_html.write(xml) url = tmp_name openInBrowserTab(url) return False, "" success = "error reading the project file" in xml or "WMS_Capabilities" in xml return success, xml
def get_capabilities(self, params, browser=False): assert self.processes_running(), 'Server processes not running' params = self._params_to_upper(params) if (('REQUEST' in params and params['REQUEST'] != 'GetCapabilities') or 'REQUEST' not in params): params['REQUEST'] = 'GetCapabilities' url = self._fcgi_url + '?' + self.process_params(params) res = urllib.request.urlopen(url) xml = res.read().decode('utf-8') if browser: tmp_name = getTempfilePath('html') with open(tmp_name, 'wt') as temp_html: temp_html.write(xml) url = tmp_name openInBrowserTab(url) return False, '' success = ('error reading the project file' in xml or 'WMS_Capabilities' in xml) return success, xml
def get_map(self, params, browser=False): assert self.processes_running(), 'Server processes not running' msg = ('Map request parameters should be passed in as a dict ' '(key case can be mixed)') assert isinstance(params, dict), msg params = self._params_to_upper(params) try: proj = params['MAP'] except KeyError as err: raise KeyError(str(err) + '\nMAP not found in parameters dict') if not os.path.exists(proj): msg = '{0}'.format(proj) w_proj = os.path.join(self._web_dir, proj) if os.path.exists(w_proj): params['MAP'] = w_proj else: msg += '\n or\n' + w_proj raise ServerProcessError( 'GetMap Request Error', 'Project not found at:\n{0}'.format(msg) ) if (('REQUEST' in params and params['REQUEST'] != 'GetMap') or 'REQUEST' not in params): params['REQUEST'] = 'GetMap' url = self._fcgi_url + '?' + self.process_params(params) if browser: openInBrowserTab(url) return False, '' # try until qgis_mapserv.fcgi process is available (for 20 seconds) # on some platforms the fcgi_server_process is a daemon handling the # launch of the fcgi-spawner, which may be running quickly, but the # qgis_mapserv.fcgi spawned process is not yet accepting connections resp = None tmp_png = None # noinspection PyUnusedLocal filepath = '' # noinspection PyUnusedLocal success = False start_time = time.time() while time.time() - start_time < 20: resp = None try: tmp_png = urllib.request.urlopen(url) except urllib.error.HTTPError as resp: if resp.code == 503 or resp.code == 500: time.sleep(1) else: raise ServerProcessError( 'Web/FCGI Process Request HTTPError', 'Cound not connect to process: ' + str(resp.code), resp.message ) except urllib.error.URLError as resp: raise ServerProcessError( 'Web/FCGI Process Request URLError', 'Cound not connect to process', resp.reason ) else: delta = time.time() - start_time print(('Seconds elapsed for server GetMap: ' + str(delta))) break if resp is not None: raise ServerProcessError( 'Web/FCGI Process Request Error', 'Cound not connect to process: ' + str(resp.code) ) if (tmp_png is not None and tmp_png.info().getmaintype() == 'image' and tmp_png.info().getheader('Content-Type') == 'image/png'): filepath = getTempfilePath('png') with open(filepath, 'wb') as temp_image: temp_image.write(tmp_png.read()) success = True else: raise ServerProcessError( 'FCGI Process Request Error', 'No valid PNG output' ) return success, filepath, url
def test_layout_exports(self): """Test mask effects in a layout export at 300 dpi""" # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0)) ]) # add an outer glow effect to the mask blur = QgsOuterGlowEffect.create({ "enabled": "1", "blur_level": "6.445", "blur_unit": "MM", "opacity": "1", "spread": "0.6", "spread_unit": "MM", "color1": "0,0,255,255", "draw_mode": "2" }) fmt.mask().setPaintEffect(blur) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) layout = QgsLayout(QgsProject.instance()) page = QgsLayoutItemPage(layout) page.setPageSize(QgsLayoutSize(50, 33)) layout.pageCollection().addPage(page) map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(1, 1, 48, 32)) map.setFrameEnabled(True) layout.addLayoutItem(map) map.setExtent(self.lines_layer.extent()) map.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) image = QImage(591, 591, QImage.Format_RGB32) image.setDotsPerMeterX(300 / 25.3 * 1000) image.setDotsPerMeterY(300 / 25.3 * 1000) image.fill(0) p = QPainter(image) exporter = QgsLayoutExporter(layout) exporter.renderPage(p, 0) p.end() tmp = getTempfilePath('png') image.save(tmp) control_name = "layout_export" self.checker.setControlName(control_name) self.checker.setRenderedImage(tmp) res = self.checker.compareImages(control_name) self.report += self.checker.report() self.assertTrue(res)
def get_map(self, params, browser=False): assert self.processes_running(), 'Server processes not running' msg = ('Map request parameters should be passed in as a dict ' '(key case can be mixed)') assert isinstance(params, dict), msg params = self._params_to_upper(params) try: proj = params['MAP'] except KeyError as err: raise KeyError(str(err) + '\nMAP not found in parameters dict') if not os.path.exists(proj): msg = '{0}'.format(proj) w_proj = os.path.join(self._web_dir, proj) if os.path.exists(w_proj): params['MAP'] = w_proj else: msg += '\n or\n' + w_proj raise ServerProcessError( 'GetMap Request Error', 'Project not found at:\n{0}'.format(msg)) if (('REQUEST' in params and params['REQUEST'] != 'GetMap') or 'REQUEST' not in params): params['REQUEST'] = 'GetMap' url = self._fcgi_url + '?' + self.process_params(params) if browser: openInBrowserTab(url) return False, '' # try until qgis_mapserv.fcgi process is available (for 20 seconds) # on some platforms the fcgi_server_process is a daemon handling the # launch of the fcgi-spawner, which may be running quickly, but the # qgis_mapserv.fcgi spawned process is not yet accepting connections resp = None tmp_png = None # noinspection PyUnusedLocal filepath = '' # noinspection PyUnusedLocal success = False start_time = time.time() while time.time() - start_time < 20: resp = None try: tmp_png = urllib.request.urlopen(url) except urllib.error.HTTPError as resp: if resp.code == 503 or resp.code == 500: time.sleep(1) else: raise ServerProcessError( 'Web/FCGI Process Request HTTPError', 'Could not connect to process: ' + str(resp.code), resp.message) except urllib.error.URLError as resp: raise ServerProcessError('Web/FCGI Process Request URLError', 'Could not connect to process', resp.reason) else: delta = time.time() - start_time print(('Seconds elapsed for server GetMap: ' + str(delta))) break if resp is not None: raise ServerProcessError( 'Web/FCGI Process Request Error', 'Could not connect to process: ' + str(resp.code)) if (tmp_png is not None and tmp_png.info().getmaintype() == 'image' and tmp_png.info().getheader('Content-Type') == 'image/png'): filepath = getTempfilePath('png') with open(filepath, 'wb') as temp_image: temp_image.write(tmp_png.read()) success = True else: raise ServerProcessError('FCGI Process Request Error', 'No valid PNG output') return success, filepath, url
def _get_layout_pdf_image(self, width, height, dpi): pdfpath = getTempfilePath('pdf') temp_size = os.path.getsize(pdfpath) p = QPrinter() p.setOutputFormat(QPrinter.PdfFormat) p.setOutputFileName(pdfpath) p.setPaperSize( QSizeF(self._c.pageCollection().page(0).sizeWithUnits().width(), self._c.pageCollection().page(0).sizeWithUnits().height()), QPrinter.Millimeter) p.setFullPage(True) p.setColorMode(QPrinter.Color) p.setResolution(self._c.renderContext().dpi()) pdf_p = QPainter(p) # page_mm = p.pageRect(QPrinter.Millimeter) # page_px = p.pageRect(QPrinter.DevicePixel) # self._c.render(pdf_p, page_px, page_mm) exporter = QgsLayoutExporter(self._c) exporter.renderPage(pdf_p, 0) pdf_p.end() if temp_size == os.path.getsize(pdfpath): return False, '' filepath = getTempfilePath('png') # Poppler (pdftocairo or pdftoppm): # PDFUTIL -png -singlefile -r 72 -x 0 -y 0 -W 420 -H 280 in.pdf pngbase # muPDF (mudraw): # PDFUTIL -c rgb[a] -r 72 -w 420 -h 280 -o out.png in.pdf if PDFUTIL.strip().endswith('pdftocairo'): filebase = os.path.join( os.path.dirname(filepath), os.path.splitext(os.path.basename(filepath))[0]) call = [ PDFUTIL, '-png', '-singlefile', '-r', str(dpi), '-x', '0', '-y', '0', '-W', str(width), '-H', str(height), pdfpath, filebase ] elif PDFUTIL.strip().endswith('mudraw'): call = [ PDFUTIL, '-c', 'rgba', '-r', str(dpi), '-w', str(width), '-h', str(height), # '-b', '8', '-o', filepath, pdfpath ] else: return False, '' qDebug("_get_layout_pdf_image call: {0}".format(' '.join(call))) res = False try: subprocess.check_call(call) res = True except subprocess.CalledProcessError as e: qDebug("_get_layout_pdf_image failed!\n" "cmd: {0}\n" "returncode: {1}\n" "message: {2}".format(e.cmd, e.returncode, e.message)) if not res: os.unlink(filepath) filepath = '' return res, filepath
def get_map(self, params, browser=False): assert self.processes_running(), "Server processes not running" msg = "Map request parameters should be passed in as a dict " "(key case can be mixed)" assert isinstance(params, dict), msg params = self._params_to_upper(params) try: proj = params["MAP"] except KeyError as err: raise KeyError(str(err) + "\nMAP not found in parameters dict") if not os.path.exists(proj): msg = "{0}".format(proj) w_proj = os.path.join(self._web_dir, proj) if os.path.exists(w_proj): params["MAP"] = w_proj else: msg += "\n or\n" + w_proj raise ServerProcessError("GetMap Request Error", "Project not found at:\n{0}".format(msg)) if ("REQUEST" in params and params["REQUEST"] != "GetMap") or "REQUEST" not in params: params["REQUEST"] = "GetMap" url = self._fcgi_url + "?" + self.process_params(params) if browser: openInBrowserTab(url) return False, "" # try until qgis_mapserv.fcgi process is available (for 20 seconds) # on some platforms the fcgi_server_process is a daemon handling the # launch of the fcgi-spawner, which may be running quickly, but the # qgis_mapserv.fcgi spawned process is not yet accepting connections resp = None tmp_png = None # noinspection PyUnusedLocal filepath = "" # noinspection PyUnusedLocal success = False start_time = time.time() while time.time() - start_time < 20: resp = None try: tmp_png = urllib.request.urlopen(url) except urllib.error.HTTPError as resp: if resp.code == 503 or resp.code == 500: time.sleep(1) else: raise ServerProcessError( "Web/FCGI Process Request HTTPError", "Cound not connect to process: " + str(resp.code), resp.message, ) except urllib.error.URLError as resp: raise ServerProcessError( "Web/FCGI Process Request URLError", "Cound not connect to process", resp.reason ) else: delta = time.time() - start_time print(("Seconds elapsed for server GetMap: " + str(delta))) break if resp is not None: raise ServerProcessError( "Web/FCGI Process Request Error", "Cound not connect to process: " + str(resp.code) ) if ( tmp_png is not None and tmp_png.info().getmaintype() == "image" and tmp_png.info().getheader("Content-Type") == "image/png" ): filepath = getTempfilePath("png") with open(filepath, "wb") as temp_image: temp_image.write(tmp_png.read()) success = True else: raise ServerProcessError("FCGI Process Request Error", "No valid PNG output") return success, filepath, url
def _get_composer_pdf_image(self, width, height, dpi): pdfpath = getTempfilePath('pdf') temp_size = os.path.getsize(pdfpath) p = QPrinter() p.setOutputFormat(QPrinter.PdfFormat) p.setOutputFileName(pdfpath) p.setPaperSize(QSizeF(self._c.paperWidth(), self._c.paperHeight()), QPrinter.Millimeter) p.setFullPage(True) p.setColorMode(QPrinter.Color) p.setResolution(self._c.printResolution()) pdf_p = QPainter(p) # page_mm = p.pageRect(QPrinter.Millimeter) # page_px = p.pageRect(QPrinter.DevicePixel) # self._c.render(pdf_p, page_px, page_mm) self._c.renderPage(pdf_p, 0) pdf_p.end() if temp_size == os.path.getsize(pdfpath): return False, '' filepath = getTempfilePath('png') # Poppler (pdftocairo or pdftoppm): # PDFUTIL -png -singlefile -r 72 -x 0 -y 0 -W 420 -H 280 in.pdf pngbase # muPDF (mudraw): # PDFUTIL -c rgb[a] -r 72 -w 420 -h 280 -o out.png in.pdf if PDFUTIL.strip().endswith('pdftocairo'): filebase = os.path.join( os.path.dirname(filepath), os.path.splitext(os.path.basename(filepath))[0] ) call = [ PDFUTIL, '-png', '-singlefile', '-r', str(dpi), '-x', '0', '-y', '0', '-W', str(width), '-H', str(height), pdfpath, filebase ] elif PDFUTIL.strip().endswith('mudraw'): call = [ PDFUTIL, '-c', 'rgba', '-r', str(dpi), '-w', str(width), '-h', str(height), # '-b', '8', '-o', filepath, pdfpath ] else: return False, '' qDebug("_get_composer_pdf_image call: {0}".format(' '.join(call))) res = False try: subprocess.check_call(call) res = True except subprocess.CalledProcessError as e: qDebug("_get_composer_pdf_image failed!\n" "cmd: {0}\n" "returncode: {1}\n" "message: {2}".format(e.cmd, e.returncode, e.message)) if not res: os.unlink(filepath) filepath = '' return res, filepath