iOS 中PDF常用操作-生成合并展示涂鸦PDF

421 阅读6分钟

#1. 合并多个PDF文件:

  • 示例一:
import PDFKit

   /// PDF 合并
   /// - Parameters:
   ///   - URLs: 需要合并的PDF数组[url] (一般从沙盒中读取本地路径的RUL)
   ///   - URL: 保存到沙盒地址的URL
    func mergePDFWithURLs(_ URLs: [AnyHashable]?, writeTo URL: URL?) {
        var context: CGContext? = nil
        if let url = URL as CFURL? {
            context = CGContext(url, mediaBox: nil, nil)
        }
        for PDFURL in URLs ?? [] {
            guard let PDFURL = PDFURL as? URL else {
                continue
            }
            if let document = CGPDFDocument(PDFURL as CFURL) {
                let numberOfPages = document.numberOfPages
                for pageNumber in 0...numberOfPages {
                    let page = document.page(at: pageNumber)
                    if var mediaBox = page?.getBoxRect(.mediaBox) {
                        context?.beginPage(mediaBox: &mediaBox)
                        if let page {
                            context?.drawPDFPage(page)
                        }
                        context?.endPage()
                    }
                }
            }
        }
        context?.closePDF()
    }

  • 示例二:
import PDFKit

let pdfDocument = PDFDocument()
if let url1 = Bundle.main.url(forResource: "example1", withExtension: "pdf"),
   let document1 = PDFDocument(url: url1) {
    for pageIndex in 0 ..< document1.pageCount {
        if let page = document1.page(at: pageIndex) {
            pdfDocument.insert(page, at: pdfDocument.pageCount)
        }
    }
}
if let url2 = Bundle.main.url(forResource: "example2", withExtension: "pdf"),
   let document2 = PDFDocument(url: url2) {
    for pageIndex in 0 ..< document2.pageCount {
        if let page = document2.page(at: pageIndex) {
            pdfDocument.insert(page, at: pdfDocument.pageCount)
        }
    }
}

// 保存合并后的PDF文件
pdfDocument.write(toFile: "/path/to/merged.pdf")

#2. 将图像保存为PDF文件:

  • 示例一:

   /// 将View图像生成为PDF文件
   /// - Parameter webView: View (此处用的WKWebView的富文本编辑器生成PDF)可以是UIView UIScrollView UIImageView 等
    func getPDFWithWebView(_ webView: WKWebView) {
        
        let render = UIPrintPageRenderer()
        render.addPrintFormatter(webView.viewPrintFormatter(), startingAtPageAt: 0);

        let width = webView.scrollView.contentSize.width
        let height = CGFloat(Int(width * 2 / 1.414)) //A4纸比例

        let page = CGRect(x: 10, y: 10, width: width, height: height) // take the size of the webView
        let printable = CGRect(x: -10, y: 0, width: width + 20 , height: height + 20)
        render.setValue(NSValue(cgRect: page), forKey: "paperRect") //纸尺寸大小
        render.setValue(NSValue(cgRect: printable), forKey: "printableRect") //可打印矩形

        // 4. Create PDF context and draw
        let pdfData = NSMutableData()
        UIGraphicsBeginPDFContextToData(pdfData, printable, nil)
        for i in 1...render.numberOfPages {
            UIGraphicsBeginPDFPage();
            let bounds = UIGraphicsGetPDFContextBounds()
            render.drawPage(at: i - 1, in: bounds)
        }
        UIGraphicsEndPDFContext()

        let path = "/path/to/creatPDF.pdf"
        // 保存生成的PDF文件
        pdfData.write(toFile: path, atomically: true)
    }

  • 示例二:

import PDFKit

guard let image = UIImage(named: "example.png") else { return }
guard let data = image.jpegData(compressionQuality: 1.0) else { return }

let pdfDocument = PDFDocument()
let pdfPage = PDFPage(image: image)
pdfDocument.insert(pdfPage!, at: pdfDocument.pageCount)

let pdfData = NSMutableData()
pdfDocument.write(to: pdfData)

// 保存PDF文件
pdfData.write(toFile: "/path/to/example.pdf", atomically: true)

