48

I have a string variable which holds HTML markup. This HTML markup basically represents the email content.

Now I want to create an image from this string content which actually holds the HTML markup. I don't want to create the HTML file by writing this content into them. I just want to create an image file using this string.

Here's what I have:

string emailBody="<html><head></head><body><p>This is my text<p>...</body</html>"

How can I create an Image from this emailBody string content?

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
Sachin
  • 40,216
  • 7
  • 90
  • 102
  • 1
    Duplicate: http://stackoverflow.com/questions/10721884/render-html-to-an-image – Kees Jul 24 '13 at 11:15
  • 1
    Do you need something like [http://htmlrenderer.codeplex.com/](http://htmlrenderer.codeplex.com/)? – Alex Filipovici Jul 24 '13 at 11:17
  • 1
    Thanks @AlexFilipovici. I have looked into this and I have also found a post on this. But I just want to know if there is any native code is available for this..Any way I will use it if nothing else is found. http://amoghnatu.wordpress.com/2013/05/13/converting-html-text-to-image-using-c/ – Sachin Jul 24 '13 at 11:20
  • 10
    @KeesDeWit - that question seems focussed on client-side rendering (in browser), while this one wants code outside of a browser. – Hans Kesting Jul 24 '13 at 11:26

4 Answers4

72

Thanks all for your responses. I used HtmlRenderer external dll (library) to achieve the same and found below code for the same.

Here is the code for this

public void ConvertHtmlToImage()
{
   Bitmap m_Bitmap = new Bitmap(400, 600);
   PointF point = new PointF(0, 0);
   SizeF maxSize = new System.Drawing.SizeF(500, 500);
   HtmlRenderer.HtmlRender.Render(Graphics.FromImage(m_Bitmap),
                                           "<html><body><p>This is some html code</p>"
                                           + "<p>This is another html line</p></body>",
                                            point, maxSize);

   m_Bitmap.Save(@"C:\Test.png", ImageFormat.Png);
}
Marcel Gruber
  • 6,668
  • 6
  • 34
  • 60
Sachin
  • 40,216
  • 7
  • 90
  • 102
  • 1
    Why this answer does not get more upvotes? Worked almost perfectly for me (except that I had to do some fine tuning for the image resolution)? – Marcel Jan 10 '14 at 15:13
  • 1
    Use HtmlRenderer.HtmlRender.RenderGdiPlus instead, or it doesn't look all too well. – Stefan Steiger Jan 27 '14 at 13:13
  • See HTML Renderer [Generate image from HTML markup](https://htmlrenderer.codeplex.com/wikipage?title=Image%20generation) for all the details. – Arthur Mar 10 '14 at 14:11
  • 2
    i tried using the above code referencing the htmlrenderer assembly.butit is not working.not able to identify the assembly .i tried using the namepspace as "using TheArtOfDev.HtmlRenderer" – subash Jul 21 '15 at 08:42
  • 1
    HtmlRenderer does not exists in the current context is the error message – subash Jul 21 '15 at 09:24
  • 7
    subash, you need to add HtmlRenderer,WinForms too and then use TheArtOfDev.HtmlRenderer.WinForms.HtmlRender.RenderToImage – adinas Sep 24 '15 at 13:57
  • you shoud use usings: using (Bitmap bitmap = new Bitmap(400, 600)) ... using (var fromImage = Graphics.FromImage(bitmap)) ... – razon Apr 26 '16 at 10:44
  • Can this render a HTML code that contains javascript code? I have a html page with d3.js chart on it and all I am getting back is blank image. I tried the sample above and it returns a proper image. is there a way to render an SVG chart? – konrad Sep 23 '16 at 03:10
  • The image looks distorted after conversion – Dainius Kreivys Oct 05 '16 at 12:56
  • Doesnt appear to support absolute positioning? – MarzSocks Jan 31 '17 at 18:14
  • 3
    I added HtmlRenderer.Core dll in my asp.net web application, and there is not HtmlRenderer.HtmlRender.Render method available . – Roshan Parmar Jan 19 '18 at 09:17
  • This library seems to be abandoned. Its latest commits are 5-6 years old, all links to documentation or demos lead to the starting page. So, unusable. – Igor Galochkin Sep 15 '19 at 08:13
  • "HtmlRender is not a member of TheArtOfDev.HtmlRenderer" , I get this error though i have installed HtmlRender from Nuget. any help? – anandhu Aug 14 '20 at 09:58
  • This does not simply work on .NET Standard. The library needs a port to the new `System.Drawing` NuGet package or `ImageSharp` – LOST Apr 14 '21 at 02:55
30

Try the following:

using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;

class Program
{
    static void Main(string[] args)
    {
        var source =  @"
        <!DOCTYPE html>
        <html>
            <body>
                <p>An image from W3Schools:</p>
                <img 
                    src=""http://www.w3schools.com/images/w3schools_green.jpg"" 
                    alt=""W3Schools.com"" 
                    width=""104"" 
                    height=""142"">
            </body>
        </html>";
        StartBrowser(source);
        Console.ReadLine();
    }

    private static void StartBrowser(string source)
    {
        var th = new Thread(() =>
        {
            var webBrowser = new WebBrowser();
            webBrowser.ScrollBarsEnabled = false;
            webBrowser.DocumentCompleted +=
                webBrowser_DocumentCompleted;
            webBrowser.DocumentText = source;
            Application.Run();
        });
        th.SetApartmentState(ApartmentState.STA);
        th.Start();
    }

    static void 
        webBrowser_DocumentCompleted(
        object sender, 
        WebBrowserDocumentCompletedEventArgs e)
    {
        var webBrowser = (WebBrowser)sender;
        using (Bitmap bitmap = 
            new Bitmap(
                webBrowser.Width, 
                webBrowser.Height))
        {
            webBrowser
                .DrawToBitmap(
                bitmap, 
                new System.Drawing
                    .Rectangle(0, 0, bitmap.Width, bitmap.Height));
            bitmap.Save(@"filename.jpg", 
                System.Drawing.Imaging.ImageFormat.Jpeg);
        }
    }
}

Note: Credits should go to Hans Passant for his excellent answer on the question WebBrowser Control in a new thread which inspired this solution.

Community
  • 1
  • 1
Alex Filipovici
  • 31,789
  • 6
  • 54
  • 78
  • This has worked well for me for a long time. Just discovered a limitation. Downloaded fonts, accessed via @font-face in css, are not rendered. – Paul Evans Aug 05 '18 at 03:46
  • I don't believe this is available in .net core. It seems to only be in framework – Sarah Jul 02 '19 at 17:53
  • @Paul Evans have you found a solution that can handle that? – Mark Z. Jul 20 '19 at 15:02
  • 1
    Simple concept! Would anyone know how to extend this solution, to **fit the entire page** into the output image, even when page's height is larger than image's height? – Bliss Mar 09 '21 at 14:36
  • Consider using `webBrowser.ScriptErrorsSuppressed = true;`. Else if error occured, it won't going to report. – Gray Programmerz Sep 27 '22 at 10:19
1

So I came along this, and I figured I would post my latest solution for anyone searching for something like this.

I used the (open source) Puppeteer Sharp (v3) The result looks something like this:

public class ImageRenderer : IDisposable
    {
        private BrowserFetcher _browserFetcher;

        public ImageRenderer()
        {
            _browserFetcher = new BrowserFetcher();
        }

        public async Task<byte[]> RenderImageDataAsync(string html)
        {
            try
            {
                // Download chrome (headless) browser (first time takes a while).
                await _browserFetcher.DownloadAsync();

                // Launch the browser and set the given html.
                await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true });
                await using var page = await browser.NewPageAsync();
                await page.SetContentAsync(html);

                // Select the element and take a screen-shot, or just use the page, for example: page.ScreenshotDataAsync()
                var elementQuery = "#myElementId";
                await page.WaitForSelectorAsync(elementQuery, new WaitForSelectorOptions { Timeout = 2000 }); // Wait for the selector to load.

                var elementHandle = await page.QuerySelectorAsync(elementQuery); // Declare a variable with an ElementHandle.
                var result = await elementHandle.ScreenshotDataAsync(
                    new ScreenshotOptions
                    {
                        Type = ScreenshotType.Png
                        // Quality = Not supported with PNG images!
                    }
                );

                await browser.CloseAsync();
                return result;
            }
            catch (Exception ex)
            {
                // Log ex $"{nameof(RenderImageDataAsync)}: Unable to render image from {nameof(html)}={html}");
            }

            return null;
        }

        public void Dispose()
        {
            _browserFetcher = null;
        }
    }
  • Pro: Uses a real browser;
  • Cons: Uses a real browser; _browserFetcher.DownloadAsync(); will download (to the folder .local-chromium) around 380MB of files for this.
