Save printTask output as image, add download button

1152
9
Jump to solution
10-24-2014 02:33 PM
TracySchloss
Frequent Contributor

I had this crazy idea today that I could use the print task to do a sort of screen scrape of my map and save it into a floating pane.  This would allow the user to keep a snapshot of what the screen looked like at a point in time.  Now I would like to allow the user to have a 'Download' button that appears at the bottom of the image so that it prompts them where to save it. 

I know browsers will let them save an image with right click, but I'd like to make it more user friendly.  At the moment it only lets them open the image in a new tab, which is the default behavior from the printTask in the first place.  I'm trying to pretty it up a bit.

http://jsfiddle.net/schlot/s2vzsL84/

Tags (2)
0 Kudos
1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Emeritus

Tracy,

  OK, here is the updated code for the .net portion. You are going to have to modify it to handle your pages ability to export as jpg, because right now you have it hard coded to handle png only:

<%@ WebHandler Language="C#" class="img" %>

using System;

using System.Web;

using System.Net;

public class img : IHttpHandler

{

    public void ProcessRequest(HttpContext context)

    {

        String content = "no data";

        String filename = "MyFile";

        if (context.Request["report"] != null)

        {

            try

            {

                content = context.Request["report"].ToString();

            }

            catch

            {

            }

        }

        if (context.Request["filename"] != null)

        {

            try

            {

                filename = context.Request["filename"].ToString() + "_" + DateTime.Now.ToString("MMddyyyy");

            }

            catch

            {

            }

        }

        byte[] imageData;

        using (WebClient client = new WebClient())

        {

            imageData = client.DownloadData(context.Request["report"].ToString());

        }

        context.Response.OutputStream.Write(imageData, 0, imageData.Length);

        context.Response.ContentType = "image/png";

        context.Response.AddHeader("content-disposition", "attachment;filename=" + filename + ".png");

    }

    public bool IsReusable

    {

        get

        {

            return false;

        }

    }

}

View solution in original post

0 Kudos
9 Replies
RobertScheitlin__GISP
MVP Emeritus

Tracy,

  The download attribute in the anchor tag is the best client side option there is but the image is dealt with differently based on the browser. In Chrome you actually get the image to download to chromes default download location (on save dialog), in Firefox the image is just opened in the browser window (no save dialog or actual download). The only cross browser solution is serverside technology. You can have an .net or php page that would set the headers content to image/octet-stream

0 Kudos
TracySchloss
Frequent Contributor

I had to do something like that to allow the user to download a table as CSV.  For that project, I found an example with instructions that worked without having to edit the C# code.  I don't know that language at all.  I've attempted to modify my CSV project code to work for images, but I don't know c# and I don't know where to insert the proper headers.

If you happen to know C#, here's my attempt to modify the code I used before. I have a form that has all it's input hidden to act as placeholders.

<div id="downloadForm" data-dojo-type="dijit/form/Form" method="post" action="webservices/img.ashx" target="_blank">
    <input type="hidden" name="report" id="reportinput" value="" />
    <input  type="hidden" name="filename"  id="filename" value="" />
</div>

function submitPrint() {

    var deferred;

  

    var printParams = new PrintParameters();

    printParams.map = map0;

    var status = dom.byId("printStatus");

    status.innerHTML = "Generating ...";

 

  var template = new PrintTemplate();

  template.format = "png32";

  template.layout="MAP_ONLY";

  template.showAttribution = false;

  template.preserveScale = false;

  template.exportOptions = {

  width: 500,

  height: 400,

  dpi: 96

};

    printParams.template = template;    

    var printTask = new PrintTask(printServiceUrl,printParams);

    deferred = printTask.execute(printParams);

       deferred.addCallback(function (response){

        var d = new Date();

        var dateTime =  d.getTime();

        var outputUrl = response.url + '?time=' + dateTime; 

        status.innerHTML = "";

        var newDiv = domConstruct.create("div", null, registry.byId('centerPane').domNode, "last");

        var imageLink = "<a  href="+ outputUrl+ " target=_blank ;'>Open Image</a> ";

        var imageLink2 = "<a  href="+ outputUrl+ " download='screenCapture.png'>Download</a>";

            

          var   saveButton = new Button({

          label: "Save Image",

          onClick: function(){

            saveImage(response.url);

            }

          },"btnSave");

      

        var pFloatingPane = new FloatingPane({

             title: "A floating pane",

             content: "<img src='"+response.url+"' />" +"</br>" ,

             resizable: true, dockable: true,  

             style: "position:absolute;top:50;left:50;width:500px;height:450px; z-index: 95;visibility:visible;"

          }, newDiv);

          pFloatingPane.addChild(saveButton);

          pFloatingPane.startup();

       });

    deferred.addErrback(function (error) {

        console.log("Print Task Error = " + error);

       status.innerHTML = "Error generating printout, try again";

    });  

}

