Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not applying true css / styles : line-height and fonts issue #3369

Closed
gidzr opened this issue Jan 8, 2024 · 13 comments
Closed

Not applying true css / styles : line-height and fonts issue #3369

gidzr opened this issue Jan 8, 2024 · 13 comments
Labels

Comments

@gidzr
Copy link

gidzr commented Jan 8, 2024

Using

  • latest dompdf
  • XAMPP, php 8.1
  • codeigniter project, base_url = http://localhost/
  • using local bootstrap style sheets with local overrides
  • bootstrap css <link href="<?php echo base_url(); ?>css/bootstrap523.min.css" rel="stylesheet" type="text/css" />
  • customecss <link href="<php echo base_url(); ?>css/customstyle.css" rel="stylesheet" type="text/css" />

Using the following code, I am able to produce a pdf, but it does not pick up css style sheet and only picks up "style: xxxx" tag in the DOM elements. Furthermore, arabic and chinese (non-latin code) is not printed although it appears correctly onscreen.

// setup the options
$options = new Options();
$options->set('isRemoteEnabled', TRUE);
$options->set('isHtml5ParserEnabled', TRUE);
$options->set('chroot', base_url('css'));


// instantiate and use the dompdf class with options
$dompdf = new Dompdf($options);

$baseurl = base_url();
$html = "
         <html>
            <head>
               <meta charset='utf-8' />
               <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>   
               <link rel='stylesheet' type='text/css' href='{$baseurl}css/bootstrap523.min.css'  media='all' />
               <link rel='stylesheet' type='text/css' href='{$baseurl}css/style.bundle.css' media='all' />
               <link rel='stylesheet' type='text/css' href='{$baseurl}css/custom_style_override.css' media='all' />
               <link rel='preconnect' href='https://fonts.googleapis.com' />
               <link rel='preconnect' href='https://fonts.gstatic.com' crossorigin  />
               <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700'  />
               <link rel='stylesheet' href='https://fonts.googleapis.com/css2?family=M+PLUS+Rounded+1c&display=swap'  />
            </head>
            <body style='padding:20px; '>
               $htmlContent
            </body>
         </html>
      ";


// rest of the html goes here
$dompdf->loadHtml($html, 'utf-8');

// (Optional) Setup the paper size and orientation
$dompdf->setPaper('A4', 'landscape');

// Render the HTML as PDF
$dompdf->render();

// Output the generated PDF as a Base64 string
$output = $dompdf->output();

// Define the path and name of the PDF file
$pdfFilePath = "C:/xampp81/tmp/filename.pdf";

// Save the PDF to a file
file_put_contents($pdfFilePath, $output);

If I have a translation onscreen with non-Latin characters like arabic or chinese, these disappear completely from the printed pdf, even though they are rendered correctly in the html onscreen.

Attemped fixes:

$str = '<html><head>';
$str .= '<link type="text/css" href="http://localhost/css/bootstrap523.min.css.css" rel="stylesheet" media="all" />';
$str .= '<link type="text/css" href="http://localhost/css/custom_style_override.css" rel="stylesheet" media="all" />';
$str .= '</head><body>';
$str .= $htmlContent;
$str .= '</body></html>';
// rest of the html goes here
$dompdf->loadHtml($str, 'utf-8');

EDITED.. I updated my code per the inclusion of styling in the html code, and saved to pdf in php, to exclude any issues occurring with front-end JS saving to pdf.

@bsweeney
Copy link
Member

bsweeney commented Jan 8, 2024

The main thing you need for resources accessed over HTTP is to set the isRemoteEnabled option to true, which you have. You would also need to make sure that allow_url_fopen is set to true, and that Dompdf has read/write access to the temp directory (which you can specify using the tempDir option) if you have images or fonts to load. The chroot option is not relevant if the files are accessed via HTTP.

I can't really help with the file loading issues because I don't have enough info. You mention having to add HTTP to the resource URLs. That would be required if the resources need to be accessed via HTTP unless you're loading the document itself over HTTP (e.g. $dompdf->loadHtml("http://example.com")). Generally speaking, resource URLs that are not fully qualified with a protocol are accessed through the same context as the HTML document itself. When you use loadHtml that context is the local filesystem.

As for missing text, the core PDF fonts do not support any characters other than those supported by Windows ANSI. The bundled DejaVu fonts support some additional characters, but not Chinese or Arabic. Read through the font information and Unicode how-to for more information.

