Technical Article

Automatizovana preflight provera PDF-a i revizija rizika pomoću PDFiuma

U tokovima posla vezanim za štampanje u preduzećima, arhiviranje i usklađenost dokumenata, PDF datoteka se ne može jednostavno "prikazati". Ona se mora revidirati. PDF može sadržati neporavnate (unflattened) grupe transparentnosti koje obaraju starije procesore rasterske slike (RIP), ugrađeni JavaScript koji predstavlja bezbednosni rizik, ili slike niske rezolucije koje će izgledati užasno kada se štampaju u 300 DPI.

Ovaj proces inspekcije PDF-a pre nego što uđe u produkcijski radni tok poznat je kao Preflight provera. U ovom članku ćemo istražiti kako da izgradite automatizovani alat za preflight proveru i reviziju rizika u Delphiju, koristeći mogućnosti parsiranja niskog nivoa koje nudi PDFium.

Ključne Preflight provere

Standardna revizija rizika obično proverava sledeće elemente unutar PDF-a:

  • Interaktivni elementi: JavaScript akcije, Launch akcije (pokretanje eksternih programa) i AcroForms.
  • Metrika resursa: Prisustvo slika niske rezolucije ili nedostajući ugrađeni fontovi.
  • Bezbednosni status: Šifrovanje dokumenta, zahtevi za lozinkom i dozvole pristupa (npr. onemogućeno štampanje).
  • Standardi dokumenata: Validacija PDF/A ili PDF/X markera usklađenosti u metapodacima dokumenta.

Izdvajanje PDF metapodataka i anotacija pomoću PDFiuma

PDFium obezbeđuje robustan C API koji Delphi može da koristi. Da bismo obavili preflight reviziju, mi ne prikazujemo samo stranicu; mi prolazimo kroz stablo PDF objekata. Pogledajmo kako proći kroz stranice dokumenta i pregledati anotacije kako bismo pronašli potencijalno rizične JavaScript akcije.

uses
  System.SysUtils, pdfium_lib;

procedure AuditPdfSecurity(const FileName: string);
var
  Doc: FPDF_DOCUMENT;
  PageCount, i, j: Integer;
  Page: FPDF_PAGE;
  AnnotCount: Integer;
  Annot: FPDF_ANNOTATION;
  AnnotSubType: FPDF_ANNOTATION_SUBTYPE;
  Action: FPDF_ACTION;
  ActionType: ULONG;
begin
  FPDF_InitLibrary();
  try
    // Load the document without a password
    Doc := FPDF_LoadDocument(PAnsiChar(AnsiString(FileName)), nil);
    if Doc = nil then
      raise Exception.Create('Failed to load document or password required.');
      
    try
      PageCount := FPDF_GetPageCount(Doc);
      Writeln(Format('Auditing %d pages...', [PageCount]));
      
      for i := 0 to PageCount - 1 do
      begin
        Page := FPDF_LoadPage(Doc, i);
        if Page <> nil then
        begin
          AnnotCount := FPDFPage_GetAnnotCount(Page);
          for j := 0 to AnnotCount - 1 do
          begin
            Annot := FPDFPage_GetAnnot(Page, j);
            if Annot <> nil then
            begin
              AnnotSubType := FPDFAnnot_GetSubtype(Annot);
              
              // Check for Link Annotations that might have malicious actions
              if AnnotSubType = FPDF_ANNOT_LINK then
              begin
                Action := FPDFAnnot_GetLinkAction(Annot);
                if Action <> nil then
                begin
                  ActionType := FPDFAction_GetType(Action);
                  // 2 represents PDFACTION_URI, 3 represents PDFACTION_SOUND, 4 represents PDFACTION_MOVIE
                  // We specifically look out for PDFACTION_LAUNCH or PDFACTION_JAVA_SCRIPT
                  if (ActionType = PDFACTION_JAVA_SCRIPT) or (ActionType = PDFACTION_LAUNCH) then
                  begin
                    Writeln(Format('WARNING: Malicious action detected on page %d', [i + 1]));
                  end;
                end;
              end;
              FPDFPage_CloseAnnot(Annot);
            end;
          end;
          FPDF_ClosePage(Page);
        end;
      end;
    finally
      FPDF_CloseDocument(Doc);
    end;
  finally
    FPDF_DestroyLibrary();
  end;
end;

Provera rezolucije slike

Još jedan kritičan korak preflight provere za tokove štampe je osiguravanje da nijedna slika ne padne ispod određenog DPI praga. PDFium vam omogućava da izdvojite objekte slika direktno iz toka stranice. Deljenjem dimenzija u pikselima izdvojene slike sa fizičkim dimenzijama (u tačkama) koje ona zauzima na PDF stranici, možete izračunati efektivni DPI.

procedure AuditPageImages(Page: FPDF_PAGE);
var
  ObjCount, i: Integer;
  PageObj: FPDF_PAGEOBJECT;
  ImgWidth, ImgHeight: Integer;
begin
  ObjCount := FPDFPage_CountObjects(Page);
  for i := 0 to ObjCount - 1 do
  begin
    PageObj := FPDFPage_GetObject(Page, i);
    if FPDFPageObj_GetType(PageObj) = FPDF_PAGEOBJ_IMAGE then
    begin
      FPDFImageObj_GetBitmap(PageObj); // Returns an FPDF_BITMAP you can inspect
      // Retrieve metadata using FPDFImageObj_GetImageMetadata
      // Calculate effective DPI based on quad coordinates
    end;
  end;
end;

Integracija sa PDFium Component-om

Izgradnja robusnog preflight mehanizma od nule koristeći sirovi PDFium C API zahteva značajan šablonski kod (boilerplate) i duboko poznavanje PDF specifikacije. Korišćenje omotača (wrapper-a) ovo neizmerno pojednostavljuje. Sa Delphi omotačem visokog nivoa, složene iteracije C pokazivača možete pretvoriti u čist objektno-orijentisani kod.

Automatizacijom preflight faze, sprečavate loše datoteke da zaguše vaš produkcijski cevovod, štedeći i vreme i resurse za prikazivanje.

Napomena: Napredno parsiranje PDF-a i mogućnosti preflight provera su u potpunosti podržani od strane PDFium Component VCL komponente.