איך לטעון מסמך ב-C++
FOSS for C++ פותח קובץ PDF קיים דרך המחלקה Document — משנת נתיב קובץ רגיל, או עם סיסמה כאשר המקור מוצפן — ומחשוף את מטא-נתוני /Info של הקובץ דרך DocumentInfo. מדריך זה מכסה טעינת מסמך, זיהוי ופתיחת קבצים המוגנים בסיסמה, קריאה ועדכון של מטא-נתוני כותרת/מחבר/מפיק, ושמירת התוצאה. הספרייה מתווספת לפרויקט דרך 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: עדכן מטא-נתונים ושמור את המסמך
הגדר מטא-נתונים דרך העומסים המתאימים של הפונקציה setter, או דרך שיטת הנוחות 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 ב-trailer שלו והסיסמה שסופקה לא התאימה לאף אחת מהסיסמאות – של המשתמש או של הבעלים – שנרשמו שם. תפוסו את std::runtime_error והציעו למשתמש להכניס את הסיסמה הנכונה, או אשרו את הסיסמה מחוץ למערכת לפני ניסיון נוסף.
Save() זורק “no source filename to save to”
ה-Save() ללא ארגומנטים כותב חזרה אל הנתיב שממנו נוצר המסמך. Document שנוצר עם הקונסטרוקטור ללא ארגומנטים — מסמך חדש בזיכרון ללא קובץ מקור — אין לו נתיב לכתיבה חזרה, ולכן Save() זורק. קראו ל-Save(outputFileName) במקום.
Decrypt() לא נראה שהוא מייצר קובץ לא מוגן
Decrypt() מנקה את הדגל IsEncrypted() בזיכרון כך שהקריאות הבאות מתייחסות למסמך כטקסט רגיל, אך במהדורה הנוכחית הוא לא כותב מחדש את מילון /Encrypt של ה-trailer ולא מקודד מחדש מחרוזות וזרמים מוצפנים. קריאה ל-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 המקורי.