مقاله فنی

PDFlibPas Compliance and Signing Workbench in Delphi به فارسی

این مقاله فارسی موضوع PDFlibPas Compliance and Signing Workbench in Delphi به فارسی را برای تیم‌هایی توضیح می‌دهد که با Delphi، C++Builder، Lazarus/FPC و کامپوننت‌های losLab راهکارهای تولیدی می‌سازند

تمرکز بر تصمیم‌های عملی، ریسک‌ها و نکته‌های بازبینی است تا خروجی در محیط واقعی قابل اعتماد بماند

زمانی که این موضوع مهم می‌شود

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

  • فایل‌های ورودی، مجوزها، خروجی مورد انتظار و حالت‌های خطا را از ابتدا مشخص کنید
  • نام محصول‌ها، نام APIها و نام فایل‌ها را دقیقاً مانند مستندات نگه دارید
  • برای پشتیبانی آینده فایل‌های آزمون و لاگ‌های کوتاه نگهداری کنید

گردش‌کار عملی

نکته‌های اصلی متن انگلیسی را به یک گردش‌کار عملی Delphi تبدیل کنید. محورهای مهم منبع عبارت‌اند از:

  • سناریوی کاربردی را پیش از تغییر کد مشخص کنید
  • نتیجه را با فایل‌های آزمون کوچک بررسی کنید
  • نام APIها و مقدارهای literal را بدون تغییر نگه دارید

ابتدا یک نمونه کوچک و قابل بازتولید بسازید، سپس فراخوانی‌های کامپوننت، مدیریت خطا و پیام‌های کاربر را به آن وصل کنید. در قالب‌های سندی، جزئیات کوچک معمولاً تفاوت بین خروجی قابل اعتماد و خطای پشتیبانی‌نشده را ایجاد می‌کنند.

نشانه‌های API و کد

var
  PDF: TPDFlib;
  ListID, I: Integer;
begin
  PDF := TPDFlib.Create;
  try
    ListID := PDF.CheckFileCompliance('invoice-fixed.pdf', '', 1, 0);  // 1 = PDF/A
    if ListID = 0 then
    begin
      if PDF.LastErrorCode <> 0 then
        raise Exception.Create('Preflight could not read the file')
      else
        Writeln('No PDF/A findings');
    end
    else
    begin
      for I := 0 to PDF.GetStringListCount(ListID) - 1 do
        Writeln(PDF.GetStringListItem(ListID, I));
      PDF.ReleaseStringList(ListID);
    end;
  finally
    PDF.Free;
  end;
end;
ProcessID := PDF.NewSignProcessFromFile('invoice-fixed.pdf', '');
if ProcessID = 0 then
  raise Exception.Create('Cannot open source for signing');
PDF.SetSignProcessField(ProcessID, 'ApprovalSig');
PDF.SetSignProcessPFXFromFile(ProcessID, 'company.pfx', PfxPassword);
PDF.SetSignProcessInfo(ProcessID, 'Invoice approval', 'Berlin', 'billing@example.com');
PDF.SetSignProcessCustomSubFilter(ProcessID, 'ETSI.CAdES.detached');  // PAdES baseline
PDF.SetSignProcessDigestAlgorithm(ProcessID, 2);                      // SHA-256
PDF.SetSignProcessReserveContentsBytes(ProcessID, 8192);              // room for a later timestamp
PDF.EndSignProcessToFile(ProcessID, 'invoice-signed.pdf');
if PDF.GetSignProcessResult(ProcessID) <> 1 then
  Writeln('Sign failed, code ', PDF.GetSignProcessResult(ProcessID));
PDF.ReleaseSignProcess(ProcessID);

بازبینی پیش از انتشار

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

نام محصولات، نام APIها و قطعه‌کدها بدون تغییر حفظ شده‌اند تا توسعه‌دهندگان بتوانند متن را با مستندات و کد منبع تطبیق دهند

مطالعه مرتبط

نمونه‌های کد تکمیلی

