Version 65 (modified by pvalsecc, 6 years ago)

--

General architecture

This module is split in two:

  1. Client side, a set of JS classes:
    • mapfish.PrintProtocol: Non-GUI dependant class for communicating with the server side.
    • mapfish.widgets.print.SimpleForm: Ext panel allowing to print a single page document.
    • mapfish.widgets.print.MultiPage: Ext panel allowing to print a multipage document.
    • mapfish.widgets.print.PrintControl: An !Openlayers control for getting a PDF in a simple click.
  2. Server side, three implementations:
    • ShellMapPrinter: A command line implementation of the map printing service. Used mainly by the python implementation and for debug.
    • MapPrinterServlet: A java servlet implementing the protocol used by mapfish.PrintProtocol.
    • PrinterController: A Pylons servlet implementing the protocol used by mapfish.PrintProtocol. It uses ShellMapPrinter to enter the java world and do the work.

The server side uses a YAML configuration file that defines the page layouts and allowed values. For more details see the "Server side Configuration" chapter.

The client side, before displaying the forms, can request the server side about the available page layouts, the allowed scales and resolutions.

Server side Configuration

Here is the general structure:

dpis:
  - 254
  - 190
  {...}

scales:
  - 25000
  - 50000
  {...}

hosts:
  - {HOST_WHITELIST_DEFINITION}
  {...}

?fonts:
? - {PATH}

layouts:
  {LAYOUT_NAME}:
?   metaData:
?     {METADATA_DEFINITION}
?   titlePage:
?     {PAGE_DEFINITION}
    mainPage:
?     rotation: false
      {PAGE_DEFINITION}
?   lastPage:
?     {PAGE_DEFINITION}
  {...}

Optional parts are shown with a question mark in the left margin. The question marks must not be put in the configuration file. Their default values is shown.

In general, PDF dimensions and positions are specified in points. 72 points == 1 inch == 25.4 mm.

The list of {HOST_WHITELIST_DEFINITION} defines the allowed URLs for getting maps. Its format will be defined in the next sub-section.

You can have as many layouts as you want. Their name must be unique and will be used on the client side. A layout can have a "titlePage" that will be added at the beginning of the generated document. It cannot contain any map. Same for the "lastPage", but for the end of the document. The "mainPage" section is mandatory and will be used once for each page requested. The details of a {PAGE_DEFINITION} section can be found in another sub-section of this document.

If you want to let the user rotate the map (for a given layout), you have to set the "rotate" field to "true" in the corresponding "mainPage" section.

Fonts definition

The "fonts" section is optional. It contains the path of the fonts you want to use. The entries can point to files (TTF, OTF, TTC, AFM, PFM) or directories. Don't point to directories containing too many files since it will slow down the start time. By default, PDF gives you access to the following fonts (Cp1252 encoding only):

  • Courrier (-Bold, -Oblique, -BoldOblique)
  • Helvetica (-Bold, -Oblique, -BoldOblique)
  • Times (-Roman, -Bold, -Oblique, -BoldOblique)
  • Symbol
  • ZapfDingbats

Host whitelist definition

In this section, you can put as many entries as you want. If at least one matches, the Map server can be used.

This section is not for defining what client can request maps. It is just here to avoid having the print module used as a proxy to access documents from computers behind firewalls.

There are 3 ways to whitelist a host.

Allowing every local services:

  - !localMatch
    dummy: true

The "dummy" parameter is ignored, but mandatory to avoid a limitation in the YAML format.

Allowing by DNS name:

  - !dnsMatch
    host: labs.metacarta.com

Allowing by IP address:

  - !ipMatch
    ip: www.camptocamp.org
?   mask: 255.255.255.255

The "ip" parameter can be a DNS name that will be resolved or directly an IP address.

All the methods accept the following optional parameters:

  • port: to limit to a certain TCP port
  • pathRegexp: a regexp that must match the path part of the URL (before the '?').

Metadata definition

Allow to add some metadata to the generated PDF. They are visible in acroread in the File->Properties menu.

The structure is like that:

    metaData:
?     title: ''
?     author: ''
?     subject: ''
?     keywords: ''
?     creator: ''
?     supportLegacyReader: false