WizxX20
  • 311
  • 2
  • 6
-3
       <!--ForExport data in iamge -->
        <script type="text/javascript">
            function ConvertToImage(btnExport) {
                html2canvas($("#dvTable")[0]).then(function (canvas) {
                    var base64 = canvas.toDataURL();
                    $("[id*=hfImageData]").val(base64);
                    __doPostBack(btnExport.name, "");
                });
                return false;
            }
        </script>

        <!--ForExport data in iamge -->

        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
        <script src="../js/html2canvas.min.js"></script> 





<table>
                <tr>
                    <td valign="top">
                        <asp:Button ID="btnExport" Text="Download Back" runat="server" UseSubmitBehavior="false"
                            OnClick="ExportToImage" OnClientClick="return ConvertToImage(this)" />
                        <div id="dvTable" class="divsection2" style="width: 350px">
                            <asp:HiddenField ID="hfImageData" runat="server" />
                            <table width="100%">
                                <tr>
                                    <td>
                                        <br />

                                    </td>
                                </tr>
                                <tr>
                                    <td>
                                        <asp:Label ID="Labelgg" runat="server" CssClass="labans4" Text=""></asp:Label>
                                    </td>
                                </tr>

                            </table>
                        </div>
                    </td>
                </tr>
            </table>


         protected void ExportToImage(object sender, EventArgs e)
                {
                    string base64 = Request.Form[hfImageData.UniqueID].Split(',')[1];
                    byte[] bytes = Convert.FromBase64String(base64);
                    Response.Clear();
                    Response.ContentType = "image/png";
                    Response.AddHeader("Content-Disposition", "attachment; filename=name.png");
                    Response.Buffer = true;
                    Response.Cache.SetCacheability(HttpCacheability.NoCache);
                    Response.BinaryWrite(bytes);
                    Response.End();

                }
Code
  • 679
  • 5
  • 9