【发布时间】:2011-08-18 10:10:05
【问题描述】:
是否可以从CGPDFDocumentRef 中检索文档的名称
【问题讨论】:
标签: ios cgpdfdocument
是否可以从CGPDFDocumentRef 中检索文档的名称
【问题讨论】:
标签: ios cgpdfdocument
“文档名称”是指文档的文件名还是标题?
如果文档“标题”包含在元数据中,则可以这样检索:
char *titleKey = "Title";
CGPDFStringRef titleStringRef;
CGPDFDictionaryRef info = CGPDFDocumentGetInfo(myDocumentRef);
CGPDFDictionaryGetString(info, titleKey, &titleStringRef);
const unsigned char *titleCstring = CGPDFStringGetBytePtr(titleStringRef);
printf("title: %s", titleCstring);
其他键在 PDF 1.7 规范的第 10.2 节中列出:Adobe PDF Reference Archives
【讨论】:
以下是在 Swift 5 中的操作方法:
extension CGPDFDocument {
var title: String? {
guard let infoDict = self.info else {
return nil
}
let titleKey = ("Title" as NSString).cString(using: String.Encoding.ascii.rawValue)!
var titleStringRef: CGPDFStringRef?
CGPDFDictionaryGetString(infoDict, titleKey, &titleStringRef)
if let stringRef = titleStringRef,
let cTitle = CGPDFStringGetBytePtr(stringRef) {
let length = CGPDFStringGetLength(stringRef)
let encoding = CFStringBuiltInEncodings.UTF8.rawValue
let allocator = kCFAllocatorDefault
let optionalTitle: UnsafePointer<UInt8>! = Optional<UnsafePointer<UInt8>>(cTitle)
if let title = CFStringCreateWithBytes(allocator, optionalTitle, length, encoding, true) {
return title as String
}
}
return nil
}
}
这是我对其工作原理的理解:
首先,我们检查 PDF 文档是否附加了信息字典。 PDF 信息字典可以包含元数据,包括文档的标题。*
guard let infoDict = self.info else {
return nil
}
如果是这样,我们会尝试使用CGPDFDictionary API 从该字典中获取标题。这个 API 只接受 C 类型,所以我们需要执行一些转换来将 Swift String ”Title” 表示为 C 字符串。
let titleKey = ("Title" as NSString).cString(using: String.Encoding.ascii.rawValue)!
CGPDFDictionaryGetString 调用将指向CGPDFStringRef? 变量的指针作为其第三个参数。要将 Swift 引用转换为指针,我们在它前面加上 &。如果在创建 PDF 时未指定标题,则字典查找的结果可能为零。
var titleStringRef: CGPDFStringRef?
CGPDFDictionaryGetString(infoDict, titleKey, &titleStringRef)
if let stringRef = titleStringRef,
let cTitle = CGPDFStringGetBytePtr(stringRef) {
此时我们知道有一个标题字符串,但是它还不是一个可用的 Swift 字符串。要从内存中读取 C 字符串(使用CFStringCreateWithBytes),我们需要知道它从哪里开始(指针)以及在多少字节之后停止读取(长度)。此外,我们指定应使用 UTF-8 编码读取字符串并使用默认内存布局。我们需要的最后一项是对 C 字符串的正确键入的引用。 C 字符串的类型是指向char 的指针,它在内存中表示为UInt8。所以我们最终得到Optional<UnsafePointer<UInt8>>。
let length = CGPDFStringGetLength(stringRef)
let encoding = CFStringBuiltInEncodings.UTF8.rawValue
let allocator = kCFAllocatorDefault
let optionalTitle: UnsafePointer<UInt8>! = Optional<UnsafePointer<UInt8>>(cTitle)
收集到这些信息后,现在是时候从 C 字符串中获取 Swift 字符串了。值得庆幸的是,CFString 是免费桥接到 Swift 的 String,这意味着我们可以使用 CFStringCreateWithBytes 调用并将结果简单地转换为 String。
if let title = CFStringCreateWithBytes(allocator, optionalTitle, length, encoding, true) {
return title as String
}
}
return nil
*此字典中值的键可在Adobe PDF Reference book,第 844 页的表 10.2“文档信息字典中的条目”中找到。
【讨论】: