创建多页 PDF

2024-01-03

我需要实现创建包含多页文本的 pdf 的功能。

class PDFCreator {

func prepareData() -> Data {
    //1
    let pdfMetaData = [
      kCGPDFContextCreator: "PDF Creator",
      kCGPDFContextAuthor: "Pratik Sodha",
      kCGPDFContextTitle: "My PDF"
    ]

    //2
    let format = UIGraphicsPDFRendererFormat()
    format.documentInfo = pdfMetaData as [String: Any]

    //3
    let pageWidth = 8.5 * 72.0
    let pageHeight = 11 * 72.0
    let pageRect = CGRect(x: 0, y: 0, width: pageWidth, height: pageHeight)

    //4
    let renderer = UIGraphicsPDFRenderer(bounds: pageRect, format: format)

    //5
    let data = renderer.pdfData { (context) in
        //6
        context.beginPage()
        self.addText("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.", pageRect: pageRect)

    }

    return data
}

@discardableResult
func addText(_ text : String, pageRect: CGRect) -> CGFloat {

    // 1
    let textFont = UIFont.systemFont(ofSize: 60.0, weight: .regular)

    // 2
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = .natural
    paragraphStyle.lineBreakMode = .byWordWrapping

    // 3
    let textAttributes = [
        NSAttributedString.Key.paragraphStyle: paragraphStyle,
        NSAttributedString.Key.font: textFont
    ]
    let attributedText = NSAttributedString(string: text, attributes: textAttributes)
    let textSize = attributedText.boundingRect(with: pageRect.size, options: [.usesFontLeading, .usesLineFragmentOrigin], context: nil)

    // 4
    let textRect = CGRect(x: 10,
                          y: 10,
                          width: pageRect.width - 20,
                          height: textSize.height)

    attributedText.draw(in: textRect)

    return textRect.origin.y + textRect.size.height
  }
}

Using PDFCreator类准备 pdf 数据并使用 PDFView 显示。

import UIKit
import PDFKit

class PDFPreviewViewController: UIViewController {

    //1
    @IBOutlet weak private var pdfView : PDFView!

    override func viewDidLoad() {

        super.viewDidLoad()

        //2
        let pdfData = PDFCreator().prepareData()

        //3
        pdfView.document = PDFDocument(data: pdfData)
        pdfView.autoScales = true
    }
}

实际产量

异常输出

整个文本将以 PDF 格式显示,并带有新的 PDF 页面,而不会减小字体大小。

非常感谢任何帮助。 谢谢。


Output

固定使用CTFramesetterCreateFrame and CFAttributedStringGetLength