You might try some of the configuration options outlined in the troubleshooting document.

@gidzr
Copy link
Author

gidzr commented Jan 8, 2024

Thanks for your response.

Re EDIT, I switched to saving pdf on php backend to exclude anything the front-end is causing, and no change to my situation.

I checked allow_url_fopen in php.ini, and it's open
; Whether to allow the treatment of URLs (like http:// or ftp://) as files.
; https://php.net/allow-url-fopen
allow_url_fopen=On

Dompdf has read/write access to the tmp folder, because it's creating the pdfs no problems. It's just not handling style sheets, fonts.

Re non-latin languages, I've used the Hello World example you provide in your non-latin font docs https://github.com/dompdf/dompdf/wiki/UnicodeHowTo. I selected a chinese character font, which has been downloaded locally but called using the localhost server location. It produces a pdf with boxes (ie. the font coding isn't working.)

  $html ="

     <html>
     <head>
         <style>
             @font-face {
                 font-family: 'Nonsans';
                 font-style: normal;
                 font-weight: normal;
                 src: url(http//localhost/projectname/fonts/Noto_Sans_TC/NotoSansTC-Regular.ttf) format('truetype');
             }
         </style>
         <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
     </head>
     <body>
         <p style=\"font-family: Nonsans, DejaVu Sans, sans-serif;\">献给母亲的爱</p>
     </body>
     </html>

  ";

  // rest of the html goes here
  $dompdf->loadHtml($html, 'utf-8');

@gidzr
Copy link
Author

gidzr commented Jan 8, 2024

Good news everyone, hello world is working but only after a) changing to a custom arabic font (google noto font for arabic), and b) using @import not @font-face (per the dompdf docs)

The following updated code produced a pdf with the arabic script.

I wish there was a universal font to make this easier. Are you aware of any? Otherwise I need to detect / tag each line of text with a language and use a font-family for per tag. Very messy.. doable but not exactly graceful.

Is there a universal font?

     <html>
     <head>
            <style>

          @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@100&display=swap');

           @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+TC&display=swap');

             @import url('https://fonts.googleapis.com/css2?family=Noto+Naskh+Arabic&display=swap');

            * {
                font-family: 'Noto Naskh Arabic', serif;
              }
         </style>
         <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
     </head>
     <body>
         <p>بيت الأرييل</p>
     </body>
     </html>

I'm still stuck on the issue re Style sheets which are supposed to, but aren't being read by dompdf when embedded into the encoded html.

@bsweeney
Copy link
Member

bsweeney commented Jan 8, 2024

The fact that the loading the font via Google instead of your local server probably means that your URL is not quite right. If you write a simple fetch script...

<?php
echo (file_get_contents("http//localhost/projectname/fonts/Noto_Sans_TC/NotoSansTC-Regular.ttf") ? "read" : "not read");

...are you able to retrieve the font? If not then it's probably the same for your stylesheets.

As for the boxes, that means the font supports Unicode, just not the characters on the page. There are very few "universal" fonts. MS Arial Unicode is one but it's not generally available and has license restrictions. Unless you can find one you'll need to style each block of text with the appropriate font family.

That is, until the next version of Dompdf (3.0.0). It adds support for detecting which of the listed fonts support the characters being rendered. With that release you'll be able to just style your document something like:

<style>
  * {
    font-family: "Noto Sans", "Noto Sans SC", "Noto Sans TC", "Noto Naskh Arabic", sans-serif;
  }
</style>

However, regardless of which version of Dompdf you're using languages that require complex text layout will not render correctly without pre-processing. For example, shaping required by Arabic has to be performed before passing the HTML document to Dompdf.

@gidzr
Copy link
Author

gidzr commented Jan 8, 2024

Hi @bsweeney , yes the font and style sheet are definitely read - otherwise it wouldn't work for the rest of the site, hwoever I checked using: echo (file_get_contents("http://localhost/projectName/css/stylesheet.css") ? "read" : "not read"), and it is "read".

For example, I have bootstrap in the head section of the site. But as I'm only printing a section of the page DOM at html code, I surround it in a new set with link back to the bootstrap css that I know works using your tester.

None of the bootstrap style are recognised though. Eg. cards, me-1, px-2, etc. I'll keep playing around to see if I can resolve, but I'm current workarounding it by putting inline styling into the code that's being sent to dompdf (eg. <\div style="blah blah">. This works but means I can't apply it to the rest of my site, which is ok for now.

