org.orbisgis.core_export.GeoSpatialPDF.java Source code

Java tutorial

Introduction

Here is the source code for org.orbisgis.core_export.GeoSpatialPDF.java

Source

/**
 * OrbisGIS is a java GIS application dedicated to research in GIScience.
 * OrbisGIS is developed by the GIS group of the DECIDE team of the 
 * Lab-STICC CNRS laboratory, see <http://www.lab-sticc.fr/>.
 *
 * The GIS group of the DECIDE team is located at :
 *
 * Laboratoire Lab-STICC  CNRS UMR 6285
 * Equipe DECIDE
 * UNIVERSIT DE BRETAGNE-SUD
 * Institut Universitaire de Technologie de Vannes
 * 8, Rue Montaigne - BP 561 56017 Vannes Cedex
 * 
 * OrbisGIS is distributed under GPL 3 license.
 *
 * Copyright (C) 2007-2014 CNRS (IRSTV FR CNRS 2488)
 * Copyright (C) 2015-2017 CNRS (Lab-STICC UMR CNRS 6285)
 *
 * This file is part of OrbisGIS.
 *
 * OrbisGIS is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * OrbisGIS is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * OrbisGIS. If not, see <http://www.gnu.org/licenses/>.
 *
 * For more information, please consult: <http://www.orbisgis.org/>
 * or contact directly:
 * info_at_ orbisgis.org
 */
package org.orbisgis.core_export;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfArray;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfLayer;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfNumber;
import com.itextpdf.text.pdf.PdfRectangle;
import com.itextpdf.text.pdf.PdfString;
import com.itextpdf.text.pdf.PdfStructureElement;
import com.itextpdf.text.pdf.PdfStructureTreeRoot;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;
import com.vividsolutions.jts.geom.Envelope;
import java.awt.Graphics2D;
import java.io.IOException;
import java.io.OutputStream;
import org.orbisgis.coremap.layerModel.ILayer;
import org.orbisgis.coremap.map.MapTransform;
import org.orbisgis.commons.progress.ProgressMonitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Utility to export a layer or a group of layer in a geospatial pdf format
 * 
 * @author Erwan Bocher
 */
public class GeoSpatialPDF {

    private final ILayer rootLayer;
    private final float width;
    private final float height;
    protected static final Logger LOGGER = LoggerFactory.getLogger(GeoSpatialPDF.class);

    public GeoSpatialPDF(ILayer rootLayer, float width, float height) {
        this.rootLayer = rootLayer;
        this.width = width;
        this.height = height;
    }

    /**
     * Create the PDF document and a the geospatial tags
     *
     * @param out
     * @param mt
     * @param pm
     * @throws IOException
     */
    public void createPDF(OutputStream out, MapTransform mt, ProgressMonitor pm) throws IOException {
        Document document = new Document(new Rectangle(width, height));
        try {
            PdfWriter writer = PdfWriter.getInstance(document, out);
            writer.setTagged();
            writer.setUserProperties(true);
            document.open();

            PdfContentByte cb = writer.getDirectContent();

            int numLayers = rootLayer.getLayerCount();
            for (int i = numLayers - 1; i >= 0; i--) {
                ILayer layer = rootLayer.getLayer(i);
                processSubLayer(layer, mt, writer, cb, pm, null);
            }
            georefPdf(writer, mt);

        } catch (DocumentException ex) {
            throw new IOException("Cannot create the pdf", ex);
        }
        document.close();
    }

    /**
     * Process all layers in the layermodel and build the corresponding pdf tree
     * layer
     *
     * @param layer
     */
    private void processSubLayer(ILayer layer, MapTransform mt, PdfWriter writer, PdfContentByte cb,
            ProgressMonitor pm, PdfLayer mainLayer) {
        if (layer.acceptsChilds() && layer.getLayerCount() > 0) {
            PdfLayer groupLayer = new PdfLayer(layer.getName(), writer);
            //To manage group of layers
            for (ILayer subLayer : layer.getChildren()) {
                processSubLayer(subLayer, mt, writer, cb, pm, groupLayer);
            }

        } else {
            if (layer.isVisible() && layer.getEnvelope().intersects(mt.getAdjustedExtent())) {
                PdfLayer mapLayer = new PdfLayer(layer.getName(), writer);
                if (mainLayer != null) {
                    mainLayer.addChild(mapLayer);
                }
                PdfTemplate layerTemplate = cb.createTemplate(width, height);
                Graphics2D g2dLayer = layerTemplate.createGraphics(width, height);
                cb.beginLayer(mapLayer);
                PdfRenderer renderer2 = new PdfRenderer(layerTemplate, width, height);
                renderer2.draw(mt, g2dLayer, (int) width, (int) height, layer, pm);
                cb.addTemplate(layerTemplate, 0, 0);
                g2dLayer.dispose();
                cb.endLayer();
            }
        }
    }