class PDFCreator {

lazy var pageWidth : CGFloat  = {
    return 8.5 * 72.0
}()

lazy var pageHeight : CGFloat = {
    return 11 * 72.0
}()

lazy var pageRect : CGRect = {
    CGRect(x: 0, y: 0, width: pageWidth, height: pageHeight)
}()

lazy var marginPoint : CGPoint = {
    return CGPoint(x: 10, y: 10)
}()

lazy var marginSize : CGSize = {
    return CGSize(width: self.marginPoint.x * 2 , height: self.marginPoint.y * 2)
}()


func prepareData() -> Data {
    //1
    let pdfMetaData = [
      kCGPDFContextCreator: "PDF Creator",
      kCGPDFContextAuthor: "Pratik Sodha",
      kCGPDFContextTitle: "My PDF"
    ]

    //2
    let format = UIGraphicsPDFRendererFormat()
    format.documentInfo = pdfMetaData as [String: Any]

    //3
    let renderer = UIGraphicsPDFRenderer(bounds: pageRect, format: format)

    //5
    let data = renderer.pdfData { (context) in

        //6
        self.addText("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.", context: context)
    }

    return data
}

@discardableResult
func addText(_ text : String, context : UIGraphicsPDFRendererContext) -> CGFloat {

    // 1
    let textFont = UIFont.systemFont(ofSize: 60.0, weight: .regular)

    // 2
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = .natural
    paragraphStyle.lineBreakMode = .byWordWrapping

    // 3
    let textAttributes = [
        NSAttributedString.Key.paragraphStyle: paragraphStyle,
        NSAttributedString.Key.font: textFont
    ]

    //4
    let currentText = CFAttributedStringCreate(nil,
                                               text as CFString,
                                               textAttributes as CFDictionary)
    //5
    let framesetter = CTFramesetterCreateWithAttributedString(currentText!)

    //6
    var currentRange = CFRangeMake(0, 0)
    var currentPage = 0
    var done = false
    repeat {

        //7
        /* Mark the beginning of a new page.*/
        context.beginPage()

        //8
        /*Draw a page number at the bottom of each page.*/
        currentPage += 1
        drawPageNumber(currentPage)


        //9
        /*Render the current page and update the current range to
          point to the beginning of the next page. */
        currentRange = renderPage(currentPage,
                                  withTextRange: currentRange,
                                  andFramesetter: framesetter)

        //10
        /* If we're at the end of the text, exit the loop. */
        if currentRange.location == CFAttributedStringGetLength(currentText) {
            done = true
        }

    } while !done

    return CGFloat(currentRange.location + currentRange.length)
}

func renderPage(_ pageNum: Int, withTextRange currentRange: CFRange, andFramesetter framesetter: CTFramesetter?) -> CFRange {
    var currentRange = currentRange
    // Get the graphics context.
    let currentContext = UIGraphicsGetCurrentContext()

    // Put the text matrix into a known state. This ensures
    // that no old scaling factors are left in place.
    currentContext?.textMatrix = .identity

    // Create a path object to enclose the text. Use 72 point
    // margins all around the text.
    let frameRect = CGRect(x: self.marginPoint.x, y: self.marginPoint.y, width: self.pageWidth - self.marginSize.width, height: self.pageHeight - self.marginSize.height)
    let framePath = CGMutablePath()
    framePath.addRect(frameRect, transform: .identity)

    // Get the frame that will do the rendering.
    // The currentRange variable specifies only the starting point. The framesetter
    // lays out as much text as will fit into the frame.
    let frameRef = CTFramesetterCreateFrame(framesetter!, currentRange, framePath, nil)

    // Core Text draws from the bottom-left corner up, so flip
    // the current transform prior to drawing.
    currentContext?.translateBy(x: 0, y: self.pageHeight)
    currentContext?.scaleBy(x: 1.0, y: -1.0)

    // Draw the frame.
    CTFrameDraw(frameRef, currentContext!)

    // Update the current range based on what was drawn.
    currentRange = CTFrameGetVisibleStringRange(frameRef)
    currentRange.location += currentRange.length
    currentRange.length = CFIndex(0)

    return currentRange
}

func drawPageNumber(_ pageNum: Int) {

    let theFont = UIFont.systemFont(ofSize: 20)

    let pageString = NSMutableAttributedString(string: "Page \(pageNum)")
    pageString.addAttribute(NSAttributedString.Key.font, value: theFont, range: NSRange(location: 0, length: pageString.length))

    let pageStringSize =  pageString.size()

    let stringRect = CGRect(x: (pageRect.width - pageStringSize.width) / 2.0,
                            y: pageRect.height - (pageStringSize.height) / 2.0 - 15,
                            width: pageStringSize.width,
                            height: pageStringSize.height)

    pageString.draw(in: stringRect)

}
}

使用 PDFCreator 类准备 pdf 数据并使用 PDFView 显示。

import UIKit
import PDFKit

class PDFPreviewViewController: UIViewController {

    //1
    @IBOutlet weak private var pdfView : PDFView!

