Some test text!

Discord Logo

Chat with us

PDFTron is now Apryse, learn more here.

Preprocess & modify documents before viewing

This JavaScript sample lets you preprocess and make modifications to a PDF, DOCX, XLSX or PPTX document before it is displayed in WebViewer (no servers or other external dependencies required). This is often used to fix corrupt PDF content or add watermarks to documents before displaying them. A common example of how this functionality is used occurs when user ID, timestamp and IP address is added to a document before loading to limit document sharing. In the case of MS Office files, modifications are applied to the PDF file. This sample works on all browsers (including IE11) and mobile devices without using plug-ins. Learn more about our JavaScript PDF Library.

Get Started Samples Download

To run this sample, get started with a free trial of Apryse SDK.



(exports => {
  const PDFNet = exports.Core.PDFNet;
  const runScript = () => {
    const ModAnnotations = async doc => {
      const imagefile = '../../samples/full-apis/TestFiles/grayscale.tif';

      await PDFNet.startDeallocateStack(); // start stack-based deallocation. All objects will be deallocated by end of function
      // The following code snippet traverses all annotations in the document
      console.log('Traversing all annotations in the document...');
      const apWriter = await PDFNet.ElementWriter.create();
      const apBuilder = await PDFNet.ElementBuilder.create();

      const sigImg = await PDFNet.Image.createFromURL(doc, imagefile);

      const itr = await doc.getPageIterator(1);
      let numMod = 0;

      for (itr; await itr.hasNext(); await {
        const page = await itr.current();
        const numAnnots = await page.getNumAnnots();

        for (let i = 0; i < numAnnots; ++i) {
          const annot = await page.getAnnot(i);
          if (!(await annot.isValid())) {

          const annotType = await annot.getType();
          switch (annotType) {
            case PDFNet.Annot.Type.e_Stamp: {
              const w = await sigImg.getImageWidth();
              const h = await sigImg.getImageHeight();
              let apElement = await apBuilder.createImageScaled(sigImg, 0, 0, w, h);
              let apObj = await apWriter.end();
              apObj.putRect('BBox', 0, 0, w, h);
              apObj.putName('Subtype', 'Form');
              apObj.putName('Type', 'XObject');
              apElement = await apBuilder.createFormFromStream(apObj);
              apObj = await apWriter.end();
              apObj.putRect('BBox', 0, 0, w, h);
              apObj.putName('Subtype', 'Form');
              apObj.putName('Type', 'XObject');
              await annot.setAppearance(apObj);
              numMod += 1;

      console.log('number of annotation modifications: ' + numMod);

      await PDFNet.endDeallocateStack();

    const main = async () => {
      let doc = null;

      try {
        // todo load a document from url
        const inputURL = '../../samples/full-apis/TestFiles/';
        const inputFilename = 'fish_stamped.pdf';
        const url = inputURL + inputFilename;
        console.log('loading document from url: ' + url);
        doc = await PDFNet.PDFDoc.createFromURL(url);
        console.log('loaded document from url: ' + url);
        // modify annotations
        await ModAnnotations(doc);
        // flatten annotations
        console.log('flattened document from url: ' + url);
        return doc;
      } catch (err) {
      } finally {
        if (doc) {
    // use "runWithoutCleanup" to lock the document data and run callback, use "with out cleanup" so data isn't cleared afterwards
    // add your own license key as the second parameter, e.g. PDFNet.runWithoutCleanup(main, 'YOUR_LICENSE_KEY')
    return PDFNet.runWithoutCleanup(main);

  window.addEventListener('viewerLoaded', () => {
      .then(() => runScript())
      .then(async doc => {
        console.log('finished script');
// eslint-disable-next-line spaced-comment
//# sourceURL=config.js