# PDF renderer library for Android

You can use Nutrient to render a PDF page into a [`Bitmap`](http://developer.android.com/reference/android/graphics/Bitmap.html) object so that you can use it in your custom application views as well. To do this, use [`Nutrient`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit/-nutrient/index.html) and [`PdfDocument`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.document/-pdf-document/index.html) class calls.

## Initializing Nutrient

Before loading or rendering a document, you have to initialize Nutrient by providing your license. [Here’s how to do it](https://www.nutrient.io/sdk/android/getting-started.md).

## Loading a document

The [`PdfDocumentLoader`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.document/-pdf-document-loader/index.html) class offers a variety of methods for loading a document. You can load documents from a [`Uri`](http://developer.android.com/reference/android/net/Uri.html) or a [`DataProvider`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.document.providers/-data-provider/index.html). The following example loads a PDF document from the app’s assets. The different available document sources are described in the [`PdfActivity`](https://www.nutrient.io/guides/android/basics/using-activity/#launching-from-a-uri) guide:

### KOTLIN

```kotlin

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)
}

```

### JAVA

```java

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 = PdfDocumentLoder.openDocument(context, documentUri);
} catch (IOException e) {
    handleDocumentLoadingError(e);
}

```

Now that the [`PdfDocument`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.document/-pdf-document/index.html) has been loaded, you can use it to render PDF pages.

## Rendering pages

The rendering of pages can be performed synchronously or asynchronously using the [`#renderPageToBitmap`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.document/-pdf-document/render-page-to-bitmap.html) and [`#renderPageToBitmapAsync`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.document/-pdf-document/render-page-to-bitmap-async.html) methods of the [`PdfDocument`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.document/-pdf-document/index.html), respectively.

### Synchronous rendering

To synchronously render a page into a [`Bitmap`](http://developer.android.com/reference/android/graphics/Bitmap.html), use any of the available [`#renderPageToBitmap`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.document/-pdf-document/render-page-to-bitmap.html) methods. These methods will block until rendering has been finished, which means you should only use them on a background thread (not from the main UI thread of your app).

To keep the original page aspect while rendering and prevent stretching of the resulting image, you can access the original [`PageSize`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.document/-pdf-document/get-page-size.html) of the rendered page (in PDF points) and calculate your resulting bitmap size:

### KOTLIN

```kotlin

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 = 2048
val 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)

```

### JAVA

```java

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

To render the document asynchronously in a background thread, you can use any of the available [`#renderPageToBitmapAsync`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.document/-pdf-document/render-page-to-bitmap-async.html) methods. These methods won’t block, but they will instead return an RxJava [`Single<Bitmap>`](http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/Single.html), which will emit the [`Bitmap`](http://developer.android.com/reference/android/graphics/Bitmap.html) once rendering has finished (similar to a callback). The rendering itself is performed on a background thread by default, so you can safely call this method from your app’s main thread:

### KOTLIN

```kotlin

// 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)
    }

```

### JAVA

```java

// 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 synchronous and asynchronous render methods allow you to specify a [`PageRenderConfiguration`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.configuration.rendering/-page-render-configuration/index.html) object for defining details about the requested rendering. You can create the configuration using its [`Builder`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.configuration.rendering/-page-render-configuration/-builder/index.html) class. The configuration allows you to specify several options:

- Enabling or disabling of an in-memory render [`cache`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.configuration.rendering/-page-render-configuration/-builder/cache.html).

- Rendering of only a specific [`region`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.configuration.rendering/-page-render-configuration/-builder/region.html) on the page (e.g. the upper half).

- A [`reuseBitmap`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.configuration.rendering/-page-render-configuration/-builder/reuse-bitmap.html) object that should be reused for rendering. Use this to optimize memory performance of your app.

- Background color, grayscale mode, or inversion of all colors.

- Rendering of [`renderedDrawables`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.configuration.rendering/-page-render-configuration/-builder/rendered-drawables.html) above the page content. This can be used to add watermarks. More information can be found in our [drawable API](https://www.nutrient.io/guides/android/features/drawable-api.md) guide.

### KOTLIN

```kotlin

val renderConfig = PageRenderConfiguration.Builder().toGrayscale(true).build()

val grayscaleBitmap : Bitmap = document.renderPageToBitmap(context, pageIndex, width, height, renderConfig)

```

### JAVA

```java

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

As previously mentioned, by using [`PageRenderConfiguration`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.configuration.rendering/-page-render-configuration/index.html), you can render a specific part of a page. See the [`PageRenderConfiguration.Builder#region()`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.configuration.rendering/-page-render-configuration/-builder/region.html) method for more information.

Here’s an example of rendering the part of the page that is currently zoomed (every step is described by a comment):

### KOTLIN

```kotlin

// You can get all visible pages by calling `PdfFragment#getVisiblePages()`.

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) as Int

// Calculate the size of the full page for the desired region bitmap size.
val pageSizeInPdfPoints = document.getPageSize(somePageIndex)
val fullPageWidth = (pageSizeInPdfPoints.width * ratio) as Int
val fullPageHeight = (pageSizeInPdfPoints.height * ratio) as Int

// Now we need to get region coordinates in relation to the full page.
val x = (currentVisibleRect.left * ratio) as Int
val y = ((pageSizeInPdfPoints.height - currentVisibleRect.top) * ratio) as Int

// 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(getContext(), 0, bitmapWidth, bitmapHeight, renderConfiguration)

```

### JAVA

```java

// 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(getContext(), 0, bitmapWidth, bitmapHeight, renderConfiguration);

```
---

## Related pages

- [Customize PDF fonts for Android applications](/guides/android/features/custom-fonts.md)
- [Rendering annotations on Android](/guides/android/annotations/rendering-annotations.md)
- [Render PDF forms on Android](/guides/android/viewer/rendering/pdf-forms.md)
- [Coordinate space conversion](/guides/android/faq/coordinate-spaces.md)
- [Customize the rendering resolution in our Android viewer](/guides/android/features/low-res-render-api.md)
- [Drawing content above displayed documents](/guides/android/features/drawable-api.md)