    override func viewDidLoad() {

        super.viewDidLoad()

        //2
        let pdfData = PDFCreator().prepareData()

        //3
        pdfView.document = PDFDocument(data: pdfData)
        pdfView.autoScales = true
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

创建多页 PDF 的相关文章

  • ios7 navigationController PushViewController 动画错误

    看来我在 navigationController PushViewController 方法中发现了一个错误 为了重新创建它 我采用了示例主详细信息项目并对 didSelectRow method void tableView UITab
  • AVCaptureSession 具有多个方向问题

    我正在尝试实现条形码扫描仪 我有一个 AVCaptureSession 它从 AVCaptureDevice 接收视频 我想支持所有方向 使用以下代码 当我运行应用程序时 纵向一切正常 然而 在横向方向上 视图会旋转 但视频输入不会旋转 所
  • 如何使用完成处理程序等待 firestore 请求的完成

    我正在慢慢地了解完成处理程序 如果我有一个 firestore 查询 如果我想使用完成处理程序 则有点向后工作 当 firestore 查询完成时 我必须使用completion 但它的设置功能仍然让我感到困惑 因此 如果这是一个将闭包作为
  • Swift:如何减少 didupdatelocations 调用

    我想出了一些代码来打印我所在位置的地址和邮政编码 这是在 didupdatelocation 函数中完成的 我遇到的唯一问题是 didupdatelocation 函数每秒都会更新该地址 因为这电池效率非常低 所以我一直在寻找使用间隔的方法
  • 从命令行调试 iOS 应用程序构建

    我正在通过命令行构建 iOS 应用程序 但在调试它时遇到问题 如果我使用 XCode 进行构建 它会让我在设备上 构建和调试 而不会出现任何问题 但现在 我不知道如何使用 gdb 在设备上启动它并逐步执行它 如果我尝试 添加自定义目标 可执
  • 当 UITextField 已满或空时显示警报 Swift

    下面的代码中 如果 userNameTF 或 passwordTF 已满或为空 则会显示警报 IBAction func LoginBtn sender AnyObject let userName userNameTF text let
  • 如何使用文件输入在PDFJS中打开本地PDF?

    我想知道是否有办法使用选择pdf文件input type file 并使用打开它PDFJS https github com mozilla pdf js 您应该能够使用 FileReader 来获取文件对象的内容作为类型化数组 pdfjs
  • iPhone UINavigationBar 使用 [UINavigationBar 外观] 更改所有控制器的字体样式

    我知道我可以单独更改导航栏的字体 如本答案所述 更改导航栏的字体 https stackoverflow com questions 5832036 change the navigation bars font 目前我正在使用一种更全局的
  • 如何将字符串日期转换为 NSDate?

    我想转换字符串 2014 07 15 06 55 14 198000 00 00 to an NSDate在斯威夫特 尝试这个 let dateFormatter NSDateFormatter dateFormatter dateForm
  • iOS 滚动视图允许滚动过去的内容

    我正在努力优化我的应用程序以适应横向和较小的屏幕 我主要使用滚动视图来实现这一点 在我的其中一个视图中 我有一个容器视图 当我在故事板中的设备之间切换时 这个容器视图看起来很完美 容器视图映射到具有滚动视图的视图控制器 该滚动视图的顶部 底
  • 添加自定义过渡会导致 xib 加载错误的屏幕尺寸

    我正在尝试向具有 xib 的 UIViewController 添加自定义过渡 我尝试了几种方法 但它们都有相同的问题 视图显示的屏幕尺寸错误 我当前的示例基于以下教程 使用 Swift 在 iOS 中自定义 UIViewControlle
  • 为什么这个谓词格式会变成 '= nil'

    有人建议这个线程 https stackoverflow com questions 40686005 nspredicate crash after swift 3 migration与我的问题完全相同 但是 我的应用程序没有崩溃 并且我
  • iphone NSDate 转换问题

    在我的 facebook 图表 Api 中 我正在获取这些数据 来自杰森 updated time 2011 05 17T14 52 16 0000 我正在使用此代码将其转换为有效的日期格式 NSDateFormatter df NSDat
  • iOS 循环对象的属性并添加操作

    我有一个具有几个类似属性的类 UISliders 我想添加用户开始和结束使用每个滑块时的操作 每个滑块都将链接到同一个选择器 因此我考虑只是迭代它们 而不是编写 10 个几乎相同的代码块 问题是 最有效的方法是什么 我尝试过这样的事情 在运
  • NVActivityIndi​​catorView 仅适用于特定视图

    我正在使用这个库https github com ninjaprox NVActivityIndi catorView https github com ninjaprox NVActivityIndicatorView用于显示加载指示器
  • 在现有 iOS 应用程序中集成 React-native(0.40.0) 后找不到 Yoga/Yoga.h 头文件

    在我的 Swift iOS 应用程序中集成 React Native 后 我无法构建 yoga Yoga h file cannot be found 我已经浏览了文档 查看了react native github页面 检查了类似问题的SO
  • SKNode 上的 runAction 未完成

    我使用 NSOperation 子类来获取串行执行SKAction正如这个问题中所描述的 如何在 Swift 中子类化 NSOperation 以将 SKAction 对象排队以进行串行执行 https stackoverflow com
  • 如何反转 CGPath 的点顺序

    我想画一个圆圈 并用它打出字母 为此 我需要顺时针抚摸圆圈 逆时针抚摸字母 这一切都很好 但是当我使用 Core Text 获取字母路径时 我不知道如何从本质上反转该路径 不是镜像或旋转或任何东西 这很简单 我希望点笔画顺序是逆时针的 这实
  • 分发内部业务 IOS 应用程序

    我遇到了 IOS 应用程序分发的一个令人困惑的部分 因此 我需要简单细分一下我的限制 即仅将我的应用程序分发给我的员工 同事或任何被视为 内部 的人 这是表明我不希望该应用程序出现在应用程序商店中的另一种方式 我的情况是我为几家公司开发 他
  • 苹果推送通知在生产中不起作用

    我们完全陷入困境 请帮忙 我和我的团队制作了一个 iPhone 应用程序 这是我们第一次在 iOS 上尝试 一切都很好 直到我们提交应用程序并在应用程序商店上可用为止 推送通知服务无法正常工作 我在网上搜索并尝试根据人们的建议仔细检查我们的

随机推荐

  • 使用 IQueryable 创建动态查询

    我正在尝试迭代字符串数组并动态创建一个IQueryable询问 它非常简单 但这就是我被困的地方 var query context QuestionsMetaDatas AsQueryable var keywords new List
  • 有界上下文的大小

    我已经开始学习 DDD 的原理 目前正在尝试掌握有界上下文的概念 特别是 您如何决定它必须有多大 或多小 是的 我知道 尽可能小 必要时尽可能大 根据沃恩 弗农的说法 假设我要为博客建模 然后我可以说涉及 3 个有界上下文 1 首页 包含最
  • STTS 标签集的英文翻译

    德语最常见的词性标记集是STTS 标签集 http www ims uni stuttgart de projekte corplex TagSets stts table html 我需要每个标签的解释的英文翻译 作为一名语言学家 我对自
  • SignalR - 从上下文调用静态类型集线器

    我试图弄清楚如何从服务器调用强类型集线器上的方法 我正在使用 Net Core 2 0 我有一个强类型集线器接口 public interface IMessageHub Task Create Message message 和一个看起来
  • Docker compose spring boot redis 连接问题

    我正在运行一个简单的休息应用程序redis在 docker 容器 docker compose 中运行 我相信 redis必须可以使用 Spring Boot 访问http redis 6379 但是 它会抛出错误 018 07 22 21
  • 哪个 Web 应用程序框架与 Neo4J 高度集成?

    我今天一直在研究 Neo4j 我发现它令人兴奋 不知道是否有与Neo4J高度集成的Web应用框架 基本上我想开始尝试 Neo4J 我想也许有明显的 Web 框架选择 如果有的话 我也想尝试一下 你知道任何 编辑 我全部收回 Neo4j 网站
  • Outlook 中的 XML 功能区 - 使其显示在特定窗口上

    我第一次尝试使用 XML 在 Outlook 中创建功能区 但无法具体找到如何告诉我的加载项我只希望功能区显示在资源管理器窗口上 Advice Thanks 我的 Ribbon1 XML 文件
  • 从 javascript 关闭 Firefox 选项卡

    我想从 JavaScript 关闭 Firefox 选项卡 请不要误解我 我不是想关闭弹出窗口 而是关闭选项卡 我知道 JavaScript 无法关闭它尚未打开的窗口 因此我尝试了下面的代码 但它适用于所有浏览器 但不适用于 Firefox
  • 如何从字符串中删除多个违规字符? [复制]

    这个问题在这里已经有答案了 这是我的工作代码 string Input string Output Input data Output Input Replace 在这里 我只是从字符串中删除括号 如果存在 现在 如何扩展 等违规字符列表以
  • %~1 在这个批处理文件中做了什么?

    我找到了这段代码 但有些部分我不明白 这是我的代码 主要 bat echo off set CallCount 0 set Mood set P Mood Your mood is call Receive bat Mood rem Ran
  • 求叶子的总和

    我应该写这样的代码 具有任意数量子节点的多态树类型可以表示如下 请注意 叶子存储一个列表 内部节点存储 ListTree 列表 data ListTree a ListLEAF a ListNODE ListTree a deriving
  • java.io.IOException:无法运行程序“:CreateProcess 错误=193,%1 不是有效的 Win32 应用程序

    当尝试在 Eclipse 中从 java 运行 shell 脚本时 出现以下错误 我刚刚在本地创建了一个文本文件 想看看它是否会运行 new ProcessBuilder C Users myDir Desktop ss1 sh start
  • 将 2 个参数传递给 Laravel 路由 - 资源

    我正在尝试使用资源构建我的路线 以便我可以将两个参数传递到我的资源中 我将向您提供一些 URL 的示例 domain com dashboard domain com projects domain com project 100 doma
  • Sequelize 模型单元测试

    我有一个User续集模型具有beforeCreate使用加密密码的钩子bcrypyt Bcrypyt模型使用以下方法将其作为依赖项加载require陈述 现在 我正在为我的模型编写测试 我想编写一个测试来确保bcrypt在创建时对密码进行哈
  • 如何使整个页面变暗? ( html )

    当我使用其他 div 来执行此操作时 它不会影响其他 dom 类 因此当我希望整个页面变暗时 我必须修改每个 dom 类 有没有办法用灰色透明平面重叠整个文档 有一个codepen http codepen io srikarg full
  • 上传到 Firebase 托管无法正常工作

    我刚刚使用 AngularJS 和 Firebase 作为实时数据库构建了我的第一个 Web 应用程序 当我在本地主机上运行它时 我想要它做的一切对我来说都很有效 但是 当我将其加载到 Firebase Hosting 并打开它时 文件尚未
  • 当数组中的 json 对象数量未知时,如何从 mysql 文本列中提取 json 数组作为表?

    有没有办法从包含具有不同数量的 json 对象的 json 数组的文本列中提取数据到表中 例如 如果我 CREATE TABLE tableWithJsonStr location TEXT jsonStr TEXT INSERT INTO
  • 尝试将实体映射到 DTO 对象时 ModelMapper 返回 NULL

    这是我尝试映射的对象的类 package com agent module entities import java util Set import javax persistence Entity import javax persist
  • 在 C# 应用程序中嵌入 Excel 的最佳方法是什么 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我想将 MS Excel 嵌入到我的 wpf C 应用程序中的选项卡式视图中 以便用户可以利用真正的 MS Excel 不是克隆 轻松
  • 创建多页 PDF

    我需要实现创建包含多页文本的 pdf 的功能 class PDFCreator func prepareData gt Data 1 let pdfMetaData kCGPDFContextCreator PDF Creator kCGP