伪代码示例(未优化):
swift
import Foundation
import PDFKit
import SnapKit
import SVProgressHUD
enum PDFEditorError: Error {
case invalidPageNumber(reason: String)
case invalidPDFDocument(reason: String)
case imageDataError(reason: String)
case createDocumentError(reason: String)
case getTempPageError(reason: String)
}
class PDFEditor {
// 远程url地址
var remoteUrl: String
init(remoteUrl: String) {
self.remoteUrl = remoteUrl
}
func loadRemote(savePath: URL,
downloadFinished: @escaping (PDFDocument) -> Void,
errorCallback: @escaping (String) -> Void)
{
if let url = URL(string: remoteUrl) {
let session = URLSession.shared
let task = session.dataTask(with: url) { data, response, error in
if let _ = error {
SVProgressHUD.showError(withStatus: "下载报告失败")
return
}
guard let httpResponse = response as? HTTPURLResponse,
(200 ... 299).contains(httpResponse.statusCode)
else {
SVProgressHUD.showError(withStatus: "下载报告失败")
return
}
if let data = data {
do {
try data.write(to: savePath)
if let document = PDFDocument(url: savePath) {
DispatchQueue.main.async {
downloadFinished(document)
}
} else {
DispatchQueue.main.async {
errorCallback("加载pdf失败")
}
}
} catch {
DispatchQueue.main.async {
errorCallback("文件保存失败: \(error)")
}
SVProgressHUD.showError(withStatus: "文件保存失败: \(error)")
}
} else {
DispatchQueue.main.async {
errorCallback("未获取到文档")
}
}
}
task.resume()
} else {
DispatchQueue.main.async {
errorCallback("PDF地址有误")
}
}
}
func addImageToPDF(pdfURL: URL, image: UIImage, pageNumber: Int, rect: CGRect) throws -> Data {
guard let pdfDocument = PDFDocument(url: pdfURL)
else {
throw PDFEditorError.invalidPDFDocument(reason: "PDF document could not be created from URL.")
}
guard pageNumber >= 0 && pageNumber < pdfDocument.pageCount,
let page = pdfDocument.page(at: pageNumber)
else {
throw PDFEditorError.invalidPageNumber(reason: "Page number is out of bounds.")
}
// 创建一个可变的 PDFDocument
let mutablePdfDocument = PDFDocument()
// 复制原始 PDF 的所有页面到新的文档中
for i in 0 ..< pdfDocument.pageCount {
if let originalPage = pdfDocument.page(at: i) {
mutablePdfDocument.insert(originalPage, at: i)
}
}
// 创建 NSMutableData 用于保存 PDF 数据
let pdfData = NSMutableData()
// 获取 PDFPage 的 bounds
let pageBounds = page.bounds(for: .mediaBox)
// 创建 PDF 上下文
UIGraphicsBeginPDFContextToData(pdfData, pageBounds, nil)
// 开始新的 PDF 页
UIGraphicsBeginPDFPageWithInfo(pageBounds, nil)
// 将背景页绘制到上下文中
let context = UIGraphicsGetCurrentContext()!
// 翻转坐标系
// 将坐标系的原点移动到页面的左上角。
context.translateBy(x: 0, y: pageBounds.size.height)
// 沿 Y 轴翻转坐标系
context.scaleBy(x: 1.0, y: -1.0)
page.draw(with: .mediaBox, to: context)
// 定义图片绘制的位置和大小,因为以上步骤会进行翻转,需要调节位置
let imageWidth: CGFloat = 200
let imageHeight: CGFloat = 150
let imageX: CGFloat = 50
let imageY: CGFloat = pageBounds.size.height - 50 - imageHeight // 调整后的 y 坐标
let imageRect = CGRect(x: imageX, y: imageY, width: imageWidth, height: imageHeight)
// 10. 绘制图片
context.draw(image.cgImage!, in: imageRect)
// 11. 结束 PDF 页
UIGraphicsEndPDFContext()
guard let tempPdfDocument = PDFDocument(data: pdfData as Data) else {
throw PDFEditorError.createDocumentError(reason: "Failed to create temporary PDF document from data.")
}
guard let pdfPage = tempPdfDocument.page(at: 0) else {
throw PDFEditorError.getTempPageError(reason: "Failed to retrieve page from temporary PDF document.")
}
mutablePdfDocument.removePage(at: pageNumber)
mutablePdfDocument.insert(pdfPage, at: pageNumber)
// 返回修改后的 PDF 数据
guard let finalData = mutablePdfDocument.dataRepresentation() else {
throw PDFEditorError.imageDataError(reason: "Failed to generate final PDF data representation.")
}
return finalData
}
}
import Foundation
import PDFKit
import SnapKit
import SVProgressHUD
enum PDFEditorError: Error {
case invalidPageNumber(reason: String)
case invalidPDFDocument(reason: String)
case imageDataError(reason: String)
case createDocumentError(reason: String)
case getTempPageError(reason: String)
}
class PDFEditor {
// 远程url地址
var remoteUrl: String
init(remoteUrl: String) {
self.remoteUrl = remoteUrl
}
func loadRemote(savePath: URL,
downloadFinished: @escaping (PDFDocument) -> Void,
errorCallback: @escaping (String) -> Void)
{
if let url = URL(string: remoteUrl) {
let session = URLSession.shared
let task = session.dataTask(with: url) { data, response, error in
if let _ = error {
SVProgressHUD.showError(withStatus: "下载报告失败")
return
}
guard let httpResponse = response as? HTTPURLResponse,
(200 ... 299).contains(httpResponse.statusCode)
else {
SVProgressHUD.showError(withStatus: "下载报告失败")
return
}
if let data = data {
do {
try data.write(to: savePath)
if let document = PDFDocument(url: savePath) {
DispatchQueue.main.async {
downloadFinished(document)
}
} else {
DispatchQueue.main.async {
errorCallback("加载pdf失败")
}
}
} catch {
DispatchQueue.main.async {
errorCallback("文件保存失败: \(error)")
}
SVProgressHUD.showError(withStatus: "文件保存失败: \(error)")
}
} else {
DispatchQueue.main.async {
errorCallback("未获取到文档")
}
}
}
task.resume()
} else {
DispatchQueue.main.async {
errorCallback("PDF地址有误")
}
}
}
func addImageToPDF(pdfURL: URL, image: UIImage, pageNumber: Int, rect: CGRect) throws -> Data {
guard let pdfDocument = PDFDocument(url: pdfURL)
else {
throw PDFEditorError.invalidPDFDocument(reason: "PDF document could not be created from URL.")
}
guard pageNumber >= 0 && pageNumber < pdfDocument.pageCount,
let page = pdfDocument.page(at: pageNumber)
else {
throw PDFEditorError.invalidPageNumber(reason: "Page number is out of bounds.")
}
// 创建一个可变的 PDFDocument
let mutablePdfDocument = PDFDocument()
// 复制原始 PDF 的所有页面到新的文档中
for i in 0 ..< pdfDocument.pageCount {
if let originalPage = pdfDocument.page(at: i) {
mutablePdfDocument.insert(originalPage, at: i)
}
}
// 创建 NSMutableData 用于保存 PDF 数据
let pdfData = NSMutableData()
// 获取 PDFPage 的 bounds
let pageBounds = page.bounds(for: .mediaBox)
// 创建 PDF 上下文
UIGraphicsBeginPDFContextToData(pdfData, pageBounds, nil)
// 开始新的 PDF 页
UIGraphicsBeginPDFPageWithInfo(pageBounds, nil)
// 将背景页绘制到上下文中
let context = UIGraphicsGetCurrentContext()!
// 翻转坐标系
// 将坐标系的原点移动到页面的左上角。
context.translateBy(x: 0, y: pageBounds.size.height)
// 沿 Y 轴翻转坐标系
context.scaleBy(x: 1.0, y: -1.0)
page.draw(with: .mediaBox, to: context)
// 定义图片绘制的位置和大小,因为以上步骤会进行翻转,需要调节位置
let imageWidth: CGFloat = 200
let imageHeight: CGFloat = 150
let imageX: CGFloat = 50
let imageY: CGFloat = pageBounds.size.height - 50 - imageHeight // 调整后的 y 坐标
let imageRect = CGRect(x: imageX, y: imageY, width: imageWidth, height: imageHeight)
// 10. 绘制图片
context.draw(image.cgImage!, in: imageRect)
// 11. 结束 PDF 页
UIGraphicsEndPDFContext()
guard let tempPdfDocument = PDFDocument(data: pdfData as Data) else {
throw PDFEditorError.createDocumentError(reason: "Failed to create temporary PDF document from data.")
}
guard let pdfPage = tempPdfDocument.page(at: 0) else {
throw PDFEditorError.getTempPageError(reason: "Failed to retrieve page from temporary PDF document.")
}
mutablePdfDocument.removePage(at: pageNumber)
mutablePdfDocument.insert(pdfPage, at: pageNumber)
// 返回修改后的 PDF 数据
guard let finalData = mutablePdfDocument.dataRepresentation() else {
throw PDFEditorError.imageDataError(reason: "Failed to generate final PDF data representation.")
}
return finalData
}
}
Pdf使用示例:
swift
let pdfView = PDFView()
// 展示模式: 单页、多页
pdfView.displayMode = .singlePageContinuous
pdfView.autoScales = true
// 设置 PDF 的显示方向 (例如垂直、水平)
pdfView.displayDirection = .vertical
if let document = PDFDocument(url: url) {
pdfView.document = document
}
let pdfView = PDFView()
// 展示模式: 单页、多页
pdfView.displayMode = .singlePageContinuous
pdfView.autoScales = true
// 设置 PDF 的显示方向 (例如垂直、水平)
pdfView.displayDirection = .vertical
if let document = PDFDocument(url: url) {
pdfView.document = document
}