LuciadLightspeed allows you to print out the maps displayed in a LuciadLightspeed view, by creating printable objects. In addition, you can display a preview of the layout of your print before you start the printout.

Creating and configuring a Printable

LuciadLightspeed views can be printed using the java.awt.print API. The class ALcdViewComponentPrintable is an implementation of java.awt.print.Printable which prints the contents of a given view.

ALcdViewComponentPrintable defines the following printing properties:

  • DPI: the desired resolution of the print in dots per inch.

  • Feature scale: the scaling of features in the print relative to their size on the screen. A value of 1 means that features such as icons, labels or line widths are printed at the same proportional size as they have on the screen. Values smaller than 1 mean that features become proportionally smaller. For instance, lines appear thinner, and labels become smaller than they are on screen. If label decluttering is used, this also implies that the print potentially displays more labels than the screen. You can also proportionally increase the size of the features by choosing a value between 1 and 2. Feature scale may also affect level-of-detail decisions, for example for raster layers. Lower feature scales may cause higher detail levels to be shown, and the other way round.

  • Horizontal and vertical page count: the number of pages across which the print should be spread out, for multi-page prints.

  • Map scale: the actual map scale that the print will have. Take, for example, a map scale of 1/10000, or 1:10000. This means that 1 meter in world coordinates corresponds to 1/10000m = 0.1mm on paper. The map scale can be derived from the number of pages and the print DPI, or you can set it explicitly. If you do, the page count is derived from the scale, instead of the other way round.

Two implementations of ALcdViewComponentPrintable are available:

These classes allow you to set all the printing properties, as well as some additional settings such as the inclusion of crop marks on multi-page prints. Please see the reference documentation for more details.

print
Figure 1. An example of a printed component containing a footer and a map view

Examples of how these classes are used can be found in samples.gxy.printing and samples.lightspeed.printing, respectively. These samples also demonstrate how the printables can be used in conjunction with TLcdPrintPreview to display a multi-page print preview dialog. Finally, the samples also illustrate how to add decorations, such as headers and footers or a legend, to the page surrounding the map.

Supporting printing for custom layers and painters in an ILspView

All the standard layer types available in Lightspeed views support printing out of the box. When you are implementing your own ILspPaintableLayer or ILspPainter, however, it may be necessary to take some additional steps to make your implementation printing-capable. This section explains these extra steps.

Tiled rendering

Lightspeed views use a tiled rendering approach to generate the high-resolution images needed for a print. This is normally transparent to the layers and painters in the view, as the tiling is performed through the manipulation of the OpenGL projection matrix. If your custom painting code modifies the projection matrix, however, it may nullify the transformations needed for the tiled rendering.

In such cases, the painter can obtain the bounds of the current tile via ALspViewXYZWorldTransformation.getClip(). This method returns a rectangle in view coordinates which bounds the area of the view that is currently being printed. The painter must apply the necessary scaling and translation to make this portion of the view fill the entire viewport.

A typical use case is drawing all manner of overlays on top of the view in screen coordinates. The following code fragment shows how you could set up an orthographic projection matrix for your layer to achieve this. If you do so, however, the layer will no longer print correctly. Therefore, you need to perform additional transformations if the printing clip is not null.

Program: Applying the print clip to custom OpenGL rendering code
int width = aView.getWidth();
int height = aView.getHeight();
double rasterizationScale = 1.0;

// Switch to an orthographic projection. This breaks printing.
gl.glMatrixMode( ILcdGL.GL_PROJECTION );
gl.glPushMatrix();
gl.glLoadIdentity();
gl.glOrtho( 0, width, height, 0, -1, 1 );

// Apply the print clip if it is set to make the layer print correctly.
ALspViewXYZWorldTransformation w2v = aView.getViewXYZWorldTransformation();
Rectangle2D clip = w2v.getClip();
if ( clip != null ) {
  // Scale so the clip fills the view
  rasterizationScale = aView.getWidth() / clip.getWidth();
  gl.glScaled( rasterizationScale, rasterizationScale, 1.0 );
  // Translate so the clip is aligned to the view
  gl.glTranslated( -clip.getX(), -clip.getY(), 0 );
}

gl.glMatrixMode( ILcdGL.GL_MODELVIEW );
gl.glPushMatrix();
gl.glLoadIdentity();

// From this point on, draw things in view coordinates.

Feature scale

Custom painters may also want to take the feature scale property, as discussed in Creating and configuring a Printable, into account. The current feature scale is available via ALspViewXYZWorldTransformation.getFeatureScale(). The feature scale can be applied to line widths, font sizes, texture resolutions, level-of-detail decisions, and so on, as you see fit. It is important to note, however, that the feature scale is relative to the print resolution. If the print resolution is 10 times that of the view, and the feature scale is 0.5, a painter should apply a combined scale factor of 5 to get the expected result.

The print resolution can be derived from the clip mentioned in the previous section: divide the width or height of the clip by that of the view to obtain the print rasterization scale factor.

The following code, which is continued from the example in Tiled rendering, shows how a line thickness is scaled for printing:

Program: Scaling line width using print resolution and feature scale
int lineWidth = 2;
gl.glLineWidth( ( float ) (lineWidth * rasterizationScale * w2v.getFeatureScale()) );