-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
In src/Renderer/Text.php there is variable replacement code commented, why ? #2669
Comments
I stumbled upon #1636 and https://gist.github.com/enumag/f670865b70d11e0b8156b1e92acc3c92 and approximately 10k posts on the internet about this topic (most referencing a examples page which doesn't exist anymore). I understand well that PAGE_NUM is trivial, but PAGE_COUNT is only available at the end of the rendering. But having PAGE_NUM only would already be nice for me. Another way would be to provide a way to mark some blocks for being lazily rendered at the end, as long as you know the height you can reserve space for it and compute pages without having their content, but I have no idea how hard it would be to implement it in the current code state. |
As you noted Dompdf can already handle the page number using CSS:
Is there any reason this isn't sufficient if "having PAGE_NUM only would already be nice?" The commented text doesn't deal with page count, though adding that would work out fine. The code has been commented out since it's introduction with commit 852d3e5. Most likely it was an experiment that was never fully realized. I suspect the reason this logic was never enabled is that it breaks the layout. Dompdf does a lot of work to determine appropriate placement of content. Rendering is the last step in the process so modifying the content here would subvert the work Dompdf did during the layout process. Perhaps in a minor way, but definitely noticeable depending on the specific styling in use (e.g. borders, background colors, or non-left alignment). It's one of the reasons we haven't really tackled this yet. FYI, you can use the PHP-based canvas functionality without incurring the security cost by accessing the canvas directly instead of embedding the logic in the HTML document. From the wiki:
|
Yes it is, thanks for confirming it, but regarding total count ? |
The question I asked is somewhat biased, I have a complex PDF generator which handles more drivers than only DOMPDF, in that regard, writing CSS which is DOMPDF-specific is something I try to avoid, hence the question about why not adding the possibility of having token replacement in text. I guess it would be CPU intensive somehow, but maybe not that much, all things considered. |
I tried to avoid this because I'd have to handle font and positioning manually, and it's going to be complex to maintain both the CSS and this at the same time in the long run. I don't see the canvas manipulation as a durable method for achieving this. |
This is a very good point, it explains a lot. |
Curious why adding this CSS would be problematic vs using the replacement variable. If a system doesn't support the replacement variable it stays in the document. But if a system doesn't support the CSS is does ... nothing? Like, are you looking for a common method for generating page number information? I guess I don't have a good mental model of the problem you're trying to solve. |
It's not that problematic, just I have two different ways of doing the same thing. The other PDF generation library I use allows some replacements token, having the same method and only one way to do the same thing would be great, it'd help me to generalise it instead of having to maintain 2 different methods. Furthermore, it seems less a mental burden to use magic tokens in text than using dedicated CSS, I naively searched this kind of solution first before finding out about the CSS trick (hence the commented piece of code I found in the source). Since that the page number is content in my mind, and not styling, it seems weird for me to put content related stuff into CSS. |
ha ha you'll have to take that one up with the CSS working group 😉 |
Yeah I guess, it surprised me. Although my problem remain is that the other PDF generation tools I use are far less advanced when working with CSS than DOMPDF (which is to my knowledge from far the best PHP tool for this). Anyway, I'll do with CSS, but I'm convinced than having some kind of pluggable text pre-processor for implementing such token replacement could be a nice to have. I'd be glad to just put the CSS some integrator did and never having to modify it, and do everything I need to do just with PHP and HTML. Thank you for all your answers, and thank you to all DOMPDF contributors, it's a great tool. |
Looking at that commented code more, even that is unable to get you the total page count. It can only give you the current number of pages rendered up to that point (Dompdf currently writes the PDF as it's laying out the document). So really there's not much point in having that block since there are other ways to get that information. Since you're looking for a non-CSS method you could use callbacks to do that kind of text replacement. With the caveat that you're tweaking the text after layout is complete so results may not be ideal. With the following HTML:
You can display the page number using the following callback:
I attempted to minimize the inaccurate layout by using "{#}" (3 characters for replacement instead of 10). But you can see on page 2 how the text doesn't quite align to the right. Getting the total number of pages in this way is more challenging because the text has already been rendered. Might be possible but I'll need to do a bit more investigation. |
And, of course, the layout issues only get worse if you have multiple frames on the same line, e.g.:
|
Ah very nice ! I wasn't aware we could plug onto DOMPDF at runtime like this, nice. This is really a great tool, but it sometime lacks documentation. Thanks a lot for this. |
Fun behaviour: $dompdf = new Dompdf();
$dompdf->loadHtml($output);
// $dompdf->setPaper('A4', 'portrait');
$dompdf->setOptions(new Options([
'defaultMediaType' => 'page',
'defaultPaperOrientation' => 'portrait',
'defaultPaperSize' => 'A4',
'isHtml5ParserEnabled' => true,
'isRemoteEnabled' => false, // Security.
]));
$canvas = $dompdf->getCanvas();
$dompdf->setCallbacks([
[
'event' => 'begin_frame',
'f' => function ($info) use ($canvas) {
$frame = $info['frame'];
\assert($frame instanceof \Dompdf\Frame);
$node = $frame->get_node();
if ($node->nodeType === XML_TEXT_NODE) {
$node->textContent = \str_replace('{PAGE_NUM}', (string) $canvas->get_page_number(), $node->textContent);
}
}
]
]); My page number is always It gets called once per page, but page number remains always I'll do some debugging to see what I did wrong the next week, but in the meantime I'll simply use the CSS method. Thanks again for all your help. |
Since we're changing the actual text of the node once the text is replaced that is what's rendered every time it appears. You can reset the text after rendering so that the next iteration of the text has the replacement variables.
|
Actually, maybe that's not what's going on? I realized I had the text replacement commented out and it was still producing the expected results. I'd try resetting the text to see if that fixes it, but something else might be going on. I'd have to see a sample of your HTML + CSS. |
Let me extract some pieces for you, I can't give you all that wouldn't be helpful, I have a huge CSS file, and a huge generated PDF. What would you be looking for in CSS/HTML ? |
Here is an example: <html>
<head>
<meta charset="utf-8">
<style type="text/css">
.page { page-break-after: always }
hr.page-break { display: none }
@media screen { hr.page-break { display: block } }
/* Reset */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
line-height: 1.2em;
position: relative;
}
body {
font-size: 9pt;
}
body {
color: #202020;
}
.page {
width: auto;
padding: 0;
margin: 0;
}
.page-inner {
padding: 1cm;
margin: 0;
/* height: 100%; /* Fixes height in MPDF */
}
@page {
margin-bottom: 1.5cm; /* Make space for footer. */
}
/* Fixes for DOMPDF and mPDF and browser printing */
@media print {
@page {
border: none;
/* margin: 0 !important; */
}
html, body {
width: 100%;
}
}
@media page {
@page {
border: none;
/* margin: 0 !important;
padding: 0 !important; */
}
html, body {
width: 100%;
}
/* Position: fixed for DomPDF. */
footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
}
}
/* Fixes for on screen display, sizes stuff like if it was a real PDF. */
@media screen {
header, footer {
display: block;
width: 21cm;
background: white;
margin: 1em auto;
}
html {
background: #808080;
color: white;
}
.page {
width: 21cm;
min-height: 29.7cm;
margin: 1em auto;
}
.page-inner {
background: white;
width: 21cm;
min-height: 29.7cm;
}
}
/******************************************************************************
*
* COMMON STYLING
*
******************************************************************************/
@font-face {
font-family: "Foo";
src: url(fonts/foo.eot);
src:
url(fonts/foo.eot) format("embedded-opentype"),
url(fonts/foo.woff) format("woff"),
url(fonts/foo.ttf) format("truetype"),
url(fonts/foo.svg) format("svg");
}
@font-face {
font-family: "Bar";
src: url(fonts/bar.eot);
src:
url(fonts/bar.eot) format("embedded-opentype"),
url(fonts/bar.woff) format("woff"),
url(fonts/bar.ttf) format("truetype"),
url(fonts/bar.svg) format("svg");
}
@font-face {
font-family: "Baz";
src: url(fonts/baz.ttf) format("truetype");
}
* {
font-family: "Baz", "Trebuchet MS", Arial, sans-serif;
}
h1, h2, h3 {
font-family: "Foo", "Trebuchet MS", Arial, sans-serif;
}
body {
box-sizing: border-box;
font-size: 9pt;
}
* {
margin: 0;
padding: 0;
color: #003a76;
}
p {
margin: 0.3cm 0;
}
hr {
border-color: #dfdfdf;
}
hr {
margin: 0.5cm 0;
border-color: #808080;
border-bottom: 0;
}
/******************************************************************************
*
* TITLES
*
******************************************************************************/
h1, h2, h3, h4 {
vertical-align: middle;
}
h1 + h2, h2 + h3, h3 + h4, h4 + h5 {
margin-top: 0;
}
h1 {
margin-top: 0;
font-size: 20pt;
font-weight: bold;
color: #00aba8;
margin-bottom: 0.8cm;
}
h2 {
border-bottom: 0.08cm solid #00aba8;
color: #003a76;
padding-bottom: 0.15cm;
font-weight: bold;
font-size: 11pt;
margin: 0.75cm 0 0.4cm 0;
text-transform: uppercase;
font-size: 11pt;
}
h2.header {
border: none;
background-color: #003a76;
color: white;
padding: 0.3cm 0.4cm;
text-transform: none;
font-size: 11pt;
}
h3 {
margin-bottom: 0.15cm;
margin-top: 0.5cm;
font-size: 10pt;
}
h1 .number {
background-color: #00aba8;
color: white;
border-radius: 0.25cm;
padding: 0.2cm 0.4cm;
margin-right: 0.4cm;
}
@media page {
h1 .number {
border-radius: 0.5em;
padding: 0.2em 0.4em;
}
}
/* REDACTED */
/* REDACTED */
/******************************************************************************
*
* PAGE LAYOUT
*
******************************************************************************/
footer {
height: auto;
padding-left: 1.35cm;
padding-right: 1.35cm;
padding-bottom: 0.5cm;
}
footer p {
margin: 0;
margin-bottom: 0;
margin-top: 0;
}
footer .page-number:before { /* DomPDF for displaying page number. */
content: counter(page);
}
.page {
box-sizing: border-box;
border-top: 0.4cm solid #00aba8;
margin-bottom: 1.5cm; /* Make space for footer */
}
.page-inner {
padding: 0.7cm 1.35cm;
}
.page-garde {
background: #00aba8;
border: none;
font-size: 12pt;
margin-bottom: 0px !important; /* Hide footer */
padding-bottom: 0px !important; /* Hide footer */
}
.page-garde > .page-inner {
border: 1cm solid #00aba8;
border-radius: 1.5cm; /* Bigger than border = inside radius */
background: white;
margin-bottom: 0px !important; /* Hide footer */
}
.page-garde > .page-inner {
padding-bottom: 5cm;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.page-garde .bottom {
position: absolute;
bottom: 0.8cm;
left: 1cm;
right: 1cm;
}
.page-garde table img {
display: block;
}
.page-garde img {
max-width: none;
}
.page-garde .traits {
margin-bottom: 0.75cm;
}
.page-garde .logo {
width: 3.2cm;
}
.page-garde h1 {
color: #003a76;
font-weight: bold;
font-size: 22pt;
text-transform: none;
}
.page-garde h2 {
color: #003a76;
border: none;
text-transform: none;
margin-top: 0;
}
.page-garde hr {
color: #00b5d5;
border-color: #00b5d5;
border-width: 0.1cm;
}
.page-bleu {
border-color: #00b5d5;
}
.page-bleu h1 {
color: #00b5d5;
}
.page-bleu h1 .number {
background-color: #00b5d5;
}
.page-bleu-fonce {
border-color: #003a76;
}
.page-bleu-fonce h1 {
color: #003a76;
}
.page-bleu-fonce h1 .number {
background-color: #003a76;
}
.page-vert {
border-color: #00aba8;
}
.page-vert h1 {
color: #00aba8;
}
.page-vert h1 .number {
background-color: #00aba8;
}
.page-jaune {
border-color: #f5a623;
}
.page-jaune h1 {
color: #f5a623;
}
.page-jaune h1 .number {
background-color: #f5a623;
}
.page-rouge {
border-color: #df2b53;
}
.page-rouge h1 {
color: #df2b53;
}
.page-rouge h1 .number {
background-color: #df2b53;
}
.page { page-break-after: always }
@media page { hr.page-break { display: none } }
@media print { hr.page-break { display: none } }
@media screen { hr.page-break { display: block } }
</style>
</head>
<body><footer id="footer"><div class="row"><div class="col el-even el-first"><p>REDACTED — REDACTED —
12/12/2021</p></div>
<div class="col el-odd el-last"><p>p.
<span class="page-number"></span></p></div>
<div class="clear"></div></div></footer><main><div class="page-garde page">
<div class="page-inner">
<table class="nostyle">
<tbody>
<tr>
<td style="width:25%">
<img src="data:image/png;base64,iVB..." class="logo"/>
</td>
<td>
<h1>Evaluation des risques professionnels</h1>
<img src="data:image/svg+xml;base64,PHN..." class="traits"/>
<h2>REDACTED accompagne les entreprises des services REDACTED dans leur démarche de prévention</h2>
</td>
</tr>
</tbody>
</table>
<div class="center"><img src="data:image/jpeg;base64,/9j/4AA..." class="image" style="width:70%"/></div>
<div class="bottom">
<p class="uppercase">REDACTED</p>
<p class="uppercase">Siret: REDACTED</p>
<hr>
<p>Date d'intervention : 12/12/2021</p>
<p>Intervenant : JeanPaul Intervenant</p>
</div>
</div>
</div>
<div class="page-jaune page"><div class="page-inner"><h1><span class="number">1</span>
Rappel des objectifs de l'intervention</h1>
<div class="panel-bleu center panel"><p>REDACTED accompagne les entreprises de la
REDACTED dans leur démarche de prévention.</p>
<p>Le but de cette intervention est d’apporter à l’entreprise un appui
méthodologique dans l’identification de ses risques professionnels les
évaluer, mettre des actions de prévention..</p></div>
<h2 class="header">Les objectifs sont les suivants :</h2>
<ul class="list-triangle list-bordure list"><li class="el-even el-first">Identifier et évaluer les principaux risques professionnels aux
postes de travail (présentation de la méthodologie de cotation de
risques et visite des locaux)</li>
<li class="el-odd">Hiérarchiser les priorités d’action en fonction des résultats
de l’évaluation des risques professionnels</li>
<li class="el-even">Proposer des mesures de prévention sous forme de plans d’action</li>
<li class="el-odd el-last">Sensibiliser le chef d’entreprise ou la personne en charge de
la prévention sur les obligations réglementaires et les outils
permettant de mettre en place une démarche de prévention.</li>
</ul>
<div class="center panel"><p>Ce rapport synthétise les résultats de l’intervention</p>
<p><span class="gros"><span class="gras">« Evaluation des risques professionnels »</span></span></p>
<p><span class="gros">Réalisée le
12/12/2021</span></p></div></div></div>
<div class="page-bleu page"><div class="page-inner"><div class="row"><div class="col el-even el-first"><h1><span class="number">2</span>
Présentation de l’entreprise</h1></div>
<div class="col el-odd el-last"><img src="data:image/svg+xml;base64,PHN..." class="image" style="height:3cm"/></div>
<div class="clear"></div></div>
<h2 class="header">Nom de l’entreprise</h2>
<p>REDACTED</p>
<h2 class="header">Activité de l'entreprise</h2>
<p>REDACTED
REDACTED
REDACTED
REDACTED
REDACTED
REDACTED</p>
<h2 class="header">Nom de(s) personne(s) présente(s) durant l’intervention</h2>
<p>Bernard, Minet et Framboisier</p>
<h2 class="header">REDACTED</h2>
<div class="row"><div class="col el-even el-first"><p><div class="rouge">Bernard, Minet et Framboisier</div></p></div>
<div class="clear"></div></div>
<h2 class="header">REDACTED</h2>
<div class="row"><div class="col el-even el-first"></div>
<div class="clear"></div></div></div></div>
<!-- HERE MANY OTHER PAGES -->
</main>
</body>
</html> |
Using |
I was looking for a simple example of how you're trying to use the |
Oh I'm sorry I misunderstood... Just replace |
I'll upgrade to 1.1.1 and try again in the next weeks (sorry I'm busy with a client right now). |
Hello,
In
src/Renderer/Text.php
I noticed that there is this code:This actually was a good idea. Why is it commented ?
In my use case, I'm trying to place the PAGE_NUM and PAGE_COUNT somewhere, in already generated HTML, and I don't want to use evaluated PHP code, for two reasons:
page_text()
you need to manually position it.Fact is my HTML code is driven by another tool and I simply don't have the flexibility of using
page_text()
for generating my footer.Is there any way at all to simply position the page number and page count without using PHP code ?
The text was updated successfully, but these errors were encountered: