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

如何在Swift PDFKit的PDFView中实现圆角且保宽高比的图片标注

PDFView 图片标注实现圆角与保持原图宽高比问题

现有实现效果

当前效果

期望实现效果

期望效果

待实现需求

  • 图片标注拥有圆角效果
  • 图片保持原始宽高比

现有代码

自定义 PDFImageAnnotation 类

class PDFImageAnnotation: PDFAnnotation {

    var image: UIImage?

    convenience init(_ image: UIImage?, bounds: CGRect, properties: [AnyHashable : Any]?) {
        self.init(bounds: bounds, forType: PDFAnnotationSubtype.stamp, withProperties: properties)
        self.image = image
    }

    override func draw(with box: PDFDisplayBox, in context: CGContext) {
        super.draw(with: box, in: context)

        // Drawing the image within the annotation's bounds.
        guard let cgImage = image?.cgImage else { return }
        context.draw(cgImage, in: bounds)
    }
}

ViewDidLoad 调用代码

if let image = pet.picture?.getImage() {
    let imageAnnotation = PDFImageAnnotation(image, bounds: CGRect(x: 80, y: 1100, width: 300, height: 300), properties: nil)
    pdfView.currentPage?.addAnnotation(imageAnnotation)
}

解决方案

你需要在draw方法中分别处理「宽高比适配」和「圆角裁剪」两个逻辑:

  1. 首先根据原始图片尺寸和传入的最大bounds计算等比缩放后的实际绘制尺寸,居中对齐
  2. 利用CoreGraphics的路径裁剪能力,先添加圆角矩形裁剪路径再绘制图片,即可实现圆角效果
  3. 操作上下文前后需要保存/恢复状态,避免影响其他绘制逻辑

修改后的完整代码

自定义PDFImageAnnotation类

class PDFImageAnnotation: PDFAnnotation {
    var image: UIImage?
    // 支持自定义圆角半径,默认值为10
    var cornerRadius: CGFloat = 10

    convenience init(_ image: UIImage?, maxBounds: CGRect, properties: [AnyHashable : Any]?) {
        self.init(bounds: maxBounds, forType: PDFAnnotationSubtype.stamp, withProperties: properties)
        self.image = image
    }

    override func draw(with box: PDFDisplayBox, in context: CGContext) {
        super.draw(with: box, in: context)
        guard let validImage = image else { return }
        
        // 计算等比缩放后的实际绘制尺寸,居中显示在最大bounds范围内
        let originSize = validImage.size
        let maxW = bounds.width
        let maxH = bounds.height
        let scaleRatio = min(maxW / originSize.width, maxH / originSize.height)
        let actualDrawSize = CGSize(width: originSize.width * scaleRatio, height: originSize.height * scaleRatio)
        let actualDrawRect = CGRect(
            x: bounds.minX + (maxW - actualDrawSize.width) / 2,
            y: bounds.minY + (maxH - actualDrawSize.height) / 2,
            width: actualDrawSize.width,
            height: actualDrawSize.height
        )

        // 上下文状态入栈,添加圆角裁剪
        context.saveGState()
        UIBezierPath(roundedRect: actualDrawRect, cornerRadius: cornerRadius).addClip()
        // 绘制图片
        validImage.draw(in: actualDrawRect)
        // 恢复上下文状态
        context.restoreGState()
    }
}

调用代码

if let image = pet.picture?.getImage() {
    // 传入图片可占用的最大区域作为maxBounds
    let imageAnnotation = PDFImageAnnotation(image, maxBounds: CGRect(x: 80, y: 1100, width: 300, height: 300), properties: nil)
    // 可按需自定义圆角大小,例如设置为20:
    // imageAnnotation.cornerRadius = 20
    pdfView.currentPage?.addAnnotation(imageAnnotation)
}

内容的提问来源于stack exchange,提问作者Jack Stark

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 03:24:02