【问题标题】:Get CGPDFDocumentRef name of document获取 CGPDFDocumentRef 文档名称
【发布时间】:2011-08-18 10:10:05
【问题描述】:

是否可以从CGPDFDocumentRef 中检索文档的名称

【问题讨论】:

    标签: ios cgpdfdocument


    【解决方案1】:

    “文档名称”是指文档的文件名还是标题?

    如果文档“标题”包含在元数据中,则可以这样检索:

        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

    【讨论】:

    • 谢谢,我实际上是指文件名,但我猜这是不可能的。您是否知道从元数据中检索创建日期的密钥?
    • “CreationDate”,还有一个“ModDate”。
    【解决方案2】:

    以下是在 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 引用转换为指针,我们在它前面加上 &amp;。如果在创建 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&lt;UnsafePointer&lt;UInt8&gt;&gt;

                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“文档信息字典中的条目”中找到。

    【讨论】:

    • 你能评论一下答案吗?这将有助于其他人了解它的工作原理。
    • @WilliamPrigolLopes 感谢您的提醒,我已尽我所知添加了解释。
    猜你喜欢
    • 1970-01-01
    • 2019-04-24
    • 2018-04-10
    • 1970-01-01
    • 2018-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多