GTRenderer
to draw maps¶
GTRenderer
renderer is the reason why you signed up for this whole GeoTools experience; you want to see a Map.
GTRenderer
is actually an interface; currently there are two implementations:
StreamingRenderer
- a great implementation that does not cache anything. This decision makes it easier to understand and allows it to tackle that large data sets without running out of memory.ShapefileRenderer
- (unsupported) restricted to shapefiles as a playground for trying out speed improvements. However all the good optimizations have been picked up byStreamingRenderer
.
Here is how to drawn an outputArea
rectangle:
GTRenderer draw = new StreamingRenderer();
draw.setMapContent(map);
draw.paint(g2d, outputArea, map.getLayerBounds() );
If you have completed the quick start, this is the approach used by the JMapPane
class we use in a
lot of our tutorials.
The important part of the above example is that GTRenderer
works on the Java2D class
Graphics2D
. You can find many implementations of Graphics2D
allowing GeoTools to work with a
range of graphics systems beyond the screen.
Swing¶
You can create a swing control to render the image interactively; we
provide an example JMapPane
for use in our tutorials.
GTRenderer
is just a rendering engine - in your own application you may
consider the following ideas:
Experiment with different Java 2D graphics settings such as anti-aliasing
Use background threads to draw tiles, and allowing your swing control to pull the tiles onto the screen for a smooth “slippy” map
3D¶
A Google summer of code student put together and example of rendering into a texture buffers and using OpenGL to handle panning and zooming.
Personally I would look for an Graphics2D
implementation that was
backed by OpenGL commands and use GeoTools to render out into the scene
graph.
If you are interested in the students code it is currently in the “spike” directory of GeoTools where we keep experiments.
Printing¶
The Java2D library is also used for Java printing. You can print using StreamingRenderer
, the code works like normal just
use the Graphics2D
object from your Printer.
uDig uses this facility to allow for printing maps directly to the printer.
PDF¶
We have also had success using GTRenderer
and Batik for the generation
of PDF output (they provide a Graphics2D
object).
You can see this functionality in uDig and GeoServer.
The following example is taken from uDig:
Rectangle suggestedPageSize = getITextPageSize(page1.getPageSize());
Rectangle pageSize = rotatePageIfNecessary(suggestedPageSize);
//rotate if we need landscape
Document document = new Document(pageSize);
...
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(outputFile));
document.open();
Graphics2D graphics = cb.createGraphics(pageSize.getWidth(), pageSize.getHeight());
// call your GTRenderer here
GTRenderer draw = new StreamingRenderer();
draw.setMapContent(map);
draw.paint(graphics, outputArea, map.getLayerBounds() );
// cleanup
graphics.dispose();
//cleanup
document.close();
writer.close();
PDF Tips:
You may wish to increase the page size by 2 and then scale the result by 50% in order to produce high resolution raster layers
SVG¶
The GeoVista team have used the Batik project to generate SVG output.
You will need to manage the Batik dependencies yourself, make sure to include batik-codec if your map contains any image based graphics.
Thanks to James Macgill for the following code example:
/**
* Generate an SVG document from the supplied information. Note, use cavasSize first if you want
* to change the default output size.
*
* @param map Contains the layers (features + styles) to be rendered
* @param env The portion of the map to generate an SVG from
* @param out Stream to write the resulting SVG out to (probable should be a new file)
* @param canvasSize optional canvas size, will default to 300x300
* @throws IOException Should anything go wrong whilst writing to 'out'
* @throws ParserConfigurationException If critical XML tools are missing from the classpath
*/
public static void exportSVG(
MapContent map, ReferencedEnvelope env, OutputStream out, Dimension canvasSize)
throws IOException, ParserConfigurationException {
if (canvasSize == null) {
canvasSize = new Dimension(300, 300); // default of 300x300
}
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
// Create an instance of org.w3c.dom.Document
Document document = db.getDOMImplementation().createDocument(null, "svg", null);
// Set up the map
SVGGeneratorContext ctx1 = SVGGeneratorContext.createDefault(document);
SVGGeneratorContext ctx = ctx1;
ctx.setComment("Generated by GeoTools2 with Batik SVG Generator");
SVGGraphics2D g2d = new SVGGraphics2D(ctx, true);
g2d.setSVGCanvasSize(canvasSize);
StreamingRenderer renderer = new StreamingRenderer();
renderer.setMapContent(map);
Rectangle outputArea = new Rectangle(g2d.getSVGCanvasSize());
ReferencedEnvelope dataArea = map.getMaxBounds();
LOGGER.finest("rendering map");
renderer.paint(g2d, outputArea, dataArea);
LOGGER.finest("writing to file");
try (OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8)) {
g2d.stream(osw);
}
}
Image¶
You can also ask Java to make you a Graphics2D
for a BufferedImage
in memory. After drawing into this
image you can write it out to disk.
Here is an example from Oliver on the email list (modified slightly to use current GeoTools classes):
public void saveImage(final MapContent map, final String file, final int imageWidth) {
GTRenderer renderer = new StreamingRenderer();
renderer.setMapContent(map);
Rectangle imageBounds = null;
ReferencedEnvelope mapBounds = null;
try {
mapBounds = map.getMaxBounds();
double heightToWidth = mapBounds.getSpan(1) / mapBounds.getSpan(0);
imageBounds = new Rectangle(
0, 0, imageWidth, (int) Math.round(imageWidth * heightToWidth));
} catch (Exception e) {
// failed to access map layers
throw new RuntimeException(e);
}
BufferedImage image = new BufferedImage(imageBounds.width, imageBounds.height, BufferedImage.TYPE_INT_RGB);
Graphics2D gr = image.createGraphics();
gr.setPaint(Color.WHITE);
gr.fill(imageBounds);
try {
renderer.paint(gr, imageBounds, mapBounds);
File fileToSave = new File(file);
ImageIO.write(image, "jpeg", fileToSave);
} catch (IOException e) {
throw new RuntimeException(e);
}
}