Search for text in PDFs on Android
Create a TextSearch instance with the loaded PdfDocument. Call TextSearch#performSearch(String) to retrieve a list of SearchResult objects. The method returns an empty list when it finds no matches:
val textSearch = TextSearch(document, configuration)val query = "Weather reports"val searchResults : List<SearchResult> = textSearch.performSearch(query)final TextSearch textSearch = new TextSearch(document, configuration);final String query = "Weather reports";final List<SearchResult> searchResults = textSearch.performSearch(query);Call #performSearch only on a background thread because it blocks until the search completes.
Asynchronous search
Use #performSearchAsync to avoid blocking the main thread and triggering Application Not Responding (ANR) dialogs. The method returns a Flowable<SearchResult>(opens in a new tab) that emits results as it finds them. Update your search UI while the search continues:
// Perform an async search on a computation thread and update the UI on the main thread.val searchSubscription = textSearch.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. }// Perform an async search on a computation thread and update the UI on the main thread.final Disposable searchSubscription = textSearch.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. });Use Flowable#toList(opens in a new tab) to collect all search results for processing together.
Specify search options
Both #performSearch and #performSearchAsync accept SearchOptions. Use these options to limit the number of results or the snippet length:
val options = SearchOptions.Builder() .maxSearchResults(100) .snippetLength(40) .build()
val results = textSearch.performSearch(query, options)final SearchOptions options = new SearchOptions.Builder() .maxSearchResults(100) .snippetLength(40) .build();
final List<SearchResult> results = textSearch.performSearch(query, options);Calling #performSearch(String) without options uses the defaults.
Compare options
Use SearchOptions.Builder#compareOptions() to configure matching. Combine the following options as needed:
| Compare Option | Description |
|---|---|
| CASE_INSENSITIVE | Ignores case. |
| DIACRITIC_INSENSITIVE | Ignores diacritics. |
| SMART_SEARCH | Ignores whitespace and hyphens. Matches typographic quotes and apostrophes, such as “”«»„“, when searching for standard equivalents. |
| REGULAR_EXPRESSION | Enables regular expression search and overrides SMART_SEARCH. |
Nutrient uses a combination of CASE_INSENSITIVE, DIACRITIC_INSENSITIVE, and SMART_SEARCH compare options by default.
TextSearch uses Java regular expressions. Refer to the Pattern documentation(opens in a new tab) for supported syntax.
Using search results
Each SearchResult contains these properties:
- Page index —
pageIndexidentifies the page. - Text block —
textBlockcontains the match’s PDF coordinates. - Snippet — The optional
snippetcontains surrounding text for a preview.
To zoom to a search result, use its page coordinates:
// 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.pageIndex, 200)// The search result consists of at least one text rect. This will create a union of all of its rects.final RectF searchResultRect = PdfUtils.createPdfRectUnion(searchResult.textBlock.pageRects);// This will also switch to the correct page if it is not active.fragment.zoomTo(searchResultRect, searchResult.pageIndex, 200);Use SearchResult#snippet to preview a match, such as in a results list. The snippet contains text and rangeInSnippet, which identifies the match’s position within that text:
// This has to be inflated from your layout before using it.private lateinit var previewText: TextView
/** * 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 highlightedText = SpannableString(snippet.text) val resultHighlight = BackgroundColorSpan(Color.YELLOW) highlightedText.setSpan(resultHighlight, highlightStart, highlightEnd, 0) previewText.text = highlightedText}// This has to be inflated from your layout before using it.private TextView previewText;
/** * Sets the search result snippet to a TextView highlighting the actual search term inside the result. */private void showSearchResultText(@NonNull final SearchResult result) { // If you deactivated snippet extraction, it may be `null`. if (result.snippet == null) return;
// This is the location of the search term inside the snippet. final int highlightStart = result.snippet.rangeInSnippet.getStartPosition(); final int highlightEnd = result.snippet.rangeInSnippet.getEndPosition();
final SpannableString highlightedText = new SpannableString(result.snippet.text); final BackgroundColorSpan resultHighlight = new BackgroundColorSpan(Color.YELLOW); highlightedText.setSpan(resultHighlight, highlightStart, highlightEnd, 0); previewText.setText(highlightedText);}Setting SearchOptions.Builder#snippetLength to 0 disables snippet extraction, so SearchResult#snippet can be null.
Highlighting search results
To highlight results on PdfFragment, follow these steps:
- Create a
SearchResultHighlighter. - Register the highlighter with your fragment.
- Pass the results to
#setSearchResults.
The following example sets up the highlighter:
lateinit var highlighter : SearchResultHighlighter
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState)
// The context is used to retrieve the highlighter color from the theme. highlighter = SearchResultHighlighter(this) // This is possible in all `PdfActivity` subclasses. // If you aren't using `PdfActivity`, add the highlighter to your own `PdfFragment` instead. requirePdfFragment().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)private SearchResultHighlighter highlighter;
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
// This is possible in all `PdfActivity` subclasses. // If you aren't using `PdfActivity`, replace this with your own code. final PdfFragment fragment = getPdfFragment();
// The context is used to retrieve the highlighter color from the theme. highlighter = new SearchResultHighlighter(this); fragment.addDrawableProvider(highlighter);
// ...}
/** * Called by your application once a search is finished. */private void onSearchFinished(@NonNull final List<SearchResult> searchResults) { // The highlighter will immediately start highlighting the given results. highlighter.setSearchResults(searchResults);}Emphasizing the selected result
Selecting a result adds a border and a pop-out animation. Select only results previously added through #setSearchResults(List<SearchResult>). Selecting another result throws 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)/** * Called by your application, e.g. if the user taps a search result inside a list. */private void onSearchResultSelected(@NonNull final SearchResult selectedResult) { highlighter.setSelectedSearchResult(selectedResult);}Pass null to SearchResultHighlighter#setSelectedSearchResult to clear the selection.
Highlighter customization
SearchResultHighlighter uses predefined colors and styles. To change its appearance, set pspdf__searchResultHighlighterStyle in your activity theme:
<!-- This is the theme you set to your activity inside AndroidManifest.xml --><style name="MyApp_Theme" parent="PSPDFKit.Theme.Default"> <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>For custom themes and highlighter styles, refer to the appearance styling guide.
The following table lists the attributes for pspdf__searchResultHighlighterStyle.
| Attribute | Description |
|---|---|
pspdf__searchResultBackgroundColor | Background color of the highlighted search result. |
pspdf__searchResultBorderColor | Border color of the highlighted search result. |
pspdf__searchResultBorderWidth | Border width of the highlighted search result. |
pspdf__searchResultPadding | Padding of the highlighted search result used when highlighting document text. |
pspdf__searchResultAnnotationPadding | Padding of the highlighted search result used when highlighting annotations. |
pspdf__searchResultAnimationPadding | Padding of the highlighted search result used when pop-out animating the currently selected search result. |
pspdf__searchResultCornerRadiusToHeightRatio | Ratio between corner radius of the search result rectangle and its height. |
pspdf__searchResultCornerRadiusMin | Minimal corner radius of the highlighted search result. |
pspdf__searchResultCornerRadiusMax | Maximal corner radius of the highlighted search result. |