Пример #1
0
 def testLabelBinding(self):
     """attribute binding can be set and get"""
     new_label = mapscript.labelObj()
     assert (not new_label.getBinding(mapscript.MS_LABEL_BINDING_COLOR))
     new_label.setBinding(mapscript.MS_LABEL_BINDING_COLOR, "NEW_BINDING")
     assert (new_label.getBinding(
         mapscript.MS_LABEL_BINDING_COLOR) == "NEW_BINDING")
Пример #2
0
    def testSettingFonts(self):
        mo = mapscript.mapObj()
        assert mo.fontset.numfonts == 0
        mo.fontset.fonts.set('Vera', os.path.join(TESTS_PATH, 'vera',
                                                  'Vera.ttf'))
        # NB: this does *not* increment the fonset.numfonts -- new bug

        mo.setSize(300, 300)
        mo.setExtent(-1.0, -1.0, 1.0, 1.0)

        lo = mapscript.layerObj()
        lo.type = mapscript.MS_LAYER_POINT
        lo.connectiontype = mapscript.MS_INLINE
        lo.status = mapscript.MS_DEFAULT

        co = mapscript.classObj()
        lbl = mapscript.labelObj()
        lbl.type = mapscript.MS_TRUETYPE
        lbl.font = 'Vera'
        lbl.size = 10
        lbl.color.setHex('#000000')
        co.addLabel(lbl)

        so = mapscript.styleObj()
        so.symbol = 0
        so.color.setHex('#000000')

        co.insertStyle(so)
        lo.insertClass(co)
        li = mo.insertLayer(lo)
        lo = mo.getLayer(li)

        point = mapscript.pointObj(0, 0)
        line = mapscript.lineObj()
        line.add(point)
        shape = mapscript.shapeObj(lo.type)
        shape.add(line)
        shape.setBounds()
        shape.text = 'Foo'
        shape.classindex = 0

        lo.addFeature(shape)
        im = mo.draw()

        # im = mo.prepareImage()
        # shape.draw(mo, lo, im)
        im.save('testSettingFonts.png')
Пример #3
0
    def setUp(self):
        # Inline feature layer
        self.ilayer = mapscript.layerObj()
        self.ilayer.type = mapscript.MS_LAYER_POLYGON
        self.ilayer.status = mapscript.MS_DEFAULT
        self.ilayer.connectiontype = mapscript.MS_INLINE

        cs = 'f7fcfd, e5f5f9, ccece6, 99d8c9, 66c2a4, 41ae76, 238b45, 006d2c, 00441b'
        colors = ['#' + h for h in cs.split(', ')]

        for i in range(9):
            # Make a class for feature
            ci = self.ilayer.insertClass(mapscript.classObj())
            co = self.ilayer.getClass(ci)
            si = co.insertStyle(mapscript.styleObj())
            so = co.getStyle(si)
            so.color.setHex(colors[i])
            li = co.addLabel(mapscript.labelObj())
            lbl = co.getLabel(li)
            lbl.color.setHex('#000000')
            lbl.outlinecolor.setHex('#FFFFFF')
            lbl.type = mapscript.MS_BITMAP
            lbl.size = mapscript.MS_SMALL

            # The shape to add is randomly generated
            xc = 4.0*(random() - 0.5)
            yc = 4.0*(random() - 0.5)
            r = mapscript.rectObj(xc-0.25, yc-0.25, xc+0.25, yc+0.25)
            s = r.toPolygon()

            # Classify
            s.classindex = i
            s.text = "F%d" % (i)

            # Add to inline feature layer
            self.ilayer.addFeature(s)
Пример #4
0
 def testLabelBinding(self):
     """attribute binding can be set and get"""
     new_label = mapscript.labelObj()
     assert (not new_label.getBinding(mapscript.MS_LABEL_BINDING_COLOR))
     new_label.setBinding(mapscript.MS_LABEL_BINDING_COLOR, "NEW_BINDING")
     assert (new_label.getBinding(mapscript.MS_LABEL_BINDING_COLOR) == "NEW_BINDING")
Пример #5
0
    def __init__(self, layer, msLayer, msMap, emitFontDefinitions=False):
        """Serialize labels of a QGis vector layer to mapscript"""

        self.layer = layer
        self.msLayer = msLayer
        self.msMap = msMap

        labelingEngine = QgsPalLabeling()
        labelingEngine.loadEngineSettings()

        if labelingEngine and labelingEngine.willUseLayer(self.layer):
            ps = QgsPalLayerSettings.fromLayer(self.layer)

            if not ps.isExpression:
                self.msLayer.labelitem = unicode(ps.fieldName).encode('utf-8')
            else:
                pass

            msLabel = mapscript.labelObj()

            msLabel.type = mapscript.MS_TRUETYPE
            msLabel.encoding = 'utf-8'
           
            # Position, rotation and scaling
            msLabel.position = utils.serializeLabelPosition(ps)
            msLabel.offsetx = int(ps.xOffset)
            msLabel.offsety = int(ps.yOffset)

            # Data defined rotation
            # Please note that this is the only currently supported data defined property.
            if QgsPalLayerSettings.Rotation in ps.dataDefinedProperties.keys():
                dd = ps.dataDefinedProperty(QgsPalLayerSettings.Rotation)
                rotField = unicode(dd.field()).encode('utf-8')
                msLabel.setBinding(mapscript.MS_LABEL_BINDING_ANGLE, rotField)
            else:
                msLabel.angle = ps.angleOffset

            if ps.scaleMin > 0:
                self.msLayer.labelminscaledenom = ps.scaleMin
            if ps.scaleMax > 0:
                self.msLayer.labelmaxscaledenom = ps.scaleMax

            fontDef, msLabel.size = utils.serializeFontDefinition(ps.textFont, ps.textNamedStyle)

            # `emitFontDefinitions` gets set based on whether a fontset path is supplied through 
            # the plugin UI. There is no point in emitting font definitions without a valid fontset,
            # so in that case we fall back to using whatever default font MapServer (thus the
            # underlying windowing system) provides.
            # Please note that substituting the default font only works in MapServer 7.0.0 and above.
            if emitFontDefinitions == True:
                msLabel.font = fontDef

            if ps.fontSizeInMapUnits:
                utils.maybeSetLayerSizeUnitFromMap(QgsSymbolV2.MapUnit, self.msLayer)

            # Font size and color
            msLabel.color = utils.serializeColor(ps.textColor)

            if ps.fontLimitPixelSize:
                msLabel.minsize = ps.fontMinPixelSize
                msLabel.maxsize = ps.fontMaxPixelSize

            # Other properties
            wrap = unicode(ps.wrapChar).encode('utf-8')
            if len(wrap) == 1:
                msLabel.wrap = wrap[0]
            elif len(wrap) > 1:
                QgsMessageLog.logMessage(
                    u'Skipping invalid wrap character ("%s") for labels.' % wrap.decode('utf-8'),
                    'RT MapServer Exporter'
                )
            else:
                # No wrap char set
                pass

            # Other properties
            msLabel.partials = labelingEngine.isShowingPartialsLabels()
            msLabel.force = ps.displayAll
            msLabel.priority = ps.priority
            msLabel.buffer = int(utils.sizeUnitToPx(
                ps.bufferSize,
                QgsSymbolV2.MapUnit if ps.bufferSizeInMapUnits else QgsSymbolV2.MM
            ))

            if ps.minFeatureSize > 0:
                msLabel.minfeaturesize = utils.sizeUnitToPx(ps.minFeatureSize)

            # Label definitions gets appended to the very first class on a layer, or to a new class
            # if no classes exist.
            #
          
            if msLayer.numclasses > 0:
                for c in range(0, msLayer.numclasses):
                    msLayer.getClass(c).addLabel(msLabel)
            else:
                mapscript.classObj(msLayer).addLabel(msLabel)
