Получить CGPDFDocumentRef название документа
Можно ли получить название документа из CGPDFDocumentRef
1 ответ
Под "названием документа" вы подразумеваете имя файла или название документа?
Если документ "title" включен в метаданные, его можно получить следующим образом:
char *titleKey = "Title";
CGPDFStringRef titleStringRef;
CGPDFDictionaryRef info = CGPDFDocumentGetInfo(myDocumentRef);
CGPDFDictionaryGetString(info, titleKey, &titleStringRef);
const unsigned char *titleCstring = CGPDFStringGetBytePtr(titleStringRef);
printf("title: %s", titleCstring);
Другие ключи перечислены в разделе 10.2 спецификации PDF 1.7: Справочные архивы Adobe PDF
Вот как это сделать в 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)
Собрав эту информацию, пришло время получить Swift String из строки C. К счастью, CFString бесплатно подключена к Swift String, что означает, что мы можем использовать
CFStringCreateWithBytes
вызовите и просто приведите результат к String.
if let title = CFStringCreateWithBytes(allocator, optionalTitle, length, encoding, true) {
return title as String
}
}
return nil
* Ключи для значений в этом словаре можно найти в Справочнике Adobe PDF, ТАБЛИЦА 10.2 "Записи в информационном словаре документа" на странице 844.