jsPDF icon indicating copy to clipboard operation
jsPDF copied to clipboard

Convert html to pdf: utf-8 works only with text, but not html (unicode/cyrillic not working)

Open potapovnikita opened this issue 4 years ago • 50 comments

I'm opening this issue again.

I need to convert html to pdf with jsPDF. It contains UTF-8 symbols (cyrillic). I used fontconverter to generate js-file for my custom font as written here: https://github.com/MrRio/jsPDF

So now example with text works like a charm (from https://github.com/MrRio/jsPDF/blob/master/examples/js/russian.js)

var pdf = new jsPDF('p', 'pt', 'letter');
doc.setFont('PTSans');
doc.setFontSize(10);
doc.text("А ну чики брики и в дамки!", 10, 10);

And example with html ignores my custom font and exports incorrect symbols.

var pdf = new jsPDF('p', 'pt', 'letter');
doc.setFont('PTSans');
doc.setFontSize(10);
pdf.html( "<html>А ну чики брики и в дамки!</html>", { callback: function (pdf) {
    var iframe = document.createElement('iframe');
    iframe.setAttribute('style', 'position:absolute;right:0; top:0; bottom:0; height:100%; width:500px');
    document.body.appendChild(iframe);
    iframe.src = pdf.output('datauristring');
    }
});

What I need to do to export html to pdf with unicode symbols?

potapovnikita avatar Oct 18 '20 19:10 potapovnikita

Please try setting the font name also in the html markup. E.g.

<html style="font-family: PTSans;">А ну чики брики и в дамки!</html>

HackbrettXXX avatar Oct 20 '20 18:10 HackbrettXXX

not working `createCert() {

  this.doc.addFileToVFS("MyFont.ttf", myFont);
  this.doc.addFont("MyFont.ttf", "MyFont", "normal");
  this.doc.setFont("MyFont");
  const html = "<html style=\"font-family: 'MyFont';\">А ну чики брики и в дамки!</html>"
  this.doc.html(html, {
    callback: (doc) => {
      doc.save("a4.pdf");
    },
    x: 10,
    y: 10
  });
}`

potapovnikita avatar Oct 21 '20 12:10 potapovnikita

Then I guess it's a bug...

HackbrettXXX avatar Oct 21 '20 12:10 HackbrettXXX

@HackbrettXXX the same with Polish signs :( Is there any chance for a quick fix of this problem?

I'm tring to create pdf in this way:

window.jsPDF = window.jspdf.jsPDF
var doc = new jsPDF('p', 'px', 'a4');

var elementToPrint = document.getElementById('printPDFtest');
doc.html(elementToPrint, {
        html2canvas: {
            scale: 0.45
        },
        callback: function (doc) {
            doc.save();
        }
    });

LucaCode92 avatar Oct 27 '20 21:10 LucaCode92

@HackbrettXXX the same with Polish signs :( Is there any chance for a quick fix of this problem?

I'm tring to create pdf in this way:

window.jsPDF = window.jspdf.jsPDF
var doc = new jsPDF('p', 'px', 'a4');

var elementToPrint = document.getElementById('printPDFtest');
doc.html(elementToPrint, {
        html2canvas: {
            scale: 0.45
        },
        callback: function (doc) {
            doc.save();
        }
    });

It works?

potapovnikita avatar Oct 28 '20 08:10 potapovnikita

@potapovnikita as I mentioned - there is a problem. I just showed part of my code in case I made a mistake somewhere :)

LucaCode92 avatar Oct 28 '20 18:10 LucaCode92

@potapovnikita

I'm opening this issue again.

I need to convert html to pdf with jsPDF. It contains UTF-8 symbols (cyrillic). I used fontconverter to generate js-file for my custom font as written here: https://github.com/MrRio/jsPDF

So now example with text works like a charm (from https://github.com/MrRio/jsPDF/blob/master/examples/js/russian.js)

var pdf = new jsPDF('p', 'pt', 'letter');
doc.setFont('PTSans');
doc.setFontSize(10);
doc.text("А ну чики брики и в дамки!", 10, 10);

And example with html ignores my custom font and exports incorrect symbols.

var pdf = new jsPDF('p', 'pt', 'letter');
doc.setFont('PTSans');
doc.setFontSize(10);
pdf.html( "<html>А ну чики брики и в дамки!</html>", { callback: function (pdf) {
    var iframe = document.createElement('iframe');
    iframe.setAttribute('style', 'position:absolute;right:0; top:0; bottom:0; height:100%; width:500px');
    document.body.appendChild(iframe);
    iframe.src = pdf.output('datauristring');
    }
});

What I need to do to export html to pdf with unicode symbols?

I would like to mention two things here.

  1. setting font as doc.setFont('PTSans') won't work for the HTML. for accessing fonts in the HTML you have to pass it as an inline style with font-family.

  2. I have observed that the .html API of jsPdf does not support directly, takes the main element of the body, and renders it. ( Correct me if I'm wrong but I have observed it many times.)

so, after spending almost my entire day on it, I have figure out the below solution which helps me to get those bullets on my pdf.

after adding custom fonts just like explained below article you have to import your font files into your component and just style your HTML like this. https://www.devlinpeck.com/tutorials/jspdf-custom-font#:~:text=Adding%20Custom%20Fonts%20to%20jsPDF,of%20your%20desired%20font%20file.&text=Once%20you%20have%20your%20.,to%20this%20jsPDF%20Font%20Converter.

`import '../../../Lato-Regular-normal';

const htmlToConvert =

doc.html(htmlToConvert,{ callback:function{ doc.save() } })`

Jigisha-sublime avatar Nov 12 '20 13:11 Jigisha-sublime

Hope that it will help some one.

Jigisha-sublime avatar Nov 12 '20 13:11 Jigisha-sublime

Then I guess it's a bug...

So, I guess it's not a bug but a lack of clarity for the use case.

Jigisha-sublime avatar Nov 12 '20 13:11 Jigisha-sublime

In my case, using the version 2.1, setting the font style on the html element like so: <html style="font-family: PTSans;">А ну чики брики и в дамки!</html> and importing the fonts according to https://www.devlinpeck.com/tutorials/jspdf-custom-font#:~:text=Adding%20Custom%20Fonts%20to%20jsPDF,of%20your%20desired%20font%20file.&text=Once%20you%20have%20your%20.,to%20this%20jsPDF%20Font%20Converter. worked for me when using an html element reference instead of using a raw html string.

Rui-Jesus avatar Nov 16 '20 15:11 Rui-Jesus

@potapovnikita which jsPDF version do you use? If it's not the current one please update.

@Rui-Jesus If this only works if the markup is passed as element, this might be an encoding issue of the file that contains the html markup?

HackbrettXXX avatar Dec 03 '20 14:12 HackbrettXXX

In my case, using the version 2.1, setting the font style on the html element like so: <html style="font-family: PTSans;">А ну чики брики и в дамки!</html> and importing the fonts according to https://www.devlinpeck.com/tutorials/jspdf-custom-font#:~:text=Adding%20Custom%20Fonts%20to%20jsPDF,of%20your%20desired%20font%20file.&text=Once%20you%20have%20your%20.,to%20this%20jsPDF%20Font%20Converter. worked for me when using an html element reference instead of using a raw html string.

It works, and it works wonderfully, thank you <3

cakesforfree avatar Dec 10 '20 01:12 cakesforfree

@HackbrettXXX I did not test passing a file with the html markup, I had it stored in memory, the html markup. To be honest I didn't look too much into the issue since the solution I provided works perfectly for me.

Rui-Jesus avatar Dec 15 '20 10:12 Rui-Jesus

In my case, using the version 2.1, setting the font style on the html element like so: <html style="font-family: PTSans;">А ну чики брики и в дамки!</html> and importing the fonts according to https://www.devlinpeck.com/tutorials/jspdf-custom-font#:~:text=Adding%20Custom%20Fonts%20to%20jsPDF,of%20your%20desired%20font%20file.&text=Once%20you%20have%20your%20.,to%20this%20jsPDF%20Font%20Converter. worked for me when using an html element reference instead of using a raw html string.

Thank you. He inspired me. I use html method, but the tag on the page does not show the Chinese I want, but after reading your reply, I added font family to the tag on the page, and it can be used.

This is the end result: QQ截图20210120095315 This is code:

const htmlStr: HTMLElement = document.querySelector('.main') || document.body;
doc.html(htmlStr, {
        callback(isPdf) {
          // add the font to jsPDF
          doc.addFileToVFS('fzjt.ttf', MyFont); // addfont
          doc.addFont('fzjt.ttf', 'MyFont', 'normal');
          doc.setFont('MyFont');
          isPdf.text('又是中文', 10, 10);
          isPdf.save();
        },
      });
.main
  background #ffffff
  width 90%
  font-family 'MyFont'

It's amazing 🎉

CurryPaste avatar Jan 20 '21 01:01 CurryPaste

I have a same problem. utf-8 characters not working with html method. window.jsPDF = window.jspdf.jsPDF; $("#downPDF").on("click", function() { var doc = new jsPDF({ orientation: "landscape" }); var source = document.getElementById("pdfCard"); doc.setFont("Roboto-Regular"); doc.html(source, { callback: function(doc) { doc.save(); }, x: 2, y: 2, html2canvas: { scale: 0.25, }, }); })

if I try only generate: doc.text("ľščťžžýáíúô", 10, 10); doc.save(); it's working

jedaix avatar Feb 17 '21 11:02 jedaix

I am building a web app with three cultures "en", "tr", "ar". I followed the process as mentioned by @Rui-Jesus, but it didn't work!

In my case, using the version 2.1, setting the font style on the html element like so: <html style="font-family: PTSans;">А ну чики брики и в дамки!</html> and importing the fonts according to https://www.devlinpeck.com/tutorials/jspdf-custom-font#:~:text=Adding%20Custom%20Fonts%20to%20jsPDF,of%20your%20desired%20font%20file.&text=Once%20you%20have%20your%20.,to%20this%20jsPDF%20Font%20Converter. worked for me when using an html element reference instead of using a raw html string.

Then I did few modifications to make it work with specific font (the same process didn't work with all fonts)

  • Download font from google fonts, in my case I used Cairo (Regular 400) because it supports all my cultures.
  • Put the font link inside <header> :
<!-- GoogleFonts: Cairo -->
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Cairo&display=swap" rel="stylesheet">
  • Use CSS rules in CSS file:
body {
    font-family: 'Cairo', sans-serif !important;
}
  • Convert the font as mentioned in the tutorial. But I changed the module format to UMD.
  • The downloaded file uses the font name as Cairo-Regular, and that was the problem. I changed it to Cairo since the CSS font name is Cairo.
// this.addFont('Cairo-Regular-normal.ttf', 'Cairo-Regular', 'normal');
this.addFont('Cairo-Regular-normal.ttf', 'Cairo', 'normal');
  • Adding the style to html didn't work, but it worked when added style to the body tag:
<body style="font-family: 'Cairo', sans-serif !important;">
  • Below is the rest of the code:
<!-- jsPDF -->
<script src="~/lib/jspdf/dist/jspdf.umd.min.js"></script>
<script src="~/js/html2canvas.min.js"></script>
<script src="~/lib/dompurify/dist/purify.min.js"></script>
<script src="~/js/Cairo-Regular-normal.js"></script>
<script>
    $(function () {
        setTimeout(function () {
            window.jsPDF = window.jspdf.jsPDF;
            // Default export is a4 paper, portrait, using millimeters for units
            const doc = new jsPDF('p', 'pt', 'a4');
            doc.html(document.body, {
                html2canvas: {
                    scale: 0.5,
                    scrollY:0
                },
                x: 0,
                y: 0,
                callback: function (doc) {
                    window.open(doc.output('bloburl'));
                }
            });
        }, 1000);
    });
</script>

Now I have a working solution with English and Turkish : image

But it is not fully supporting Arabic. Some letters are missing, and if I have multiple languages the latin letters are rendred over each other as seen in the below image: image

The correct html page looks like below: image

I also tried with adding doc.addLanguage("ar") but it didn't help.

LazZiya avatar Mar 09 '21 07:03 LazZiya

my solution to this problem:

  1. create custom font ( use this : https://www.devlinpeck.com/tutorials/jspdf-custom-font#:~:text=Adding%20Custom%20Fonts%20to%20jsPDF,of%20your%20desired%20font%20file.&text=Once%20you%20have%20your%20.,to%20this%20jsPDF%20Font%20Converter )
  2. add font to project :
    image
  3. import this font: image
  4. add font to pdf doc.: image

Shidesin avatar Mar 11 '21 06:03 Shidesin

I have the same problem. I'm surprised there is no good solution. How this library got so many likes? Everything is so hard to solve in there.

so it is my code but not supporting fornAwesome and cyrylic.

import './RobotoBlackNormal';
...
var doc = new jsPDF('p', 'pt', 'a4');
        // doc.addFont("test/reference/PTSans.ttf", "PTSans", "normal");
        doc.addFont('https://use.fontawesome.com/releases/v5.3.1/webfonts/fa-regular-400.ttf', 'FontAwesome', 'normal');
        doc.addFont('Roboto-Regular.ttf', 'Roboto-Regular', 'normal');
        doc.addFont('Roboto-Black.ttf', 'Roboto-Black', 'normal');
        doc.addFont('Roboto-Bold.ttf', 'Roboto-Bold', 'normal');
        doc.addFont('Roboto-Medium.ttf', 'Roboto-Medium', 'normal');
        doc.setFont('Font Awesome 5 Free');
        doc.setFont('Roboto-Regular');
        doc.setFont('Roboto-Black');
        doc.setFont('Roboto-Bold');
        doc.setFont('Roboto-Medium');

        doc.html(ref.current.querySelector('#response-list'), {
            callback: function (doc) {
                doc.save();
            }});

image

bemulima avatar Apr 21 '21 11:04 bemulima

just cyrylic text correct displaying but by document element not supported

var doc = new jsPDF('p', 'pt', 'a4');
        // doc.addFont("test/reference/PTSans.ttf", "PTSans", "normal");
        doc.addFont('https://use.fontawesome.com/releases/v5.3.1/webfonts/fa-regular-400.ttf', 'FontAwesome', 'normal');
        // doc.addFont('Roboto-Regular.ttf', 'Roboto-Regular', 'normal');
        // doc.addFont('Roboto-Black.ttf', 'Roboto-Black', 'normal');
        // doc.addFont('Roboto-Bold.ttf', 'Roboto-Bold', 'normal');
        // doc.addFont('Roboto-Medium.ttf', 'Roboto-Medium', 'normal');
        doc.setFont('Font Awesome 5 Free');
        doc.setFont('Roboto-Regular');
        // doc.setFont('Roboto-Black');
        // doc.setFont('Roboto-Bold');
        // doc.setFont('Roboto-Medium');
        doc.text("А ну чики брики и в дамки!", 10, 10);
        // doc.html('<html style="font-family: Roboto;">' + ref.current.querySelector('#response-list').innerHTML + '</html>>',
        //     {
        //     callback: function (doc) {
        //         doc.save();
        //     }});
        doc.save('ho-ho-ho.pdf');

image

bemulima avatar Apr 21 '21 12:04 bemulima

also I can't set HTML as just string to doc.html():

 console.log('doc', ref.current.querySelector('#response-list'))
        var doc = new jsPDF('p', 'pt', 'a4');
        // doc.addFont("test/reference/PTSans.ttf", "PTSans", "normal");
        doc.addFont('https://use.fontawesome.com/releases/v5.3.1/webfonts/fa-regular-400.ttf', 'FontAwesome', 'normal');
        // doc.addFont('Roboto-Regular.ttf', 'Roboto-Regular', 'normal');
        // doc.addFont('Roboto-Black.ttf', 'Roboto-Black', 'normal');
        // doc.addFont('Roboto-Bold.ttf', 'Roboto-Bold', 'normal');
        // doc.addFont('Roboto-Medium.ttf', 'Roboto-Medium', 'normal');
        doc.setFont('Font Awesome 5 Free');

        // doc.setFont('Roboto-Black');
        // doc.setFont('Roboto-Bold');
        // doc.setFont('Roboto-Medium');
        // doc.text("А ну чики брики и в дамки!", 10, 10);
        // doc.html(ref.current.querySelector('#response-list'),
        doc.html("<html style='font-family: Roboto;'>А ну чики брики и в дамки!</html>",
            {
            callback: function (doc) {
                doc.setFont('Roboto-Regular');
                doc.setFont('Roboto-Bold');
                doc.save();
            }});

image

bemulima avatar Apr 21 '21 12:04 bemulima

any progress on this issue?

jedaix avatar Sep 07 '21 14:09 jedaix

Well, dear friends, perhaps I have found the Main Evil. To display .html with a specific font as of October 05, 2021, it is enough to specify the font as a style for the html element, and it will be applied to all the text inside it. It is important to use the correct fonts, which have the layout of your alphabet, Cyrillic, Polish, etc. This is my experience of 2 days searching for an answer to my problem. Hope this helps someone not to waste time. Alternatively, write the same set of fonts that is used on your site using the .addFont & .setFont method. That is, the text in your html has exactly the same font set as you specify with the .addFont & .setFont methods. Otherwise, the font will be displayed incorrectly. All the best, be attentive and quick

NeonDB avatar Oct 05 '21 11:10 NeonDB

@NeonDB not working for me. I'm using Roboto font on page. And this initialization is not working: var doc = new jsPDF({ orientation: "landscape" }); var source = document.getElementById("pdfCard"); doc.addFont("src/Roboto-Regular.ttf", "Roboto-Regular", "normal"); doc.setFont("Roboto-Regular"); doc.html(source, { callback: function (doc) { doc.save(); }, x: 2, y: 2, html2canvas: { scale: 0.25, }, });

jedaix avatar Oct 05 '21 12:10 jedaix

@NeonDB не работает на меня. Я использую шрифт Roboto на странице. И эта инициализация не работает: var doc = new jsPDF({ orientation: "landscape" }); var source = document.getElementById("pdfCard"); doc.addFont("src/Roboto-Regular.ttf", "Roboto-Regular", "normal"); doc.setFont("Roboto-Regular"); doc.html(source, { callback: function (doc) { doc.save(); }, x: 2, y: 2, html2canvas: { scale: 0.25, }, });

This cannot work, since the html markup source is passed as the first property to the .html method. You are not explicitly specifying which part of the html code you are going to use, be it body, div.container_kek, etc. Fix that and this piece of code should work correctly. I also recommend getting rid of "var" by replacing it with "let", it's prettier :) If you are using the same font on the page, you may not need to use the .addFont & .setFont methods. Importantly, different styles, such as Bold, Italic are also a type of font, and they also need to be specified. I forgot an important point, this is adding a font to the jsPDF API, for this use this link, https://rawgit.com/MrRio/jsPDF/master/fontconverter/fontconverter.html load your font in the .ttf format into it and paste the resulting code into yours.

NeonDB avatar Oct 05 '21 13:10 NeonDB

@NeonDB what do you mean by "not explicitly specifying" there is a variable "source" which is specifying "div" in html code. Here is part of it: <div class="modal-body" id="pdfCard" style="font-family: Roboto, sans-serif !important;"> <!-- first row --> <div class="row"> <div class="col-lg-12 d-flex align-items-center justify-content-center"> <span class="h4" style="font-family: Roboto, sans-serif !important;">ľščťžýáéúäô</span> </div> </div>

this is what i see on webpage: image

and this is how i see it on generated PDF: image

jsPDF can't generate characters: ľ č ť

i have converted Robot font and attach to code `

`

jedaix avatar Oct 06 '21 06:10 jedaix

https://github.com/parallax/jsPDF/issues/2968#issuecomment-796507870

my solution to this problem:

  1. create custom font ( use this : https://www.devlinpeck.com/tutorials/jspdf-custom-font#:~:text=Adding%20Custom%20Fonts%20to%20jsPDF,of%20your%20desired%20font%20file.&text=Once%20you%20have%20your%20.,to%20this%20jsPDF%20Font%20Converter )
  2. add font to project : image
  3. import this font: image
  4. add font to pdf doc.: image

thank you so much this solution works wry well!

a-givertzman avatar Mar 01 '22 10:03 a-givertzman

My solution is:

  1. Convert file font .ttf to base64 string.
  2. Add font to doc:
  const doc = new jsPDF({
      orientation: "portrait",
      format: "a4",
      unit: "px",
      hotfixes: ["px_scaling"],
  });

   doc.addFileToVFS("Roboto.ttf", RobotoStringBase64);
   doc.addFont("Roboto.ttf", "Roboto", "normal");
   doc.setFont("Roboto");
  1. Render HTML string PDF:
  await doc.html(
     `<html>
        <body >
          <div style="width: 210mm;">${element.innerHTML}</div>
        </body>
     </html>`,
     {
        callback(doc) {
          window.open(URL.createObjectURL(doc.output("blob")));
        },
        margin: [30, 15, 30, 15],
     },
  )

robinhuy avatar Oct 18 '22 04:10 robinhuy

In my case, using the version 2.1, setting the font style on the html element like so: <html style="font-family: PTSans;">А ну чики брики и в дамки!</html> and importing the fonts according to https://www.devlinpeck.com/tutorials/jspdf-custom-font#:~:text=Adding%20Custom%20Fonts%20to%20jsPDF,of%20your%20desired%20font%20file.&text=Once%20you%20have%20your%20.,to%20this%20jsPDF%20Font%20Converter. worked for me when using an html element reference instead of using a raw html string.

Thanks it work for me!

stm-seek avatar Oct 21 '22 04:10 stm-seek

It works for me, if use div tag instead html <div style="font-family: PTSans;">А ну чики брики и в дамки!</div>

chetvertkoff avatar Dec 12 '22 08:12 chetvertkoff

I've tried this and it worked, except the text rendered was a bit overlapped.

sogrbilja avatar Dec 24 '22 18:12 sogrbilja