bpampuch / pdfmake

Client/server side PDF printing in pure JavaScript
http://pdfmake.org
Other
11.7k stars 2.04k forks source link

Set custom size and margin for each page #325

Open diegito opened 9 years ago

diegito commented 9 years ago

I need to set my own margins and dimensions for each page. I managed to do that for the whole document but not for a single page.

Could you point out where I need to change the code? Kind of the same way we change the page orientation, but for the size.

Or is there any other way to do it? I'm developing a front-end app so cannot use nodejs.

Thanks

diegito commented 9 years ago

I believe I can add something here https://github.com/bpampuch/pdfmake/blob/master/build/pdfmake.js#L15090 inside DocumentContext.prototype.moveToNextPage

I'll try to play around some more...

diegito commented 9 years ago

To allow for custom dimensions, I've included these parameters to be added at the beginning of the document definition.

if (!docDefinition.pageSize && docDefinition.pageCustomWidth && docDefinition.pageCustomHeight) {
  pageSize = { width: docDefinition.pageCustomWidth, height: docDefinition.pageCustomHeight }
} else 
  pageSize = pageSize2widthAndHeight(docDefinition.pageSize || 'a4');

If pageSize is not defined but pageCustomWidth and pageCustomHeight are, the document's pages will have those dimensions set.

This works for all the pages though. Looking for a solution that customizes the size of every single page in the document.

diegito commented 9 years ago

Would it be possible to have some leads on the pieces of code that I can edit to obtain this result? I tried several solutions but till now they all failed..

If you could give me some insight on what section of the code deals with the new pages and how the size is passed I can try to hack a bit :)

I'm using pdfmake for a project and I need to have it done... thanks for any help!

jthoenes commented 9 years ago

The trouble is, there is not a single piece of code you need to touch. It's a bit spread through the code.

The page is created internally here: https://github.com/bpampuch/pdfmake/blob/master/src/documentContext.js#L194 And for the pdfkit output, here: https://github.com/bpampuch/pdfmake/blob/master/src/printer.js#L118 and here https://github.com/bpampuch/pdfmake/blob/master/src/printer.js#L183

But because we have tables and column contexts spanning across pages, it's not that simple. Have a look at initializePage in DocumentContext - it's also re-using the page, when another column already has been there.

That's everything from the top of my mind.

diegito commented 9 years ago

Thanks, I'll try something and let you know how it goes...

Raven24 commented 9 years ago

I'd be interested in that kind of functionality, too. In my usecase it would even be sufficient if I could just print multiple document definitions into the same pdf as seperate pages - so in my understanding of how the layout works, there would be no need to handle flowing content onto different-sized pages. I would just like to specify pageSize per document definition and get a pdf with every document on a new page with the specified attributes. ... don't know if that would reduce the amount of work necessary to get it implemented.

pianetarosso commented 6 years ago

Hi, I need this feature to show some parts of a document in A3. There are any updates?

pianetarosso commented 5 years ago

Hi, I've set up a simple way to create a document in multiple page sizes. Two notes about it:

I've worked directly on sources for version 1.4.

First, when generating contents, I added the property pageSize to identify the page size of the element, like 'a4' or 'a3'.

Then file src/browser-extensions/pdfMake.js line ~32 is changed as following:

Document.prototype._createDoc = function (options, callback) {
    options = options || {};
    if (this.tableLayouts) {
        options.tableLayouts = this.tableLayouts;
    }
    var printer = new PdfPrinter(this.fonts);
    require('fs').bindFS(this.vfs); // bind virtual file system to file system

    let contestBackup = this.docDefinition.content.slice(); // backup of contents of the document
    let originalFooter = this.docDefinition.footer; // backup of the footer function 

        // generates an array from document's content, grouped by page size
    let contentsArray = this.docDefinition.content.reduce((acc, c) => {
        if (acc.length === 0 || (c.pageSize && acc[acc.length - 1].size !== c.pageSize)) {
            acc.push({size: c.pageSize, content: []});
        }
        acc[acc.length - 1].content.push(c);
        return acc;
    }, []);

    var doc = undefined; // doc generated by pdfKit
    var total = 0; //total number of pages of the document

    contentsArray.map(c => { // we must do this first cycle to obtain the page numbers
        this.docDefinition.pageSize = c.size; // forcing the size of the document to the subset of the content
        this.docDefinition.content = c.content; // forcing the subset of the content
        doc = printer.createPdfKitDocument(this.docDefinition, options, doc); // this method has been changed to get in input also a pre-existing doc instead of generating a new one every time
        let range = doc.bufferedPageRange();
        c.start = total; // we keep track of the start point of pages of this subset of the document
        total = range.start + range.count; // updating the max number of pages
    });

    var doc = undefined; // resetting the doc
    contentsArray.map(c => { // second cycle, with correct page numbers
        this.docDefinition.pageSize = c.size; // forcing the size of the document to the subset of the content
        this.docDefinition.content = c.content; // forcing the subset of the content
        this.docDefinition.footer = (currentPage, pageCount) => { //override of footer function
            return originalFooter(currentPage + c.start, total);
        };
        doc = printer.createPdfKitDocument(this.docDefinition, options, doc); // this method has been changed to get in input also a pre-existing doc instead of generating a new one every time
    });

    // restoring old values, otherwise subsequentials doc generation will be messed up
    this.docDefinition.content = contestBackup;
    this.docDefinition.footer = originalFooter;
    this.docDefinition.pageSize = undefined;
        .....

And also the file /src/printer.js at line ~85

// added the capability to get an original doc in input
PdfPrinter.prototype.createPdfKitDocument = function (docDefinition, options, doc = undefined) {
    options = options || {};

    var pageSize = fixPageSize(docDefinition.pageSize, docDefinition.pageOrientation);
    var compressPdf = isBoolean(docDefinition.compress) ? docDefinition.compress : true;
    var bufferPages = options.bufferPages || false;

    if (doc) { // if we passed a doc, we set it and update the pageSize
        this.pdfKitDoc = doc;
        this.pdfKitDoc.options.size = [pageSize.width, pageSize.height];
    }
    else { // original flow
        this.pdfKitDoc = PdfKitEngine.createPdfDocument({
            size: [pageSize.width, pageSize.height],
            bufferPages: bufferPages,
            autoFirstPage: false,
            compress: compressPdf
        });
        setMetadata(docDefinition, this.pdfKitDoc);
        this.fontProvider = new FontProvider(this.fontDescriptors, this.pdfKitDoc);
         }
         ...

Currently this solution seems to work well also with tables and images. Hope that someone else find this useful.

Best Regards

mmpatel78 commented 2 years ago

Hi.. All.. need a Help. i want to have pageMargins dynamically to be set for footer.. if there is more than one page i need pageMargins for the first page to be as [40,15,40,60] and for the another page it should be like [40,15,40,250] as in the footer i need to mention some text and images.. as i tried here but couldn't found the solution or else i am missing out something.. so if anyone know the solution.. for this kind of thing.. I would be grateful