galkahana / HummusJS

Node.js module for high performance creation, modification and parsing of PDF files and streams
http://www.pdfhummus.com
Other
1.15k stars 170 forks source link

Changing existing page margins #132

Closed krulik closed 7 years ago

krulik commented 7 years ago

Hi Gal, we're Augury, located @ Haifa. Our favourite hummus in the area is Abu Shaker and our favourite pdf lib is HummusJS :)

We're trying to use your great tool to post-process a pdf (generated with NightmareJS). We're adding an image at the footer of every page, and to leave enough space for it we're using CSS @page { margin ... }.

(We can't add the space inside the page since it won't be rendered when there's a page break inside).

Problem is the @page margins are causing an issue with repeating table headers (https://github.com/segmentio/nightmare/issues/958) and we'd like to generate the margins too in the post-process stage with HummusJS.

I saw this issue ( #82 ) but couldn't understand whether and how can I create a margin around existing content in the page?

When using the ModifyingExistingFileContent code the MediaBox objects for our pages are empty.

Our code so far:

function addFooter() {
  var fileName = '...';

  var pdfReader = hummus.createReader(fileName);
  var numPages = pdfReader.getPagesCount();
  var pdfWriter = hummus.createWriterToModify(fileName);

  var dimensions = pdfWriter.getImageDimensions(logoFileName);

  for (var i = 0; i < numPages; i++) {
    drawFooterInPage(pdfWriter, i, dimensions);
    ModifyingExistingFileContent(i);
  }
  pdfWriter.end();
}

function drawFooterInPage(pdfWriter, page, dimensions) {
  var pageModifier = new hummus.PDFPageModifier(pdfWriter, page, true);

  var pageWidth = 72 * 8.5;

  var x = pageWidth - dimensions.width * 0.75;
  var y = 20;

  var ctx = pageModifier.startContext().getContext();
  ctx.drawImage(0, 0, logoFileName, {
    transformation: [0.5, 0, 0, 0.5, x, y]
  });
  pageModifier.endContext().writePage();
}

function ModifyingExistingFileContent(page) {
  var fileName = '...';
  var outFileName = '...';
  var inPDFWriter = hummus.createWriterToModify(fileName, {modifiedFilePath: outFileName});

  var copyingContext = inPDFWriter.createPDFCopyingContextForModifiedFile();
  var thirdPageID = copyingContext.getSourceDocumentParser().getPageObjectID(page);
  var thirdPageObject = copyingContext.getSourceDocumentParser().parsePage(page).getDictionary().toJSObject();
  var objectsContext = inPDFWriter.getObjectsContext();

  objectsContext.startModifiedIndirectObject(thirdPageID);
  var modifiedPageObject = inPDFWriter.getObjectsContext().startDictionary();
  console.log(`modifiedPageObject ${page}`, modifiedPageObject);

  Object.getOwnPropertyNames(thirdPageObject).forEach(function (element, index, array) {
    console.log('key=', element);
    console.log('value=', thirdPageObject[element])
    if (element != 'MediaBox') {
      modifiedPageObject.writeKey(element);
      copyingContext.copyDirectObjectAsIs(thirdPageObject[element]);
    }
  });
  modifiedPageObject.writeKey('MediaBox');
  objectsContext
    .startArray()
    .writeNumber(0)
    .writeNumber(0)
    .writeNumber(500)
    .writeNumber(500)
    .endArray()
    .endLine()
    .endDictionary(modifiedPageObject)
    .endIndirectObject();
}
krulik commented 7 years ago

UPDATE: Forgot to add the inPDFWriter.end(); from the after clause. Together with getMediaBox to have the current margins it seems to have an effect. Will post a final update after everything's working.

galkahana commented 7 years ago

Seems like you're on the right track. Good luck :)