dcnx1
dcnx1

Reputation: 19

Converting contenteditable content to PDF

I would like to know the most efficient way to convert contenteditable features (something that the user puts in) to an pdf. Here is an illustration of what i mean:

1.

User inputs something in div contenteditable

2

Then download the pdf

3

And lastly the text that has been put into the pdf

I would also like to know how to convert css features since jsPDF doesn't suppoert this (to my knowledge)

Upvotes: 0

Views: 425

Answers (1)

Tân
Tân

Reputation: 1

jsPDF doesn't support almost the features what you need. I suggest to create an application to do that.

My background is C#. So:

Program.cs

using HtmlToPdf.Models;

namespace HtmlToPdf.Console
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var model = new HtmlToPdfModel();
            model.HTML = "<h3>Hello world!</h3>";
            model.CSS = "h3{color:#f00;}";

            HtmlToPdf.Convert(model);
        }
    }
}

HtmlToPdfModel.cs

namespace HtmlToPdf.Models
{
    public class HtmlToPdfModel
    {
        public string HTML { get; set; }

        public string CSS { get; set; }

        public string OutputPath { get; set; }

        public string FontName { get; set; }

        public string FontPath { get; set; }
    }
}

HtmlToPdf.cs

using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.tool.xml;
using HtmlToPdf.Models;
using System;
using System.IO;
using System.Text;

namespace HtmlToPdf.Console
{
    public class HtmlToPdf
    {
        public static void Convert(HtmlToPdfModel model)
        {
            try
            {
                if (model == null) return;

                Byte[] bytes;

                //Boilerplate iTextSharp setup here
                //Create a stream that we can write to, in this case a MemoryStream
                using (var stream = new MemoryStream())
                {
                    //Create an iTextSharp Document which is an abstraction of a PDF but **NOT** a PDF
                    using (var doc = new Document())
                    {
                        //Create a writer that's bound to our PDF abstraction and our stream
                        using (var writer = PdfWriter.GetInstance(doc, stream))
                        {
                            //Open the document for writing
                            doc.Open();

                            //In order to read CSS as a string we need to switch to a different constructor
                            //that takes Streams instead of TextReaders.
                            //Below we convert the strings into UTF8 byte array and wrap those in MemoryStreams
                            using (var cssStream = new MemoryStream(Encoding.UTF8.GetBytes(model.CSS)))
                            {
                                using (var htmlStream = new MemoryStream(Encoding.UTF8.GetBytes(model.HTML)))
                                {
                                    var fontProvider = new XMLWorkerFontProvider();

                                    if (!string.IsNullOrEmpty(model.FontPath) && !string.IsNullOrEmpty(model.FontName))
                                    {
                                        fontProvider.Register(model.FontPath, model.FontName);

                                        //Parse the HTML with css font-family
                                        XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, htmlStream, cssStream, Encoding.UTF8, fontProvider);
                                    }
                                    else
                                    {
                                        //Parse the HTML without css font-family
                                        XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, htmlStream, cssStream);
                                    }
                                }
                            }

                            doc.Close();
                        }
                    }

                    //After all of the PDF "stuff" above is done and closed but **before** we
                    //close the MemoryStream, grab all of the active bytes from the stream
                    bytes = stream.ToArray();
                }

                //Now we just need to do something with those bytes.
                //Here I'm writing them to disk but if you were in ASP.Net you might Response.BinaryWrite() them.
                //You could also write the bytes to a database in a varbinary() column (but please don't) or you
                //could pass them to another function for further PDF processing.

                // use this line on Windows version
                //File.WriteAllBytes(model.OutputPath, bytes);

                // use these lines on Mac version
                string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "data");
                path = Path.Combine(path, "test.pdf");

                File.WriteAllBytes(path, bytes);
            }
            catch (Exception e)
            {
                throw e;
            }
        }
    }
}

enter image description here

When I wrote this application, I've tested on Windows. So, if you're using Mac, you can replace the line:

File.WriteAllBytes(model.OutputPath, bytes);

in the file HtmlToPdf.cs to

string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "data");
path = Path.Combine(path, "test.pdf");

File.WriteAllBytes(path, bytes);

I've commented inside the code.

About the font problem, if you want to use specific font (ex: Roboto), you must provide the font file and the path which your application can assign to.

Nuget packages: iTextSharp and itextsharp.xmlworker

You can convert this console application to web application, everytime you want to make PDF file, just make a request (ajax) to server and hit the method HtmlToPdf.Convert.

Upvotes: 1

Related Questions