#3. 将多张图片保存为PDF文件(分页):


   func imagesConvertPDFAction(images:[UIImage], title:String = "") -> URL {
        
        //创建二进制流载体
        let pdfData = createSearchablePDF(from: images)
        //获取沙箱路径
        let dir = URL(fileURLWithPath: "/filePath")
        print(dir)
        //URL 追加 文件名
        var path = dir.appendingPathComponent("example.pdf")
        if title != "" {
            path = dir.appendingPathComponent("\(title).pdf")
        }
        do {
            //写文件到路径
            try pdfData.write(to: path, options: .atomic)
        } catch {
            print("error catched")
        }
        return path
    }
    
    func createSearchablePDF(from images: [UIImage]) -> Data {
        // Start creating the PDF data
        let data = UIGraphicsPDFRenderer().pdfData { (context) in
            // Grab the raw core graphics context
            // let drawContext = context.cgContext
            // Iterate over the images
            images.forEach { image in
                // 3. Calculate the size of the PDF page we are going to create
                let pageWidth = image.size.width
                let pageHeight = image.size.height
                let pageRect = CGRect(x: 0, y: 0, width: pageWidth, height: pageHeight)
                // 3. Initialize a PDF page
                context.beginPage(withBounds: pageRect, pageInfo: [:])
                // 5. Draw the image on the PDF page
                image.draw(in: pageRect)
            }
        }
        return data
    }
    

#4. 提取PDF页面作为图像:


import PDFKit

guard let url = Bundle.main.url(forResource: "example", withExtension: "pdf") else { return }
let pdfView = PDFView(frame: CGRect(x: 0, y: 0, width: 300, height: 400))
if let document = PDFDocument(url: url) {
    if let page = document.page(at: 0) {
        let thumbnailSize = CGSize(width: 100, height: 100)
        let thumbnail = page.thumbnail(of: thumbnailSize, for: .artBox)
        // 在这里使用提取的缩略图
    }
}

#5. 读取PDF文件并显示在PDF视图中:


import PDFKit

let pdfView = PDFView(frame: CGRect(x: 0, y: 0, width: 300, height: 400))
if let url = Bundle.main.url(forResource: "example", withExtension: "pdf") {
    if let document = PDFDocument(url: url) {
        pdfView.document = document
    }
}

#6. 生成PDF的其他方法(不常用): 我们可以使用Core Graphics框架来生成PDF文件。以下是一个示例代码,实现了创建一个简单的PDF文件,并对代码进行了注解:



import UIKit

func createPDF() {
    // 获取文档路径
    let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
    let filePath = documentsPath + "/example.pdf"
    
    // 创建PDF上下文
    UIGraphicsBeginPDFContextToFile(filePath, CGRect.zero, nil)
    
    // 开始新的页面
    UIGraphicsBeginPDFPageWithInfo(CGRect(x: 0, y: 0, width: 595.2, height: 841.8), nil)
    
    // 获取当前上下文
    guard let context = UIGraphicsGetCurrentContext() else {
        return
    }
    
    // 绘制文本
    let text = "Hello, PDF!"
    let attributes: [NSAttributedString.Key: Any] = [
        .font: UIFont.systemFont(ofSize: 24)
    ]
    let attributedText = NSAttributedString(string: text, attributes: attributes)
    attributedText.draw(at: CGPoint(x: 50, y: 50))
    
    // 绘制矩形
    context.setFillColor(UIColor.red.cgColor)
    context.fill(CGRect(x: 150, y: 150, width: 200, height: 100))
    
    // 结束PDF上下文
    UIGraphicsEndPDFContext()
    
    print("PDF创建完成,路径:\(filePath)")
}

这段代码首先获取文档路径,然后使用UIGraphicsBeginPDFContextToFile函数创建一个PDF上下文,并将其保存到指定的路径。然后,使用UIGrahpicsBeginPDFPageWithInfo函数开始一个新的页面,并设置页面的尺寸。接下来,通过UIGraphicsGetCurrentContext函数获取当前上下文,以便进行绘制操作。

在示例中,我们绘制了一段文本和一个红色矩形。使用NSAttributedString创建带有属性的文本,并使用其draw(at:)方法来绘制在指定位置。然后,使用上下文的setFillColor函数设置填充色,并使用fill方法绘制矩形。

最后,使用UIGraphicsEndPDFContext函数结束PDF上下文。

