Search code examples
c#asp.net-mvcdatazen-server

Datazen - exporting dashboard to image


We have a requirement to save a Datazen dashboard report to an image file.

The report will be hosted in an MVC view via an iframe. The underlying reports will be secured via active directory authentication within Datazen.

I was thinking I would use a WebBrowser control in a thread launched in STA mode. This kind of works but I get presented with the login screen when I try to view a url such as:

http://MyServerAddress/viewer/dashboard?dashboardguid=17EF844E-DEBE-4FE5-B22E-CD6F74A9E6C9

This is the code I have so far.

    public ActionResult Save()
    {
        var url = "http://MyServerAddress/viewer/dashboard?dashboardguid=17EF844E-DEBE-4FE5-B22E-CD6F74A9E6C9";

        FileContentResult result = null;
        Bitmap bitmap = null;

        var thread = new Thread(
            () =>
            {
                bitmap = ExportUrlToImage(url, 1280, 1024);
            });

        thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
        thread.Start();
        thread.Join();

        if (bitmap != null)
        {
            using (var memstream = new MemoryStream())
            {
                bitmap.Save(memstream, ImageFormat.Jpeg);
                result = this.File(memstream.GetBuffer(), "image/jpeg");
            }
        }

        return result;
    }

    private Bitmap ExportUrlToImage(string url, int width, int height)
    {
        // Load the webpage into a WebBrowser control
        WebBrowser wb = new WebBrowser();
        wb.ScrollBarsEnabled = false;
        wb.ScriptErrorsSuppressed = true;

        string hdr = "Authorization: Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("username" + ":" + "password")) + System.Environment.NewLine;


        wb.Navigate(url, null, null, hdr);
        while (wb.ReadyState != WebBrowserReadyState.Complete)
        {
            Application.DoEvents();
        }

        // Set the size of the WebBrowser control
        wb.Width = width;
        wb.Height = height;

        Bitmap bitmap = new Bitmap(wb.Width, wb.Height);
        wb.DrawToBitmap(bitmap, new System.Drawing.Rectangle(0, 0, wb.Width, wb.Height));
        wb.Dispose();

        return bitmap;
    }

Wanted to see if I was on track and hadn't missed an alternative approach?


Solution

  • In the end we decided to use the following client library Html2Canvas

    Need to be mindful of CORS issues so ensure the Datazen iframe is hosted on the same server / port etc as your web page.

    There were issues rendering the entire page (i.e. parent page AND iframe content) so for that reason I just ended up exporting the iframe content only.

    $(document).ready(function () {
    
            $("#btnSave").click(function () {
                // just render the body of the datazen iframe 
                var body = $("#iframe").contents().find('body');
                html2canvas(body, {
                    allowTaint: true,
                    onrendered: function (canvas) {
                        // canvas is the final rendered <canvas> element
                        var myImage = canvas.toDataURL("image/png");
                        window.open(myImage);
                    }
                })
            });