获取文档的 CGPDFDocumentRef 名称

发布于 2024-11-05 04:06:41 字数 38 浏览 1 评论 0 原文

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

Is it possible to retrieve the name of a document from a CGPDFDocumentRef

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

北方的韩爷 2024-11-12 04:06:41

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

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

    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 参考档案

By "name of a document", do you mean the document filename or title?

If the document "title" is included in the metadata it can be retrieved like this:

    char *titleKey = "Title";
    CGPDFStringRef titleStringRef;

    CGPDFDictionaryRef info = CGPDFDocumentGetInfo(myDocumentRef);
    CGPDFDictionaryGetString(info, titleKey, &titleStringRef);
    const unsigned char *titleCstring = CGPDFStringGetBytePtr(titleStringRef);

    printf("title: %s", titleCstring);

The other keys are listed in section 10.2 of the PDF 1.7 specification: Adobe PDF Reference Archives

亣腦蒛氧 2024-11-12 04:06:41

以下是如何在 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>

            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 参考书,第 844 页表 10.2“文档信息字典中的条目”。

Here's how to do it in 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
    }
}

And here’s my understanding of how it works:

First, we check to see if the PDF document has an info dictionary attached. The PDF info dictionary can contain metadata including the title of the document.*

        guard let infoDict = self.info else {
            return nil
        }

If it does, we try to get the title from that dictionary using the CGPDFDictionary API. This API only accepts C types, so we need to perform some conversions to get the Swift String ”Title” represented as a C string.

        let titleKey = ("Title" as NSString).cString(using: String.Encoding.ascii.rawValue)!

The CGPDFDictionaryGetString call takes a pointer to a CGPDFStringRef? variable as its third argument. To convert a Swift reference to a pointer, we prepend it with &. The result of the dictionary lookup can be nil if the title wasn't specified when the PDF was created.

        var titleStringRef: CGPDFStringRef?
        CGPDFDictionaryGetString(infoDict, titleKey, &titleStringRef)
        if let stringRef = titleStringRef,
           let cTitle = CGPDFStringGetBytePtr(stringRef) {

At this point we know there is a title string, however it's not in a usable Swift string, yet. To read the C string from memory (with CFStringCreateWithBytes), we need to know where it starts (pointer) and after how many bytes to stop reading (length). Additionally, we specify that the string should be read using UTF-8 encoding and use the default memory layout. The last item we need is a properly typed reference to the C string. The type of a C string is a pointer to a char, which is represented as a UInt8 in memory. So we end up with Optional<UnsafePointer<UInt8>>.

            let length = CGPDFStringGetLength(stringRef)
            let encoding = CFStringBuiltInEncodings.UTF8.rawValue
            let allocator = kCFAllocatorDefault
            let optionalTitle: UnsafePointer<UInt8>! = Optional<UnsafePointer<UInt8>>(cTitle)

With that information collected, it’s now time to get the Swift String from the C string. Thankfully, CFString is toll-free bridged to Swift’s String, which means we can use the CFStringCreateWithBytes call and simply cast the result to String.

            if let title = CFStringCreateWithBytes(allocator, optionalTitle, length, encoding, true) {
                return title as String
            }
        }
        return nil

*The keys for the values in this dictionary can be found in the Adobe PDF Reference book, TABLE 10.2 "Entries in the document information dictionary" on page 844.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文