elliotblackburn / mdpdf

Markdown to PDF command line app with support for stylesheets
https://npmjs.com/package/mdpdf
Apache License 2.0
717 stars 47 forks source link

Trying to add Page Number in the footer #116

Open DEYROS opened 2 years ago

DEYROS commented 2 years ago

I'm trying to add a page number in the footer of my PDF.

index.js that I run(node) to create the PDF:

const path = require('path');
const mdpdf = require('mdpdf');

const options = {
    source: path.join("examples/api/", 'fichierConcatDoitAvoir.md'), 
    destination: path.join("examples/api/", 'pdf-file.pdf'), 
    styles: path.join("examples/api/", 'styles.css'), 
    ghStyle: false,
    defaultStyle: true,
    footer: path.join("examples/api/", 'footer.html'),
    header: path.join("examples/api/", 'header.html'),
    pdf: {
        format: 'A4', 
        orientation: 'portrait',
        quality: '100',
        header: {
            height: '25mm'
        },
        footer: {
            height: '17mm'
        },
        border: {
            top: '10mm',
            left: '20mm',
            bottom: '5mm',
            right: '20mm'
        },
    }
};

// Call convert which returns a thenable promise with the pdfPath
mdpdf.convert(options).then(pdfPath => {
    console.log('Fichier PDF créé :', pdfPath);
}).catch(err => {
    // Don't forget to handle errors
    console.error(err);
});

The footer that I have created in HTML :

<footer>
    <div id="footer">
        <h1 class="txt">SpringCard</h1>
        <hr class="solid">
        <div class="nbPages">Page <span class="pageNumber">?</span>/ <span class="totalPages ">4</span></div>
    </div>
</footer>

I think I'm not supposed to write "?" or even "4" but it is so that you understand well what I expect. Here is what I got : image I think that I have to use puppeteer but I don't know/understand how. Thx !

elliotblackburn commented 2 years ago

I think I'm not supposed to write "?" or even "4" but it is so that you understand well what I expect.

Just to clarify, does this mean you've tried using it without specifying those values? Such as:

<div class="nbPages">Page <span class="pageNumber"></span>/<span class="totalPages"></span></div>

Would it be possible to try a div rather than a span for those as well and see what happens?

DEYROS commented 2 years ago

I tried it and nothing happened : image And if i try a div rather than a span these happen : image

<footer>
    <div id="footer">
        <h1 class="txt">SpringCard</h1>
        <hr class="solid">
        <div class="nbPages">Page <div class="pageNumber"></div>/ <div class="totalPages "></div></div>
    </div>
</footer>
nopeless commented 2 years ago
<footer>
    <div id="footer">
        <h1 class="txt">SpringCard</h1>
        <hr class="solid">
        <div class="nbPages">Page <span class="pageNumber"></span>/ <span class="totalPages ">4</span></div>
    </div>
</footer>

This works for me

Are you sure you properly saved your file

DEYROS commented 2 years ago

hello @nopeless how did you create the pdf ? Like me or with puppeteer ? Could you please show me how did you did it ? Thx !

nopeless commented 2 years ago

hello @nopeless how did you create the pdf ? Like me or with puppeteer ? Could you please show me how did you did it ? Thx !

Its just your code. It worked first try. Would you like a stackblitz (free repo hosting website) for reproduction?

DEYROS commented 2 years ago

Nothing else really ? Yes it would be perfect thx

nopeless commented 2 years ago

GitPod*

I have no idea why the machine in GitPod can't install some libraries (can't run puppeteer) but use this code

const path = require('path');
const mdpdf = require('./src/index.js');

const options = {
    source: "test.md", 
    destination: "test.pdf", 
    footer: 'footer.html',
    pdf: {
        format: 'A4', 
        orientation: 'portrait',
        quality: '100',
        header: {
            height: '25mm'
        },
        footer: {
            height: '17mm'
        },
        border: {
            top: '10mm',
            left: '20mm',
            bottom: '5mm',
            right: '20mm'
        },
    }
};

// Call convert which returns a thenable promise with the pdfPath
mdpdf.convert(options).then(pdfPath => {
    console.log('Fichier PDF créé :', pdfPath);
}).catch(err => {
    // Don't forget to handle errors
    console.error(err);
});