Question:

  • Does it matter if the stylesheet is a .min vs full readable css?

Btw. I'm looking forward to your auto-language detection version. That's pretty hectic! When's the release eta?

@bsweeney
Copy link
Member

bsweeney commented Jan 8, 2024

No specific release date, and I avoid giving estimates just because I have to fit in the work when I can. That being said, it shouldn't be too long before it's ready I'm trying to finish up a few pending updates.

It's entirely possible the Bootstrap styling you're using isn't supported. For example, Dompdf doesn't yet support flexbox or grid so some of the styling from Bootstrap 5 in particular just won't work. Older versions of Bootstrap work OK, though there are still some issues to resolve.

Minified CSS shouldn't be a problem. If you can provide a sample document, I'm happy to take a look and see if there's anything that just won't work.

@gidzr
Copy link
Author

gidzr commented Jan 9, 2024

I've being running some tests and have now resolved most issues, except for one more niggling item.

Line-height seems to get hijacked - it's the only css/style that's not getting replicated from stylesheet, inline, or classes. The line-height rendered by dompdf is the default for the font.

Is this a known issue?

These are from previous version of dompdf:
#1646
#670
#1801
#814

@gidzr gidzr closed this as completed Jan 9, 2024
@gidzr gidzr reopened this Jan 9, 2024
@bsweeney
Copy link
Member

bsweeney commented Jan 9, 2024

The only line-height issue I'm aware of has to do with lines that contain varying size block-level inline element such as images. That's being worked on with #2762. Can't say if that's impacting you without seeing a sample of your HTML.

@gidzr
Copy link
Author

gidzr commented Jan 9, 2024

Cool.. ok, here are the screenshots and code:

Current setup

Onscreen
I'm rendering using javascript to produce dynamic html, hence the variables in the html code below.
CSS uses Poppins font.

html onscreen

        htmlInner += `
           <div style="
              position:absolute; top:`+(yPosPx-borderAdjust)+`px; left:`+(xPosPx-borderAdjust)+`px; padding:0 !important; 
              XXborder: solid `+borderAdjust+`px red; XXbackground:red !important; 
              width:`+(paraWidthPx+borderAdjust)*1.15+`px; 
              height:`+(paraHeightPx+(borderAdjust*0))+`px; 
              font-weight:`+fontWeight+`; font-size:`+fontSizePx+`px;  XXtransform-origin: left; XXtransform: scale(`+fontStretch+`, 1);
              line-height:`+lineHeightPx+`px !important; margin-top:`+(marginTopPx-(borderAdjust*5))+`px; vertical-align: top !important; letter-spacing:`+letterSpacing+`px;"
              class="p-0 m-0 bg-body" >

              <span id="paraText_`+p+`" style="
                 display: inline-block;  padding:0 !important; 
                 width:auto; max-width:auto; min-width:`+(paraWidthPx+borderAdjust)*1.15+`px; 
                 height:auto; max-height:auto; Xmin-height:`+(paraHeightPx+(borderAdjust*0))+`px; 
                 line-height:`+lineHeightPx+`px !important; XXvertical-align: middle !important; 
                 outline:`+borderAdjust+`px solid white; background:white; vertical-align: top !important; "
                 class="paraText body-bg p-0 m-0 d-inline-block" >`+paraItem.text+`</span>

           </div>
        `;
     });

DOMPDF pdf output
I'm wrapping DOM inner html in html page code with all the same style sheets

html dompdf

     <html>
     <head>
        <meta charset='utf-8' />
        <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>   

        <link href='{$baseurl}css/bootstrap523.min.css' rel='stylesheet' type='text/css' />
        <link href='{$baseurl}css/style.bundle.css' rel='stylesheet' type='text/css' />
        <link href='{$baseurl}css/custom_style_override.css' rel='stylesheet' type='text/css' />

        <style>
           * {
              font-family: 'Poppins', sans-serif;
              line-height:none !important;
              line-height:0 !important;
           }
        </style>


     </head>
     <body'>
        $htmlContent
     </body>
     </html>

Testing

Hypothesis
Fonts may have default line-heights attached to them, and these are being used by DOMPDF.

Experiment 1
I switched out a number of san-serif fonts, such as roboto, montessera, open sans, noto, arial, etc in the DOMPDF php html page wrapper while holding line-height = 0.

