TPDFlibDynamicComponentSession

頁面版面配置、分頁、資料類型

描述

每次在一個目標頁面上合成有狀態的元件,不預先為後續頁面建構內容

每次嘗試都在隔離 Form XObject 內的複本上執行,只在驗證過的內容成功放置後才提交複本

延伸放置可拒絕溢出、裁切自然尺寸內容,或按比例縮小並在目標槽位內對齊

分頁政策可允許正常切分、把第一個部分片段延後到新區域,或要求整個元件在提交任何內容前保持可見

flow-space 約束可在呼叫元件前拒絕過短的區域,或在其最終片段之後為下一個元件保留足夠高度

被拒的結果、失敗的繪製呼叫或回呼例外會移除暫時頁面、還原呼叫者所選頁面,目標內容與目前元件狀態都保持不變

附加的 TPDFlib 執行個體仍由呼叫者擁有,且必須比 session 存活更久

宣告

const
  PDF_DYNAMIC_COMPONENT_ERROR = 0;
  PDF_DYNAMIC_COMPONENT_MORE = 1;
  PDF_DYNAMIC_COMPONENT_COMPLETE = 2;
  PDF_DYNAMIC_COMPONENT_RETRY = 3;

type
  TPDFlibDynamicPageContext = record
    LibraryInstance: TPDFlib;
    PageNumber: Integer;
    CompositionIndex: Integer;
    DestinationLeft: Double;
    DestinationTop: Double;
    AvailableWidth: Double;
    AvailableHeight: Double;
  end;

  TPDFlibDynamicPageResult = record
    HasContent: Boolean;
    HasMoreContent: Boolean;
    UsedWidth: Double;
    UsedHeight: Double;
  end;

  TPDFlibDynamicOverflowPolicy = (dopReject, dopClip, dopScaleDown);
  TPDFlibDynamicHorizontalAlignment = (dhaLeft, dhaCenter, dhaRight);
  TPDFlibDynamicVerticalAlignment = (dvaTop, dvaCenter, dvaBottom);
  TPDFlibDynamicPaginationPolicy = (dppAllowSplit, dppKeepTogether,
    dppRequireComplete);
  TPDFlibDynamicRetryReason = (drrNone, drrKeepTogether,
    drrRequireComplete, drrMinimumSlotHeight, drrMinimumFollowingHeight);

  TPDFlibDynamicLayoutOptions = record
    ContentWidth: Double;
    ContentHeight: Double;
    OverflowPolicy: TPDFlibDynamicOverflowPolicy;
    HorizontalAlignment: TPDFlibDynamicHorizontalAlignment;
    VerticalAlignment: TPDFlibDynamicVerticalAlignment;
    PaginationPolicy: TPDFlibDynamicPaginationPolicy;
    MinimumSlotHeight: Double;
    MinimumFollowingHeight: Double;
  end;

  TPDFlibDynamicPlacementTransform = record
    M11, M12, M21, M22, MDX, MDY: Double;
  end;

  TPDFlibDynamicPagePlacement = record
    PageNumber: Integer;
    CompositionIndex: Integer;
    Left: Double;
    Top: Double;
    Width: Double;
    Height: Double;
    HasContent: Boolean;
    HasMoreContent: Boolean;
    SourceWidth: Double;
    SourceHeight: Double;
    SlotLeft: Double;
    SlotTop: Double;
    SlotWidth: Double;
    SlotHeight: Double;
    Transform: TPDFlibDynamicPlacementTransform;
    WasClipped: Boolean;
    WasScaled: Boolean;
  end;

  TPDFlibDynamicComponent = class
  public
    function CloneComponent: TPDFlibDynamicComponent; virtual; abstract;
    function Compose(const Context: TPDFlibDynamicPageContext;
      out ComposeResult: TPDFlibDynamicPageResult): Integer; virtual; abstract;
  end;

  TPDFlibDynamicComponentSession = class
  private
    FLibrary: TPDFlib;
    FCompositionCount: Integer;
    FCompleted: Boolean;
    FKeepTogetherRetryPending: Boolean;
    FLastRetryReason: TPDFlibDynamicRetryReason;
    FLastRequiredSlotHeight: Double;
  public
    constructor Create(ALibrary: TPDFlib;
      AComponent: TPDFlibDynamicComponent);
    function AttachComponent(AComponent: TPDFlibDynamicComponent): Integer;
    function Reset: Integer;
    function CloneCurrentComponent: TPDFlibDynamicComponent;
    class function CreateLayoutOptions(ContentWidth, ContentHeight: Double;
      OverflowPolicy: TPDFlibDynamicOverflowPolicy = dopReject;
      HorizontalAlignment: TPDFlibDynamicHorizontalAlignment = dhaLeft;
      VerticalAlignment: TPDFlibDynamicVerticalAlignment = dvaTop;
      PaginationPolicy: TPDFlibDynamicPaginationPolicy = dppAllowSplit;
      MinimumSlotHeight: Double = 0;
      MinimumFollowingHeight: Double = 0):
      TPDFlibDynamicLayoutOptions; static;
    function ComposeNext(Page: Integer; Left, Top, Width, Height: Double;
      out Placement: TPDFlibDynamicPagePlacement): Integer;
    function ComposeNextLayout(Page: Integer; SlotLeft, SlotTop, SlotWidth,
      SlotHeight: Double; const Options: TPDFlibDynamicLayoutOptions;
      out Placement: TPDFlibDynamicPagePlacement): Integer;
    property LibraryInstance: TPDFlib read FLibrary;
    property CompositionCount: Integer read FCompositionCount;
    property Completed: Boolean read FCompleted;
    property KeepTogetherRetryPending: Boolean
      read FKeepTogetherRetryPending;
    property LastRetryReason: TPDFlibDynamicRetryReason read FLastRetryReason;
    property LastRequiredSlotHeight: Double read FLastRequiredSlotHeight;
  end;

