Technical Article

Automatisoitu PDF-ennakkotarkastus ja riskien auditointi PDFiumilla

Yritysten tulostuksen, arkistoinnin ja asiakirjojen vaatimustenmukaisuuden työnkuluissa PDF-tiedostoa ei voida yksinkertaisesti "renderöidä". Se on auditoitava. PDF saattaa sisältää litistämättömiä läpinäkyvyysryhmiä, jotka kaatavat vanhoja rasterikuvaprosessoreita (RIP), upotettua JavaScriptiä, joka aiheuttaa tietoturvariskin, tai matalan resoluution kuvia, jotka näyttävät kamalilta 300 DPI:n tulostuksessa.

Tätä PDF-tiedoston tarkastusprosessia ennen sen saapumista tuotantotyönkulkuun kutsutaan nimellä Preflighting (ennakkotarkastus). Tässä artikkelissa tutkimme, kuinka rakennetaan automatisoitu ennakkotarkastus- ja riskien auditointityökalu Delphissä hyödyntämällä PDFiumin matalan tason jäsennysominaisuuksia.

Tärkeimmät ennakkotarkastukset

Vakio riskien auditointi tarkistaa tyypillisesti seuraavat elementit PDF-tiedostossa:

  • Interaktiiviset elementit: JavaScript-toiminnot, Launch-toiminnot (ulkoisten ohjelmien suorittaminen) ja AcroForms-lomakkeet.
  • Resurssimittarit: Matalan resoluution kuvien tai puuttuvien upotettujen fonttien esiintyminen.
  • Tietoturvan tila: Asiakirjan salaus, salasanavaatimukset ja käyttöoikeudet (esim. tulostus poistettu käytöstä).
  • Asiakirjastandardit: PDF/A- tai PDF/X-vaatimustenmukaisuusmerkintöjen vahvistaminen asiakirjan metatiedoissa.

PDF-metatietojen ja huomautusten purkaminen PDFiumilla

PDFium tarjoaa vankan C-rajapinnan, jota Delphi voi käyttää. Ennakkotarkastuksen suorittamiseksi emme vain renderöi sivua; käymme läpi PDF-objektipuun. Katsotaanpa, kuinka selataan asiakirjan sivuja ja tarkastellaan huomautuksia (annotations) mahdollisten riskialttiiden JavaScript-toimintojen löytämiseksi.

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;

Kuvan resoluution tarkistaminen

Toinen kriittinen ennakkotarkastusvaihe tulostustyönkuluissa on sen varmistaminen, ettei yksikään kuva alita tiettyä DPI-kynnystä. PDFium antaa sinun purkaa kuvaobjekteja suoraan sivuvirrasta. Jakamalla puretun kuvan pikselimitat sen fyysisillä mitoilla (pisteinä), jotka se vie PDF-sivulla, voit laskea tehollisen DPI:n.

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;

Integrointi PDFium Componentin kanssa

Vankan ennakkotarkastusmoottorin rakentaminen alusta alkaen käyttämällä raakaa PDFium C -rajapintaa vaatii huomattavasti mallikoodia ja syvällistä PDF-määrityksen tuntemusta. Kääreen (wrapper) käyttö yksinkertaistaa tätä valtavasti. Korkean tason Delphi-kääreen avulla voit muuttaa monimutkaiset C-osoitiniterointien suoritukset puhtaaksi oliopohjaiseksi koodiksi.

Automatisoimalla ennakkotarkastusvaiheen estät viallisia tiedostoja tukkimasta tuotantoputkeasi säästäen sekä aikaa että renderöintiresursseja.

Huomautus: Edistyneet PDF-jäsennys- ja ennakkotarkastusominaisuudet ovat täysin tuettuja PDFium Component VCL -komponentissa.