Technical Article

مدیریت فایل‌های PDF با مرجع ترکیبی از برنامه‌های آفیس در دلفی

هنگام توسعه راهکارهای سازمانی برای اسناد، ناگزیر با فایل‌های PDF تولید شده توسط ابزارهای بسیار متنوعی مواجه خواهید شد؛ از نرم‌افزارهای پیشرفته Adobe گرفته تا کتابخانه‌های متن‌باز پر از باگ یا درایورهای چاپگر مجازی. یکی از معروف‌ترین مشکلات ساختاری که با آن روبرو خواهید شد، فایل‌های PDF با "مرجع ترکیبی" (hybrid-reference) است.

در این مقاله، توضیح خواهیم داد که مراجع ترکیبی چه هستند، چرا برخی برنامه‌های آفیس آن‌ها را تولید می‌کنند، و چگونه می‌توان با استفاده از دلفی و کتابخانه‌های قدرتمند PDF، این ساختارها را به صورت برنامه‌نویسی تجزیه و تعمیر کرد.

سیر تکامل جدول مرجع متقابل PDF

برای یافتن سریع اشیاء (فونت‌ها، تصاویر، صفحات) بدون تجزیه کل فایل، PDF از یک جدول مرجع متقابل (XRef) استفاده می‌کند. در مشخصات اولیه PDF (نسخه 1.4 و قدیمی‌تر)، این جدول به صورت یک متن ASCII در انتهای فایل بود.

با شروع از نسخه PDF 1.5، شرکت Adobe جریان‌های مرجع متقابل (XRefStm) را معرفی کرد که داده‌های مرجع متقابل را در یک جریان باینری فشرده می‌کرد و اندازه فایل را به طور قابل توجهی کاهش می‌داد. با این حال، برای حفظ سازگاری با خواننده‌های قدیمی‌تر PDF، برخی تولیدکنندگان شروع به ساخت فایل‌های PDF با مرجع ترکیبی کردند. این فایل‌ها شامل هم یک جدول متنی XRef قدیمی و هم یک جریان XRef جدید هستند.

مشکل مراجع ترکیبی

فایل‌های ترکیبی از نظر تئوری معتبر هستند، اما بسیاری از تولیدکنندگان PDF (به‌ویژه افزونه‌های قدیمی "Save to PDF" در مجموعه‌های آفیس قدیمی) آن‌ها را به درستی نمی‌نویسند. یک باگ رایج، نوشتن افست بایت نادرست برای اشاره‌گر startxref، یا ایجاد جریان‌های شیء از هم گسیخته است که در آن جدول XRef به شماره نسل اشتباهی اشاره می‌کند.

اگر برنامه دلفی شما تلاش کند یک فایل PDF ترکیبی با ساختار ضعیف را با استفاده از یک تجزیه‌کننده سخت‌گیر بخواند، تجزیه‌کننده با خطای "جدول XRef خراب" یا "شماره شیء نامعتبر" متوقف می‌شود.

مدیریت جایگزین‌های ترکیبی با PDFium

موتور PDFium (که در ابتدا توسط Foxit توسعه یافت و توسط گوگل متن‌باز شد) در برابر فایل‌های PDF دارای ساختار نامعتبر بسیار مقاوم است. هنگامی که یک جدول XRef خراب را تشخیص می‌دهد، به طور خودکار فایل را از انتها (EOF) به عقب اسکن می‌کند تا XRefStm جایگزین را پیدا کند.

در دلفی، هنگام کار با PDFium، نیازی نیست دیکشنری‌های تریلر را به صورت دستی تجزیه کنید. با این حال، باید هشدارهای ساختاری را بررسی کنید تا بتوانید به کاربر اطلاع دهید یا مشکل را در لاگ ثبت کنید.

uses
  System.SysUtils, pdfium_lib;

procedure LoadAndCheckHybridPDF(const FileName: string);
var
  Doc: FPDF_DOCUMENT;
  LastError: ULONG;
begin
  FPDF_InitLibrary();
  try
    Doc := FPDF_LoadDocument(PAnsiChar(AnsiString(FileName)), nil);
    if Doc = nil then
    begin
      LastError := FPDF_GetLastError();
      case LastError of
        FPDF_ERR_FILE: Writeln('File not found or could not be opened.');
        FPDF_ERR_FORMAT: Writeln('File not in PDF format or corrupted.');
        FPDF_ERR_PASSWORD: Writeln('Password required or incorrect password.');
        FPDF_ERR_SECURITY: Writeln('Unsupported security scheme.');
        FPDF_ERR_XFDF: Writeln('Invalid XRef or Hybrid Reference structure.');
      else
        Writeln('Unknown error occurred loading PDF.');
      end;
      Exit;
    end;
    
    Writeln('PDF loaded successfully despite hybrid or structural anomalies.');
    
    // Proceed with processing...
    
    FPDF_CloseDocument(Doc);
  finally
    FPDF_DestroyLibrary();
  end;
end;

تعمیر و بازسازی PDF

اگر جریان کاری شما نیازمند ارسال PDF به یک سیستم پایین‌دستی سخت‌گیرتر (مانند یک سخت‌افزار قدیمی RIP) است، باید ساختار ترکیبی را "تخت" (flatten) کنید. مطمئن‌ترین راه برای تعمیر یک فایل PDF ترکیبی خراب در دلفی، بارگذاری آن در یک موتور مقاوم و انجام عملیات Save-As است. این کار تجزیه‌کننده را مجبور می‌کند تا یک جدول XRef تمیز و یکپارچه را از درخت اشیاء موجود در حافظه بازسازی کند.

// Conceptual example using a high-level wrapper
procedure RebuildPdfStructure(const InputFile, OutputFile: string);
var
  Doc: TlxPDFDocument;
begin
  Doc := TlxPDFDocument.Create;
  try
    // Tolerant engine ignores the broken hybrid XRef and walks the objects
    Doc.LoadFromFile(InputFile);
    
    // Saving rewrites the file with a clean PDF 1.7 XRef stream
    Doc.SaveToFile(OutputFile);
    Writeln('PDF structure successfully rebuilt.');
  finally
    Doc.Free;
  end;
end;

درک و پیش‌بینی خرابی مراجع ترکیبی تضمین می‌کند که خطوط لوله پردازش اسناد شما مقاوم باقی بمانند، حتی زمانی که با فایل‌های قدیمی مربوط به دهه‌های گذشته مواجه می‌شوند.

توجه: رفع مشکلات مراجع ترکیبی و تعمیرات ساختاری خودکار به طور کامل در کامپوننت PDFium Component VCL پشتیبانی می‌شوند.