Генерация PDF отчётов на Kotlin: обзор библиотек и практические примеры
Kotlin, будучи современным языком для JVM, отлично подходит для создания серверных приложений, включая генерацию сложных PDF-отчётов. В отличие от Python, где популярны ReportLab или FPDF, в экосистеме Kotlin/Java используются проверенные временем библиотеки: iText, Apache PDFBox и OpenPDF. В этой статье мы разберём каждую из них, покажем примеры кода на Kotlin и дадим рекомендации по выбору.
1. iText (версии 7 и 8)
iText — это де-факто стандарт для генерации PDF на JVM. Библиотека предоставляет мощный API для создания документов с нуля, работы с формами, водяными знаками и цифровыми подписями. Однако начиная с версии 7, iText перешёл на лицензию AGPL (или коммерческую), что важно учитывать при коммерческом использовании.
Пример создания простого PDF с таблицей на Kotlin:
import com.itextpdf.kernel.pdf.PdfDocument
import com.itextpdf.kernel.pdf.PdfWriter
import com.itextpdf.layout.Document
import com.itextpdf.layout.element.Paragraph
import com.itextpdf.layout.element.Table
import com.itextpdf.layout.property.UnitValue
fun generateReportItext(outputPath: String) {
val writer = PdfWriter(outputPath)
val pdf = PdfDocument(writer)
val document = Document(pdf)
// Заголовок
document.add(Paragraph("Отчёт о продажах").setFontSize(20))
// Таблица
val table = Table(UnitValue.createPercentArray(3)).useAllAvailableWidth()
table.addCell("Товар")
table.addCell("Количество")
table.addCell("Цена")
table.addCell("Ноутбук")
table.addCell("10")
table.addCell("75000")
table.addCell("Монитор")
table.addCell("5")
table.addCell("25000")
document.add(table)
document.close()
println("PDF создан: $outputPath")
}
2. Apache PDFBox
PDFBox — бесплатная библиотека (лицензия Apache 2.0), которая позволяет не только создавать PDF, но и извлекать текст, заполнять формы, рендерить страницы в изображения. API чуть более низкоуровневый, чем у iText, но даёт полный контроль над содержимым.
Пример с изображением и форматированием текста:
import org.apache.pdfbox.pdmodel.PDDocument
import org.apache.pdfbox.pdmodel.PDPage
import org.apache.pdfbox.pdmodel.PDPageContentStream
import org.apache.pdfbox.pdmodel.font.PDType0Font
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject
import java.io.File
fun generateReportPdfBox(outputPath: String) {
val document = PDDocument()
val page = PDPage()
document.addPage(page)
val contentStream = PDPageContentStream(document, page)
// Загрузка шрифта (TrueType)
val font = PDType0Font.load(document, File("fonts/DejaVuSans.ttf"))
contentStream.setFont(font, 14f)
// Текст
contentStream.beginText()
contentStream.newLineAtOffset(50f, 750f)
contentStream.showText("Отчёт за январь 2025")
contentStream.endText()
// Изображение (логотип)
val image = PDImageXObject.createFromFile("logo.png", document)
contentStream.drawImage(image, 50f, 650f, 100f, 50f)
contentStream.close()
document.save(outputPath)
document.close()
println("PDFBox отчёт готов: $outputPath")
}
3. OpenPDF
OpenPDF — форк старой версии iText (LGPL), который остаётся полностью свободным. Идеально подходит для простых отчётов: текст, таблицы, базовые графические примитивы. API напоминает iText 2.x, но в современном Kotlin-коде это не является проблемой.
Пример создания PDF с параграфами и списком:
import com.lowagie.text.Document
import com.lowagie.text.Paragraph
import com.lowagie.text.pdf.PdfWriter
import java.io.FileOutputStream
fun generateReportOpenPdf(outputPath: String) {
val document = Document()
PdfWriter.getInstance(document, FileOutputStream(outputPath))
document.open()
document.add(Paragraph("Сводка по проекту"))
document.add(Paragraph("Дата: 01.02.2025"))
document.add(Paragraph("Статус: Выполнено"))
// Список
document.add(Paragraph("Основные задачи:"))
document.add(Paragraph("• Разработка модуля авторизации"))
document.add(Paragraph("• Тестирование API"))
document.add(Paragraph("• Документирование"))
document.close()
println("OpenPDF отчёт сохранён: $outputPath")
}
Сравнение библиотек
- iText — самый мощный, но требует лицензии для коммерческого использования (AGPL-проекты — бесплатно).