Swift中PDF缩略图生成器始终返回nil的问题求助
PDF缩略图生成器始终返回nil的排查与解决
请问有人能帮我解释一下,我所使用的PDF缩略图生成器为何始终返回nil?我希望在UITableView中展示PDF文件名的同时显示对应的缩略图,但尝试过的约4种生成器均仅返回nil。以下是我的Swift代码:
func uploadPDF() { let types = UTType.types(tag: "pdf", tagClass: UTTagClass.filenameExtension, conformingTo: nil) let documentPickerController = UIDocumentPickerViewController(forOpeningContentTypes: types) documentPickerController.delegate = self self.present(documentPickerController, animated: true, completion: nil) } func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { for url in urls { let thumbnail = thumbnailFromPdf(withUrl: url, pageNumber: 0) self.modelController.bidPDFUploadThumbnails.append(thumbnail!) } tableView.reloadData() } func thumbnailFromPdf(withUrl url:URL, pageNumber:Int, width: CGFloat = 240) -> UIImage? { guard let pdf = CGPDFDocument(url as CFURL), let page = pdf.page(at: pageNumber) else { return nil } var pageRect = page.getBoxRect(.mediaBox) let pdfScale = width / pageRect.size.width pageRect.size = CGSize(width: pageRect.size.width*pdfScale, height: pageRect.size.height*pdfScale) pageRect.origin = .zero UIGraphicsBeginImageContext(pageRect.size) let context = UIGraphicsGetCurrentContext()! // White BG context.setFillColor(UIColor.white.cgColor) context.fill(pageRect) context.saveGState() // Next 3 lines makes the rotations so that the page look in the right direction context.translateBy(x: 0.0, y: pageRect.size.height) context.scaleBy(x: 1.0, y: -1.0) context.concatenate(page.getDrawingTransform(.mediaBox, rect: pageRect, rotate: 0, preserveAspectRatio: true)) context.drawPDFPage(page) context.restoreGState() let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image }
核心问题与修复方案
1. 文件访问权限缺失
UIDocumentPicker返回的URL属于沙盒临时访问路径,必须主动申请权限才能读取文件内容,否则CGPDFDocument会直接返回nil。
修改documentPicker方法:
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { for url in urls { // 申请文件访问权限 guard url.startAccessingSecurityScopedResource() else { print("无法访问目标PDF文件") continue } defer { url.stopAccessingSecurityScopedResource() // 用完后释放权限 } if let thumbnail = thumbnailFromPdf(withUrl: url, pageNumber: 0) { self.modelController.bidPDFUploadThumbnails.append(thumbnail) } else { print("该PDF无法生成缩略图") } } tableView.reloadData() }
2. PDF页码索引错误
CGPDFDocument的page(at:)方法是从1开始计数的,你传入的pageNumber:0会导致无法获取页面,直接触发guard分支返回nil。
修改thumbnailFromPdf方法的页码获取逻辑:
guard let pdf = CGPDFDocument(url as CFURL), // 转换为CGPDF要求的1起始索引 let page = pdf.page(at: pageNumber + 1) else { print("PDF文件损坏或指定页码不存在") return nil }
3. 绘图上下文兼容性问题
UIGraphicsBeginImageContext在Retina屏幕下会生成模糊图片,且存在上下文获取失败的风险,推荐使用iOS 10+引入的UIGraphicsImageRenderer替代。
修改后的完整thumbnailFromPdf方法:
func thumbnailFromPdf(withUrl url: URL, pageNumber: Int, width: CGFloat = 240) -> UIImage? { guard let pdf = CGPDFDocument(url as CFURL), let page = pdf.page(at: pageNumber + 1) else { return nil } let pageRect = page.getBoxRect(.mediaBox) let pdfScale = width / pageRect.size.width let targetSize = CGSize(width: pageRect.size.width * pdfScale, height: pageRect.size.height * pdfScale) // 使用UIGraphicsImageRenderer生成高清缩略图 let renderer = UIGraphicsImageRenderer(size: targetSize) return renderer.image { context in let cgContext = context.cgContext // 填充白色背景 cgContext.setFillColor(UIColor.white.cgColor) cgContext.fill(CGRect(origin: .zero, size: targetSize)) cgContext.saveGState() // 调整坐标系适配PDF绘制方向 cgContext.translateBy(x: 0, y: targetSize.height) cgContext.scaleBy(x: 1.0, y: -1.0) cgContext.concatenate(page.getDrawingTransform(.mediaBox, rect: CGRect(origin: .zero, size: targetSize), rotate: 0, preserveAspectRatio: true)) cgContext.drawPDFPage(page) cgContext.restoreGState() } }
4. 额外优化:UTType简化
iOS 14+可以直接使用系统定义的UTType.pdf,避免手动构造类型可能出现的匹配错误:
func uploadPDF() { let documentPickerController = UIDocumentPickerViewController(forOpeningContentTypes: [.pdf]) documentPickerController.delegate = self self.present(documentPickerController, animated: true, completion: nil) }
内容的提问来源于stack exchange,提问作者Christian W
相关产品推荐
相关产品推荐