元件合約

方法

Create附加呼叫端擁有的程式庫,並將提供的元件複製成獨立的初始與目前快照
AttachComponent以呼叫端擁有元件的複本,以原子方式取代兩個快照,並清除完成狀態
Reset從初始快照還原新的目前複本,並重設成功的組合計數
CloneCurrentComponent傳回呼叫端擁有的複本,用於檢視目前已提交的元件狀態
CreateLayoutOptions為延伸放置建立具型別的自然畫布、溢出、對齊、分頁與流排空間設定
ComposeNext組合一個頁面插槽、驗證並放置其 Form XObject、釋放擷取控制代碼,並提交工作狀態
ComposeNextLayout在設定的自然畫布上組合、套用溢出與對齊原則,並傳回來源、插槽與最終轉換資料

溢出與放置

dopReject拒絕比插槽更寬或更高的內容,且不變更目的地內容或已提交的元件狀態
dopClip保持縮放 1,並在叫用 Form XObject 之前將頁面剪裁路徑與目的地插槽相交
dopScaleDown只在需要時使用較小的寬度或高度比例,且絕不放大內容

對齊會從轉換後的使用矩形解析,因此置中或尾端被裁剪的內容會選取對應的可見部分

Transform[M11 M12 M21 M22 MDX MDY]

SlotLeft 回報從元件區域座標到最終由上而下文件座標的邏輯版面矩陣 SlotTop SlotWidth、SlotHeight、

分頁原則

dppAllowSplit保留預設行為,並提交其回呼回報還有更多內容的任何有效片段
dppKeepTogether第一次出現部分或不可見的嘗試時傳回 PDF_DYNAMIC_COMPONENT_RETRY,然後在同一個未提交片段的下一次有效嘗試時允許分割或所選的裁剪後備
dppRequireComplete持續傳回 PDF_DYNAMIC_COMPONENT_RETRY,直到回呼回報沒有剩餘內容,且完整的使用矩形能符合插槽,或透過等比例縮小保持可見

Placement

KeepTogetherRetryPending 記錄 Reset 識別單次後備狀態,並在成功提交、AttachComponent 或

流程空間限制

MinimumSlotHeight目標槽位短於設定高度時,在複製或呼叫元件之前即傳回 PDF_DYNAMIC_COMPONENT_RETRY
MinimumFollowingHeight只適用於最終內容片段,要求其解析高度加上保留的後續高度能放進槽位

後續高度重試會捨棄隔離的試排、保留先前已提交的片段,讓標題、標籤或短導入能跟著下一個元件的第一個可用區域一起移動

LastRetryReason 區分整元件、嚴格完整、最小槽位與後續空間重試;LastRequiredSlotHeight 回報 flow-space 約束已知的所需高度

最小槽位檢查在元件複製與 Form 擷取之前執行,因此反覆被拒的過短區域不會產生元件回呼或暫時頁面成本

傳回值

PDF_DYNAMIC_COMPONENT_ERROR請求、元件回呼、結果幾何或 Form 放置失敗,且未提交任何狀態
PDF_DYNAMIC_COMPONENT_MORE內容已提交,且元件要求另一個頁面插槽
PDF_DYNAMIC_COMPONENT_COMPLETE元件已完成,或工作階段已經完成而未進行任何回呼
PDF_DYNAMIC_COMPONENT_RETRY所選的分頁或流排空間原則延後放置,而未提交內容或狀態

範例

type
  TNumberedPagesComponent = class(TPDFlibDynamicComponent)
  private
    FNextPage: Integer;
    FPageCount: Integer;
  public
    constructor Create(ANextPage, APageCount: Integer);
    function CloneComponent: TPDFlibDynamicComponent; override;
    function Compose(const Context: TPDFlibDynamicPageContext;
      out ComposeResult: TPDFlibDynamicPageResult): Integer; override;
  end;

constructor TNumberedPagesComponent.Create(ANextPage, APageCount: Integer);
begin
  inherited Create;
  FNextPage := ANextPage;
  FPageCount := APageCount;
end;

function TNumberedPagesComponent.CloneComponent: TPDFlibDynamicComponent;
begin
  Result := TNumberedPagesComponent.Create(FNextPage, FPageCount);
end;

function TNumberedPagesComponent.Compose(
  const Context: TPDFlibDynamicPageContext;
  out ComposeResult: TPDFlibDynamicPageResult): Integer;
begin
  Context.LibraryInstance.DrawText(0, 0, IntToStr(FNextPage));
  Inc(FNextPage);
  ComposeResult.HasContent := True;
  ComposeResult.HasMoreContent := FNextPage <= FPageCount;
  ComposeResult.UsedWidth := Context.AvailableWidth;
  ComposeResult.UsedHeight := 24;
  Result := 1;
end;

Template := TNumberedPagesComponent.Create(1, 10);
try
  Session := TPDFlibDynamicComponentSession.Create(PDF, Template);
  try
    repeat
      Status := Session.ComposeNext(PageNumber, 36, 36, 540, 720,
        Placement);
      if Status = PDF_DYNAMIC_COMPONENT_MORE then
        PageNumber := PDF.NewPage;
    until Status <> PDF_DYNAMIC_COMPONENT_MORE;
  finally
    Session.Free;
  end;
finally
  Template.Free;
end;

另請參閱

BeginFormXObject, ReleaseCapturedPage, ApplyRepeatedPageFragment