footer.html

<footer>
    <div id="footer">
        <h1 class="txt">SpringCard</h1>
        <hr class="solid">
        <div class="nbPages">Page <span class="pageNumber" style="font-size: 50px"></span>/ <span class="totalPages ">4</span></div>
    </div>
</footer>

@DEYROS

nopeless commented 2 years ago

oh and uh... You might have to use path.join again (this code is tested on a custom branch #119) and this pr fixes path resolve

DEYROS commented 2 years ago

Ok ok could you make a screenshot of the pages ? To see what you get ?

nopeless commented 2 years ago

@DEYROS image

DEYROS commented 2 years ago

When I try to use your code here is what happen :

Error: Cannot find module './src/index.js'
Require stack:
- D:\aperrot\markdowntopdf\index.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
    at Function.Module._load (node:internal/modules/cjs/loader:778:27)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at Object.<anonymous> (D:\aperrot\markdowntopdf\index.js:2:15)
    at Module._compile (node:internal/modules/cjs/loader:1105:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [ 'D:\\aperrot\\markdowntopdf\\index.js' ]
DEYROS commented 2 years ago

@nopeless Why did you put :

const mdpdf = require('./src/index.js');

instead of :

const mdpdf = require('mdpdf');

That's maybe why it doesn't work for me.

DEYROS commented 2 years ago

I also tried something like that :

const path = require('path');
const mdpdf = require('mdpdf');

// Configure les différentes options
const options = {
    source: 'ConcatSpringCore.md', //Le fichier à transformer en PDF DOIT ETRE DANS LE MEME QUE CELUI CREE
    destination:'pdfFinal.pdf', //Le fichier PDF qui sera créé
    footer: 'footer.html',//Le bas de page
    header: 'header.html',//Le haut de page
    pdf: {
        format: 'A4', 
        orientation: 'portrait',
        quality: '100',
        header: {
            height: '25mm'
        },
        footer: {
            height: '17mm'
        },
        border: {
            top: '1mm',
            left: '20mm',
            bottom: '5mm',
            right: '20mm'
        },
    }
};

// Call convert which returns a thenable promise with the pdfPath
mdpdf.convert(options).then(pdfPath => {
    console.log('Fichier PDF créé :', pdfPath);
}).catch(err => {
    // Don't forget to handle errors
    console.error(err);
});

and for my footer.html :

<footer>
    <div id="footer">
        <h1 class="txt">SpringCard</h1>
        <hr class="solid">
        <div class="nbPages">Page <span class="pageNumber" style="font-size: 50px"></span>/ <span class="totalPages ">4</span></div>
    </div>
</footer>

And I got this : image So it doesn't work

nopeless commented 2 years ago

@nopeless Why did you put :

const mdpdf = require('./src/index.js');

instead of :

const mdpdf = require('mdpdf');

That's maybe why it doesn't work for me.

Because I am running this code on a clone of this repo. Let me test something real quick

DEYROS commented 2 years ago

OK ok thx

nopeless commented 2 years ago

@DEYROS I am totally unable to replicate your issue. Can you upload an entire zip file here or create a new repository containing all source code? My best guess is that your CSS is causing issues but this entire thread was beating around the bush and I want to nail it down this time

DEYROS commented 2 years ago

No problem, here it is : pdfFinal.zip Thnak you for your help !

DEYROS commented 2 years ago

I deleted the css from the index.js :

styles: 'styles.css',

This line. It doesn't work, I don't have any page numbers. So I don't think the problem come from the css

nopeless commented 2 years ago

@DEYROS General tip: when people ask u to send a zip for node project, include package.json and package-lock.json

DEYROS commented 2 years ago

Sorry for that, here it is pdfFinal.zip

nopeless commented 2 years ago

I tried running your poject and for some reason the footer appears squished

Nonetheless, the page number is still there

image

I think it might be a puppeteer issue. What is your puppeteer version?

DEYROS commented 2 years ago

I have just done an "npm i puppeteer" so I should have the last version ?

nopeless commented 2 years ago
npm list puppeteer
(async()=>{const x = require("puppeteer"); console.log(await(await(await x.launch()).newPage()).browser().version())})()

I have 8.13.0 and HeadlessChrome/80.0.3987.0 what about you

DEYROS commented 2 years ago

Could you please explain me how did you execute the index.js(node index.js or you create a script into package.json?) and where he is into your folder ?

elliotblackburn commented 2 years ago

Puppeteer is a dependency of mdpdf, so you don't need to install it seperately. I've pushed a branch with the latest puppeteer because we're very far behind.

Using mdpdf via cli (npm install -g mdpdf)

If you uninstall mdpdf globally npm uninstall -g mdpdf, pull this branch https://github.com/BlueHatbRit/mdpdf/pull/123 and then run npm install && npm link you'll pull down all the latest dependencies including my puppeteer upgrade. You'll also have mdpdf linked to your global installation so you can run it from the command line.

Using mdpdf via the js api

If you're using mdpdf in a nodejs project using a package.json you can use git://github.com/bluehatbrit/mdpdf.git#puppeteer-upgrade instead of the mdpdf version number and run an npm install which will pull in my branch.

You can then run the code provided by @nopeless to see if there's any difference.

nopeless commented 2 years ago

Could you please explain me how did you execute the index.js(node index.js or you create a script into package.json?) and where he is into your folder ?

That is just mdpdf's index.js. I ran the script in a clone of this repo and src/index.js should be identical to mdpdf in most cases

DEYROS commented 2 years ago

image The problem maybe come from my node_modules ? I have installed a lot of libraries how could I start from the begining(clear everything) and then install only mdpdf ? If I delete "node_modules" what happen ? What does this file do exactly ? Curently I have all this files open in vsCode and I execute index.js with node index.js in the integrated terminal : image

nopeless commented 2 years ago

image The problem maybe come from my node_modules ? I have installed a lot of libraries how could I start from the begining(clear everything) and then install only mdpdf ? If I delete "node_modules" what happen ? What does this file do exactly ? Curently I have all this files open in vsCode and I execute index.js with node index.js in the integrated terminal : image

node_modules is just how node manages external libraries

you should NOT delete that folder

elliotblackburn commented 2 years ago

If you're using the js api (as you seem to be with a node project) you should open your package.json and replace the mdpdf line's version number with git://github.com/bluehatbrit/mdpdf.git#puppeteer-upgrade. Then run npm install on the command line and re-run your code. That will put you on the experimental branch where I have just upgraded Puppeteer in mdpdf.

DEYROS commented 2 years ago

image image I should replace that :

"mdpdf": {
      "version": "1.7.3",
      "resolved": "https://registry.npmjs.org/mdpdf/-/mdpdf-1.7.3.tgz",
      "integrity": "sha512-yvLnXcg1j7JsaC1l1BNc7QUePOF5br8Oqi0lUu2NzysWbe2YKgSBWFi9V9/5X4rx2BjCHxD5+f5jLXkkN4t8qg==",
      "requires": {
        "bluebird": "^3.4.7",
        "cheerio": "^0.22.0",
        "file-url": "^2.0.2",
        "handlebars": "^4.0.6",
        "html-pdf": "^2.2.0",
        "loophole": "^1.1.0",
        "meow": "^3.7.0",
        "showdown": "^1.6.0",
        "showdown-emoji": "^1.0.3"
      }
    },

into that : git://github.com/bluehatbrit/mdpdf.git#puppeteer-upgrade

image Or the first one ?

nopeless commented 2 years ago

image image I should replace that :

"mdpdf": {
      "version": "1.7.3",
      "resolved": "https://registry.npmjs.org/mdpdf/-/mdpdf-1.7.3.tgz",
      "integrity": "sha512-yvLnXcg1j7JsaC1l1BNc7QUePOF5br8Oqi0lUu2NzysWbe2YKgSBWFi9V9/5X4rx2BjCHxD5+f5jLXkkN4t8qg==",
      "requires": {
        "bluebird": "^3.4.7",
        "cheerio": "^0.22.0",
        "file-url": "^2.0.2",
        "handlebars": "^4.0.6",
        "html-pdf": "^2.2.0",
        "loophole": "^1.1.0",
        "meow": "^3.7.0",
        "showdown": "^1.6.0",
        "showdown-emoji": "^1.0.3"
      }
    },

into that : git://github.com/bluehatbrit/mdpdf.git#puppeteer-upgrade

image Or the first one ?

package.json not package-lock you should never edit package-lock

DEYROS commented 2 years ago

Oh my bad, So I should make something like that ? image And run npm install and re run my code ?

elliotblackburn commented 2 years ago

Yep!

DEYROS commented 2 years ago

I did it but now I encounter a timeout how can I change this one ? image I already did it but don't remember

 _LifecycleWatcher_createTimeoutPromise = async function _LifecycleWatcher_createTimeoutPromise() {
    if (!__classPrivateFieldGet(this, _LifecycleWatcher_timeout, "f")) {
        return new Promise(noop);
    }
    const errorMessage = 'Navigation timeout of ' + __classPrivateFieldGet(this, _LifecycleWatcher_timeout, "f") + ' ms exceeded';
    await new Promise(fulfill => {
        return (__classPrivateFieldSet(this, _LifecycleWatcher_maximumTimer, setTimeout(fulfill, __classPrivateFieldGet(this, _LifecycleWatcher_timeout, "f")), "f"));
    });
    return new Errors_js_1.TimeoutError(errorMessage);
},
nopeless commented 2 years ago

I did it but now I encounter a timeout how can I change this one ? image I already did it but don't remember

 _LifecycleWatcher_createTimeoutPromise = async function _LifecycleWatcher_createTimeoutPromise() {
    if (!__classPrivateFieldGet(this, _LifecycleWatcher_timeout, "f")) {
        return new Promise(noop);
    }
    const errorMessage = 'Navigation timeout of ' + __classPrivateFieldGet(this, _LifecycleWatcher_timeout, "f") + ' ms exceeded';
    await new Promise(fulfill => {
        return (__classPrivateFieldSet(this, _LifecycleWatcher_maximumTimer, setTimeout(fulfill, __classPrivateFieldGet(this, _LifecycleWatcher_timeout, "f")), "f"));
    });
    return new Errors_js_1.TimeoutError(errorMessage);
},

Can you make your .md file smaller? Just to see whether footer will work. After fixing that problem, you can start working on figuring out how to increase navigation timeout

DEYROS commented 2 years ago

I make it smaller and : image image image It """""work"""" I don't really understand why there is not any css or even the image at the top

DEYROS commented 2 years ago

So when I have this I can saw the number of pages : image But the css isn't used anymore And when I have this : image The css is used but I can't see the number of pages hmmm interesting

nopeless commented 2 years ago

I make it smaller and : image image image It """""work"""" I don't really understand why there is not any css or even the image at the top

Hey at least its working

DEYROS commented 2 years ago

😂

elliotblackburn commented 2 years ago

In the puppeteer update I just did a blind update from v2 to v15 so I've not actually checked much but that the tests run. It could be that they process css differently now. It was always a real ballache because we had to hand in the CSS basically 3 times when I first integrated it.

It might be a case of just checking the docs to see how to pass in css now. IIRC last time I figured it out with trial and error as it wasn't well documented so there's a good chance it's changed now.

DEYROS commented 2 years ago

But actually the css is used but not completly as you can see the title are in red : image with the font "calibri" i just don't have the css on the footer and to the header

elliotblackburn commented 2 years ago

Headers and footers don't use the main document css, we have the inject it for the body, header, and footer seperately. It sounds like between v2 and v15 something was changed with how puppeteer handles those.

nopeless commented 2 years ago

@BlueHatbRit with that being said, the puppeteer bump should be released as a major version

elliotblackburn commented 2 years ago

I agree, I'll need to do some additional testing as well to ensure other scenarios still work.

I think it'd be wise to do the release after the final security upgrade as well. Meow requires the project to be using esmodules which has potential to slightly shift out API also. It's something I'm looking at but may take a bit. If it's going to take me longer than a week or so I may need to just do them separately though.

elliotblackburn commented 2 years ago

3.0.1 is released now which fixes the numbering, will continue to look into the styling issue when time permits though.