Edição delimitada de parágrafos

HPDFParagraphReflow seleciona centros de glyphs carregados dentro de um retângulo fonte explícito e escreve um parágrafo recém-medido dentro de um retângulo alvo explícito na mesma página

O perfil de aceitação cobre Delphi Win32/Win64 e Windows FPC/Lazarus; a geração de tipos de letra medidos usa o construtor existente de aparências de documentos e o suporte dele de tipos de letra instalados

Seleção, layout e preservação

As coordenadas são pontos de espaço de utilizador de páginas PDF sem rotação, com eixo y para cima; ambos os retângulos têm de ser finitos, ter dimensões positivas não superiores a 14400 pontos e caber no MediaBox da página

A seleção pode atravessar múltiplas linhas de base originais e múltiplas streams de conteúdo de páginas; operandos de texto literal, hexadecimal, TJ, de plica e de aspa dupla são reescritos nas fronteiras selecionadas de códigos de carateres

Prefixos, sufixos, avanços de texto e ajustes originais de kerning numérico retidos permanecem no lugar; o texto fonte é removido dos operandos reais em vez de ser escondido por um retângulo de fundo

Form XObjects aninhados usam o Matrix e o BBox deles; cada invocação selecionada e os recursos ancestrais dela são copiados em privado, preservando outras invocações e outras páginas que partilhem os Forms originais

Centros de glyphs fora de um BBox de Form são excluídos; bounds parciais de glyphs da fonte são rejeitados por defeito, e RejectPartialSourceGlyphs = False permite explicitamente a remoção de um código de caráter inteiro quando o centro dele está selecionado

Appearance escolhe o tipo de letra instalado, o estilo, o tamanho, a cor, o padding, o alinhamento e a política de transbordo; a largura do alvo controla o wrap, e o ajuste por redução reporta o EffectiveFontSize real

A geometria gerada de glyphs é interpretada de forma independente e verificada contra o retângulo alvo; a rotação é fixada em zero e a opacidade em um para este helper delimitado

Uma substituição vazia elimina o texto fonte selecionado; defina RequireSourceText = False para inserir um parágrafo numa região fonte vazia

Evidência de colisões

Texto não selecionado que não seja whitespace, imagens XObject e inline, bounds de caminhos pintados e retângulos de anotações são comparados com os bounds gerados de glyphs de substituição

Cada colisão identifica o tipo dela, os bounds em espaço de página, o texto vizinho opcional e um índice de glyph de substituição; a contagem total é retida mesmo quando a lista devolvida de colisões atinge o teto dela

Pontos de controlo de caminhos, bounds de clips de Forms transformados, larguras de strokes e limites de miter produzem caixas conservadoras; um shading com extensão de pintura desconhecida ocupa conservadoramente todo o retângulo alvo

Este teste de geometria pode reportar em excesso imagens transparentes, áreas de anotações não pintadas, curvas, caminhos cortados e envelopes de Forms rodados; não prova separação de tinta perfeita ao píxel nem inspeciona caminhos de clipping arbitrários, composição de misturas ou contornos de tipos de letra

RejectCollisions = True rejeita substituições sobrepostas sem mutação; defini-lo como false mantém o relatório permitindo a política deliberada de sobreposições de quem chama

Pré-visualização, commit e rollback

HPDFPreviewParagraphReflow devolve um plano selado próprio de quem chama, layout semântico de substituição, fingerprints e evidência de colisões, e depois reverte os objetos de documentos gerados

HPDFCommitParagraphReflow repete a análise delimitada e aplica atomicamente o plano apenas quando o conteúdo da fonte, os bounds de Forms, a geometria de anotações e a geometria do tipo de letra de substituição ainda correspondem à pré-visualização

Um plano pertence à mesma instância viva de documento; liberte-o quando terminar, mantenha o documento vivo ao longo de todo o processo e regenere a pré-visualização depois de carregar outro documento ou alterar o conteúdo selecionado