Results 1

  1. Default line-height varies between different fonts, while holding line-height = 0, but no font was reproduced successfully at a 0 line height.
  2. The only 'font' that responded to the true line-height setting of 0, was the non-font, system fallback, 'san-serif'
    ie. "font-family: sans-serif;"

which DOMPDF pdf'd to this:

html dompdf_sanserif

Experiment 2
Using the standard san-serif in DOMPDF html wrapper, I increased line-height in the DOMPDF wrapper to see if it responded with the new font.

Results 2
No change. Line-height changed in the php for DOMPDF did not impact the output

Experiment 3
Using the standard san-serif, adjusting line-height in the client side html being generated by javascript to see if it's rendered in the back-end because of the san-serif.

Results 3
Line-height increase in the javascript onscreen when using 'san-serif' (no custom font), DOES translate to the DOMPDF pdf output

DOMPDF pdf output
html onscreen_line-height

Conclusion

  1. Using a fallback standard 'san-serif' in DOMPDF wrapper, DOMPDF responded correctly the the line-height sent to it from client-side.
  2. All other fonts, whether declared at the client or the php-side wrapper, causes DOMPDF to fail in applying the line-height. This is irrespective of whether the line-height for a styled font was set in client or php-side. Instead, when using a specified font, DOMPDF ignores line-height and instead applies a default line-height which is either coming from DOMPDF settings (eg. line-height defaults to 1em, thus still appears to change for fonts), or is a built in line-height from the font.

Hope this helps.
Cheers!

@gidzr gidzr changed the title Not using the css stylesheet, and unable to print languages that are correctly rendered in browser Not applying true css / styles : line-height and fonts issue Jan 9, 2024
@bsweeney
Copy link
Member

Hard to say what's going on here. I would need to see a whole lot more of your actual HTML and CSS (instead of the logic that generates it). It's just too hard to debug with what you've provided.

Regarding your thought about line height. A font does not have a line height. The line height "specifies the minimum height of line boxes within the element" (mdn). The actual height of a line depends on how it's specified as well as the content of the line. So, while a font does not come with a line height, the height of that font (based on the font size) does impact the height of the line.

The sample line height styling you show is in px, which is not recommended. That sets a static line height as opposed to one calculated based on the content. You can see the impact by rendering the css_line_height.html document in the debug helper.

@gidzr
Copy link
Author

gidzr commented Jan 10, 2024

You've just solved it.

You are a freakin genius!

Ok, here's the use-case I'm working on. I'm scanning doc using tesseract, then reproducing the elements onscreen overlaid onto the original image in the same positions. Because tesseract and other OCR don't provide font, font-size or line-spacing data, I have to infer everything based on the fixed width and height blocks. eg. if there are two sentences on a block with 30px height, then line-height is 15px.

This was working perfectly for the onscreen rendering... but NOT for dompdf rendering.

I've replaced line-height px with relative non-unit measure, removed the vertical alignment, and made the spans absolute to top=0 padding=0.

Line-height is now controllable and I can put a workaround in place, which mostly works but still not 100% faithful to the oscreen rendering.
I've added this in the php wrapper

span {
       line-height:70% !important; 
}

Also found this: $options->set('fontHeightRatio', 1.1); is default. That's been a big issue too.

I'm still a bit weirded out that:

  1. line-height isn't replicating what's in the browser.. the effect is magnified.. dompdf reads the line-height being much greater than what's been assigned in the css.
  2. the effects of px were not an issue when using the fallback 'sans-serif' non-font
  3. that effect wasn't visible when rendering in browser, but only in dompdf
  4. that px set on line-height, wasn't being overridden with line-height:0 !important in the backend
  5. that moz says px is good practice (https://developer.mozilla.org/en-US/docs/Web/CSS/line-height).. so I'm assuming you mean that px line-height is bad for dompdf..

BIG BIG THANKS :)

@gidzr gidzr closed this as completed Jan 10, 2024
@bsweeney
Copy link
Member

I can't speak as to what you're seeing in the browser vs dompdf without a simple, self-contained, reproducible example so I think we can leave that for now.

Per the mdn documentation "Prefer unitless numbers for line-height values." Meaning you should avoid using px or any other unit, just a bare number. It is supported but can produce unexpected results for lines with different font sizes.

@gidzr
Copy link
Author

gidzr commented Jan 11, 2024

Ok, I'll test it out and see what I can do. I'll let you know the outcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants