Primeros pasos con PDF Oxide (Kotlin)
PDF Oxide es la librería de PDF más rápida para la JVM con extracción de texto integrada: 0,8 ms de media y 100 % de éxito en 3.830 PDF. El binding de Kotlin es una fachada idiomática y lista para Android sobre el binding de Java: añade use { } a los handles que se pueden cerrar y convierte los retornos Optional<T> de Java en T? anulables. Una sola librería para extraer, crear y editar PDF. Licencia MIT, construida sobre un núcleo en Rust.
Instalación
Añade el binding de Kotlin a tu build.gradle.kts. Este arrastra de forma transitiva el binding de Java, que es el propietario del puente nativo JNI:
dependencies {
implementation("fyi.oxide:pdf-oxide-kotlin:0.3.69")
}
Requisitos: JDK 17 o superior. En Android, distribuye la librería nativa libpdf_oxide_jni.so en jniLibs/<abi>/; en la JVM de escritorio el cargador la encuentra automáticamente (puedes anular este comportamiento con -Dfyi.oxide.pdf.lib.path=<path> cuando lo necesites).
Guía rápida
Construye un PDF a partir de Markdown, ábrelo y vuelve a leer el texto. Los handles Pdf y PdfDocument son AutoCloseable, así que envuélvelos en use { }:
import fyi.oxide.pdf.Pdf
import fyi.oxide.pdf.PdfDocument
import fyi.oxide.pdf.producerOrNull
Pdf.fromMarkdown("# Hello pdf_oxide\n\nThis is a **Kotlin** binding.\n").use { pdf ->
PdfDocument.open(pdf.save()).use { doc ->
println("pages: ${doc.pageCount()}")
println("producer: ${doc.producerOrNull() ?: "(none)"}")
println(doc.extractText(0))
}
}
Pdf.fromMarkdown(String) devuelve un constructor Pdf que se puede cerrar; pdf.save() lo serializa a un ByteArray. PdfDocument.open(ByteArray) abre esos bytes para su lectura.
Abrir un PDF
Abre un documento existente a partir de bytes e inspecciona sus metadatos. producerOrNull() y creatorOrNull() son las vistas anulables de Kotlin sobre los getters Optional de Java:
import fyi.oxide.pdf.PdfDocument
import fyi.oxide.pdf.producerOrNull
import fyi.oxide.pdf.creatorOrNull
PdfDocument.open(pdfBytes).use { doc ->
println("open: ${doc.isOpen}")
println("pages: ${doc.pageCount()}")
println("producer: ${doc.producerOrNull() ?: "(none)"}")
println("creator: ${doc.creatorOrNull() ?: "(none)"}")
}
Extracción de texto
Extrae texto plano de cualquier página por su índice (empezando en cero), o recorre todas las páginas:
import fyi.oxide.pdf.PdfDocument
PdfDocument.open(pdfBytes).use { doc ->
// una sola página
println(doc.extractText(0))
// todas las páginas
for (i in 0 until doc.pageCount()) {
println("--- Page ${i + 1} ---")
println(doc.extractText(i))
}
}
Elementos de la página
doc.page(i) devuelve un PdfPage que expone la geometría estructurada: palabras, líneas, caracteres, tablas, imágenes y anotaciones. Cada palabra incluye su texto y un cuadro delimitador:
import fyi.oxide.pdf.PdfDocument
PdfDocument.open(pdfBytes).use { doc ->
val page = doc.page(0)
println("size: ${page.width()} x ${page.height()}")
page.words().take(8).forEach { word ->
println("${word.text()} @ ${word.bbox()}")
}
println("lines: ${page.lines().size}")
println("chars: ${page.chars().size}")
println("tables: ${page.tables().size}")
println("images: ${page.images().size}")
println("annotations: ${page.annotations().size}")
}
El bbox() de una palabra es un BBox con utilidades como width() y height().
Conversión a Markdown y HTML
Convierte todo el documento a Markdown, o renderiza una página a HTML:
import fyi.oxide.pdf.PdfDocument
PdfDocument.open(pdfBytes).use { doc ->
val markdown = doc.toMarkdown() // todas las páginas
println(markdown)
val html = doc.toHtml()
println(html)
}
Búsqueda
Busca texto en todo el documento. Cada coincidencia expone su texto mediante text():
import fyi.oxide.pdf.PdfDocument
PdfDocument.open(pdfBytes).use { doc ->
val matches = doc.search("configuration")
matches.forEach { m ->
println("match: ${m.text()}")
}
}
Extracción automática
AutoExtractor ejecuta toda la canalización de extracción en una sola llamada y devuelve un AutoResult con el texto, más renderizados opcionales en Markdown/HTML. Las extensiones markdownOrNull() / htmlOrNull() convierten los retornos Optional de Java en valores anulables:
import fyi.oxide.pdf.PdfDocument
import fyi.oxide.pdf.AutoExtractor
import fyi.oxide.pdf.markdownOrNull
import fyi.oxide.pdf.htmlOrNull
PdfDocument.open(pdfBytes).use { doc ->
val result = AutoExtractor.of(doc).extractDocument()
println(result.text())
result.markdownOrNull()?.let { println(it) }
result.htmlOrNull()?.let { println(it) }
}
Edición
DocumentEditor abre un PDF para realizar ediciones estructurales —por ejemplo, depurar los metadatos antes de compartirlo— y luego serializa el resultado de vuelta a bytes:
import fyi.oxide.pdf.DocumentEditor
DocumentEditor.open(pdfBytes).use { editor ->
editor.scrubMetadata()
val cleaned: ByteArray = editor.save()
println("cleaned: ${cleaned.size} bytes")
}
Próximos pasos
- Primeros pasos con Java – el binding de la JVM que envuelve la fachada de Kotlin
- Primeros pasos con Python – cómo usar PDF Oxide desde Python
- Extracción de texto – opciones y recetas de extracción en detalle
- Creación de PDF – creación avanzada con constructores, cifrado y metadatos
- Edición – modificar PDF existentes, anotaciones y campos de formulario