THPDFParagraphReflowSession acrescenta um estado de revisão aplicada: Apply expõe o documento editado para extração ou renderização, Commit publica-o, e Rollback ou a destruição restaura o grafo original

Use sessões em série; o documento tem de sobreviver à sessão, e outras transações de grafos ou chamadas de edição não devem ser intercaladas enquanto Pending estiver true

O rollback restaura o estado do documento em memória; ficheiros externos já guardados continuam a ser responsabilidade de quem chama

Trabalho finito e comportamento de falhas

Os limites por defeito são 64 MiB de conteúdo descodificado, 64 MiB de streams geradas, 100000000 unidades de trabalho, 100000 glyphs, 250000 tokens, 12 níveis de Forms, 256 invocações de Forms, 256 colisões devolvidas e 100000 nós de recursos clonados

Os bytes de strings codificadas são verificados antes da interpretação de glyphs contra o limite restante de glyphs, pelo que encodings de carateres multibyte podem consumir conservadoramente mais orçamento do que a contagem visível de glyphs deles

Os limites descodificados e gerados cobrem o conteúdo tratado pelo helper; o tamanho de streams geradas é verificado antes da publicação, e não representa um limite de memória de pico do processo nem limita todas as alocações do construtor de tipos de letra instalados

O cancelamento é cooperativo através da tokenização de conteúdo e dos ciclos do helper, com verificações em torno das chamadas existentes de geração de tipos de letra; retenha o token até a chamada terminar

Fonte em falta, entrada inválida, colisões, planos obsoletos, conteúdo não suportado, orçamentos esgotados, cancelamento e falhas ordinárias devolvem false com um status explícito e preservam o grafo original de objetos

Texto vertical ou singular selecionado, Forms cíclicos ou não resolvidos, tipos de XObjects pintados não suportados e documentos com campos de assinatura são rejeitados; edição incremental que preserve assinaturas exige um workflow separado

Exemplo

Options := HPDFDefaultParagraphReflowOptions;
Options.Appearance.FontName := 'Arial';
Options.Appearance.FontSize := 11;
Source.Left := 55; Source.Bottom := 659;
Source.Right := 350; Source.Top := 714;
Target := Source;
Plan := nil;
try
  if HPDFPreviewParagraphReflow(Document, 0, Source, Target,
    'The Supplier must deliver signed monthly reports.', Options,
    Plan, Report, CancellationToken) then
    if HPDFCommitParagraphReflow(Document, Plan, Report, CancellationToken) then
      Document.SaveLoadedDocument('reviewed-contract.pdf');
finally
  Plan.Free;
end;

Aceitação e saída guardada

Os runners dedicados de Delphi e de FPC usam fixtures reais de PDFs carregados para parágrafos multilinha, operandos parciais, Forms aninhados partilhados, texto de Forms cortado, alterações de largura e de tipos de letra, tipos de colisões, cancelamento e rollback de grafos

Gravações repetidas de ficheiro/ficheiro e de stream/ficheiro preservam o grafo editado; documentos carregados frescos e inalterados mantêm os bytes exatos da fonte deles, e uma falha injetada de escrita de saída pode ser seguida de uma repetição bem-sucedida

Tests/Fixtures/ParagraphReflow/loaded-repeat-save.pdf isola a regressão de gravação sem usar o helper de parágrafos: carregue, insira um marcador, grave duas vezes e leia de forma independente o segundo ficheiro

Corra Tests/Delphi/Run-ParagraphReflowTests.ps1 -Platform Win64 ou Tests/FPC/Run-ParagraphReflowTests.ps1 -Platform Win64, e selecione Win32 para a outra arquitetura

O verificador Python opcional Tests/Fixtures/ParagraphReflow/verify_output.py usa PyMuPDF para extrair o texto Unicode realmente guardado e renderizar páginas editadas; todos os runners suprimem o lançamento automático do leitor

Tópicos relacionados

Edição delimitada de parágrafos · Opções · Relatório