Search and Redact

A common workflow in WebViewer is a programatic search and redact - search a document for text and permanently removing it from the document.

There are four steps involved in setting up this workflow. This guide will walk you through each step and explain the core concepts in setting up this workflow.

Step 1 - Enable redaction

As mentioned in the setup redaction guide, there are a few parameters you need to pass to the WebViewer constructor to get redaction working. The two properties are fullAPI and enableRedaction.

In your WebViewer constructor call, ensure you are setting both those properties to true.

Enabling redaction in WebViewer

1WebViewer(
2 {
3 path: '/webviewer/lib',
4 fullAPI: true,
5 enableRedaction: true
6 },
7 document.getElementById('viewer'),
8)

Step 2 - Search for text

Once redactions are enabled, we can begin implementing our workflow by searching for the text we want to redact. The easiest way to do this is using the textSearchInit API.

This API accepts a string or a regex to search for, as well as some additional options and callbacks.

Using the textSearchInit function looks like this:

JavaScript

1const { documentViewer, Search } = instance;
2
3// The text to search for
4const searchText = "redact me"
5
6// Set the mode for the search. See the documentation for more options
7const modes = [Search.Mode.PAGE_STOP, Search.Mode.HIGHLIGHT];
8
9const searchOptions = {
10 // search the entire document
11 fullSearch: true,
12 onDocumentEnd: () => {
13 // called when search is complete
14 },
15 onResult: (result) => {
16 // called when a search result is found
17 console.log(result);
18 },
19}
20documentViewer.textSearchInit(searchText, modes, searchOptions);

There are a few main parts to look at here.

The mode parameter sets the search mode. There are many different options here, and you can set one or many search modes by passing them as an array. For example, if you wanted to use a wildcard ("*") in your search pattern, you would have to append the WILD_CARD mode like so:

JavaScript

1const modes = [Search.Mode.PAGE_STOP, Search.Mode.HIGHLIGHT, Search.Mode.WILD_CARD]

The searchOptions parameter lets you provide a set of callbacks and additional options for your search. A full list list of all the options can be seen here. In this workflow, we care about fullSearch, onResult, and onDocumentEnd.

You can also search for text using a regular expression by setting the REGEX search mode and passing in a regex expression as your search query. This would look something like this:

Searching via Regex

1const { documentViewer, Search } = instance;
2
3// The regex to search for
4const searchText = "text1|text2"
5
6// Set the mode for the search. See the documentation for more options
7const modes = [Search.Mode.PAGE_STOP, Search.Mode.HIGHLIGHT, Search.Mode.REGEX];
8const searchOptions = {
9 ...
10}
11
12documentViewer.textSearchInit(searchText, modes, searchOptions);

Step 3 - Create redactions

Now that we have our search code implemented, we can use the results of that search to programmatically create redaction annotations. This process involves using the onResult callback and using the result object to get the coordinates of the text we want to redact. Using these coordinates, we can place a redaction annotation on the document.

The implementation will look something like this:

Creating redaction annotations

1const { documentViewer, Search, annotationManager, Annotations } = instance;
2
3// The text to search for
4const searchText = "Redact me"
5
6// Set the mode for the search. See the documentation for more options
7const modes = [Search.Mode.PAGE_STOP, Search.Mode.HIGHLIGHT];
8
9const searchOptions = {
10 // search the entire document
11 fullSearch: true,
12 onDocumentEnd: () => {
13 // called when search is complete
14 },
15 onResult: (result) => {
16 if (result.resultCode === Search.ResultCode.FOUND) {
17
18 // Get the page number and the quads for the search result
19 const { pageNum, quads } = result;
20
21 // Create a new redaction annotation using the quads and page number
22 const redactAnnot = new Annotations.RedactionAnnotation({
23 PageNumber: pageNum,
24 Quads: quads.map((quad) => quad.getPoints())
25 });
26
27 // Apply and redraw the redaction annotation
28 annotationManager.addAnnotations([redactAnnot]);
29 annotationManager.drawAnnotationsFromList([redactAnnot]);
30 }
31 },
32}
33documentViewer.textSearchInit(searchText, modes, searchOptions);
34

At this point, you should be able to search for text and place a redaction annotation on top of all the results. The last step is to apply those redactions to permanently remove the text from the document.

Step 4 - Apply redactions

At this point we have only placed redaction annotations on the document and have not actually removed the content from the underlying document. To do the actual content removal, we need to "apply" the redactions.

To do this, we can call the annotationManager.applyRedactions API, passing in all the redactions we created in step 3.

We want to do this after the search is complete, so we can add the code into the onDocumentEnd callback.

Applying redactions

1const { documentViewer, Search, annotationManager, Annotations } = instance;
2
3// The text to search for
4const searchText = "Redact me"
5
6// Set the mode for the search. See the documentation for more options
7const modes = [Search.Mode.PAGE_STOP, Search.Mode.HIGHLIGHT];
8
9const searchOptions = {
10 // search the entire document
11 fullSearch: true,
12 onDocumentEnd: () => {
13 // get all the redaction annotations on the document and apply them
14 const redactionList = annotationManager.getAnnotationsList().filter(annot => annot instanceof Annotations.RedactionAnnotation);
15 annotationManager.applyRedactions(redactionList)
16 },
17 onResult: (result) => {
18 // onResult code from previous steps omitted for brevity
19 },
20}
21
22documentViewer.textSearchInit(searchText, modes, searchOptions);

After calling the above code, the redactions should be applied to the underlying document and the text you searched for should be permanently removed!

Next steps

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales