Serve PDF and DXF files using qgis-server

You might be faced with the need to distribute “plan” files. For some businesses, paper maps (pdf) and CAD drawings (dxf) are still the primary source of information, and sometimes you can’t propose anything else. If you’re working with QGIS there are simple ways to serve those files without much to do, and all with opensource solutions using qgis and qgis-server.

Setup

You’ll need… Well, qgis and qgis-server, and that’s it. First install qgis-server using instructions for you environment, you might have a look at the official doc or this short tuto. While working on this article, I followed the containerized deployment instruction from the QGIS documentation. I’ll link a repository with the resources for you to follow along.

The next step is the preparation of your exports using qgis. Your projects will serve as configuration, where you’ll define symbologies, renderings, services, etc. We’ll show some possibilities to configure pdf and dxf exports.

Export PDF files

For simple cases it’s the easiest setup, you’ll just need to configure a layout in your project. Define a map that suits your taste (or better your objectives) and save everything in a location where your server has the right to read your project and the linked data. And that’s it for the most part. You can then have a look at a resulting map by querying an url of the like:

http://localhost:8080/qgis-server?
SERVICE=WMS
&VERSION=1.3.0
&REQUEST=GetPrint
&MAP=project.qgz
&TEMPLATE=layout
&CRS=EPSG:3857
&map0:extent=-591992,-1689591,4318167,3574909
&FORMAT=application/pdf

If we divide the query we have:

  • http://localhost:8080/qgis-server the url of your qgis-server.
  • SERVICE=WMS tells the server to use its WMS service.
  • VERSION=1.3.0 version of the service.
  • REQUEST=GetPrint run the GetPrint request.
  • MAP=project.qgz path to the qgis project to read.
  • TEMPLATE=layout the name of a template defined within the project that describes a layout, where you’ll define your map.
  • CRS=3857 the coordinate system to use, usually the one defined in your project.
  • map0:extent=xmin,ymin,xmax,ymax the bounding box defining the extent to print. In the CRS system.
  • FORMAT=application/pdf specify the output format, here pdf.

Your browser will show you something like the following:

export-pdf

In this simple case, we could imagine a service where you define an extraction extent, which then will be passed to your printing service in the form of a mapx:extent parameter. You’d receive your pdf as a response.

Export PDF files: atlas version

You can create atlases in QGIS which allows you to produce maps using predefined extents. Your qgis-server also supports those and you can request a specific map from an atlas by using the ATLAS_PK parameter in you query.

If we create a layout_atlas in our project, using a grid as overlay (see the example project), we could then query our atlas pages using the following:

http://localhost:8080/qgis-server?
SERVICE=WMS
&VERSION=1.3.0
&REQUEST=GetPrint
&MAP=project.qgz
&TEMPLATE=layout_atlas
&CRS=EPSG:3857
&ATLAS_PK=1

Which would then send back something like:

export-atlas

Warning

The server doesn’t seem to know the number of pages in the atlas. The printed page then shows Page 1/1 while in the desktop version of the atlas it would show Page 1/112.

Here you’d need to get the atlas elements that intersect your region of interest and pass their id as ATLAS_PK. A query like the following could get you this information:

curl -X POST -H "Content-Type: application/xml" -d @BODY.xml localhost:8080/qgis-server?SERVICE=WFS&VERSION=1.3.0&REQUEST=GetFeature&MAP=project.qgs  

Where BODY.xml contains the following body:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<wfs:GetFeature maxFeatures="5000" version="1.1.0" service="WFS" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd" xmlns:wfs="http://www.opengis.net/wfs" xmlns:gml="http://www.opengis.net/gml" xmlns:ogc="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <wfs:Query typeName="grid">
    <ogc:Filter>
      <ogc:Intersects>
        <ogc:PropertyName>geom</ogc:PropertyName>
          <Polygon xmlns="http://www.opengis.net/gml" srsName="EPSG:3857">
            <exterior>
              <LinearRing>
                <posList srsDimension="2">1471131.73 1257643.13 2471131.7 1257643.13 2471131.7 257643.1 1471131.7 257643.1 1471131.73 1257643.1</posList>
              </LinearRing>
            </exterior>
          </Polygon>
      </ogc:Intersects>
    </ogc:Filter>
  </wfs:Query>
</wfs:GetFeature>

Extracting the ids from the response you could then query you atlas on the server with:

http://localhost:8080/qgis-server/?atlas_pk=44,45,46,52,53,54&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetPrint&MAP=project.qgz&TEMPLATE=layout_atlas&CRS=EPSG:3857&FORMAT=application/pdf
Info

You’ll need to allow your server to print multiple pages. This can be done in Project > Properties > QGIS Server > WMS > Maximum page number for atlas queries.

Export DXF

At this point you have everything you need to export dxf files. Make sure you expose the layers you want to export through WFS (Project > Properties > QGIS Server > WFS > Tick Publish for the layers you want). You can then get your dxf using something like:

localhost:8080/qgis-server?
SERVICE=WMS
&VERSION=1.3.0
&REQUEST=GetMap
&MAP=project.qgz
&TEMPLATE=layout
&CRS=EPSG:3857
&map0:extent=-591992,-1689591,4318167,3574909
&LAYERS=point,line,polygon
&FORMAT=application/dxf
&FILE_NAME=output.dxf
Info

For dxf exports, the symbology is a bit trickier to get right in my opinion. You might have to play with units to get a configuration and a rendering that suits your needs. Also, Polylines3D don’t support linetypes and weight, so you might need to use the FORCE_2D parameter.

To conclude

PDF and DXF are, after all, rather easy to create with a qgis-server. No need for any other piece of software, potentially expensive. Make sure to play with the QGIS Server properties of your project and layers within QGIS to see how it influences the exports. Again, all the material used in this article is accessible in this repo.