Search for text in PDFs on Android

To search text inside a document, create an instance of TextSearch, passing in the loaded PdfDocument via its constructor. The simplest way to retrieve search results is by calling TextSearch#performSearch(String), which will return a list of found SearchResult objects. If a search has no results, this method will return an empty list:

val textSearch = TextSearch(document, configuration)
val query = "Weather reports"
val searchResults : List<SearchResult> = textSearch.performSearch(query)

ℹ️ Note: #performSearch is a blocking call and should only be used on a background thread.

To keep the main thread operational and to avoid ANR dialogs while performing a search, you can use the non-blocking #performSearchAsync method, which will return a Flowable<SearchResult>(opens in a new tab). The flowable emits search results as soon as they are available — you can already use them during the ongoing search, e.g. to populate your search UI:

// Perform an async search on a computation thread and update the UI on the main thread.
val searchSubscription = search.performSearchAsync(query)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { nextResult ->
// This will be called once for every `SearchResult` object.
// Put your search result handling here.
}

💡 Tip: You can use Flowable#toList(opens in a new tab) to collect all search results if you want to handle them at once.

Specify search options

Both methods — #performSearch and #performSearchAsync — offer overloaded versions that take SearchOptions for specifying search options. Use this to limit search results or search result snippet length:

val options = SearchOptions.Builder()
.maxSearchResults(100)
.snippetLength(40)
.build()
val results = textSearch.performSearch(query, options)

ℹ️ Note: Calling #performSearch(String) without options will use default options.

Compare options

SearchOptions.Builder#compareOptions() can be used to tweak how the text search matches its results. A combination of the following options is possible.

Compare OptionDescription
CASE_INSENSITIVEText search ignores case when this option is used.
DIACRITIC_INSENSITIVEText search ignores diacritic when this option is used.
SMART_SEARCHEnables smart search. Smart search ignores white spaces and hyphens. It also resolves typographic quotes and apostrophes. For example, when searching for standard quotes or apostrophes, typographic variants such as “”«»„“ are also matched.
REGULAR_EXPRESSIONEnables regular expression search. When this option is used, the SMART_SEARCH option is ignored.

Nutrient uses a combination of CASE_INSENSITIVE, DIACRITIC_INSENSITIVE, and SMART_SEARCH compare options by default.

ℹ️ Note: TextSearch uses regular expression capabilities available in Java. Refer to the Pattern documentation(opens in a new tab) for the supported regular expression syntax.

Using search results

Every SearchResult consists of the pageNumber, a textBlock containing the PDF coordinates on the page, and an optional snippet containing a preview text usable for showing text around search matches in the user interface. For example, if you would like to zoom to a search result, you can do the following:

// The search result consists of at least one text rect. This will create a union of all of its rects.
val searchResultRect: RectF = PdfUtils.createPdfRectUnion(searchResult.textBlock.pageRects)
// This will also switch to the correct page if it is not active.
fragment.zoomTo(searchResultRect, searchResult.pageNumber, 200)

SearchResult#snippet can be used to present an upfront preview of the search result — for example, inside a search result list. The snippet consists of both the text and the rangeInSnippet, the latter of which gives the position of the actual result inside the snippet:

// Use the synthetic property for accessing a view from the layout.
import kotlinx.android.synthetic.main.activity_main.previewText
/**
* Sets the search result snippet to a TextView highlighting the actual search term inside the result.
*/
private fun showSearchResultText(result: SearchResult) {
// If you deactivated snippet extraction, it may be `null`.
val snippet = result.snippet ?: return
// This is the location of the search term inside the snippet.
val highlightStart = snippet.rangeInSnippet.startPosition
val highlightEnd = snippet.rangeInSnippet.endPosition
val previewText = SpannableString(snippet.text)
val resultHighlight = BackgroundColorSpan(Color.YELLOW)
previewText.setSpan(resultHighlight, highlightStart, highlightEnd, 0)
}

ℹ️ Note: The SearchResult#snippet may be null if you deactivated snippet extraction by setting the SearchOptions.Builder#snippetLength to 0.

Highlighting search results

To display search results on the PdfFragment, create a SearchResultHighlighter and register it with your fragment. Once you have a list of search results, you can start highlighting them by calling #setSearchResults on the highlighter:

lateinit var highlighter : SearchResultHighlighter
/** Holds your PdfFragment. You don't need to define this when using PdfActivity. */
val fragment: PdfFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// The context is used to retrieve the highlighter color from the theme.
highlighter = SearchResultHighlighter(context)
fragment.addDrawableProvider(highlighter)
}
/**
* Called by your application once a search is finished.
* The highlighter will immediately start highlighting the given results.
*/
fun onSearchFinished(searchResults : List<SearchResult>) = highlighter.setSearchResults(searchResults)

Emphasizing the selected result

You can emphasize a single, selected search result, which will reveal itself with a pop-out animation and receive an additional border. Note that you can only select a search result that was previously set on the highlighter using #setSearchResults(List<SearchResult>). Setting a search result that was not previously added will raise an exception:

/**
* Called by your application, e.g. if the user taps a search result inside a list.
*/
fun onSearchResultSelected(selectedResult : SearchResult) =
highlighter.setSelectedSearchResult(selectedResult)

ℹ️ Note: SearchResultHighlighter#setSelectedSearchResult also allows null as an argument, which will then clear any previously selected result.

Highlighter customization

The SearchResultHighlighter uses predefined colors and styles. If you want to change the appearance, you can apply a custom style to the pspdf__searchResultHighlighterStyle attribute of your activity theme:

<!-- This is the theme you set to your activity inside AndroidManifest.xml -->
<style name="MyApp_Theme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="pspdf__searchResultHighlighterStyle">@style/MyApp_Theme_SearchResultHighlighter</item>
</style>
<!-- This is a custom style for search result highlights. -->
<style name="MyApp_Theme_SearchResultHighlighter" parent="PSPDFKit.SearchResultHighlighter">
<item name="pspdf__searchResultBackgroundColor">#FF009999</item>
<item name="pspdf__searchResultBorderColor">#FF888888</item>
<item name="pspdf__searchResultBorderWidth">2px</item>
<item name="pspdf__searchResultPadding">2dp</item>
<item name="pspdf__searchResultAnnotationPadding">3dp</item>
<item name="pspdf__searchResultAnimationPadding">8dp</item>
<item name="pspdf__searchResultCornerRadiusToHeightRatio">0.1</item>
<item name="pspdf__searchResultCornerRadiusMin">2dp</item>
<item name="pspdf__searchResultCornerRadiusMax">10dp</item>
</style>

💡 Tip: Take a look at DarkThemeExample, which explains how to apply custom themes, including a custom search result highlighter style.

Below is a complete list of the style attributes you can define for the pspdf__searchResultHighlighterStyle.

AttributeDescription
pspdf__searchResultBackgroundColorBackground color of the highlighted search result.
pspdf__searchResultBorderColorBorder color of the highlighted search result.
pspdf__searchResultBorderWidthBorder width of the highlighted search result.
pspdf__searchResultPaddingPadding of the highlighted search result used when highlighting document text.
pspdf__searchResultAnnotationPaddingPadding of the highlighted search result used when highlighting annotations.
pspdf__searchResultAnimationPaddingPadding of the highlighted search result used when pop-out animating the currently selected search result.
pspdf__searchResultCornerRadiusToHeightRatioRatio between corner radius of the search result rectangle and its height.
pspdf__searchResultCornerRadiusMinMinimal corner radius of the highlighted search result.
pspdf__searchResultCornerRadiusMaxMaximal corner radius of the highlighted search result.