I'm working on an app using GeoServer and OpenLayers 2.13.1. I have several WMS layers and I need to export whatever in my openlayers map div as an image. After researching, I found this blog: http://blogs.edina.ac.uk/category/openlayers-html5-canvas/ which is working fine (exporting my layers as an image).

However, my wms layer also has dynamic sld functionality (using SLD_BODY). The problem shows up when I use attribute-based sld: it wasn't drawn on the canvas. It only works when I use non-attribute-based sld.

Did I miss something here?

This is how I call the wms layer:

wms = new OpenLayers.Layer.WMS(layer_name,
    WMSServiceURL, {
        layers: "bappeko:"+map_name, 
        styles: null,
        transparent: true,
        format: "image/jpeg"
        ratio: 1,
        singleTile: true,
        tileOptions: {maxGetUrlLength: 2048},
        buffer: 0,
        projection: new OpenLayers.Projection("EPSG:32749")

This is JS function I used to export:

function exportMap() {
var mapcanvasDiv = null ;
var mapDiv = document.getElementById("mapdiv") ;

if (mapcanvasDiv === null) {              
    var canvasElement = document.createElement("canvas");
    canvasElement.id = "mapcvs";
    mapcanvasDiv = document.getElementById("mapcanvas");
    mapcanvasDiv.appendChild(canvasElement) ;

    canvasElement.width = mapDiv.clientWidth ;
    canvasElement.height = mapDiv.clientHeight ;

var mapCanvas = document.getElementById("mapcvs");
var mapContainer = document.getElementById("OpenLayers_Map_2_OpenLayers_Container");

if (mapCanvas !== null) {
    var ctx = mapCanvas.getContext("2d");
    ctx.clearRect(0, 0, mapCanvas.width, mapCanvas.height);

    var olLayersDiv = document.getElementsByClassName("olLayerDiv");
    var olLayers = map.layers;

    for (var i=0; i<olLayersDiv.length; i++){
        if (olLayers[i].visibility == true) {
            var layertiles = olLayersDiv[i].getElementsByClassName("olTileImage");
            for(var j=0; j<layertiles.length; j++) {
                var tileImg = layertiles[j];
                var offsetLeft = tileImg.offsetLeft;
                var offsetTop = tileImg.offsetTop;
                var left = Number(mapContainer.style.left.slice(0, mapContainer.style.left.indexOf("p")));
                var top = Number(mapContainer.style.top.slice(0, mapContainer.style.top.indexOf("p")));
                ctx.drawImage(tileImg, 0, 0);

    var dataUrl = mapCanvas.toDataURL();
    window.open(dataUrl, "toDataURL() image", "width=600, height=360");

This is how I set my dynamic SLD (the SLD is created dynamically by PHP script via Ajax) in JS:

l = map.getLayersByName(layer_name)[0];
l.mergeNewParams({sld_body: sld, styles: null});

I guess I've found the culprit: It seems that my PHP-created SLD is way too long even when I've set tileOptions: {maxGetUrlLength: 2048} because I use many <ogc:Filter> for my Attribute-Based SLD.

Here's what I've tried: I put my SLD in a text file and load it using SLD: some_url/text.sld param, instead of putting it straight to SLD_BODY like I did before. But another error happens, the map won't load (pink image) and I'm getting this error Resource interpreted as Image but transferred with MIME type application/vnd.ogc.se_xml: http://localhost/geoserver/wms?... Seems like the WMS request doesn't return an image but XML.

  • If you are triggering off the Layer Loadend Event and copying to the Canvas, it should not matter if you have attribute based SLD, it is still just a WMS call! Are you sure your attribute SLD WMS calls are working and returning images? – Mark Cupitt Sep 2 '14 at 6:25
  • Hi, @MarkC Yes, that's what I thought so. The SLD is working fine, I know that from seeing the correct style applied on my map. It's just don't show up on the canvas, thus, I can't export that layer to an image (the other layers with non-attribute based SLD is working fine though). – ariespranata Sep 2 '14 at 14:34
  • It will help if you modify your question and post your code so we can see how it is implemented .. – Mark Cupitt Sep 3 '14 at 0:13
  • Hi @MarkC I've posted the code on the post above. :D – ariespranata Sep 3 '14 at 5:52
  • It looks Ok, but you have not included the OL Code. CORS could be an issue, possibly your layers are not loaded properly before you try and export them to to Canvas, maybe the visible property is set to false when this routine executes. I wonder if OL WMS handles the Dynamic SLD differently than a normal layer .. – Mark Cupitt Sep 3 '14 at 11:23

Here's what I did, and it finally works.

First, I created a sld file and saved it to the some folder in PHP:

$sld = "sld_here..";
$temp_link = sys_get_temp_dir()."/";

$tmpfname = tempnam($temp_link, $map_name);
file_put_contents($tmpfname, $sld);

echo $tmpfname;

Then the file url is passed to JS using AJAX and set it to the layer using SLD param:

l = map.getLayersByName("layer_name")[0];

    type: 'POST',
    dataType: "text",
    url: "SLDCreator.php",
    data: {
        //Sending what is required to create a valid SLD file
        map_name: "map_name",
        data: "some sld parameters here"
    success: function(sld) {
        //Set the SLD to the layer
        l.mergeNewParams({sld: "file:///"+sld});

the file:/// will works on localhost. When online, you need to save it to a folder (e.g. sld/) and call it from http_your_domain/sld/your_sld_file.

So this way, I don't need to send my complete sld (which can be very-very long when we use many filters). I just need to send the url of sld file created which is much shorter.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.