Как загрузить документ в C++
Aspose.PDF FOSS for C++ открывает существующий PDF через класс Document — из простого пути к файлу или с паролем, если источник зашифрован — и предоставляет метаданные /Info файла через DocumentInfo. Это руководство охватывает загрузку документа, обнаружение и открытие файлов, защищённых паролем, чтение и обновление метаданных title/author/producer, а также сохранение результата. Библиотека добавляется в проект через CMake; шаг установки через менеджер пакетов отсутствует.
Пошаговое руководство
Шаг 1: Установить пакет
Добавьте библиотеку как подкаталог CMake и свяжите её с целью aspose_pdf_foss:
add_subdirectory(aspose.pdf-foss-for-cpp)
target_link_libraries(your_app PRIVATE aspose_pdf_foss)Проверьте, что набор инструментов и заголовки разрешаются, скомпилировав минимальную программу:
#include <aspose/pdf/document.hpp>
#include <iostream>
int main() {
Aspose::Pdf::Document doc;
std::cout << "Linked OK — pages: " << doc.Pages().Count() << "\n";
}Успешная сборка, печатающая pages: 0, подтверждает, что библиотека правильно связана.
Шаг 2: Импортировать необходимые классы
#include <aspose/pdf/document.hpp>
#include <aspose/pdf/document_info.hpp>
using namespace Aspose::Pdf;Document и DocumentInfo объявлены непосредственно в пространстве имён Aspose::Pdf.
Шаг 3: Открыть PDF-документ по пути к файлу
Конструктор Document(filename) читает файл, разбирает его таблицу перекрестных ссылок и дерево страниц, и строит модель в памяти. Он бросает std::system_error, если файл не существует или его нельзя прочитать, и std::runtime_error, если файл не является действительным PDF:
#include <iostream>
#include <stdexcept>
try {
Document doc("input.pdf");
std::cout << "Pages: " << doc.Pages().Count() << "\n";
} catch (const std::runtime_error& e) {
std::cerr << "Not a valid PDF: " << e.what() << "\n";
} catch (const std::system_error& e) {
std::cerr << "Could not read file: " << e.what() << "\n";
}Шаг 4: Открыть документ, защищённый паролем
Одноаргументный конструктор из Шага 3 никогда не проверяет пароль и не изучает запись /Encrypt трейлера, поэтому IsEncrypted() у документа, открытого таким способом, всегда сообщает false — даже если исходный файл действительно зашифрован. Чтобы обнаружить и открыть зашифрованный PDF, используйте двухаргументный конструктор, который читает /Encrypt и аутентифицирует предоставленный вами пароль:
try {
Document doc("input.pdf", "user-password");
if (doc.IsEncrypted()) {
std::cout << "Opened an encrypted document.\n";
}
} catch (const std::runtime_error& e) {
// Thrown when /Encrypt is present and the password matches
// neither the user nor the owner entry in the trailer.
std::cerr << "Wrong password or unreadable /Encrypt dictionary: "
<< e.what() << "\n";
}Если исходный PDF не зашифрован, аргумент пароля просто игнорируется, и документ открывается нормально — поэтому безопасно использовать двухаргументный конструктор, даже если вы не уверены, защищён ли файл.
Шаг 5: Прочитать метаданные документа с помощью DocumentInfo
Document.Info() возвращает DocumentInfo&, привязанный к словарю /Info документа. Каждое предопределённое поле имеет собственный аксессор чтения, который возвращает пустую строку, когда ключ отсутствует в исходном файле:
Document doc("input.pdf");
DocumentInfo& info = doc.Info();
std::cout << "Title: " << info.Title() << "\n";
std::cout << "Author: " << info.Author() << "\n";
std::cout << "Subject: " << info.Subject() << "\n";
std::cout << "Producer: " << info.Producer() << "\n";
std::cout << "Creator: " << info.Creator() << "\n";
std::cout << "Keywords: " << info.Keywords() << "\n";DocumentInfo::IsPredefinedKey сообщает, является ли указанное имя ключа /Info одним из этих встроенных полей, в отличие от пользовательского ключа, добавленного с помощью Add:
bool builtin = DocumentInfo::IsPredefinedKey("Title"); // true
bool custom = DocumentInfo::IsPredefinedKey("MyKey"); // false
Шаг 6: Обновить метаданные и сохранить документ
Установите метаданные через соответствующие перегрузки сеттера или через удобный метод SetTitle на Document, затем зафиксируйте изменение с помощью Save:
Document doc("input.pdf");
doc.Info().Author("Report Generator");
doc.SetTitle("Quarterly Report"); // equivalent to doc.Info().Title(title)
doc.Save("output.pdf");Изменения метаданных накапливаются в памяти и записываются только при следующем вызове Save. Вызовите Save(outputFileName), чтобы записать в новый путь, или безаргументный Save(), чтобы перезаписать файл, из которого документ был изначально открыт:
Document doc("input.pdf");
doc.SetTitle("Updated In Place");
doc.Save(); // writes back to "input.pdf"
Распространённые проблемы и решения
IsEncrypted() returns false для PDF, который, как я знаю, защищён паролем
Конструктор Document(path) с одним аргументом никогда не аутентифицируется против словаря /Encrypt файла, поэтому IsEncrypted() всегда сообщает false для документа, открытого таким способом, независимо от того, зашифрован ли источник на самом деле. Откройте файл с помощью конструктора Document(path, password) с двумя аргументами — это единственная перегрузка, которая заполняет состояние шифрования.
Конструктор с двумя аргументами бросает std::runtime_error
Это означает, что у исходного PDF есть запись /Encrypt в трейлере, и предоставленный пароль не совпадает ни с пользовательским, ни с паролем владельца, записанными там. Перехватите std::runtime_error и запросите правильный пароль, либо подтвердите пароль вне канала связи перед повторной попыткой.
Save() бросает “no source filename to save to”
Конструктор Save() без аргументов записывает изменения обратно в путь, из которого был построен документ. Document, созданный конструктором без аргументов — новый документ в памяти без исходного файла — не имеет пути для записи, поэтому Save() бросает исключение. Вместо этого вызовите Save(outputFileName).
Decrypt() не кажется, что создаёт незащищённый файл
Decrypt() сбрасывает в памяти флаг IsEncrypted(), поэтому последующие чтения рассматривают документ как обычный текст, но в текущей версии он не переписывает словарь /Encrypt трейлера и не перекодирует зашифрованные строки и потоки. Вызов Save() после Decrypt() всё равно записывает оригинальные байты, включая исходное шифрование — этот метод пока не создает копию в открытом виде на диске.
Title/Author/etc. выводятся как пустые строки
Аксессоры DocumentInfo возвращают пустую строку, а не ошибку, когда соответствующий ключ /Info отсутствует в исходном PDF. Пустой результат означает, что поле никогда не было установлено в этом документе, а не то, что чтение завершилось с ошибкой.
Часто задаваемые вопросы
Работает ли Document(path) с зашифрованным PDF?
Обычно он разбирает дерево страниц без исключений, но никогда не аутентифицирует пароль и всегда оставляет IsEncrypted() на уровне false. Используйте конструктор с двумя аргументами, когда источник может быть зашифрован.
Безопасно ли передавать пароль в Document(path, password) для файла, который окажется незашифрованным?
Да. Когда в трейлере отсутствует запись /Encrypt, аргумент пароля игнорируется, и документ открывается так же, как при использовании конструктора с одним аргументом.
Как отличить пользовательский ключ /Info от встроенного?
Вызовите статический DocumentInfo::IsPredefinedKey(key). Он возвращает true для Title, Author, Subject, Keywords, Creator, Producer и Trapped, а также false для всех остальных.
Могу ли я перезаписать только что загруженный файл вместо записи в новый путь?
Да — вызовите Save() без аргументов у Document, построенного из пути к файлу; он записывает обратно в тот же исходный путь. Он генерирует исключение для документов, созданных конструктором без аргументов, у которых нет исходного пути.
Удаляет ли сохранение после Decrypt() парольную защиту PDF?
Нет, в текущем выпуске — см. раздел «Общие проблемы» выше. Decrypt() влияет только на состояние в памяти, используемое читателями контента; файл, записанный Save(), всё равно содержит оригинальный словарь /Encrypt.