Пример #6
0
    def accept(self):
        # check user inputs
        if self.txtMapFilePath.text() == "":
            QMessageBox.warning(self, "RT MapServer Exporter", "Mapfile output path is required")
            return

        # create a new ms_map
        ms_map = mapscript.mapObj()
        ms_map.name = _toUtf8( self.txtMapName.text() )

        # map size
        (width, widthOk), (height, heightOk) = self.txtMapWidth.text().toInt(), self.txtMapHeight.text().toInt()
        if widthOk and heightOk:
            ms_map.setSize( width, height )

        # map units
        ms_map.units = self.unitMap[ self.canvas.mapUnits() ]
        if self.cmbMapUnits.currentIndex() >= 0:
            units, ok = self.cmbMapUnits.itemData( self.cmbMapUnits.currentIndex() ).toInt()
            if ok:
                ms_map.units = units

        # map extent
        extent = self.canvas.fullExtent()
        ms_map.extent.minx = extent.xMinimum()
        ms_map.extent.miny = extent.yMinimum()
        ms_map.extent.maxx = extent.xMaximum()
        ms_map.extent.maxy = extent.yMaximum()
        ms_map.setProjection( _toUtf8( self.canvas.mapRenderer().destinationCrs().toProj4() ) )

        if self.txtMapShapePath.text() != "":
            ms_map.shapepath = _toUtf8( self.getMapShapePath() )

        # image section
        r,g,b,a = self.canvas.canvasColor().getRgb()
        ms_map.imagecolor.setRGB( r, g, b )    #255,255,255
        ms_map.setImageType( _toUtf8( self.cmbMapImageType.currentText() ) )
        ms_outformat = ms_map.getOutputFormatByName( ms_map.imagetype )
        ms_outformat.transparent = self.onOffMap[ True ]

        # legend section
        #r,g,b,a = self.canvas.canvasColor().getRgb()
        #ms_map.legend.imageColor.setRgb( r, g, b )
        #ms_map.legend.status = mapscript.MS_ON
        #ms_map.legend.keysizex = 18
        #ms_map.legend.keysizey = 12
        #ms_map.legend.label.type = mapscript.MS_BITMAP
        #ms_map.legend.label.size = MEDIUM??
        #ms_map.legend.label.color.setRgb( 0, 0, 89 )
        #ms_map.legend.label.partials = self.trueFalseMap[ self.checkBoxPartials ]
        #ms_map.legend.label.force = self.trueFalseMap[ self.checkBoxForce ]
        #ms_map.legend.template = "[templatepath]"

        # web section
        ms_map.web.imagepath = _toUtf8( self.getWebImagePath() )
        ms_map.web.imageurl = _toUtf8( self.getWebImageUrl() )
        ms_map.web.temppath = _toUtf8( self.getWebTemporaryPath() )

        # web template
        ms_map.web.template = _toUtf8( self.getTemplatePath() )
        ms_map.web.header = _toUtf8( self.getTemplateHeaderPath() )
        ms_map.web.footer = _toUtf8( self.getTemplateFooterPath() )

        # map metadata
        ms_map.setMetaData( "ows_title", ms_map.name )
        ms_map.setMetaData( "ows_onlineresource", _toUtf8( u"%s?map=%s" % (self.txtMapServerUrl.text(), self.txtMapFilePath.text()) ) )
        srsList = []
        srsList.append( _toUtf8( self.canvas.mapRenderer().destinationCrs().authid() ) )
        ms_map.setMetaData( "ows_srs", ' '.join(srsList) )
        ms_map.setMetaData( "ows_enable_request", "*" )

        for layer in self.legend.layers():
            # create a layer object
            ms_layer = mapscript.layerObj( ms_map )
            ms_layer.name = _toUtf8( layer.name() )
            ms_layer.type = self.getLayerType( layer )
            ms_layer.status = self.onOffMap[ self.legend.isLayerVisible( layer ) ]

            # layer extent
            extent = layer.extent()
            ms_layer.extent.minx = extent.xMinimum()
            ms_layer.extent.miny = extent.yMinimum()
            ms_layer.extent.maxx = extent.xMaximum()
            ms_layer.extent.maxy = extent.yMaximum()

            ms_layer.setProjection( _toUtf8( layer.crs().toProj4() ) )

            if layer.hasScaleBasedVisibility():
                ms_layer.minscaledenom = layer.minimumScale()
                ms_layer.maxscaledenom = layer.maximumScale()

            ms_layer.setMetaData( "ows_title", ms_layer.name )

            # layer connection
            if layer.providerType() == 'postgres':
                ms_layer.setConnectionType( mapscript.MS_POSTGIS, "" )
                uri = QgsDataSourceURI( layer.source() )
                ms_layer.connection = _toUtf8( uri.connectionInfo() )
                data = u"%s FROM %s" % ( uri.geometryColumn(), uri.quotedTablename() )
                if uri.keyColumn() != "":
                    data += u" USING UNIQUE %s" % uri.keyColumn()
                data += u" USING UNIQUE %s" % layer.crs().postgisSrid()
                if uri.sql() != "":
                  data += " FILTER (%s)" % uri.sql()
                ms_layer.data = _toUtf8( data )

            elif layer.providerType() == 'wms':
                ms_layer.setConnectionType( mapscript.MS_WMS, "" )
                if hasattr(QgsDataSourceURI, 'paramValue'):
                    uri = QgsDataSourceURI( layer.source() )
                else:
                    uri = QUrl( layer.source() )
                    uri.paramValue = uri.queryItemValue # forward to the QUrl method
                ms_layer.connection = _toUtf8( uri.paramValue("url") )

                # loop thru wms sub layers
                names = []
                styles = []
                wmsLayerNames = uri.paramValues("layers")
                wmsLayerStyles = uri.paramValues("styles")
                for index in range(len(wmsLayerNames)): 
                    wmsNames.append( _toUtf8( wmsLayerNames[index] ) )
                    wmsStyles.append( _toUtf8( wmsLayerStyles[index] ) )

                # output SRSs
                srsList = []
                srsList.append( _toUtf8( layer.crs().authid() ) )

                # Create necessary wms metadata
                ms_layer.setMetaData( "ows_name", ','.join(wmsNames) )
                ms_layer.setMetaData( "wms_server_version", "1.1.1" )
                ms_layer.setMetaData( "ows_srs", ' '.join(srsList) )
                #ms_layer.setMetaData( "wms_format", layer.format() )
                ms_layer.setMetaData( "wms_format", ','.join(wmsStyles) )

            elif layer.providerType() == 'wfs':
                ms_layer.setConnectionType( mapscript.MS_WMS, "" )
                uri = QgsDataSourceURI( layer.source() )
                ms_layer.connection = _toUtf8( uri.uri() )

                # output SRSs
                srsList = []
                srsList.append( _toUtf8( layer.crs().authid() ) )

                # Create necessary wms metadata
                ms_layer.setMetaData( "ows_name", ms_layer.name )
                #ms_layer.setMetaData( "wfs_server_version", "1.1.1" )
                ms_layer.setMetaData( "ows_srs", ' '.join(srsList) )
           
            elif layer.providerType() == 'spatialite':
                ms_layer.setConnectionType( mapscript.MS_OGR, "" )
                uri = QgsDataSourceURI( layer.source() )
                ms_layer.connection = _toUtf8( uri.database() )    
                ms_layer.data = _toUtf8( uri.table() )    

            elif layer.providerType() == 'ogr':
                #ms_layer.setConnectionType( mapscript.MS_OGR, "" )
                ms_layer.data = _toUtf8( layer.source().split('|')[0] )    

            else:
                ms_layer.data = _toUtf8( layer.source() )    

            # set layer style
            if layer.type() == QgsMapLayer.RasterLayer:
                if hasattr(layer, 'renderer'):    # QGis >= 1.9
                    opacity = layer.renderer().opacity()
                else:
                    opacity = int( 100 * layer.getTransparency() / 255.0 )
                ms_layer.opacity = opacity

            else:
                # use a SLD file set the layer style
                tempSldFile = QTemporaryFile("rt_mapserver_exporter-XXXXXX.sld")
                tempSldFile.open()
                tempSldPath = tempSldFile.fileName()
                tempSldFile.close()

                # export the QGIS layer style to SLD file
                errMsg, ok = layer.saveSldStyle( tempSldPath )
                if not ok:
                    QgsMessageLog.logMessage( errMsg, "RT MapServer Exporter" )
                else:
                    # set the mapserver layer style from the SLD file
                    with open( unicode(tempSldPath), 'r' ) as fin:
                        sldContents = fin.read()
                    if mapscript.MS_SUCCESS != ms_layer.applySLD( sldContents, ms_layer.name ):
                        QgsMessageLog.logMessage( u"Something went wrong applying the SLD style to the layer '%s'" % ms_layer.name, "RT MapServer Exporter" )
                    QFile.remove( tempSldPath )

            # set layer labels
            #XXX the following code MUST be removed when QGIS will 
            # have SLD label support
            labelingEngine = self.canvas.mapRenderer().labelingEngine()
            if labelingEngine and labelingEngine.willUseLayer( layer ):
                palLayer = labelingEngine.layer( layer.id() )
                if palLayer.enabled:
                    if not palLayer.isExpression:
                        ms_layer.labelitem = _toUtf8( palLayer.fieldName )    
                    else:
                        #XXX expressions won't be supported until 
                        # QGIS have SLD label support
                        pass

                    if palLayer.scaleMin > 0:
                        ms_layer.labelminscaledenom = palLayer.scaleMin
                    if palLayer.scaleMax > 0:
                        ms_layer.labelmaxscaledenom = palLayer.scaleMax

                    ms_label = mapscript.labelObj()

                    ms_label.type = mapscript.MS_TRUETYPE
                    ms_label.antialias = mapscript.MS_TRUE

                    ms_label.position = self.getLabelPosition( palLayer )
                    # TODO: convert offset to pixels
                    ms_label.offsetx = int( palLayer.xOffset )
                    ms_label.offsety = int( palLayer.yOffset )
                    ms_label.angle = palLayer.angleOffset

                    # set label font name, size and color
                    fontFamily = palLayer.textFont.family().replace(" ", "")
                    fontStyle = palLayer.textNamedStyle.replace(" ", "")
                    ms_label.font = _toUtf8( u"%s-%s" % (fontFamily, fontStyle) )    
                    if palLayer.textFont.pixelSize() > 0:
                        ms_label.size = int( palLayer.textFont.pixelSize() )
                    r,g,b,a = palLayer.textColor.getRgb()
                    ms_label.color.setRGB( r, g, b )

                    if palLayer.fontLimitPixelSize:
                        ms_label.minsize = palLayer.fontMinPixelSize
                        ms_label.maxsize = palLayer.fontMaxPixelSize
                    ms_label.wrap = _toUtf8( palLayer.wrapChar )    

                    ms_label.priority = palLayer.priority

                    # TODO: convert buffer size to pixels
                    ms_label.buffer = int( palLayer.bufferSize )

                    if int( palLayer.minFeatureSize ) > 0:
                        # TODO: convert feature size from mm to pixels
                        ms_label.minfeaturesize = int( palLayer.minFeatureSize )

                    ms_class = mapscript.classObj()
                    ms_class.addLabel( ms_label )
                    ms_layer.insertClass( ms_class )
        

        # save the map file now!
        if mapscript.MS_SUCCESS != ms_map.save( _toUtf8( self.txtMapFilePath.text() )     ):
            return

        # Most of the following code does not use mapscript because it asserts 
        # paths you supply exists, but this requirement is usually not meet on 
        # the QGIS client used to generate the mafile.

        # get the mapfile content as string so we can manipulate on it
        with open( unicode(self.txtMapFilePath.text()), 'r' ) as fin:
            # parts holds the content lines
            parts = QString(fin.read()).split(u"\n")
        partsContentChanged = False

        # retrieve the list of used font aliases searching for FONT keywords
        fonts = []
        searchFontRx = QRegExp("^\\s*FONT\\s+")
        for line in parts.filter( searchFontRx ):
            # get the font alias, remove quotes around it
            fontName = line.replace(searchFontRx, "")[1:-1]
            # remove spaces within the font name
            fontAlias = QString(fontName).replace(" ", "")

            # append the font alias to the font list
            if fontAlias not in fonts:
                fonts.append( fontAlias )

                # update the font alias in the mapfile
                # XXX: the following lines cannot be removed since the SLD file 
                # could refer a font whose name contains spaces. When SLD specs
                # ate clear on how to handle fonts than we'll think whether 
                # remove it or not. 
                replaceFontRx = QRegExp(u"^(\\s*FONT\\s+\")%s(\".*)$" % QRegExp.escape(fontName))
                parts.replaceInStrings(replaceFontRx, u"\\1%s\\2" % fontAlias)
                partsContentChanged = True

        # create the file containing the list of font aliases used in the 
        # mapfile
        if self.checkCreateFontFile.isChecked():
            fontPath = QFileInfo(self.txtMapFilePath.text()).dir().filePath(u"fonts.txt")
            with open( unicode(fontPath), 'w' ) as fout:
                for fontAlias in fonts:
                    fout.write( unicode(fontAlias) )

        # add the FONTSET keyword with the associated path
        if self.txtMapFontsetPath.text() != "":
            pos = parts.indexOf( QRegExp("^MAP$") )
            if pos >= 0:
                parts.insert( pos+1, u'  FONTSET "%s"' % self.txtMapFontsetPath.text() )
                partsContentChanged = True
            else:
                QgsMessageLog.logMessage( u"'FONTSET' keyword not added to the mapfile: unable to locate the 'WEB' keyword...", "RT MapServer Exporter" )

        # if mapfile content changed, store the file again at the same path
        if partsContentChanged:
            with open( unicode(self.txtMapFilePath.text()), 'w' ) as fout:
                fout.write( unicode( parts.join(u"\n") ) )

        # XXX for debugging only: let's have a look at the map result! :)
        # XXX it works whether the file pointed by the fontset contains ALL the 
        # aliases of fonts referred from the mapfile.
        #ms_map = mapscript.mapObj( unicode( self.txtMapFilePath.text() ) )
        #ms_map.draw().save( _toUtf8( self.txtMapFilePath.text() + ".png" )    , ms_map )

        QDialog.accept(self)
