foliojs / pdfkit

A JavaScript PDF generation library for Node and the browser
http://pdfkit.org/
MIT License
9.82k stars 1.15k forks source link

Adding content at the beginning after switching page #370

Closed MathieuLoutre closed 7 years ago

MathieuLoutre commented 9 years ago

Switching pages in 0.7.0 is very handy, and solves a lot of problems. However, to add a watermark (e.g. transparent background image) it's proving to be a little more complicated.

I had a quick look at the code and how content was added to each page before they're flushed but if I understand correctly, it's actually written just not "finished", so there's no way to go back.

In this case, would it be a good idea to add another stream, on the same page, which would be written before the main stream and to which you could add content after switching. I'm not sure about the feasibility because the PDF format seems pretty complicated, but maybe it's an option?

devongovett commented 9 years ago

You're correct. Commands are written directly to a buffer, so later drawing commands appear on top of previously drawn content.

I guess you can't write the watermark before the rest of your page's content? If not, you may need to do a two pass rendering process where you lay out your content first, then write it to a PDF second once you know where everything needs to go.

MathieuLoutre commented 9 years ago

In my case, I could have the watermark before the content (say a background image with a little transparency). However, yes, I do need to know how long the document is going to run (procedurally generated with different length of texts, etc.) to create all the pages beforehand and then switch back to the first to write it all.

I know this has been suggested before, but maybe a solution to that is am optional hook called when the page is created? This way, no need to know the length in advance etc. Helpful for headers etc.

devongovett commented 9 years ago

Yes, we should add an event when a page is added. Especially necessary when pages are created for you automatically by text wrapping.

MathieuLoutre commented 9 years ago

Would you be interested in a PR? Not sure if I'll be able to do it, but I can have a go!

devongovett commented 9 years ago

Sure, should be fairly simple. Just emit an event before the end of document.addPage.

MathieuLoutre commented 9 years ago

Sorry, just had the time to look into this now. I haven't submitted a PR yet, because I'd like to check this is ok first (and I haven't written the docs to go with it).

My first solution was to have afterAddPage as a optional function, called just before the end of addPage: https://github.com/MathieuLoutre/pdfkit/blob/new-page-hook/lib/document.coffee#L102

The reason I did this was that I'm not sure how to handle the events correctly. I looked into using events and EventEmitter, exposing the latter to be able to listen on, which would result in a call like this doc.eventEmitter.on('addPage', afterAddPageCustomFunction). However, I don't know how this can work for the first addPage which is called automatically, before the instance would be available to listen on. Basically, as far as I did it, you'd always miss the first addPage event.

Any thoughts on this? Am I doing this entirely wrong?

devongovett commented 9 years ago

The reason it should be an event is that you might want to have multiple functions do something when a page is added. But yes, the first page is a problem. There was talk of adding an autoFirstPage: false option, that wouldn't automatically add the first page for you. Alternatively, you could just call the function yourself manually immediately after creating the document.

MathieuLoutre commented 9 years ago

Makes sense. With the new option that's been merged, the event system makes sense. I'll have a go on another branch and submit a PR.

sly7-7 commented 5 years ago

Is there a way to remove the listener ? For example I want to add some background image only when pages are created for me automatically by text wrapping.