All fields are optional and can use global variables, as defined in the Block definition chapter. Page specific variables are not accessible.

Page definition

The structure is like that:

      pageSize: A4
?     landscape: false
?     marginLeft: 40
?     marginRight: 40
?     marginTop: 20
?     marginBottom: 20
?     backgroundPdf: template.pdf
?     header:
        height: 50
        items:
          - {BLOCK_DEFINITION}
          {...}
      items:
        - {BLOCK_DEFINITION}
        {...}
?     footer:
        height: 50
        items:
          - {BLOCK_DEFINITION}
          {...}

If "backgroundPdf" is specified, the first page of the given PDF file will be added as background of every page.

The "header" and "footer" sections are optional. If the "items" that are in the main section are too big, more pages are generated. The header and footer will be drawn on those pages as well.

Here is a short list of supported pageSizes:

namewidthheight
LETTER612792
LEGAL6121008
A4595842
A38421191

If you want to use a custom page size, you can set pageSize to the width and the height separated by a space.

Block definition

The next sub-sections document the possible types of blocks.

In general, text values or URLs can contain values taken from the spec structure coming with the client's request. A syntax similar to shell is used: ${variableName}. If the current page is a titlePage, only the root values are taken. If it's a mainPage, the service will first look in the current page section then in the root values. Here is how to use this functionality:

            text: 'The value of mapTitle is: ${mapTitle}'

Some virtual variables can be used:

  • ${pageNum}: The current page number.
  • ${pageTot}: The total number of pages. Can be used only in text blocks.
  • ${now}: The current date and time as defined by the machine's locale.
  • ${now FORMAT}: The current date and time as defined by the FORMAT string. The syntax is documented here.
  • ${configDir}: The absolute path to the directory of the configuration file.
  • ${format PRINTF VAR}: Format the value of VAR using the provided PRINTF format (for example: %,d).

All the blocks can have a condition attribute that take an spec attribute name. If the attribute name exists and is not equal to "false" or "0", the block is drawn. Otherwise, it is ignored. An exclamation mark may precede the condition to invert it.

Text block

        - !text
?         font: Helvetica
?         fontSize: 12
?         fontEncoding: Cp1252
?         fontColor: black
?         spacingAfter: 0
?         align: left
?         vertAlign: middle
?         backgroundColor: #FFFFFF
          text: 'Blahblah'

Typical "fontEncoding" values are:

  • Cp1250
  • Cp1252
  • Cp1257
  • Identity-H (horizontal UTF-8)
  • Identity-V (vertical UTF-8)
  • MacRoman

The "font" must refer to a standard PDF font or a declared font.

Image block

        - !image
          maxWidth: 200
          maxHeight: 100
?         spacingAfter: 0
?         align: left
?         vertAlign: middle
          url: http://trac.mapfish.org/trac/mapfish/chrome/site/img/mapfish.png

Supported formats are PNG, GIF, Jpeg, Jpeg2000, BMP, WMF (vector), SVG and TIFF.

The original aspect ratio will be respected. The url can contain "${}" variables.

Columns block

        - !columns
?         config: {TABLE_CONFIG}
?         widths: [25,25,25,25]
?         backgroundColor: #FFFFFF
?         absoluteX: null
?         absoluteY: null
?         width: {PAGE_WIDTH}
?         spacingAfter: 0
?         nbColumns: -1
          items:
            - {BLOCK_DEFINITION}
            {...}

By default, the width of the columns will be equal.

Each item will be in its own column.

If the absoluteX, absoluteY and width are given, the columns block will be floating on top of the page at the specified position.

Every block type is allowed except for map if the column has an absolute position.

Look here for how to specify the config field.

Map block

Allowed only within a mainPage.

        - !map
?         name: map
?         spacingAfter: 0
?         align: left
?         vertAlign: middle
?         absoluteX: null
?         absoluteY: null
?         absoluteX: null
?         overviewMap: null
          width: 440
          height: 483

If the absoluteX, absoluteY and width are given, the map block will be floating on top of the page at the specified position.