Пример #7
0
    def _get_map(self):
        """
        Generate a mapserver mapObj.
        """
        # create a mapscript map from scratch
        map = mapscript.mapObj()
        # Configure the map
        # NAME
        map.name = "BCCVLMap"
        # EXTENT ... in projection units (we use epsg:4326) WGS84
        map.extent = mapscript.rectObj(-180.0, -90.0, 180.0, 90.0)
        # map.extent = mapscript.rectObj(-20026376.39, -20048966.10, 20026376.39, 20048966.10)
        # UNITS ... in projection units
        map.units = mapscript.MS_DD
        # SIZE
        map.setSize(256, 256)
        # PROJECTION ... WGS84
        map.setProjection("init=epsg:4326")
        # IMAGETYPE
        map.selectOutputFormat("PNG24")  # PNG, PNG24, JPEG
        map.outputformat.imagemode = mapscript.MS_IMAGEMODE_RGBA
        map.outputformat.transparent = mapscript.MS_ON

        # TRANSPARENT ON
        map.transparent = mapscript.MS_ON
        # IMAGECOLOR 255 255 255
        # map.imagecolor = mapscript.colorObj(255, 255, 255) ... initial color if transparent is on
        # SYMBOLSET  (needed to draw circles for CSV points)
        self._update_symbol_set(map)
        # metadata: wms_feature_info_mime_type text/htm/ application/json
        # WEB
        # TODO: check return value of setMetaData MS_SUCCESS/MS_FAILURE
        map.setMetaData("wms_enable_request", "*")
        map.setMetaData("wms_title", "BCCVL WMS Server")
        # allow reprojection to Web Mercator
        map.setMetaData("wms_srs", "EPSG:4326 EPSG:3857")
        # wms_enable_request enough?
        map.setMetaData("ows_enable_request", "*")
        onlineresource = urlparse.urlunsplit(
            (self.request.scheme,
             "{}:{}".format(self.request.host, self.request.host_port),
             self.request.path,
             urllib.urlencode((('DATA_URL', self.request.params.get('DATA_URL').encode('utf-8')), )),
             ""))
        map.setMetaData("wms_onlineresource", onlineresource)
        # TODO: metadata
        #       title, author, xmp_dc_title
        #       wms_onlineresource ... help to generate GetCapabilities request
        #       ows_http_max_age ... WMS client caching hints http://www.mnot.net/cache_docs/#CACHE-CONTROL
        #       ows_lsd_enabled ... if false ignore SLD and SLD_BODY
        #       wms_attribution_xxx ... do we want attribution metadata?

        # SCALEBAR
        if False:
            # LABEL
            sbl = mapscript.labelObj()
            sbl.color = mapscript.colorObj(0, 0, 0)
            sbl.antialias = mapscript.MS_TRUE
            sbl.size = mapscript.MS_LARGE
            sb = mapscript.scalebarObj()
            sb.label = sbl
            sb.status = mapscript.MS_ON
            map.scalebar = sb
        # LEGEND
        if False:
            # LABEL
            legl = mapscript.labelObj()
            legl.color = mapscript.colorObj(64, 64, 64)
            legl.antialias = mapscript.MS_TRUE
            legl.offsetx = -23
            legl.offsety = -1
            leg = mapscript.legendObj()
            leg.keysizex = 32
            leg.keysizey = 10
            leg.keyspacingx = 5
            leg.keyspacingy = -2
            leg.status = mapscript.MS_ON
            map.legend = leg
        return map