function saveImage(inputData) {   

    var f = registry.byId("downloadForm");

    dom.byId("reportinput").value = inputData;

//   var outFileName = setOutName(gridName);

    dom.byId("filename").value = "imageOutput";

//    console.log(inputData);  

    f.submit(); 

}

C# code

<%@ WebHandler Language="C#" class="img" %>

using System;

using System.Web;

public class img : IHttpHandler {

public void ProcessRequest (HttpContext context) {

    String content = "no data";

    String filename = "MyFile";

    if (context.Request["report"] != null)

    {

        try

        {

            content = context.Request["report"].ToString();

        }

        catch

        {

        }

    }

    if (context.Request["filename"] != null)

    {

        try

        {

            filename = context.Request["filename"].ToString() + "_" + DateTime.Now.ToString("MMddyyyy");

        }

        catch

        {

        }

    }

    context.Response.ContentType = "image/png";

    context.Response.AddHeader("content-disposition","attachment;filename="+filename+".png");

    context.Response.Write(content);

}

public bool IsReusable {

    get {

        return false;

    }

}

}

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Tracy,

    So just change this line:

context.Response.ContentType = "image/octet-stream";

0 Kudos
TracySchloss
Frequent Contributor

It just opens my img.ashx code in the browser.  I'm not sure I'm feeding in the right input into the saveImage function.  It's the url to the image location, not an image object. 

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Tracy,

  OK, here is the updated code for the .net portion. You are going to have to modify it to handle your pages ability to export as jpg, because right now you have it hard coded to handle png only:

<%@ WebHandler Language="C#" class="img" %>

using System;

using System.Web;

using System.Net;

public class img : IHttpHandler

{

    public void ProcessRequest(HttpContext context)

    {

        String content = "no data";

        String filename = "MyFile";

        if (context.Request["report"] != null)

        {

            try

            {

                content = context.Request["report"].ToString();

            }

            catch

            {

            }

        }

        if (context.Request["filename"] != null)

        {

            try

            {

                filename = context.Request["filename"].ToString() + "_" + DateTime.Now.ToString("MMddyyyy");

            }

            catch

            {

            }

        }

        byte[] imageData;

        using (WebClient client = new WebClient())

        {

            imageData = client.DownloadData(context.Request["report"].ToString());

        }

        context.Response.OutputStream.Write(imageData, 0, imageData.Length);

        context.Response.ContentType = "image/png";

        context.Response.AddHeader("content-disposition", "attachment;filename=" + filename + ".png");

    }

    public bool IsReusable

    {

        get

        {

            return false;

        }

    }

}

0 Kudos
TracySchloss
Frequent Contributor

Since I only have one option in the printTask, png, I figured it made sense to hard code it for png for saving.  It still just opens the img.ashx file as a separate tab. 

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Tracy,

  OK the solution seems to be this (change target):

<div id="downloadForm" data-dojo-type="dijit/form/Form" method="post" action="webservices/img.ashx" target="_self">

TracySchloss
Frequent Contributor

I guess I can't mark more than one thread as correct, so I'll just do the C# script since that's the bulk of what people need.  I was just running the script from the development environment.  I needed to run it from the server URL in order to get it to work. 

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Tracy,

   Glad you got it working.

I guess I can't mark more than one thread as correct

That is correct but you can use the actions menu on the thread and choose "mark as helpful" this will give other readers the indication that that particular thread was helpful in answering the question.

0 Kudos