If overviewMap is specified, the map will be an overview of the extent augmented by the given factor.

The name is what will be displayed in the Acrobat's reader layer panel. The map layers will be displayed bellow it.

Scalebar block

Display a scalebar.

Allowed only within a mainPage.

        - !scalebar
          maxSize: 150
?         type: line
?         intervals: 3
?         subIntervals: false
?         units: m
?         barSize: 5
?         lineWidth: 1
?         barDirection: up
?         textDirection: up
?         labelDistance: 3
?         font: Helvetica
?         fontSize: 12
?         fontColor: black
?         color: #000000
?         barBgColor: null
?         spacingAfter: 0
?         align: left
?         vertAlign: middle
?         backgroundColor: #FFFFFF

The scalebar, will adapt its width up to maxSize (includes the labels) in order to have a multiple of 1, 2 or 5 values at each graduation. For example:

  • 0, 1, 2, ...
  • 0, 2, 4, ...
  • 0, 5, 10, ...
  • 0, 10, 20, ...

The barSize is the thickness of the bar or the height of the tick marks on the line. The lineWith is for the thickness of the lines (or bar border).

Units can be any of:

  • m (mm, cm, m or km)
  • ft (in, ft, yd, mi)
  • degrees (min, sec, °)

If the value is too big or too small, the module will switch to one of the unit in parenthesis (the same unit is used for every intervals).

The number of intervals can be set to anything >=2. Labels are drawn only at main intervals. If there is no space to display a label at a certain interval, this label won't be displayed. If subIntervals are enabled, their number will depend on the length of an interval.

The type can be:

  • line: A simple line with graduations
  • bar: A thick bar with a suite of color and barBgColor blocks.
  • bar_sub: Like bar, but with little lines for labels.

Error: Macro Image(scalebarTypes.png) failed
Attachment 'wiki:PrintModuleDoc: scalebarTypes.png' does not exist.

The bar and/or text orientation can be set to "up", "down", "left" or "right".

The align attribute is for placing the whole scalebar withing the surrounding column or page. The vertAlign attribute is used only when placed in a column.

Labels are always centered on the graduation, at a distance specified by labelDistance.

Attributes block

Allows to display a table of the displayed feature's attributes.

Allowed only within a mainPage.

        - !attributes
          source: results
?         tableConfig: {TABLE_CONFIG}
          columnDefs:
            {COLUMN_NAME}:
              header: {BLOCK_DEFINITION}
              cell: {BLOCK_DEFINITION}
            {...}

Look here for how to specify the tableConfig field.

The source value defines the name of the entry in the root of the client's spec. For example, it would look like that:

{
  ...
  pages: [
    {
      ...
      results: {
        data: [
          {id:1, name: 'blah', icon: 'icon_pan'},
          ...
        ],
        columns: ['id', 'name', 'icon']
      }
    }
  ]
  ...
}

With this spec you would have to define 3 columnDefs with the names id, name and icon. Each cell definition blocks have access to all the values of the current row.

The spec part is filled automatically by the 2 MapFish widgets when their grids parameter is set.

Here is a crazy example of columnDef that will show the name of the icon and it's bitmap side-by-side inside a single column:

          columnDefs:
            icon:
              header: !text
                text: Symbol
                backgroundColor: #A0A0A0
              cell: !columns
                items:
                  - !text
                    text: '${icon}'
                  - !image
                    align: center
                    maxWidth: 15
                    maxHeight: 15
                    url: 'http://www.mapfish.org/svn/mapfish/trunk/MapFish/client/mfbase/mapfish/img/${icon}.png'

Legends block

Display each layers along with its classes (icons and labels).

        - !legends
?         maxIconWidth: 8
?         maxIconHeight: 8
?         classIndentation: 20
?         layerSpace: 5
?         classSpace: 2
?         backgroundColor: #FFFFFF
?         layerFont: Helvetica
?         layerFontSize: 10
?         classFont: Helvetica
?         classFontSize: 8
?         fontEncoding: Cp1252

layerSpace and classSpace is to specify the line space to add before layers and classes.

For this to work, you need to set the layerTree config option on MF print widgets.

Table configuration

