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
예제 #5
0
    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))
예제 #6
0
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
예제 #7
0
    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
예제 #9
0
    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))
예제 #11
0
    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
예제 #12
0
    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
예제 #13
0
    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)
예제 #15
0
    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
예제 #16
0
    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
예제 #17
0
    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
예제 #18
0
    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