运行以上代码后,会在应用的文档目录中创建一个名为"example.pdf"的PDF文件,并打印出文件的路径。


当实现 PDF 手绘签名并涂鸦部分内容时,你可以借助 UIGraphicsPDFRendererUIGraphicsRendererContext 来实现。下面是一个简单的示例代码,演示如何在 PDF 上手绘涂鸦部分内容:

import UIKit

class PDFDrawingViewController: UIViewController {
    
    var pdfData = Data()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 创建 PDF 渲染器
        let renderer = UIGraphicsPDFRenderer(bounds: CGRect(x: 0, y: 0, width: 300, height: 300), format: UIGraphicsPDFRendererFormat())
        
        // 绘制 PDF 页面
        let pdfPage = renderer.pdfPage { context in
            context.beginPage()
            
            // 绘制原始 PDF 内容
            let originalPDFURL = Bundle.main.url(forResource: "original_pdf", withExtension: "pdf")!
            let originalPDF = CGPDFDocument(originalPDFURL as CFURL)!
            let page = originalPDF.page(at: 1)!
            context.cgContext.drawPDFPage(page)
            
            // 手绘
            context.cgContext.setStrokeColor(UIColor.black.cgColor)
            context.cgContext.setLineWidth(2.0)
            context.cgContext.move(to: CGPoint(x: 50, y: 50))
            context.cgContext.addLine(to: CGPoint(x: 100, y: 100))
            context.cgContext.strokePath()
            
            // 
            let text = "Confidential"
            let attributedText = NSAttributedString(string: text, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12), NSAttributedString.Key.foregroundColor: UIColor.red])
            attributedText.draw(at: CGPoint(x: 150, y: 150))
            
            context.endPage()
        }
        
        // 保存 PDF 数据
        pdfData = pdfPage.dataRepresentation()
        
        // 保存 PDF 文件到沙盒中
        let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
        let pdfFilePath = documentsPath + "/edited_pdf.pdf"
        pdfData.write(toFile: pdfFilePath, atomically: true)
    }
}

在以上示例中,我们首先创建了一个 PDF 渲染器 renderer,然后在闭包中绘制了 PDF 页面。在绘制 PDF 页面时,我们首先绘制了原始的 PDF 内容,然后手绘了签名和涂鸦部分内容。最后,将绘制好的 PDF 数据保存到 pdfData 中,并将其写入沙盒中作为新的 PDF 文件。

UIGraphicsPDFRenderer 是 iOS 中用于绘制 PDF 内容的类,它提供了一种简单的方式来创建包含图形、文本和其他内容的 PDF 文档。下面是对 UIGraphicsPDFRenderer 的详细解析:

创建 UIGraphicsPDFRenderer 对象

let renderer = UIGraphicsPDFRenderer(bounds: CGRect, format: UIGraphicsPDFRendererFormat)
  • bounds: 指定 PDF 渲染器的绘制区域大小和位置。
  • format: 指定 PDF 渲染器的格式,可以设置页面方向、缩放因子等属性。

绘制 PDF 页面

let pdfPage = renderer.pdfPage { context in
    // 在闭包中进行 PDF 页面的绘制操作
}
  • pdfPage: 表示一个 PDF 页面,包含在闭包中绘制的内容。
  • context: 一个 UIGraphicsRendererContext 对象,用于执行实际的绘制操作。

绘制内容到 PDF 页面

在闭包中,可以使用 context 执行绘制操作,比如绘制文本、图形等内容。

context.beginPage()
// 在这里添加需要绘制的内容
context.endPage()
  • beginPage(): 开始新的页面绘制。
  • endPage(): 结束当前页面的绘制。

保存 PDF 数据

let pdfData = NSMutableData()
pdfData.append(pdfPage.dataRepresentation())
  • 将绘制好的 PDF 页面数据追加到 pdfData 中,从而生成完整的 PDF 文档数据。

总结

通过使用 UIGraphicsPDFRenderer 类,我们可以轻松地创建包含各种内容的 PDF 文档。在绘制 PDF 页面时,我们可以利用上下文对象执行各种绘制操作,并最终将绘制好的页面数据保存为完整的 PDF 文档数据。这为我们在 iOS 应用中生成和处理 PDF 文件提供了便捷的方式。