PDF генерация в Swift (iOS/macOS): UIGraphicsPDFRenderer, PDFKit и Core Graphics

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

PDF генерация в Swift (iOS/macOS): от простого к сложному

Создание PDF-документов — одна из частых задач в мобильной и десктопной разработке. На платформах Apple (iOS/macOS) встроенные инструменты позволяют генерировать качественные PDF без сторонних библиотек. В этой статье мы разберём три основных подхода: UIGraphicsPDFRenderer (современный и простой), PDFKit (для работы с существующими PDF) и Core Graphics (для полного контроля). Все примеры написаны на Swift и подходят как для iOS, так и для macOS (с минимальными изменениями).

1. UIGraphicsPDFRenderer — современный стандарт

UIGraphicsPDFRenderer появился в iOS 10 и macOS 10.12. Он предоставляет высокоуровневый API для создания многостраничных PDF. Основные преимущества: автоматическая работа с контекстом, поддержка метаданных и простота использования.

Базовый пример: создание PDF с текстом

import UIKit

func generateSimplePDF() -> Data? {
    let pageWidth: CGFloat = 612   // A4
    let pageHeight: CGFloat = 792
    
    let renderer = UIGraphicsPDFRenderer(bounds: CGRect(x: 0, y: 0, width: pageWidth, height: pageHeight))
    
    let data = renderer.pdfData { context in
        // Первая страница
        context.beginPage()
        
        let text = "Привет, мир PDF!"
        let attributes: [NSAttributedString.Key: Any] = [
            .font: UIFont.systemFont(ofSize: 24),
            .foregroundColor: UIColor.black
        ]
        text.draw(at: CGPoint(x: 50, y: 50), withAttributes: attributes)
        
        // Вторая страница
        context.beginPage()
        
        let secondText = "Это вторая страница"
        secondText.draw(at: CGPoint(x: 50, y: 50), withAttributes: attributes)
    }
    
    return data
}

// Сохранение в файл
if let pdfData = generateSimplePDF() {
    let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    let pdfURL = documentsPath.appendingPathComponent("sample.pdf")
    try? pdfData.write(to: pdfURL)
    print("PDF сохранён: \(pdfURL)")
}

Продвинутый пример: таблица и изображение

func generateInvoicePDF() -> Data {
    let renderer = UIGraphicsPDFRenderer(bounds: CGRect(x: 0, y: 0, width: 612, height: 792))
    
    return renderer.pdfData { context in
        context.beginPage()
        
        // Рисуем логотип (если есть)
        if let logo = UIImage(named: "logo") {
            logo.draw(in: CGRect(x: 50, y: 50, width: 100, height: 50))
        }
        
        // Заголовок
        let titleAttributes: [NSAttributedString.Key: Any] = [
            .font: UIFont.boldSystemFont(ofSize: 28),
            .foregroundColor: UIColor.darkGray
        ]
        "СЧЁТ №123".draw(at: CGPoint(x: 400, y: 50), withAttributes: titleAttributes)
        
        // Таблица
        let items = [("Товар", "Цена"), ("Ноутбук", "1200$"), ("Мышь", "25$")]
        var yPosition: CGFloat = 200
        
        for (name, price) in items {
            let nameAttributes: [NSAttributedString.Key: Any] = [
                .font: UIFont.systemFont(ofSize: 14),
                .foregroundColor: UIColor.black
            ]
            name.draw(at: CGPoint(x: 100, y: yPosition), withAttributes: nameAttributes)
            price.draw(at: CGPoint(x: 400, y: yPosition), withAttributes: nameAttributes)
            yPosition += 30
        }
        
        // Итого
        let totalAttributes: [NSAttributedString.Key: Any] = [
            .font: UIFont.boldSystemFont(ofSize: 18),
            .foregroundColor: UIColor.red
        ]
        "Итого: 1225$".draw(at: CGPoint(x: 350, y: yPosition + 20), withAttributes: totalAttributes)
    }
}

2. PDFKit — работа с существующими PDF и аннотации

PDFKit — это более мощный фреймворк, который позволяет не только создавать, но и редактировать PDF, добавлять аннотации, формы и просматривать документы. Он доступен на iOS 11+ и macOS 10.13+.

Пример: объединение двух PDF

import PDFKit

func mergePDFs(urls: [URL]) -> PDFDocument? {
    let mergedDocument = PDFDocument()
    
    for url in urls {
        guard let document = PDFDocument(url: url) else { continue }
        for pageIndex in 0..<document.pageCount {
            if let page = document.page(at: pageIndex) {
                mergedDocument.insert(page, at: mergedDocument.pageCount)
            }
        }
    }
    
    return mergedDocument
}

// Использование
let pdf1 = Bundle.main.url(forResource: "doc1", withExtension: "pdf")!
let pdf2 = Bundle.main.url(forResource: "doc2", withExtension: "pdf")!
if let merged = mergePDFs(urls: [pdf1, pdf2]) {
    let url = FileManager                    

Рекомендаций