var
  Doc: TPDFlibSignDoc;
  Names: TStringList;
  FS: TFileStream;
  I: Integer;
  SourceSize, RangeStart, GapStart, TailStart, TailLen: Int64;
begin
  // Capture the size before Open: the audit object holds a share lock on the file
  FS := TFileStream.Create('invoice-signed.pdf', fmOpenRead or fmShareDenyNone);
  SourceSize := FS.Size;
  FS.Free;
  Doc := TPDFlibSignDoc.Create;
  Names := TStringList.Create;
  try
    if not Doc.Open('invoice-signed.pdf', '', False) then Exit;
    Doc.GetSignatureFieldNames(Names);
    for I := 0 to Names.Count - 1 do
      if Doc.GetSignatureValueObjNum(Names[I]) > 0 then  // > 0 means the field is signed
      begin
        RangeStart := StrToInt64(string(Doc.GetSignatureValueByName(Names[I], 11)));
        GapStart   := StrToInt64(string(Doc.GetSignatureValueByName(Names[I], 12)));
        TailStart  := StrToInt64(string(Doc.GetSignatureValueByName(Names[I], 13)));
        TailLen    := StrToInt64(string(Doc.GetSignatureValueByName(Names[I], 14)));
        if (RangeStart = 0) and (TailStart + TailLen = SourceSize) then
          Writeln(Names[I], ': signature covers the file to EOF')
        else
          Writeln(Names[I], ': earlier revision, or unusual ByteRange layout');
      end;
    Doc.Close;
  finally
    Names.Free;
    Doc.Free;
  end;
end;

یادداشت‌های تکمیلی

این بخش تکمیلی نسخه کوتاه را به یک راهنمای عملی‌تر تبدیل می‌کند و همچنان با عنوان Building a Compliance and Signing Workbench in Delphi with PDFlibPas و توضیح پایهٔ انگلیسی آن هماهنگ می‌ماند. متن اصلی باید مشخص کند که مسئله از چه ورودی‌ای شروع می‌شود، چه خروجی‌ای انتظار می‌رود و چه وضعیتی باید به‌صورت دقیق در validation دیده شود.

در هنگام بازنویسی، ترتیب تصمیم‌ها مهم است: ابتدا شکل داده، سپس محدودهٔ تغییر، بعد وابستگی‌های API و در پایان رفتار نهایی. اگر مقاله به انتخاب میان چند مسیر اشاره می‌کند، توضیح بده چرا یکی از مسیرها برای نگه‌داری، پشتیبانی و بازتولید خطا قابل‌دفاع‌تر است.

هر جا code block، نام فایل، نام API یا مقدار literal وجود دارد، همان مقدار باید بدون تغییر بماند. توضیح پیرامونی می‌تواند گسترده‌تر شود، اما نمونهٔ کد باید همان مرجع دقیق باشد تا خواننده بتواند متن را با پروژهٔ Delphi، C++Builder یا Lazarus/FPC خودش تطبیق دهد.

در بخش validation باید از نمونهٔ ورودی کوچک، مقایسهٔ خروجی و ثبت نسخهٔ component یا validator حرف زده شود. اگر رفتار bug fix یا migration توضیح داده می‌شود، مسیر بازتولید، مشاهدهٔ اولیه و نقطهٔ تأیید باید صریح باشد تا بعداً بتوان regression را بدون حدس دنبال کرد.

این نوع گسترش به صفحه کمک می‌کند بعد از خواندن اول هم ارزش داشته باشد: برای reviewer به‌عنوان توضیح تصمیم، برای support به‌عنوان زمینهٔ تشخیص، و برای تیم نگه‌داری به‌عنوان یادداشت قابل استناد هنگام تغییرهای بعدی.

  • نام محصول، API، فایل و literal را تغییر نده
  • در صورت وجود code block آن را همان‌طور نگه دار
  • validation را با فایل نمونه و خروجی قابل مقایسه توضیح بده
  • مسیر تصمیم‌گیری را به‌جای خلاصهٔ خیلی کوتاه روشن کن