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

iOS开发中如何在旋转的PDFKit.PDFPage上绘制正向注释

iOS PDFKit旋转页面注释适配方案

坐标转换通用规则(对应问题Q1)

所有坐标计算的基准为页面未旋转时的媒体框(MediaBox)尺寸:先取rotation = 0状态下页面的媒体框宽高,记为originalPageWidth、originalPageHeight。
API返回的坐标规则固定为:原点在可见页面左下角、X轴向右延伸、Y轴向上延伸,先将接口返回的坐标组装为标准矩形:

let apiRect = CGRect(
    x: start_x,
    y: start_y,
    width: end_x - start_x,
    height: end_y - start_y
)

根据页面当前rotation属性值(仅可能为0、90、180、270,顺时针递增),将API矩形转换为PDFKit当前页面坐标系可直接使用的矩形,规则如下:

  • rotation = 0:无需转换,直接使用apiRect即可
  • rotation = 90:
    let convertedRect = CGRect(
        x: apiRect.minY,
        y: originalPageWidth - apiRect.maxX,
        width: apiRect.height,
        height: apiRect.width
    )
    
  • rotation = 180:
    let convertedRect = CGRect(
        x: originalPageWidth - apiRect.maxX,
        y: originalPageHeight - apiRect.maxY,
        width: apiRect.width,
        height: apiRect.height
    )
    
  • rotation = 270:
    let convertedRect = CGRect(
        x: originalPageHeight - apiRect.maxY,
        y: apiRect.minX,
        width: apiRect.height,
        height: apiRect.width
    )
    

注意:不要取旋转后页面的媒体框尺寸做计算,旋转后的媒体框会自动交换宽高,会导致坐标偏移。

注释边界与文本正向绘制实现(对应问题Q2)

不要通过在注释内嵌套UILabel的方式绘制文本,会受页面旋转上下文影响出现错位、消失问题,直接通过CoreGraphics在注释绘制回调中做矩阵抵消即可,步骤如下:

  1. 用上述步骤得到的convertedRect初始化PDF注释对象,设置好背景色、边框样式后添加到对应页面。
  2. 重写注释的绘制方法,在绘制内容前对上下文做反向旋转变换,抵消页面旋转的影响,保证文本始终正向显示:
    override func draw(with box: PDFDisplayBox, in context: CGContext) {
        // 先绘制注释默认的背景、边框
        super.draw(with: box, in: context)
        context.saveGState()
        
        let currentRotation = self.page?.rotation ?? 0
        let annoBounds = self.bounds
        
        // 根据页面旋转角度做反向矩阵变换
        switch currentRotation {
        case 90:
            context.rotate(by: -.pi / 2)
            context.translateBy(x: -annoBounds.height, y: 0)
        case 180:
            context.rotate(by: .pi)
            context.translateBy(x: -annoBounds.width, y: -annoBounds.height)
        case 270:
            context.rotate(by: .pi / 2)
            context.translateBy(x: 0, y: -annoBounds.width)
        default:
            break
        }
        
        // 直接在修正后的上下文绘制文本
        let textInset: CGFloat = 4
        let textRect = CGRect(
            x: textInset,
            y: textInset,
            width: annoBounds.width - textInset * 2,
            height: annoBounds.height - textInset * 2
        )
        let content = "Sample Anno" as NSString
        content.draw(in: textRect, withAttributes: [
            .font: UIFont.systemFont(ofSize: 14),
            .foregroundColor: UIColor.black
        ])
        
        context.restoreGState()
    }
    
  3. Xamarin.iOS环境下逻辑完全一致,仅需将语法替换为C#对应实现:用CGAffineTransform.Rotate、Context.TranslateCTM实现矩阵变换,用NSString.DrawString完成文本绘制即可。

常见避坑点

  • 不要直接修改页面的rotation属性,会导致整个页面渲染方向错乱,所有适配逻辑都在注释侧完成即可。
  • 无需套用通用任意角度旋转公式,PDFKit页面旋转角度只有四个固定值,硬编码四个场景的转换逻辑稳定性更高,不会出现随机偏移、文本缩放问题。
  • 尽量不要依赖UIKit原生控件(如UILabel)作为注释内容,直接用CoreGraphics接口绘制,矩阵变换可控性更强,不会出现文本丢失问题。

示例示意图

内容的提问来源于stack exchange,提问作者Hung X. Tran

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 16:12:16