4

I have a fairly simple HTML page rendered via asp.net. It looks beautiful in the PDF after running it through HtmlRenderer.PdfSharp EXCEPT that the images don't appear. Just the red X of a missing image in the PDF even though the web page itself does display the image correctly.

Here is my HtmlRenderer.PdfSharp code:

public void BuildPDF( string url, string pdfPath ) {
   string html = GetHTML(url);
   Byte[] res = null;
   using( MemoryStream ms = new MemoryStream() ) {
      using( FileStream file = new FileStream(pdfPath, FileMode.Create, FileAccess.Write) ) {
         byte[] bytes = new byte[ms.Length];
         var pdf = TheArtOfDev.HtmlRenderer.PdfSharp.PdfGenerator.GeneratePdf(html, PdfSharp.PageSize.A4);
         pdf.Save(ms);
         res = ms.ToArray();
         file.Write(res, 0, res.Length);
         ms.Close();
      }
   }
}

private string GetHTML(string url) {
   string html = string.Empty;
   HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
   request.AutomaticDecompression = DecompressionMethods.GZip;

   using( HttpWebResponse response = (HttpWebResponse)request.GetResponse() )
   using( Stream stream = response.GetResponseStream() )
   using( StreamReader reader = new StreamReader(stream) ) {
      html = reader.ReadToEnd();
   }

   return html;
}

And here is the img HTML that doesn't render in the PDF: <img src="images/ChartImg.png" />

How can I solve this?

HerrimanCoder
  • 5,858
  • 20
  • 65
  • 111

4 Answers4

9

Use the absolute path to the images.

<img src="http://example.org/images/ChartImg.png" />

You can parse the html and do a string replace first before passing it to the pdf converter.

Ibu
  • 39,552
  • 10
  • 71
  • 99
2

The Code below:

var pdf = PdfGenerator.GeneratePdf(Html, PageSize.A4, 20, null, OnStylesheetLoad, OnImageLoadPdfSharp);
... ...
public static void OnImageLoadPdfSharp(object sender, HtmlImageLoadEventArgs e)
{
    var url = e.Src;
    if (!e.Src.StartsWith("http://") && !e.Src.StartsWith("https://"))
    {
        var ImgFilePath = System.Web.HttpContext.Current.Server.MapPath(url);
        if (XImage.ExistsFile(ImgFilePath))
            e.Callback(XImage.FromFile(ImgFilePath));
        var ImgFilePath2 = System.Web.HttpContext.Current.Server.MapPath(url);
        if (XImage.ExistsFile(ImgFilePath2))
            e.Callback(XImage.FromFile(ImgFilePath2));
    }
    else
    {
        using (var client = new WebClient())
        {
            using (var stream = new MemoryStream(client.DownloadData(url)))
            {
                e.Callback(XImage.FromStream(stream));
            }
        }
    }
}
ohjo
  • 39
  • 4
1

It's better to use the image resolution callback for this for this:

var pdf = PdfGenerator.GeneratePdf(html, pdfConfig, imageLoad: OnImageLoad);

// snip

private void OnImageLoad(object sender, HtmlImageLoadEventArgs e)
{
    using (var client = new WebClient())
    {
        var url = e.Src;
        if (!e.Src.StartsWith("http://") && !e.Src.StartsWith("https://"))
        {
            url = Properties.Settings.Default.BaseUrl.TrimEnd('/') + e.Src;
        }
        using (var stream = new MemoryStream(client.DownloadData(url)))
        {
            e.Callback(XImage.FromStream(stream));
        }
    }
}
Dave de Jong
  • 393
  • 2
  • 12
0

I'm late for your problem but maybe this will help someone else.

I used absolute urls and they were correct. Images were loaded correctly when I opened html file in browser.

However, they were not loaded after I converted this html to pdf. So I tried to use image resolution callback like @ohjo suggested. An exception occured here: An existing connection was forcibly closed by the remote host.

I was able to solve this but adding one more line that sets SecurityProtocol to this solution:

var pdf = PdfGenerator.GeneratePdf(Html, PageSize.A4, 20, null, OnStylesheetLoad, OnImageLoadPdfSharp);
... ...
public static void OnImageLoadPdfSharp(object sender, HtmlImageLoadEventArgs e)
{
    var url = e.Src;
    if (!e.Src.StartsWith("http://") && !e.Src.StartsWith("https://"))
    {
        var ImgFilePath = System.Web.HttpContext.Current.Server.MapPath(url);
        if (XImage.ExistsFile(ImgFilePath))
            e.Callback(XImage.FromFile(ImgFilePath));
        var ImgFilePath2 = System.Web.HttpContext.Current.Server.MapPath(url);
        if (XImage.ExistsFile(ImgFilePath2))
            e.Callback(XImage.FromFile(ImgFilePath2));
    }
    else
    {
        using (var client = new WebClient())
        {
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            using (var stream = new MemoryStream(client.DownloadData(url)))
            {
                e.Callback(XImage.FromStream(stream));
            }
        }
    }
}
a.farkas2508
  • 357
  • 3
  • 12