PDF renderer library for Android
Use Nutrient and PdfDocument to render PDF pages into Bitmap(opens in a new tab) objects for custom app views.
Initializing Nutrient
Initialize Nutrient before loading or rendering a document. By default, Nutrient initializes at app startup using the license key in AndroidManifest.xml. For details and manual initialization, refer to the initializing Nutrient guide.
Loading a document
PdfDocumentLoader loads documents from a Uri(opens in a new tab) or DataProvider. For supported sources, refer to the PdfActivity guide.
The following example loads a PDF from the app’s assets:
val document : PdfDocument
try { // Use this `Uri` format to access files inside your app's assets. val documentUri = Uri.parse("file:///android_asset/shopping-center-plan.pdf")
// This synchronously opens the document. To keep your app UI responsive, you should do this call // on a background thread, or use the asynchronous version of this method instead. document = PdfDocumentLoader.openDocument(context, documentUri)} catch (e : IOException) { handleDocumentLoadingError(e) return}final PdfDocument document;
try { // Use this `Uri` format to access files inside your app's assets. final Uri documentUri = Uri.parse("file:///android_asset/shopping-center-plan.pdf");
// This synchronously opens the document. To keep your app UI responsive, you should do this call // on a background thread, or use the asynchronous version of this method instead. document = PdfDocumentLoader.openDocument(context, documentUri);} catch (IOException e) { handleDocumentLoadingError(e); return;}Use the loaded PdfDocument to render its pages.
Rendering pages
PdfDocument provides #renderPageToBitmap for synchronous rendering and #renderPageToBitmapAsync for asynchronous rendering.
Synchronous rendering
Use #renderPageToBitmap to render a page into a Bitmap(opens in a new tab) synchronously. These methods block until rendering completes, so call them only on a background thread.
Calculate bitmap dimensions from the original PageSize in PDF points to preserve the page’s aspect ratio:
val pageIndex = 0// Page size is in PDF points (not pixels).val pageSize : Size = document.getPageSize(pageIndex)// We define a target width for the resulting bitmap and use it to calculate the final height.val width = 2048val height = (pageSize.height * (width / pageSize.width)).toInt()
// This will render the first page uniformly into a bitmap with a width of 2,048 pixels.val pageBitmap : Bitmap = document.renderPageToBitmap(context, pageIndex, width, height)final int pageIndex = 0;// Page size is in PDF points (not pixels).final Size pageSize = document.getPageSize(pageIndex);// We define a target width for the resulting bitmap and use it to calculate the final height.final int width = 2048;final int height = (int) (pageSize.height * (width / pageSize.width));
// This will render the first page uniformly into a bitmap with a width of 2,048 pixels.final Bitmap pageBitmap = document.renderPageToBitmap(context, pageIndex, width, height);Asynchronous rendering
Use #renderPageToBitmapAsync to render without blocking. It returns an RxJava Single<Bitmap>(opens in a new tab) that emits the bitmap when rendering completes.
Rendering runs on a background thread by default, so you can call this method from the main thread:
// Render the page on a background thread and return the resulting bitmap on the main thread.document.renderPageToBitmapAsync(context, pageIndex, width, height) .observeOn(AndroidSchedulers.mainThread()) .subscribe { bitmap -> // Your code can now use the bitmap. updateUserInterface(bitmap) }// Render the page on a background thread and return the resulting bitmap on the main thread.document.renderPageToBitmapAsync(context, pageIndex, width, height) .observeOn(AndroidSchedulers.mainThread()) .subscribe(bitmap -> { // Your code can now use the bitmap. updateUserInterface(bitmap); });Providing a render configuration
Both rendering methods accept PageRenderConfiguration. Create it with Builder to configure these options:
- Control memory and disk caching with
cache, or only disk caching withdiskCache. - Render a specific
region, such as the upper half of a page. - Reuse a bitmap with
reuseBitmapto reduce memory allocation. - Set background color, grayscale, sepia, or color inversion.
- Add overlays, such as watermarks, with
renderedDrawables.
For overlays, refer to the drawable API guide. The following example renders in grayscale:
val renderConfig = PageRenderConfiguration.Builder() .toGrayscale(true) .build()
val grayscaleBitmap : Bitmap = document.renderPageToBitmap(context, pageIndex, width, height, renderConfig)final PageRenderConfiguration renderConfig = new PageRenderConfiguration.Builder() .toGrayscale(true) .build();
final Bitmap grayscaleBitmap = document.renderPageToBitmap(context, pageIndex, width, height, renderConfig);Rendering a specific part of a page
Use PageRenderConfiguration.Builder#region() to render part of a page.
The following example renders the currently visible region:
// You can get all visible pages from `pdfFragment.visiblePages`.val somePageIndex = ...
// In order to render just a part of the page, you first need the visible rect.val currentVisibleRect = RectF()
// This saves the visible rect in PDF coordinates to `currentVisibleRect`.pdfFragment.getVisiblePdfRect(currentVisibleRect, somePageIndex)
// Define a desired width for the bitmap in pixels.val bitmapWidth = 2000
// Now calculate the height, keeping the aspect ratio of the bitmap as the visible area.val ratio = bitmapWidth / currentVisibleRect.width()
// Invert the height so it's not negative (in PDF, the rect top has a higher value than the bottom).val bitmapHeight = (-currentVisibleRect.height() * ratio).toInt()
// Calculate the size of the full page for the desired region bitmap size.val pageSizeInPdfPoints = document.getPageSize(somePageIndex)val fullPageWidth = (pageSizeInPdfPoints.width * ratio).toInt()val fullPageHeight = (pageSizeInPdfPoints.height * ratio).toInt()
// Now we need to get region coordinates in relation to the full page.val x = (currentVisibleRect.left * ratio).toInt()val y = ((pageSizeInPdfPoints.height - currentVisibleRect.top) * ratio).toInt()
// Offsets define the movement of the full page, so we move the page region in the top/left direction// by x and y and then capture it.val renderConfiguration = PageRenderConfiguration.Builder() .region(-x, -y, fullPageWidth, fullPageHeight) .build()
// Captures the region and renders it to the bitmap.val regionBitmap = document.renderPageToBitmap(context, somePageIndex, bitmapWidth, bitmapHeight, renderConfiguration)// You can get all visible pages by calling `PdfFragment#getVisiblePages()`.int somePageIndex = ...
// In order to render just a part of the page, we first need the visible rect.RectF currentVisibleRect = new RectF();
// This saves the visible rect in PDF coordinates to `currentVisibleRect`.pdfFragment.getVisiblePdfRect(currentVisibleRect, somePageIndex);
// Define a desired width for the bitmap in pixels.int bitmapWidth = 2000;
// Now calculate the height, keeping the aspect ratio of the bitmap as the visible area.float ratio = bitmapWidth / currentVisibleRect.width();
// Invert the height so it's not negative (in PDF, the rect top has a higher value than the bottom).int bitmapHeight = (int) (-currentVisibleRect.height() * ratio);
// Calculate the size of the full page for the desired region bitmap size.Size pageSizeInPdfPoints = document.getPageSize(somePageIndex);int fullPageWidth = (int) (pageSizeInPdfPoints.width * ratio);int fullPageHeight = (int) (pageSizeInPdfPoints.height * ratio);
// Now we need to get region coordinates in relation to the full page.int x = (int) (currentVisibleRect.left * ratio);int y = (int) ((pageSizeInPdfPoints.height - currentVisibleRect.top) * ratio);
// Offsets define the movement of the full page, so we move the page region in the top/left direction// by x and y and then capture it.PageRenderConfiguration renderConfiguration = new PageRenderConfiguration.Builder() .region(-x, -y, fullPageWidth, fullPageHeight) .build();
// Captures the region and renders it to the bitmap.Bitmap regionBitmap = document.renderPageToBitmap(context, somePageIndex, bitmapWidth, bitmapHeight, renderConfiguration);