当前位置: 首页 > 工具软件 > Queue for iOS > 使用案例 >

iOS 创建PDF文件

钱浩荡
2023-12-01

前言

最近有个项目,功能为将多张图片创建为PDF文件。

创建PDF文档在iOS中有两种方法

  1. PDFKit
  2. UIKit -> UIGraphicsPDFRenderer

PDFKit

iOS 11 版本之后,iOS 提供了生成与预览 PDF 文件的框架,即为 PDFKit。本篇文章不讨论使用 PDFKit 预览 PDF 文档的功能( PDFView )。感兴趣的同学可以自己去看看,不难。

PDFKit提供了大量的类

  • PDFDocument:描述为整个PDF文档,用于生成或获取PDF文档
  • PDFPage:PDF的页
  • PDFAction: 点击PDF的事件,基本使用其子类完成相关点击动作,如点击链接(PDFActionURL)。点击名称(PDFActionName)等。
  • PDFAnnotation: PDF的注释,如向PDF的某一处添加一段文字。

PDFKit在生成文档时只要使用了两个类 PDFDocumentPDFPage

废话不多说,上代码

    /// - Parameters:
    ///   - url: 创建PDF的根路径
    ///   - name: PDF文件名称
    ///   - images: 图片列表
    ///   - completed: 返回
    func convertPDF(url: URL, name: String, images: [UIImage], completed: @escaping (String) -> Void) {
        var path = url.appendingPathComponent(name).appendingPathExtension("pdf")
        var number = 0
        // 防止重名
        while self.isExist(path: path.path) {
            number += 1
            path = url.appendingPathComponent(name + "(\(number))")
                .appendingPathExtension("pdf")
        }
        let queue = DispatchQueue(label: "com.create.pdf")
        queue.async {
            let pdfDocument = PDFDocument()
            for (index, image) in images.enumerated() {
            	// 创建页
                let pdfPage = PDFPage(image: image)
                // 设置页面大小
                pdfPage?.setBounds(CGRect(origin: .zero, size: PDFSettingState.shared.size), for: .mediaBox)
                // 添加页
                pdfDocument.insert(pdfPage!, at: index)
            }
            pdfDocument.write(to: path)
            // 加密PDF文档
            // pdfDocument.write(to: path, withOptions: [.ownerPasswordOption: "123456"])
            DispatchQueue.main.async {
                completed(path.path)
            }
        }
    }

缺陷

  • 固定大小之后图片会失真,图片变得发白
  • 如果图片与所设定的尺寸不一致时,图片将会自适应纸张大小,类似 UIImageViewUIViewContentModeScaleAspectFill 方式。

UIKit

如果项目需要适配 iOS 11 以下的系统版本,那么就只能使用 UIGraphicsPDFRendererFormat 进行 PDF 创建了。

上代码

	/// - Parameters:
    ///   - url: 创建PDF的根路径
    ///   - name: PDF文件名称
    ///   - images: 图片列表
    ///   - completed: 返回
    func createPDF(url: URL, name: String, images: [UIImage], completed: @escaping (String) -> Void) {
        var path = url.appendingPathComponent(name).appendingPathExtension("pdf")
        var number = 0
        // 防止重名
        while self.isExist(path: path.path) {
            number += 1
            path = url.appendingPathComponent(name + "(\(number))")
                .appendingPathExtension("pdf")
        }
        let queue = DispatchQueue(label: "com.create.pdf")
        queue.async {
        	// 纸张大小
            let rect = PDFSettingState.shared.getSize()
            var pdfInfo = [String: Any]()
            // 加密
            if !PDFSettingState.shared.password.isEmpty {
                pdfInfo[kCGPDFContextOwnerPassword as String] = PDFSettingState.shared.password
            }
            let format = UIGraphicsPDFRendererFormat()
            format.documentInfo = pdfInfo

            let render = UIGraphicsPDFRenderer(bounds: rect, format: format)
            let data = render.pdfData { context in
                var x: CGFloat = 0
                for image in images {
                	// 开启PDF中的一页
                    context.beginPage()
                    if image.size.width <= rect.size.width {
                        x = (rect.size.width - image.size.width) / 2.0
                    } else {
                        x = 0
                    }
                    image.draw(at: CGPoint(x: x, y: 0))
                }
            }
            UIGraphicsEndPDFContext()
            try! data.write(to: path)
            DispatchQueue.main.async {
                completed(path.path)
            }
        }
    }

缺陷

  • 图片会自适应纸张大小,类似 UIImageViewUIViewContentModeScaleAspectFill 方式。

总结

由于网上的文档多数都有问题,没办法只能自己看官方文档以及代码进行学习。相比较而言,PDFKit 要比 UIKit 的使用方式要简单一点,但功能也要简单一点。最起码无法设置纸张大小,也许是因为图片大小不符合纸张大小而不成功吧。这个问题就交给大家了。

最后附上纸张大小的尺寸网址 Paper Sizes

 类似资料: