> ## Documentation Index
> Fetch the complete documentation index at: https://mahmoud-b28887f9.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# PDF sources: load PDFs from URLs, bytes, or Base64

> Learn how to point KPDF at a PDF document using KPdfSource — choose from remote URLs with auth headers, raw byte arrays, or Base64-encoded strings.

`KPdfSource` is the sealed interface that tells KPDF where to find a PDF document. Every viewer instance is backed by exactly one source, and the SDK treats distinct source values as distinct documents. Choose the variant that matches how your app obtains the PDF — a remote URL, an already-decoded byte array, or an inline Base64 string — and pass it to `rememberPdfViewerState` or `KPdfViewerState.open`.

## The three source variants

<AccordionGroup>
  <Accordion title="KPdfSource.Url — remote PDF over HTTP/HTTPS">
    Use `KPdfSource.Url` when the document lives at a network address. Pass custom headers to authenticate the request or negotiate the response format. KPDF treats headers as part of the source identity: two `Url` instances with the same URL but different headers are considered different sources, so the viewer reloads when headers change.

    ```kotlin theme={null}
    // Public document — no headers needed
    val publicSource = KPdfSource.Url(
        url = "https://example.com/report.pdf"
    )

    // Protected document — pass a Bearer token
    val authSource = KPdfSource.Url(
        url = "https://api.example.com/documents/42.pdf",
        headers = mapOf("Authorization" to "Bearer eyJhbGci...")
    )

    // Multiple custom headers
    val negotiatedSource = KPdfSource.Url(
        url = "https://api.example.com/export",
        headers = mapOf(
            "Authorization" to "Bearer eyJhbGci...",
            "X-Tenant-Id"   to "acme-corp",
            "Accept"        to "application/pdf",
        )
    )
    ```
  </Accordion>

  <Accordion title="KPdfSource.Bytes — raw byte array">
    Use `KPdfSource.Bytes` when your app already has the PDF content in memory — for example, after downloading it yourself, generating it programmatically, or reading it from a local file. Hand the `ByteArray` directly to KPDF; the SDK does not perform any network requests.

    ```kotlin theme={null}
    // From your own network call
    val pdfBytes: ByteArray = myHttpClient.get("https://example.com/file.pdf")
    val bytesSource = KPdfSource.Bytes(data = pdfBytes)

    // From a local file read
    val fileBytes: ByteArray = File("/path/to/document.pdf").readBytes()
    val fileSource = KPdfSource.Bytes(data = fileBytes)
    ```

    <Note>
      `KPdfSource.Bytes` implements `equals` and `hashCode` using `contentEquals` / `contentHashCode` on the underlying array, so two `Bytes` instances wrapping identical content compare as equal.
    </Note>
  </Accordion>

  <Accordion title="KPdfSource.Base64 — inline Base64 content">
    Use `KPdfSource.Base64` when the PDF arrives as a Base64-encoded string, such as from a JSON API response or an embedded asset. Pass either a raw Base64 string or a complete data URL — KPDF handles both formats.

    ```kotlin theme={null}
    // Raw Base64 string
    val rawBase64Source = KPdfSource.Base64(
        value = "JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBv..."
    )

    // Data URL (data:application/pdf;base64,...)
    val dataUrlSource = KPdfSource.Base64(
        value = "data:application/pdf;base64,JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBv..."
    )
    ```
  </Accordion>
</AccordionGroup>

## Passing a source to the viewer

```kotlin theme={null}
@Composable
fun PdfScreen() {
    val source = remember {
        KPdfSource.Url(
            url = "https://example.com/annual-report.pdf",
            headers = mapOf("Authorization" to "Bearer eyJhbGci...")
        )
    }

    val viewerState = rememberPdfViewerState(source = source)

    KPdfViewer(
        state = viewerState,
        modifier = Modifier.fillMaxSize(),
    )
}
```

To switch the active document at runtime, call `viewerState.open(newSource)`. KPDF cancels any in-flight work and starts loading the new source immediately.

```kotlin theme={null}
Button(onClick = { viewerState.open(KPdfSource.Url("https://example.com/other.pdf")) }) {
    Text("Load another document")
}
```

<Tip>
  Wrap your `KPdfSource` in `remember` (or hoist it to a ViewModel) so that Compose recompositions do not create a new source object on every frame. If the source reference changes, `rememberPdfViewerState` treats it as a new document and restarts the load pipeline.

  ```kotlin theme={null}
  // Good — source is stable across recompositions
  val source = remember(url) { KPdfSource.Url(url) }

  // Avoid — creates a new object on every recomposition
  val source = KPdfSource.Url(url)
  ```
</Tip>
