Technical Article

Avtomatiziran predogled (Preflight) PDF dokumentov in revizija tveganj s PDFium

V podjetniškem tisku, arhiviranju in potekih dela za skladnost dokumentov datoteke PDF ni mogoče preprosto "upodobiti". Potrebno jo je revidirati. Datoteka PDF lahko vsebuje nesploščene skupine prosojnosti, ki povzročijo sesutje starejših procesorjev rastrskih slik (RIP), vgrajen JavaScript, ki predstavlja varnostno tveganje, ali slike nizke ločljivosti, ki bodo pri tisku na 300 DPI videti obupno.

Ta postopek pregledovanja datoteke PDF, preden vstopi v produkcijski proces, je znan kot Preflighting (Predogled). V tem članku bomo raziskali, kako v Delphiju zgraditi avtomatizirano orodje za predogled in revizijo tveganj z izkoriščanjem zmožnosti razčlenjevanja na nizki ravni mehanizma PDFium.

Ključna preverjanja v predogledu

Standardna revizija tveganj običajno preverja naslednje elemente znotraj PDF dokumenta:

  • Interaktivni elementi: Akcije JavaScript, akcije za zagon (izvajanje zunanjih programov) in obrazci AcroForms.
  • Metrika virov: Prisotnost slik z nizko ločljivostjo ali manjkajočih vdelanih pisav.
  • Varnostni status: Šifriranje dokumenta, zahteve za geslo in dovoljenja za dostop (npr. onemogočeno tiskanje).
  • Standardi dokumentov: Preverjanje skladnosti z oznakami PDF/A ali PDF/X v metapodatkih dokumenta.

Luščenje metapodatkov in opomb PDF s PDFium

PDFium zagotavlja robusten C API, ki ga lahko uporablja Delphi. Za izvedbo revizije v predogledu strani ne upodobimo le vizualno, temveč se sprehodimo po drevesu PDF objektov. Poglejmo, kako iterirati skozi strani dokumenta in pregledati opombe, da bi našli potencialno tvegane akcije JavaScript.

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;

Preverjanje ločljivosti slike

Še en kritičen korak predogleda za delovne procese tiskanja je zagotavljanje, da nobena slika ne pade pod določen prag DPI. PDFium vam omogoča neposredno luščenje objektov slik iz toka strani. Z deljenjem dimenzij v pikslih izluščene slike z njenimi fizičnimi dimenzijami (v točkah), ki jih zaseda na PDF strani, lahko izračunate 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 s PDFium Component

Gradnja robustnega mehanizma za predogled iz nič z uporabo surovega API-ja PDFium C zahteva precej stereotipne kode (boilerplate) in globoko poznavanje specifikacije PDF. Uporaba ovoja (wrapper) to izjemno poenostavi. Z Delphi ovojem na visoki ravni lahko pretvorite kompleksne iteracije kazalcev C v čisto, objektno usmerjeno kodo.

Z avtomatizacijo faze predogleda preprečite, da bi slabe datoteke zamašile vaš produkcijski cevovod, ter prihranite čas in vire upodabljanja.

Opomba: Napredno razčlenjevanje PDF in zmožnosti predogleda so v celoti podprte v komponenti PDFium Component.