The columns block and the attributes block can take a table configuration object like that:

    config:
?     borderWidth: 0
?     borderWidthLeft: 0
?     borderWidthRight: 0
?     borderWidthTop: 0
?     borderWidthBottom: 0
?     borderColor: black
?     borderColorLeft: black
?     borderColorRight: black
?     borderColorTop: black
?     borderColorBottom: black
?     cells:
?       - {CELL_CONFIGURATION}

A cell configuration looks like that:

?     row: {...}
?     col: {...}
?     borderWidth: 0
?     borderWidthLeft: 0
?     borderWidthRight: 0
?     borderWidthTop: 0
?     borderWidthBottom: 0
?     borderColor: black
?     borderColorLeft: black
?     borderColorRight: black
?     borderColorTop: black
?     borderColorBottom: black
?     padding: 0
?     paddingLeft: 0
?     paddingRight: 0
?     paddingTop: 0
?     paddingBottom: 0
?     backgroundColor: white
?     align: LEFT
?     vertAlign: TOP

The stuff configured at table level is for the table border, not every cell.

The cells list defines overrides for some cells. The cells an override is applied to is defined by the row and col attribute. Those attributes can have several formats:

  • 0: apply only to row or column 0 (the first)
  • 0-10: applies only the row or columns from 0 to 10
  • or you can use any regular expression

Every matching overrides is applied in order and will override the values defined in the previous ones.

For example, if you want to draw an attribute block like that:

Error: Macro Image(tableConfig.png) failed
Attachment 'wiki:PrintModuleDoc: tableConfig.png' does not exist.

You define that:

        - !attributes
          tableConfig:
            borderWidth: 1
            cells:
              # match every cell (default cell formatting)
              - borderWidthBottom: 0.5
                borderWidthLeft: 0.5
                padding: 4
                paddingTop: 0
              # match every even cell (yellowish background)
              - row: '\d*[02468]'
                backgroundColor: #FFFFCC
              # for the header
              - row: 0
                borderWidthBottom: 1
                backgroundColor: #FA0002
                align: center
          {...}

Protocol

Four commands are available and are documented in the next sections.

Every command uses the HTTP status code to notify errors.

info.json

HTTP command:

GET {PRINT_URL}/info.json?url={PRINT_URL}%2Finfo.json&var=printConfig

Returns a JSON structure as such:

var printConfig = {
    "scales":[
        {"name":"25000"},
        {"name":"50000"},
        {"name":"100000"}
    ],
    "dpis":[
        {"name":"190"},
        {"name":"254"}
    ],
    "layouts":[
        {
            "name":"A4 portrait",
            "map":{
                "width":440,
                "height":483
            }
        }
    ],
    "printURL":"http:\/\/localhost:5000\/print\/print.pdf",
    "createURL":"http:\/\/localhost:5000\/print\/create.json"
}

This can be loaded through an HTML script tag like that:

<script type="text/javascript"
        src="http://localhost:5000/print/info.json?var=printConfig"></script>

Or through an AJAX request by omitting the "var" query parameter. All the print widget implementations have a "configUrl" parameter. If this parameter is set, the widget will do this request by AJAX automatically.

The "url" query parameter is here to help the print servlet to know what URL is used by the browser to access the servlet. This parameter is here because the servlet can be behind a proxy, hiding the real URL.

print.pdf

HTTP command:

GET {PRINT_URL}/print.pdf?spec={SPEC}

The "SPEC" parameter is a JSON structure like that:

{
    layout: 'A4 portrait',
    ...CUSTOM_PARAMS...
    srs: 'EPSG:4326',
    units: 'degrees',
    layers: [
        {
            type: 'WMS',
            layers: ['basic'],
            baseURL: 'http://labs.metacarta.com/wms/vmap0',
            format: 'image/jpeg'
        }
    ],
    pages: [
        {
            center: [6, 45.5],
            scale: 4000000,
            dpi: 190,
            ...CUSTOM_PARAMS...
        }
    ]
}

The location to show on the map can be specified with a center and a scale as show or with a bbox like that:

   bbox: [5, 45, 6, 46]

