Have you ever come across a converted PDF document and noticed a typo or something out of date, like a heading, title, or revision number? How do we correct this? One approach is to find the original DOCX format file. If the original is unavailable, you might convert from PDF back to Office using a converter such as the PDFTron PDF to Word component or a free web-based tool like PDF.online.

However, this approach is inefficient in many professional workflows, not to mention less secure; first, your users have to jump through several hoops using various tools to edit, convert, and upload the file as a new version. Second, converting to and from formats with most converters likely results in some changes, so the edited file will not look like the original.

WebViewer solves this problem by allowing users to edit PDFs and MS Office documents directly in the browser without losing information or having sensitive data leave your application.

Let’s look at how.

Edit Text in a PDF with WebViewer UI

Beginning with version 8.3, WebViewer allows editing of PDF text with an out-of-the-box UI.

To enable editing functionality, go in the callback function when WebViewer initializes, and select ‘enable content edit button’:

Webviewer({`
  path: '/lib',
  preloadWorker: 'contentEdit'
}, document.getElementById('viewer')).then(async instance => {
  instance.UI.enableElements(['contentEditButton']);
});

Notice the new constructor option that allows you to preload a PDF text editing worker. This improves the user experience, if you know that users will be editing text, and can reduce loading times. After you have enabled the button, you will see a new edit tool under the edit tab.

select-paragraph

You can now select any paragraph and either resize, delete, or edit the text.

detect-styles

The styles are automatically detected and selected. You can now enter new text and toggle styling options like Bold, Italic or Underline. More styles and font selections are coming soon.

To save or persist the edits, simply exit the edit mode, and the text will be updated.

WebViewer also detects any embedded images and allows users to select, resize and reposition images. This is extremely useful when there is more content on-page like when a logo needs to be repositioned, for example.

The fonts and styling are preserved between edits. One of the most popular PDF optimization techniques is to strip font characters and font families that are not in use. In this case, when a user enters the edit mode and types a character that is not embedded in a PDF, you can utilize a font substitution logic that will pick a font from the same font family.

Edit PDF Text Programmatically

WebViewer allows editing text via APIs that can be utilized to perform edits programmatically or help you build your own UI. Let’s preload the worker and enter the edit mode.

Core.ContentEdit.preloadWorker(myDocumentViewer);

const contentEditTool = myDocumentViewer.getTool(Core.Tools.ToolNames.CONTENT_EDIT);

myDocumentViewer.setToolMode(contentEditTool);

The editable areas or paragraphs are annotations drawn on top of a PDF. You can either loop over the annotations or get the selected annotation and check if it is editable.

// is the currently selected annotation a placeholder

const selectedAnnotation = annotationManager.getSelectedAnnotations()[0];

if (selectedAnnotation && selectedAnnotation.isContentEditPlaceholder()) {

  const content = await Core.ContentEdit.getDocumentContent(selectedAnnotation);

  // pass content to library that can display rich text, for example Quill

}

// later after the content has been updated this will update it on the page

await Core.ContentEdit.updateDocumentContent(annotation, newContent);

The content of the annotation is editable HTML with inline styling. You can edit however you like and then update the annotation.

If you want to differentiate between editable text area or image, you can do so by calling getContentEditType.

if (annotation.getContentEditType() === Core.ContentEditTypes.TEXT) {

  // this has text that can be updated

}

You can also move the editable areas, paragraphs or images:

annotationManager.deleteAnnotation(myContentEditAnnotation);

myOtherContentEditAnnotation.X = 50;

annotationManager.trigger(Core.AnnotationManager.Events.ANNOTATION_CHANGED, ['modify', [myOtherContentEditAnnotation], {}]);

Events for Text Edits

You can set up analytics or have an audit trail for paragraphs or areas that have been edited. Since the editable areas are just annotations with HTML, you can tap into the same events.

const { Core } = instance;

  const { annotationManager } = Core;

  annotationManager.addEventListener(

    'annotationChanged',

    (annotations, action) => {

      annotations.forEach(async (annot) => {

        if (annot.isContentEditPlaceholder()) {

          const content = await Core.ContentEdit.getDocumentContent(annot);

          console.log(content);

        }

      });

    }

  );

The annotation has properties on who made the change and when your implementation is necessary.

More Key Information

You can count on your edits with this component to write into documents accurately.

Nevertheless, users will be presented with a warning when entering edit mode for the very first time.

warning

After a user enters edit mode, existing annotations may no longer display as expected. This is because, in PDF, annotations get drawn over top of page content as a separate layer, with positioning tracked through a coordinate system. Annotations have an additional property that contains text selected at the moment of selection – a static snapshot of content that allows for preview generation. Therefore, should the page underneath an annotation change because a user edits, the annotation and its contents will not be updated, resulting in changes of its placement relative to text, or preview content differing from what’s actually in the underlying document.

Wrap up

This is just the beginning for PDF and MS Office text editing, with more features being worked on as you read this blog. Please let us know if you have any questions or feedback by reaching out directly to me.