How to export and image from a map and insert it into a new PDF file?

1.7k views Asked by At

I have a webpage where I display a map using openstreetmap's ol3 library and other elements from primefaces:

<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://primefaces.org/ui">
    <ui:define name="title"></ui:define>
    <ui:define name="content" style="border-style: none;">
    <script type="text/javascript" src="resources/js/ol.js"></script>
    <script type="text/javascript" src="resources/js/map.js"></script>
    <p:layoutUnit>
      <p:messages id="messages" showDetail="true" autoUpdate="true" closable="true"/>
      <h:form id="mainForm">
        <!--content-->
        <p:commandButton value="Build PDF" class="buttonFont" process="@all" actionListener="#{bean.createPDF}"     ajax="false"/>
      </h:form>  
    </p:layoutUnit>
     <p:layoutUnit position="center">
     <h:panelGroup  layout="block" id="map">
     </h:panelGroup>  

Script map.js:

var map; 
var osmlayer = new ol.layer.Tile({
            source: new ol.source.OSM()
        });

 var position = ol.proj.transform([longitude, latitude], 'EPSG:4326', 'EPSG:3857');
        var  view = new ol.View({
            center : position,
                    zoom : 12 

map = new ol.Map({
                target : document.getElementById('map'),
                layers : [osmlayer],
                controls : [ new ol.control.Zoom(), new ol.control.ScaleLine({
                    geodesic : true
                }), new ol.control.Attribution(), new ol.control.Rotate() ],
                view : view
            }); 

I need to get an image(png/jpeg) from what's been displayed on my map and add it to a new PDF generated by itextpdf in the current ManagedBean:

@ManagedBean(name = "bean")
@ViewScoped
public class mapBean{

    public void createPDF(){
        Document document = new Document(PageSize.A4, 50, 50, 50, 50);
        ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
        ec.setResponseHeader("Content-Type", "application/pdf");
        ec.setResponseHeader("Content-Disposition", "attachment; filename=\"Title.pdf\"");
        try{
           PdfWriter writer = PdfWriter.getInstance(document,ec.getResponseOutputStream());
           document.open();
           Image mapPDF = Image.getInstance(/*Set image from map*/);
           mapaPDF.scaleToFit(450,200);
           document.add(mapaPDF);
           document.close();
           FacesContext.getCurrentInstance().responseComplete();
        }
        catch (Exception er) {
        // TODO Auto-generated catch block
        er.printStackTrace();
        }
    }
}
2

There are 2 answers

2
pavlos On

You dont need to do it on the server side. You can just do it on the client side.

check this example

You can get the map image out of the canvas using canvas.toDataURL('image/jpeg');

0
Cris P. On

In javascript, I created a function to get the canvas of the map and insert it into an h:inputHidden :

function imagePDF(){
            canvas = document.getElementsByTagName('canvas')[0];
            var imagen = canvas.toDataURL('image/png');
            document.getElementById('mainForm:imagen').value = imagen;
        }

I call this function inside the p:commandButton :

<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://primefaces.org/ui">
    <ui:define name="title"></ui:define>
    <ui:define name="content" style="border-style: none;">
    <script type="text/javascript" src="resources/js/ol.js"></script>
    <script type="text/javascript" src="resources/js/map.js"></script>
<p:layoutUnit>
      <p:messages id="messages" showDetail="true" autoUpdate="true" closable="true"/>
      <h:form id="mainForm">
        <h:inputHidden id="imagen" value="#{reporteController.imagen}" />
        <!--content-->
        <p:commandButton value="Build PDF" class="buttonFont" process="@all,mainForm:imagen" onclick="imagePDF();" actionListener="#{bean.createPDF}" ajax="false"/>
      </h:form>  
    </p:layoutUnit>
     <p:layoutUnit position="center">
     <h:panelGroup  layout="block" id="map">
     </h:panelGroup>  

And in the ManagedBean I retrieve the content of the h:inputHiddenand proceed with the decoding process of the canvas and get a byte array, which I can insert into the PDF:

@ManagedBean(name = "bean")
@ViewScoped
public class mapBean{

    public String getImagen() {
        return imagen;
    }

    public void setImagen(String imagen) {
        this.imagen = imagen;
    }

    public void createPDF(){
        Document document = new Document(PageSize.A4, 50, 50, 50, 50);
        ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
        ec.setResponseHeader("Content-Type", "application/pdf");
        ec.setResponseHeader("Content-Disposition", "attachment; filename=\"Title.pdf\"");
        try{
           PdfWriter writer = PdfWriter.getInstance(document,ec.getResponseOutputStream());
           document.open();
           BASE64Decoder decoder = new BASE64Decoder();
            byte[] decodedBytes = decoder.decodeBuffer(getImagen().split("^data:image/(png|jpg);base64,")[1]);
           Image mapPDF = Image.getInstance(decodedBytes);
           mapaPDF.scaleToFit(450,200);
           document.add(mapaPDF);
           document.close();
           FacesContext.getCurrentInstance().responseComplete();
        }
        catch (Exception er) {
        // TODO Auto-generated catch block
        er.printStackTrace();
        }
    }
}