The print module will use the nearest scale and will make sure the aspect ratio stays correct.

There are two locations where custom parameters can be added. Those will be ignored by the web service but, will be accessible from the layout templates.

For the format of the layers section, please look at the implementations pointed by mapfish.PrintProtocol.SUPPORTED_TYPES.

This command returns the PDF file directly.

create.json

HTTP command:

POST {PRINT_URL}/create.json?url={PRINT_URL}%2Fcreate.json

The spec defined in the "print.pdf" command must be included in the POST body.

Returns a JSON structure like that:

{
    getURL: 'http:\/\/localhost:5000\/print\/56723.pdf'
}

The URL returned can be used to retrieve the PDF file. See the next section.

{ID}.pdf

This command's URL is returned by the "create.json" command.

HTTP command:

GET {PRINT_URL}/{ID}.pdf

Returns the PDF. Can be called only during a limited time since the server side temporary file is deleted afterwards.

Client side

Please look at the examples in examples/print/ examples/print/.

Overrides

All the JS classes are accepting an overrides parameters. This parameter can be used to change the OL layers settings just for the print output. This can be usefull for several purpose:

  • Go around a TileCache server and access the WMS server directly (baseURL and layers).
  • Change the format of the requested map (format).
  • Change the style (styles).

Any value passed in the spec can be overridden like this.

It is a dictionary where the key are the layer's names and the values are dictionaries of parameters to change when printing.

For example:

var overrides = {
  'rivers': {
    format: 'image/svg+xml'
  },
  'far': {
    visibility: false
  },
  'sometimes' {
    visibility: false,
    300: {
      visibility: true
    }
  }
}

In this case, the rivers layer will be printed vectorized (type 2 layer) and the far layer won't be printed. For the sometimes layer, we use the possibility to have an override that depends on the DPI chosen by the use for printing and this layer will be printed only when 300DPI is chosen.

Override legends

To use another text in legend (layer name or classe name), we can use the attribut "printText" in layer tree model:

...

text: '<img src="images/information.png"/>&nbsp;'
       + OpenLayers.i18n('Layer label'),
checked: false,
layerNames: ['myLayer'],
printText: OpenLayers.i18n('Print layer label'),
children : [
    {text: 'Zone 1: 0.6 m/s<sup>2</sup>',
     printText: 'Zone 1: 0.6 m/s2'
    }
]
...

Installation

Please read the README.

FAQ

All I get in my PDF is: "ERROR: infinite table loop".

Something in your page is too big. For example, the width or the height of your !map block.

I tried to print (pylons mode) and I get a "Java error". What's next?

Look in the apache error log, you'll find more information.

What are the limitations of the type 2 layers?

It depends mostly on the map server you use. For the moment, GeoServer has not been extensively tested. With MapServer:

  • The PDF output must be enabled when you compile and doesn't work in WMS mode, only in native MapServer mode. There are some limitations. on the styling. And you must use truetype fonts.
  • The SVG output is limited regarding the stylings you can use. For example only plain polygon fillings are supported by MapServer. If a complex styling is used, your features may appear plain black.

I tried to change the layout and half the Map is printed off the page on the right. Or I have an empty page added. Is it a bug?

It's mostly a feature ;-) . This kind of behavior can be seen in iText, when adding a block that is too big for the page size. Try to reduce the size of your map block.

When I look at my generated PDF in Acrobat Reader, it looks good. But, when I print it, it misses some tiles/layers, some bitmaps are just weird or there are no page printed. What's wrong?

There are three possible explanations:

  • Your printer has not enough memory: in Acrobat's print dialog, select "Save printer memory"
  • Your printer firmware is buggy: upgrade it
  • Your printer driver is buggy: upgrade it

The module needs to go through a proxy to acces the map services.

It's so 90s... you should hire some fresh guys for your IT team. ;-)

You need to set some system properties (http.proxy*) when you start your java programs.

When I try to print under IE7, a window opens and closes right away even if I have the popup blocking disabled. Is it a bug?

No, it's a IE7 "feature". For that to work, you have to set:

Internet Options > Security > Custom level... > Downloads > Automatic prompring for file downloads = Enable