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;

컴포넌트 계약

메서드

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는 흐름 공간 제약의 알려진 요구 높이를 보고합니다

최소 슬롯 검사는 컴포넌트 클론과 폼 캡처 전에 실행되므로, 거듭 거부되는 짧은 영역이 컴포넌트 콜백이나 임시 페이지 비용을 내지 않습니다

반환 값

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