TPDFlibDynamicComponentSession
页面版面、分页、数据类型
描述
每次向一个目标页面合成有状态组件,不预先构造后续页面的内容
每次尝试都在隔离 Form XObject 内的克隆上运行,只有验证过的内容成功放置后才提交克隆
扩展放置可以拒绝溢出、裁剪自然尺寸内容,或在目标槽位内对齐的同时按比例缩小
分页策略可以允许正常拆分、把首个部分片段推迟到新区域,或要求整个组件保持可见后才提交任何内容
流空间约束可以在调用组件之前拒绝过小的区域,或在其最后片段之后为后续组件预留足够高度
被拒绝的结果、失败的绘制调用或回调异常会移除临时页面、恢复调用方所选页面,并保持目标内容与当前组件状态不变
挂接的 TPDFlib 实例保持为调用方所有,且必须比会话存活更久
声明
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;
组件契约
CloneComponent返回所有可变分页状态的独立于调用方的副本Compose通过Context.LibraryInstance在本地 Form 坐标中绘制,其可用尺寸为AvailableWidth乘AvailableHeightPageNumber标识目标页面,即使回调运行期间库选择的是隔离的临时页面- 回调可以使用绘制和内容 API,但不得更改文档、页面或嵌套绘图容器
- 内容结果要求在内容画布内具有有限的正
UsedWidth和UsedHeight值 - 使用矩形从本地坐标零开始,并应包围所有可见的组件内容
- 无内容结果仅在
HasMoreContent为False且两个使用尺寸均为零时有效 - 返回零表示拒绝该尝试;抛出的异常会在临时状态清理完毕后传播
方法
| 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,直到回调报告没有剩余内容且完整已用矩形要么适合槽位、要么经比例缩小保持可见 |
重试丢弃 Form XObject 试验,保留目标页面、组件快照、完成标志和合成计数,并返回空的 Placement 记录
KeepTogetherRetryPending 标识一次性回退状态,在成功提交、Reset 或 AttachComponent 之后清除
流空间约束
MinimumSlotHeight | 当目标槽位短于配置高度时,在克隆或调用组件之前返回 PDF_DYNAMIC_COMPONENT_RETRY |
|---|---|
MinimumFollowingHeight | 仅适用于最终内容片段,要求其解析高度加上预留的后续高度能放入槽位 |
后续高度重试在保留先前已提交片段的同时丢弃隔离试验,使标题、标签或短引文能与下一组件的第一个可用区域一起移动
LastRetryReason 区分整组件、严格完成、最小槽位和后续空间重试;LastRequiredSlotHeight 报告流空间约束的已知所需高度
最小槽位检查在组件克隆和 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