Пример #8
0
    def _get_map(self):
        """
        Generate a mapserver mapObj.
        """
        # create a mapscript map from scratch
        map = mapscript.mapObj()
        # Configure the map
        # NAME
        map.name = "BCCVLMap"
        # EXTENT ... in projection units (we use epsg:4326) WGS84
        map.extent = mapscript.rectObj(-180.0, -90.0, 180.0, 90.0)
        # map.extent = mapscript.rectObj(-20026376.39, -20048966.10, 20026376.39, 20048966.10)
        # UNITS ... in projection units
        map.units = mapscript.MS_DD
        # SIZE
        map.setSize(256, 256)
        # PROJECTION ... WGS84
        map.setProjection("init=epsg:4326")
        # IMAGETYPE
        map.selectOutputFormat("PNG24")  # PNG, PNG24, JPEG
        map.outputformat.imagemode = mapscript.MS_IMAGEMODE_RGBA
        map.outputformat.transparent = mapscript.MS_ON

        # TRANSPARENT ON
        map.transparent = mapscript.MS_ON
        # IMAGECOLOR 255 255 255
        # map.imagecolor = mapscript.colorObj(255, 255, 255) ... initial color if transparent is on
        # SYMBOLSET  (needed to draw circles for CSV points)
        self._update_symbol_set(map)
        # metadata: wms_feature_info_mime_type text/htm/ application/json
        # WEB
        # TODO: check return value of setMetaData MS_SUCCESS/MS_FAILURE
        map.setMetaData("wms_enable_request", "*")
        map.setMetaData("wms_title", "BCCVL WMS Server")
        # allow reprojection to Web Mercator
        map.setMetaData("wms_srs", "EPSG:4326 EPSG:3857")
        # wms_enable_request enough?
        map.setMetaData("ows_enable_request", "*")
        onlineresource = urlparse.urlunsplit(
            (self.request.scheme, "{}:{}".format(self.request.host,
                                                 self.request.host_port),
             self.request.path,
             urllib.urlencode(
                 (('DATA_URL', self.request.params.get('DATA_URL')), )), ""))
        map.setMetaData("wms_onlineresource", onlineresource)
        # TODO: metadata
        #       title, author, xmp_dc_title
        #       wms_onlineresource ... help to generate GetCapabilities request
        #       ows_http_max_age ... WMS client caching hints http://www.mnot.net/cache_docs/#CACHE-CONTROL
        #       ows_lsd_enabled ... if false ignore SLD and SLD_BODY
        #       wms_attribution_xxx ... do we want attribution metadata?

        # SCALEBAR
        if False:
            # LABEL
            sbl = mapscript.labelObj()
            sbl.color = mapscript.colorObj(0, 0, 0)
            sbl.antialias = mapscript.MS_TRUE
            sbl.size = mapscript.MS_LARGE
            sb = mapscript.scalebarObj()
            sb.label = sbl
            sb.status = mapscript.MS_ON
            map.scalebar = sb
        # LEGEND
        if False:
            # LABEL
            legl = mapscript.labelObj()
            legl.color = mapscript.colorObj(64, 64, 64)
            legl.antialias = mapscript.MS_TRUE
            legl.offsetx = -23
            legl.offsety = -1
            leg = mapscript.legendObj()
            leg.keysizex = 32
            leg.keysizey = 10
            leg.keyspacingx = 5
            leg.keyspacingy = -2
            leg.status = mapscript.MS_ON
            map.legend = leg
        return map
    def accept(self):
        layerGroups = []

        # check user inputs
        if self.txtMapFilePath.text() == "":
            QMessageBox.warning(self, "RT MapServer Exporter", "Mapfile output path is required")
            return

        # create a new ms_map
        ms_map = mapscript.mapObj()
        ms_map.name = _cleanStr( self.txtMapName.text() )

        # map size
        (width, widthOk), (height, heightOk) = self.txtMapWidth.text().toInt(), self.txtMapHeight.text().toInt()
        if widthOk and heightOk:
            ms_map.setSize( width, height )

        # map units
        ms_map.units = self.unitMap[ self.canvas.mapUnits() ]
        if self.cmbMapUnits.currentIndex() >= 0:
            units, ok = self.cmbMapUnits.itemData( self.cmbMapUnits.currentIndex() ).toInt()
            if ok:
                ms_map.units = units

        # config options
        ms_map.setConfigOption("MS_ERRORFILE", "/tmp/ms_"+ ms_map.name +".log")

        # map extent
        extent = self.canvas.fullExtent()
        ms_map.extent.minx = extent.xMinimum()
        ms_map.extent.miny = extent.yMinimum()
        ms_map.extent.maxx = extent.xMaximum()
        ms_map.extent.maxy = extent.yMaximum()
        if self.canvas.mapRenderer().destinationCrs().authid() != "":
            ms_map.setProjection( "+init=" + _toUtf8( self.canvas.mapRenderer().destinationCrs().authid() ).lower() )
        else:
            ms_map.setProjection( _toUtf8( self.canvas.mapRenderer().destinationCrs().toProj4() ) )

        if self.txtMapShapePath.text() != "":
            ms_map.shapepath = _toUtf8( self.getMapShapePath() )

        # image section
        r,g,b,a = self.canvas.canvasColor().getRgb()
        ms_map.imagecolor.setRGB( r, g, b )    #255,255,255
        ms_map.setImageType( _toUtf8( self.cmbMapImageType.currentText() ) )
        ms_outformat = ms_map.getOutputFormatByName( ms_map.imagetype )
        ms_outformat.transparent = self.onOffMap[ True ]
        ms_map.transparent = mapscript.MS_TRUE

        # legend section
        #r,g,b,a = self.canvas.canvasColor().getRgb()
        #ms_map.legend.imageColor.setRgb( r, g, b )
        #ms_map.legend.status = mapscript.MS_ON
        #ms_map.legend.keysizex = 18
        #ms_map.legend.keysizey = 12
        #ms_map.legend.label.type = mapscript.MS_BITMAP
        #ms_map.legend.label.size = MEDIUM??
        #ms_map.legend.label.color.setRgb( 0, 0, 89 )
        #ms_map.legend.label.partials = self.trueFalseMap[ self.checkBoxPartials ]
        #ms_map.legend.label.force = self.trueFalseMap[ self.checkBoxForce ]
        #ms_map.legend.template = "[templatepath]"

        # web section
        ms_map.web.imagepath = _toUtf8( self.getWebImagePath() )
        ms_map.web.imageurl = _toUtf8( self.getWebImageUrl() )
        ms_map.web.temppath = _toUtf8( self.getWebTemporaryPath() )

        # web template
        ms_map.web.template = _toUtf8( self.getTemplatePath() )
        ms_map.web.header = _toUtf8( self.getTemplateHeaderPath() )
        ms_map.web.footer = _toUtf8( self.getTemplateFooterPath() )

        # map metadata
        if (QgsProject.instance().readBoolEntry( "WMSServiceCapabilities", "/", False )[0]):
            ms_map.setMetaData( "ows_title", _toUtf8( QgsProject.instance().readEntry("WMSServiceTitle", "/", "")[0] ) )
            ms_map.setMetaData( "ows_abstract", _toUtf8( QgsProject.instance().readEntry("WMSServiceAbstract", "/", "")[0] ) )
            ms_map.setMetaData( "ows_contactorganization", _toUtf8( QgsProject.instance().readEntry("WMSContactOrganization", "/", "")[0] ) )
            ms_map.setMetaData( "ows_contactperson", _toUtf8( QgsProject.instance().readEntry("WMSContactPerson", "/", "")[0] ) )
            ms_map.setMetaData( "ows_contactelectronicmailaddress", _toUtf8( QgsProject.instance().readEntry("WMSContactMail", "/", "")[0] ) )
            ms_map.setMetaData( "ows_contactvoicetelephone", _toUtf8( QgsProject.instance().readEntry("WMSContactPhone", "/", "")[0] ) )
            ms_map.setMetaData( "ows_keywordlist", _toUtf8( QgsProject.instance().readListEntry("WMSKeywordList", "/") [0].join(",") ) )
            ms_map.setMetaData( "ows_accessconstraints", _toUtf8( QgsProject.instance().readEntry("WMSAccessConstraints", "/", "")[0] ) )
        else:
            ms_map.setMetaData( "ows_title", _toUtf8( self.txtMapName.text() ) )
        
        ms_map.setMetaData( "ows_onlineresource", _toUtf8( u"%s?map=%s" % (self.txtMapServerUrl.text(), self.txtMapFilePath.text()) ) )
        srsList = ["EPSG:4326"]
        srsList.append( _toUtf8( self.canvas.mapRenderer().destinationCrs().authid() ) )
        ms_map.setMetaData( "ows_srs", ' '.join(srsList) )
        ms_map.setMetaData( "ows_enable_request", "*" )
        ms_map.setMetaData( "wms_feature_info_mime_type", "text/html")

        for layer in self.legend.layers():
            # do not process invisible layer
            if not self.legend.isLayerVisible( layer ):
               continue;

            # create a layer object
            ms_layer = mapscript.layerObj( ms_map )
            ms_layer.name = _cleanStr( layer.name() )
            ms_layer.type = self.getLayerType( layer )
            ms_layer.status = mapscript.MS_ON

            # layer extent
            extent = layer.extent()
            ms_layer.extent.minx = extent.xMinimum()
            ms_layer.extent.miny = extent.yMinimum()
            ms_layer.extent.maxx = extent.xMaximum()
            ms_layer.extent.maxy = extent.yMaximum()

            if layer.crs().authid() != "":
                ms_layer.setProjection( "+init=" + _toUtf8( layer.crs().authid() ).lower() )
            else:
                ms_layer.setProjection( _toUtf8( layer.crs().toProj4() ) )

            if layer.hasScaleBasedVisibility():
                ms_layer.minscaledenom = layer.minimumScale()
                ms_layer.maxscaledenom = layer.maximumScale()

            if layer.title() != "":
                ms_layer.setMetaData( "ows_title", _toUtf8(layer.title()))
            else:
                ms_layer.setMetaData( "ows_title", _toUtf8(layer.name()))

            if layer.abstract() != "":
                ms_layer.setMetaData( "ows_abstract",  _toUtf8(layer.abstract()))

            arrPath = self.getGroupPath(layer)
            if arrPath != "":
                path = '/' +'/'.join(arrPath)
                ms_layer.setMetaData( "wms_layer_group", _cleanStr( path ))

                if not path in layerGroups :
                    ms_layer_group = mapscript.layerObj( ms_map )
                    ms_layer_group.name = _cleanStr(arrPath[-1] )
                    ms_layer_group.setMetaData( "ows_title", arrPath[-1])
                    ms_layer_group.type = ms_layer.type
                    ms_layer.status = mapscript.MS_ON
                    layerGroups.append( path )

            # layer connection
            if layer.providerType() == 'postgres':
                ms_layer.setConnectionType( mapscript.MS_POSTGIS, "" )
                uri = QgsDataSourceURI( layer.source() )
                ms_layer.connection = _toUtf8( uri.connectionInfo() )
                data = u"%s FROM %s" % ( uri.geometryColumn(), uri.quotedTablename() )
                #The keyColumn name is invalid with QGis 1.9dev
                if uri.keyColumn() != "":
                    data += u" USING UNIQUE %s" % uri.keyColumn()
                data += u" USING srid=%s" % uri.srid()
                if uri.sql() != "":
                  data += " FILTER (%s)" % uri.sql()
                ms_layer.data = _toUtf8( data )

            elif layer.providerType() == 'wms':
                ms_layer.setConnectionType( mapscript.MS_WMS, "" )
                q = parse_qs(_toUtf8(layer.source()), True)
                ms_layer.connection = q["url"][0]

                # loop thru wms sub layers
                wmsNames = []
                wmsStyles = []
                wmsLayerNames = q["layers"]
                wmsLayerStyles = q["styles"]
                for index in range(len(wmsLayerNames)): 
                    wmsNames.append( _toUtf8( wmsLayerNames[index] ) )
                    wmsStyles.append( _toUtf8( wmsLayerStyles[index] ) )

                # output SRSs
                srsList = []
                srsList.append( _toUtf8( layer.crs().authid() ) )

                # Create necessary wms metadata
                ms_layer.setMetaData( "ows_name", ',' . join(wmsNames) )
                ms_layer.setMetaData( "wms_server_version", "1.1.1" )
                ms_layer.setMetaData( "ows_srs", ' ' . join(srsList) )
                ms_layer.setMetaData( "wms_format", q["format"][0] )

            elif layer.providerType() == 'wfs':
                ms_layer.setConnectionType( mapscript.MS_WFS, "" )
                uri = QgsDataSourceURI( layer.source() )
                ms_layer.connection = _toUtf8( uri.uri() )

                # output SRSs
                srsList = []
                srsList.append( _toUtf8( layer.crs().authid() ) )

                # Create necessary wms metadata
                ms_layer.setMetaData( "ows_name", ms_layer.name )
                #ms_layer.setMetaData( "wfs_server_version", "1.1.1" )
                ms_layer.setMetaData( "ows_srs", ' '.join(srsList) )
           
            elif layer.providerType() == 'spatialite':
                ms_layer.setConnectionType( mapscript.MS_OGR, "" )
                uri = QgsDataSourceURI( layer.source() )
                ms_layer.connection = _toUtf8( uri.database() )    
                ms_layer.data = _toUtf8( uri.table() )    

            elif layer.providerType() == 'ogr':
                #ms_layer.setConnectionType( mapscript.MS_OGR, "" )
                ms_layer.data = _toUtf8( layer.source().split('|')[0] )    

            else:
                ms_layer.data = _toUtf8( layer.source() )    

            # set layer style
            if layer.type() == QgsMapLayer.RasterLayer:
                if hasattr(layer, 'renderer'):    # QGis >= 1.9
                    opacity = int( 100 *layer.renderer().opacity())
                else:
                    opacity = int( 100 * layer.getTransparency() / 255.0 )
                ms_layer.opacity = opacity

            else:
                # use a SLD file set the layer style
                tempSldFile = QTemporaryFile("rt_mapserver_exporter-XXXXXX.sld")
                tempSldFile.open()
                tempSldPath = tempSldFile.fileName()
                tempSldFile.close()

                # export the QGIS layer style to SLD file
                errMsg, ok = layer.saveSldStyle( tempSldPath )
                if not ok:
                    QgsMessageLog.logMessage( errMsg, "RT MapServer Exporter" )
                else:
                    # set the mapserver layer style from the SLD file
                    with open( unicode(tempSldPath), 'r' ) as fin:
                        sldContents = fin.read()
                    if mapscript.MS_SUCCESS != ms_layer.applySLD( sldContents, _toUtf8( layer.name() ) ):
                        QgsMessageLog.logMessage( u"Something went wrong applying the SLD style to the layer '%s'" % ms_layer.name, "RT MapServer Exporter" )
                    QFile.remove( tempSldPath )

                    # Convert units between QGis (mm) and MapServer (pixels)
                    self.convertMapUnit(ms_layer)

                    # MapServer patch : SLD "GAP" is not recognized
                    self.patchGAP(layer, ms_layer)

		    # set layer labels
		    #XXX the following code MUST be removed when QGIS will 
		    # have SLD label support
		    palLayer = QgsPalLayerSettings()
		    palLayer.readFromLayer(layer)
		    if palLayer.enabled:
		            if not palLayer.isExpression:
		                ms_layer.labelitem = _toUtf8( palLayer.fieldName )    
		            else:
		                #XXX expressions won't be supported until 
		                # QGIS have SLD label support
		                pass

		            if palLayer.scaleMin > 0:
		                ms_layer.labelminscaledenom = palLayer.scaleMin
		            if palLayer.scaleMax > 0:
		                ms_layer.labelmaxscaledenom = palLayer.scaleMax

		            ms_label = mapscript.labelObj()

		            ms_label.type = mapscript.MS_TRUETYPE
		            ms_label.antialias = mapscript.MS_TRUE

                            if layer.geometryType() == QGis.Line:
                                 if palLayer.placementFlags & QgsPalLayerSettings.AboveLine:
                                      ms_label.position = mapscript.MS_UC
                                 elif palLayer.placementFlags & QgsPalLayerSettings.BelowLine:
                                      ms_label.position = mapscript.MS_LC
                                 elif palLayer.placementFlags & QgsPalLayerSettings.OnLine:
                                      ms_label.position = mapscript.MS_CC
                                 ms_label.offsety = int( mmToPixelFactor * palLayer.dist )
                            else:
		                 ms_label.position = self.getLabelPosition( palLayer )
		                 # TODO: convert offset to pixels
		                 ms_label.offsetx = int( mmToPixelFactor * palLayer.xOffset )
		                 ms_label.offsety = int( mmToPixelFactor * palLayer.yOffset )

                            if palLayer.placement == palLayer.Line:
                                ms_label.anglemode = mapscript.MS_AUTO
                            if palLayer.placement == palLayer.Curved:
                                ms_label.anglemode = mapscript.MS_FOLLOW
                            else:
		                ms_label.angle = palLayer.angleOffset

		            # set label font name, size and color
		            fontFamily = palLayer.textFont.family().replace(" ", "")
		            fontStyle = palLayer.textNamedStyle.replace(" ", "")
		            ms_label.font = _toUtf8( u"%s-%s" % (fontFamily, fontStyle) )    
		            if palLayer.textFont.pointSize() > 0:
                                # Facteur 0.75 a ete mis en place pour s'approcher du rendu Qgis
		                ms_label.size = palLayer.textFont.pointSize() * 0.75
		            r,g,b,a = palLayer.textColor.getRgb()
		            ms_label.color.setRGB( r, g, b )

                            r,g,b,a = palLayer.bufferColor.getRgb()
		            ms_label.outlinecolor.setRGB( r, g, b )
                            ms_label.outlinewidth = int( mmToPixelFactor * palLayer.bufferSize )

		            if palLayer.fontLimitPixelSize:
		                ms_label.minsize = palLayer.fontMinPixelSize
		                ms_label.maxsize = palLayer.fontMaxPixelSize
		            ms_label.wrap = _toUtf8( palLayer.wrapChar )    

		            ms_label.priority = palLayer.priority

		            # TODO: convert buffer size to pixels
		            # ms_label.buffer = int( mmToPixelFactor * palLayer.bufferSize )

		            if int( palLayer.minFeatureSize ) > 0:
		                # TODO: convert feature size from mm to pixels
		                ms_label.minfeaturesize = int( mmToPixelFactor * palLayer.minFeatureSize )

                            for n in range(0, ms_layer.numclasses):
                                ms_class = ms_layer.getClass(n)
                                ms_class.addLabel( ms_label )
		           # ms_class = mapscript.classObj()
		           # ms_class.addLabel( ms_label )
		           # ms_layer.insertClass( ms_class )
        

        # save the map file now!
        if mapscript.MS_SUCCESS != ms_map.save( _toUtf8( self.txtMapFilePath.text() )     ):
            return

        # Save GUI parameters
        self.storeProperties()

        # Most of the following code does not use mapscript because it asserts 
        # paths you supply exists, but this requirement is usually not meet on 
        # the QGIS client used to generate the mafile.

        # get the mapfile content as string so we can manipulate on it
        with open( unicode(self.txtMapFilePath.text()), 'r' ) as fin:
            # parts holds the content lines
            parts = QString(fin.read()).split(u"\n")
        partsContentChanged = False

        # retrieve the list of used font aliases searching for FONT keywords
        fonts = []
        searchFontRx = QRegExp("^\\s*FONT\\s+")
        for line in parts.filter( searchFontRx ):
            # get the font alias, remove quotes around it
            fontName = line.replace(searchFontRx, "")[1:-1]
            # remove spaces within the font name
            fontAlias = QString(fontName).replace(" ", "")

            # append the font alias to the font list
            if fontAlias not in fonts:
                fonts.append( fontAlias )

                # update the font alias in the mapfile
                # XXX: the following lines cannot be removed since the SLD file 
                # could refer a font whose name contains spaces. When SLD specs
                # ate clear on how to handle fonts than we'll think whether 
                # remove it or not. 
                replaceFontRx = QRegExp(u"^(\\s*FONT\\s+\")%s(\".*)$" % QRegExp.escape(fontName))
                parts.replaceInStrings(replaceFontRx, u"\\1%s\\2" % fontAlias)
                partsContentChanged = True

        # create the file containing the list of font aliases used in the 
        # mapfile
        if self.checkCreateFontFile.isChecked():
            fontPath = QFileInfo(self.txtMapFilePath.text()).dir().filePath(u"fonts.txt")
            with open( unicode(fontPath), 'w' ) as fout:
                for fontAlias in fonts:
                    fout.write( unicode(fontAlias) )

        # add the FONTSET keyword with the associated path
        if self.txtMapFontsetPath.text() != "":
            pos = parts.indexOf( QRegExp("^MAP$") )
            if pos >= 0:
                parts.insert( pos+1, u'  FONTSET "%s"' % self.txtMapFontsetPath.text() )
                partsContentChanged = True
            else:
                QgsMessageLog.logMessage( u"'FONTSET' keyword not added to the mapfile: unable to locate the 'WEB' keyword...", "RT MapServer Exporter" )

        # if mapfile content changed, store the file again at the same path
        if partsContentChanged:
            with open( unicode(self.txtMapFilePath.text()), 'w' ) as fout:
                fout.write( unicode( parts.join(u"\n") ) )

        # XXX for debugging only: let's have a look at the map result! :)
        # XXX it works whether the file pointed by the fontset contains ALL the 
        # aliases of fonts referred from the mapfile.
        #ms_map = mapscript.mapObj( unicode( self.txtMapFilePath.text() ) )
        #ms_map.draw().save( _toUtf8( self.txtMapFilePath.text() + ".png" )    , ms_map )

        QDialog.accept(self)