    /**
     * This method is used to georeference the pdf.
     * Note : The CRS is not yet supported.
     *
     * @param writer
     * @param mt
     * @throws IOException
     * @throws DocumentException
     */
    public void georefPdf(PdfWriter writer, MapTransform mt) throws IOException, DocumentException {

        PdfStructureTreeRoot tree = writer.getStructureTreeRoot();

        //the part of the document where maps are displayed
        float mapWidth = width;
        float mapHeight = height;
        float mapLX = 0;
        float mapLY = 0;

        //ViewPort Dictionary
        PdfDictionary viewPortDict = new PdfDictionary();
        viewPortDict.put(PdfName.TYPE, new PdfName("Viewport"));
        viewPortDict.put(PdfName.BBOX, new PdfRectangle(mapLX, mapLY, mapLX + mapWidth, mapLY + mapHeight));
        viewPortDict.put(PdfName.NAME, new PdfString("Layers"));

        //Measure dictionary
        PdfDictionary measureDict = new PdfDictionary();
        measureDict.put(PdfName.TYPE, new PdfName("Measure"));
        measureDict.put(PdfName.SUBTYPE, new PdfName("GEO"));

        //Bounds
        PdfArray bounds = new PdfArray();
        bounds.add(new PdfNumber(0));
        bounds.add(new PdfNumber(0));
        bounds.add(new PdfNumber(1));
        bounds.add(new PdfNumber(0));
        bounds.add(new PdfNumber(1));
        bounds.add(new PdfNumber(1));
        bounds.add(new PdfNumber(0));
        bounds.add(new PdfNumber(1));

        measureDict.put(new PdfName("Bounds"), bounds);

        //GPTS
        Envelope adjustedBbox = mt.getAdjustedExtent();

        if (!adjustedBbox.isNull()) {

            //ly lx ly ux uy ux uy lx
            PdfArray gptsTable = new PdfArray();
            gptsTable.add(new PdfNumber(((Double) adjustedBbox.getMinY()).toString()));
            gptsTable.add(new PdfNumber(((Double) adjustedBbox.getMinX()).toString()));
            gptsTable.add(new PdfNumber(((Double) adjustedBbox.getMinY()).toString()));
            gptsTable.add(new PdfNumber(((Double) adjustedBbox.getMaxX()).toString()));
            gptsTable.add(new PdfNumber(((Double) adjustedBbox.getMaxY()).toString()));
            gptsTable.add(new PdfNumber(((Double) adjustedBbox.getMaxX()).toString()));
            gptsTable.add(new PdfNumber(((Double) adjustedBbox.getMaxY()).toString()));
            gptsTable.add(new PdfNumber(((Double) adjustedBbox.getMinX()).toString()));

            measureDict.put(new PdfName("GPTS"), gptsTable);

            //The CRS will be added when the mapcontext will support it.

            //            //GCS Geospatial Coordinate system
            //            PdfDictionary gcsDict = new PdfDictionary();
            //            if (context.getBbox().getCrs() != null) {
            //
            //                if (context.getBbox().getCrs().getType() != null) {
            //                    gcsDict.put(PdfName.TYPE, new PdfName(context.getBbox().getCrs().getType()));
            //                } else {
            //                    LOGGER.warn("No type of crs : the pdf cannot be georeferenced");
            //                    return;
            //                }
            //
            //                if (context.getBbox().getCrs().getEpsg() != 0) {
            //                    gcsDict.put(new PdfName("EPSG"), new PdfNumber(context.getBbox().getCrs().getEpsg()));
            //                } else {
            //                    LOGGER.warn("No epsg : the pdf cannot be georeferenced");
            //                    return;
            //                }
            //
            //
            //            } else {
            //                LOGGER.warn("No crs :  the pdf cannot be georeferenced");
            //
            //            }
            //
            //            measureDict.put(new PdfName("GCS"), gcsDict);
        } else {
            LOGGER.warn("Envelope of bbox null : the pdf cannot be georeferenced");

        }

        //PDU : array of units
        PdfArray pdu = new PdfArray();
        pdu.add(new PdfName("KM"));
        pdu.add(new PdfName("SQKM"));
        pdu.add(new PdfName("DEG"));

        measureDict.put(new PdfName("PDU"), pdu);

        //LPTS
        PdfArray lptsTable = new PdfArray();
        lptsTable.add(new PdfNumber(0));
        lptsTable.add(new PdfNumber(0));
        lptsTable.add(new PdfNumber(1));
        lptsTable.add(new PdfNumber(0));
        lptsTable.add(new PdfNumber(1));
        lptsTable.add(new PdfNumber(1));
        lptsTable.add(new PdfNumber(0));
        lptsTable.add(new PdfNumber(1));

        measureDict.put(new PdfName("LPTS"), lptsTable);

        viewPortDict.put(new PdfName("Measure"), measureDict);

        PdfStructureElement top = new PdfStructureElement(tree, new PdfName("VP"));
        top.putAll(viewPortDict);
    }
}