TPDFlibDynamicComponentSession

Esquema de página, paginação, tipos de dados

Descrição

Compõe um componente com estado numa página de destino de cada vez, sem construir antecipadamente conteúdo para páginas posteriores

Cada tentativa corre num clone dentro de um Form XObject isolado e só consolida o clone depois de o conteúdo validado ter sido colocado com sucesso

A colocação estendida pode recusar transbordo, recortar conteúdo de tamanho natural ou reduzi-lo proporcionalmente enquanto o alinha numa ranhura de destino

A política de paginação pode permitir a divisão normal, adiar o primeiro fragmento parcial para uma região fresca ou exigir que o componente inteiro permaneça visível antes de consolidar qualquer coisa

As restrições de espaço de fluxo podem recusar uma região baixa antes de invocar o componente ou reservar altura suficiente após o respetivo fragmento final para um componente seguinte

Um resultado recusado, uma chamada de desenho com falha ou uma exceção de chamada de retorno remove a página temporária, restaura a página selecionada pelo chamador e deixa tanto o conteúdo de destino como o estado atual do componente inalterados

A instância TPDFlib anexada permanece propriedade do chamador e tem de sobreviver à sessão

Declaração

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;

Contrato do componente

Métodos

CreateAnexa uma biblioteca propriedade do chamador e clona o componente fornecido em capturas iniciais e atuais independentes
AttachComponentSubstitui atomicamente ambas as capturas por clones de um componente propriedade do chamador e limpa o estado de conclusão
ResetRestaura um novo clone atual a partir da captura inicial e repõe a contagem de composições bem-sucedidas
CloneCurrentComponentDevolve um clone propriedade do chamador para inspecionar o estado atual confirmado do componente
CreateLayoutOptionsConstrói definições tipadas de tela natural, transbordo, alinhamento, paginação e espaço de fluxo para a colocação estendida
ComposeNextCompõe uma ranhura de página, valida e coloca o respetivo Form XObject, liberta o handle de captura e confirma o estado de trabalho
ComposeNextLayoutCompõe na tela natural configurada, aplica a política de transbordo e de alinhamento e devolve dados de origem, de ranhura e da transformação final

Transbordo e colocação

dopRejectRecusa conteúdo mais largo ou mais alto do que a ranhura sem alterar o conteúdo de destino nem o estado consolidado do componente
dopClipMantém a escala 1 e interseca o caminho de recorte da página com a ranhura de destino antes de invocar o Form XObject
dopScaleDownUtiliza o menor rácio de largura ou de altura apenas quando necessário e nunca amplia o conteúdo

O alinhamento resolve-se a partir do retângulo usado transformado, pelo que o conteúdo centrado ou com recorte final seleciona a parte visível correspondente

Transform comunica a matriz de esquema lógico [M11 M12 M21 M22 MDX MDY] das coordenadas locais do componente para as coordenadas finais do documento, de cima para baixo

SlotLeft, SlotTop, SlotWidth e SlotHeight preservam a região fornecida pelo chamador mesmo quando a origem final do conteúdo se situa fora dela, sob recorte

Políticas de paginação

dppAllowSplitPreserva o comportamento predefinido e consolida qualquer fragmento válido cuja chamada de retorno comunique haver mais conteúdo
dppKeepTogetherDevolve PDF_DYNAMIC_COMPONENT_RETRY para a primeira tentativa parcial ou invisível e depois permite a divisão ou o recurso de recorte selecionado na próxima tentativa válida do mesmo fragmento não consolidado
dppRequireCompleteDevolve PDF_DYNAMIC_COMPONENT_RETRY até a chamada de retorno comunicar que não resta conteúdo e o retângulo usado completo caiba na ranhura ou permaneça visível através de redução proporcional de escala

Uma repetição descarta a tentativa de Form XObject, preserva a página de destino, o instantâneo do componente, a flag de conclusão e a contagem de composição, e devolve um registo Placement vazio

KeepTogetherRetryPending identifica o estado de recurso de uso único e é limpo depois de uma consolidação bem-sucedida, de Reset ou de AttachComponent

Restrições de espaço de fluxo

MinimumSlotHeightDevolve PDF_DYNAMIC_COMPONENT_RETRY antes de clonar ou invocar o componente quando a ranhura de destino é mais baixa do que a altura configurada
MinimumFollowingHeightAplica-se apenas a um fragmento de conteúdo final e exige que a respetiva altura resolvida mais a altura seguinte reservada caibam na ranhura

Uma repetição por altura seguinte descarta a tentativa isolada preservando os fragmentos anteriormente consolidados, permitindo que um título, um rótulo ou uma introdução curta se mova com a primeira região utilizável do componente seguinte

LastRetryReason distingue repetições de componente inteiro, de conclusão estrita, de ranhura mínima e de espaço seguinte, enquanto LastRequiredSlotHeight comunica a altura exigida conhecida para restrições de espaço de fluxo

A verificação de ranhura mínima corre antes da clonagem do componente e da captura do formulário, pelo que as regiões baixas repetidamente recusadas não incorrem em custo de chamada de retorno de componente nem de página temporária

Valores devolvidos

PDF_DYNAMIC_COMPONENT_ERRORO pedido, a callback do componente, a geometria do resultado ou a colocação do Form falhou, e nenhum estado foi confirmado
PDF_DYNAMIC_COMPONENT_MOREO conteúdo foi confirmado e o componente pediu outra ranhura de página
PDF_DYNAMIC_COMPONENT_COMPLETEO componente concluiu, ou a sessão já estava concluída e nenhuma callback foi feita
PDF_DYNAMIC_COMPONENT_RETRYA política de paginação ou de espaço de fluxo selecionada adiou a colocação sem confirmar conteúdo nem estado

Exemplo

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;

Consulte também

BeginFormXObject, ReleaseCapturedPage, ApplyRepeatedPageFragment