Although WebViewer is often used for document viewing and annotating, you might not realize that it also exposes a full PDF editing and manipulation API that previously would only have been possible on the server but now is available completely client side in the browser.

The full APIs sample page provides many code samples showing how to use these APIs and we'll walk through a few of them below.

linkModifying and saving the resulting file

The viewer preprocessing sample shows how to process a PDF file before loading it in the viewer. The entire sample code is located here and we'll go through key parts of it.

First we create the PDFDoc object from a URL:

var doc = yield PDFNet.PDFDoc.createFromURL(url);

Then replace the appearance for the stamp annotations in the document with our image:

switch (annotType) {
  case PDFNet.Annot.Type.e_Stamp:
  {
    // ...
    var apElement = yield apBuilder.createImageScaled(sigImg, 0, 0, w, h);
    // ...
    yield annot.setAppearance(apObj);
  }
  default:
    break;
}

Then we can view the PDFDoc object that we've modified directly in WebViewer by calling loadDocument and passing in the PDFDoc:

$(document).on('viewerLoaded', function() {
  PDFNet.initialize().then(function() {
    return runScript();
  }).then(function(doc) {
    readerControl.loadDocument(doc);
    console.log('finished script');
  });
});

If you press the download button in WebViewer then the downloaded PDF will have all the modifications that we made. If you want to get the file data as a blob from the PDFDoc you can use the following code:

doc.saveMemoryBuffer(PDFNet.SDFDoc.SaveOptions.e_linearized).then(function(docBuf) {
  var blob = new Blob([docBuf], { type: 'application/pdf' });
  // upload blob to server
});

linkConverting Office files to PDF

WebViewer is the only SDK in the world that can convert Office files to PDF without a server component or MS Office dependencies. Using the office2PDFBuffer function you can easily convert and then download office files without having to upload them to a server. Full sample code is here and you can see it running here.

var convertOfficeToPDF = function(input_url, outputName, l) {
  return PDFNet.Convert.office2PDFBuffer(input_url, { l: l }).then(function(buffer) {
    saveBufferAsPDFDoc(buffer, outputName);
    console.log('Finished downloading ' + outputName);
  });
};

PDFNet.initialize(l).then(function() {
  return convertOfficeToPDF(input_dir + docx_filename, 'converted_docx.pdf', l);
});

linkAdding images and text to a page

WebViewer allows adding stamp annotations to a document, but these are editable and resizable. What if you wanted to add an image so that it wasn't editable and actually became part of the document content?

Using PDFNet.ElementBuilder this can be done directly in the browser. We'll walk through parts of the code sample found here.

var builder = yield PDFNet.ElementBuilder.create();
var writer = yield PDFNet.ElementWriter.create();

// ...

writer.beginOnPage(page, PDFNet.ElementWriter.WriteMode.e_overlay);

We've created an ElementBuilder to build new elements and an ElementWriter to actually add them to the document. We can then add a jpg and png to the page:

// Adding a JPEG image to output file
var img = yield PDFNet.Image.createFromURL(doc, input_url + 'peppers.jpg');
var matrix = yield PDFNet.Matrix2D.create(200, 0, 0, 250, 50, 500);
var matrix2 = yield PDFNet.Matrix2D.createZeroMatrix();
yield matrix2.set(200, 0, 0, 250, 50, 500);
var element = yield builder.createImageFromMatrix(img, matrix2);
writer.writePlacedElement(element);

// Add a PNG to output file
img = yield PDFNet.Image.createFromURL(doc, input_url + 'butterfly.png');
var matrix = yield PDFNet.Matrix2D.create((yield img.getImageWidth()), 0, 0, (yield img.getImageHeight()), 300, 500);
element = yield builder.createImageFromMatrix(img, matrix);
writer.writePlacedElement(element);

Images added to PDF

We can add a number of other image formats (for example JPEG2000) and add text to the document as well:

img = yield PDFNet.Image.createFromURL(doc, input_url + 'palm.jp2');
matrix = yield PDFNet.Matrix2D.create((yield img.getImageWidth()), 0, 0, (yield img.getImageHeight()), 96, 80);
element = yield builder.createImageFromMatrix(img, matrix);
writer.writePlacedElement(element);

// write 'JPEG2000 Sample' text under image
var timesFont = yield PDFNet.Font.create(doc, PDFNet.Font.StandardType1Font.e_times_roman);
writer.writeElement(yield builder.createTextBeginWithFont(timesFont, 32));
element = yield builder.createTextRun('JPEG2000 Sample', timesFont, 32);
matrix = yield PDFNet.Matrix2D.create(1, 0, 0, 1, 190, 30);
element.setTextMatrix(matrix);// yield?
writer.writeElement(element);
var element2 = yield builder.createTextEnd();
writer.writeElement(element2);

Image and text added to PDF

The full running sample can be found here.

linkSelect elements of the page in a viewer

The ViewerDisplayPoints sample demonstrates how you can integrate with the full WebViewer APIs while viewing a document. When you click on an element of the page you'll see a bounding box and outline.

The sample code is extensive but we'll walk through a few key parts.

Setup a listener for mouse clicks to run the check for elements underneath:

documentViewer.getViewer()[0].addEventListener('mousedown', handleMouseClick);

Extracts the elements from the page:

function* ExtractElements(page_reader) {
  var elementArray = [];
  // Read page contents
  for (var element = (yield page_reader.next()); element !== null; element = (yield page_reader.next())) {
    // ...
    switch (elemType) {
      case PDFNet.Element.Type.e_path:
      // ...
      case PDFNet.Element.Type.e_image:
      // ...
    }
  }
  return elementArray;
}

Draws annotations at the location of the selected page element:

function* DrawPointAnnot(pageIndex, x, y) {
  var p1 = docCore.getViewerCoordinates(pageIndex, x, y);
  var p2 = docCore.getViewerCoordinates(pageIndex, x, y);
  p1.x -= 2;
  p1.y -= 2;
  p2.x += 2;
  p2.y += 2;
  var displayAnnot = new Annotations.RectangleAnnotation();
  displayAnnot.setPageNumber(pageIndex + 1);

  displayAnnot.FillColor = new Annotations.Color(255, 255, 0, 1);
  displayAnnot.StrokeColor = new Annotations.Color(255, 0, 0, 1);

  displayAnnot.setRect(new Annotations.Rect(p1.x, Math.min(p1.y, p2.y), p2.x, Math.max(p1.y, p2.y)));
  annotManager.addAnnotation(displayAnnot);
  prevAnnotations.push(displayAnnot);
}

Here's a picture from the viewer where you can see the points around the selected letter "e".

Display points aroune letter 'e'

The full running sample can be found here.

linkConclusion

The examples above are just scratching the surface of what's possible using WebViewer's full PDF APIs. Be sure to check out the samples and guides for more information.

If you have any questions about PDFTron's PDF SDK, please feel free to get in touch!