You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Swift中使用CGPDFDocument将两页PDF半尺寸并排至新PDF单页的实现问题

iOS Swift中使用CGPDFDocument将两页PDF半尺寸并排至新PDF单页的实现问题

你之前用UIImage转格式的方式遇到分辨率损失太正常了——毕竟转成位图就丢了PDF的矢量特性,直接操作CGPDFDocument才是正确的方向,能完美保留原PDF的清晰度!

你的现有代码是单独绘制单页的逻辑,要把两页并排到同一个新页面,核心问题是没正确管理绘图上下文的状态和坐标变换,导致第二页没画到正确位置。我给你梳理下关键思路和修正后的代码:

核心思路

  1. 先计算好新页面的尺寸:因为要把两页旋转90度后缩放到一半并排,新页面的宽度应该是原页面高度的1倍(两个半宽相加),高度是原页面宽度的一半;
  2. 在同一个新页面的上下文里,分别对两页做坐标变换(平移、缩放、旋转),用saveGState()和restoreGState()隔离每个页面的变换,避免互相干扰;
  3. 处理PDF坐标系和Core Graphics坐标系的翻转问题(PDF原点在左下角,CG默认是左上角)。

修正后的完整代码

// 确保能获取到原PDF的两页
guard let page1 = theCGPdfDocument.page(at: 1), 
      let page2 = theCGPdfDocument.page(at: 2) else {
    print("无法获取PDF页面")
    return
}

// 获取原页面的媒体框尺寸
let originalPageRect = page1.getBoxRect(.mediaBox)

// 计算单页缩放旋转后的尺寸:旋转90度后宽高互换,再缩放到1/2
let scaledSingleWidth = originalPageRect.size.height * 0.5
let scaledSingleHeight = originalPageRect.size.width * 0.5

// 新页面的媒体框:宽度是两个缩放页面的宽度之和,高度是单页缩放后的高度
var newPageRect = CGRect(x: 0, y: 0, width: scaledSingleWidth * 2, height: scaledSingleHeight)

// 开启新页面
writeContextInDestination!.beginPage(mediaBox: &newPageRect)

// ========== 绘制第一页 ==========
writeContextInDestination!.saveGState()

// 1. 先翻转坐标系,适配PDF的左下角原点
writeContextInDestination!.translateBy(x: scaledSingleWidth, y: scaledSingleHeight)
writeContextInDestination!.scaleBy(x: -1, y: -1)

// 2. 缩放到原尺寸的1/2,再旋转90度(顺时针)
writeContextInDestination!.scaleBy(x: 0.5, y: 0.5)
writeContextInDestination!.rotate(by: .pi/2)

// 3. 绘制第一页
writeContextInDestination!.drawPDFPage(page1)

// 恢复上下文状态,不影响第二页的绘制
writeContextInDestination!.restoreGState()

// ========== 绘制第二页 ==========
writeContextInDestination!.saveGState()

// 1. 平移到第二页的起始位置(x轴偏移一个单页宽度),再翻转坐标系
writeContextInDestination!.translateBy(x: scaledSingleWidth * 2, y: scaledSingleHeight)
writeContextInDestination!.scaleBy(x: -1, y: -1)

// 2. 同样的缩放和旋转
writeContextInDestination!.scaleBy(x: 0.5, y: 0.5)
writeContextInDestination!.rotate(by: .pi/2)

// 3. 绘制第二页
writeContextInDestination!.drawPDFPage(page2)

writeContextInDestination!.restoreGState()

// 结束当前页面并关闭PDF
writeContextInDestination!.endPage()
writeContextInDestination!.closePDF()

关键注意点

  • saveGState()和restoreGState()必须配对使用:每绘制一页前保存当前上下文状态,绘制完恢复,这样第一页的变换不会影响第二页的坐标计算;
  • 坐标变换的顺序很重要:Core Graphics的变换是矩阵叠加,顺序是从后往前生效,所以我们先做坐标系翻转,再做缩放旋转,最后绘制页面;
  • 新页面的尺寸一定要计算准确,不然会出现页面被裁剪或者留白过多的问题。

这样操作出来的新PDF完全是矢量格式,不会有任何分辨率损失,完美解决你之前的问题!

备注:内容来源于stack exchange,提问作者claude31

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 18:05:30