Edição de parágrafos com limites
HPDFParagraphReflow seleciona centros de glyphs carregados dentro de um retângulo explícito de origem e grava um parágrafo recém-medido dentro de um retângulo explícito de alvo na mesma página
O perfil de aceitação cobre Delphi Win32/Win64 e FPC/Lazarus do Windows; a geração de fontes medidas usa o builder existente de aparências de documentos e o suporte dele a fontes instaladas
Seleção, layout e preservação
As coordenadas são pontos não rotacionados do user space de páginas PDF, com eixo y para cima; ambos os retângulos precisam ser finitos, ter dimensões positivas de no máximo 14400 pontos e caber no MediaBox da página
A seleção pode atravessar múltiplas baselines originais e múltiplos streams de conteúdo de páginas; operands de texto literal, hexadecimal, TJ, aspas simples e aspas duplas são regravados nas fronteiras selecionadas de códigos de caracteres
Prefixos e sufixos retidos, advances de texto e ajustes originais numéricos de kerning permanecem no lugar; o texto de origem é removido dos operands reais, em vez de ser escondido por um retângulo de fundo
Form XObjects aninhadas usam o Matrix e o BBox delas; cada invocação selecionada e os recursos ancestrais dela são copiados privadamente, preservando outras invocações e outras páginas que compartilham as Forms originais
Centros de glyphs fora do BBox de uma Form são excluídos; limites parciais de glyphs da origem são rejeitados por default, e RejectPartialSourceGlyphs = False permite explicitamente a remoção de um código de caractere inteiro quando o centro dele está selecionado
Appearance escolhe a fonte instalada, estilo, tamanho, cor, padding, alinhamento e política de overflow; a largura do alvo controla o wrapping, e shrink-to-fit reporta o EffectiveFontSize real
A geometria gerada de glyphs é interpretada de forma independente e checada contra o retângulo alvo; a rotação é fixa em zero e a opacidade em um para este helper delimitado
Uma substituição vazia exclui o texto de origem selecionado; defina RequireSourceText = False para inserir um parágrafo numa região de origem vazia
Evidências de colisões
Texto não selecionado que não é whitespace, imagens XObject e inline, limites de paths pintados e retângulos de anotações são comparados com os limites gerados de glyphs de substituição
Cada colisão identifica o tipo dela, os limites em page space, o texto vizinho opcional e um índice de glyph de substituição; a contagem total é retida mesmo quando a lista retornada de colisões atinge o teto dela
Control points de paths, clip bounds transformados de Forms, largura de strokes e limites de miter produzem caixas conservadoras; shading com extensão de pintura desconhecida ocupa conservadoramente o retângulo alvo inteiro
Este teste geométrico pode reportar em excesso imagens transparentes, áreas de anotações não pintadas, curvas, paths clipados e envelopes rotacionados de Forms; ele não prova separação de tinta pixel-perfect nem inspeciona clipping paths arbitrários, composição de blend nem contornos de fontes
RejectCollisions = True rejeita substituições sobrepostas sem mutação; defini-lo como false retém o relatório permitindo a política deliberada de sobreposição do chamador
Preview, commit e rollback
HPDFPreviewParagraphReflow retorna um plan selado de posse do chamador, layout semântico de substituição, fingerprints e evidências de colisões, e depois reverte os objetos gerados do documento
HPDFCommitParagraphReflow repete a análise delimitada e aplica atomicamente o plan somente quando o conteúdo da origem, os bounds das Forms, a geometria das anotações e a geometria da fonte de substituição ainda correspondem ao preview
Um plan pertence à mesma instância viva de documento; libere-o ao terminar, mantenha o documento vivo durante todo o processo, e regenere o preview depois de carregar outro documento ou alterar o conteúdo selecionado
THPDFParagraphReflowSession adiciona um estado aplicado de revisão: Apply expõe o documento editado para extração ou rendering, Commit o publica, e Rollback ou a destruição restaura o grafo original
Use sessões serialmente; o documento precisa sobreviver à sessão, e outras transações de grafo ou chamadas de edição não podem ser intercaladas enquanto Pending for true
Rollback restaura o estado em memória do documento; arquivos externos já salvos permanecem responsabilidade do chamador
Trabalho finito e comportamento de falhas
Os limites default são 64 MiB de conteúdo decodificado, 64 MiB de streams gerados, 100000000 unidades de trabalho, 100000 glyphs, 250000 tokens, 12 levels de Forms, 256 invocações de Forms, 256 colisões retornadas e 100000 nós clonados de recursos
Os bytes de strings codificadas são checados antes da interpretação de glyphs contra o limite restante de glyphs, de modo que encodings de caracteres multibyte podem consumir conservadoramente mais orçamento do que a contagem visível de glyphs deles
Os limites decodificados e gerados cobrem o conteúdo tratado pelo helper; o tamanho do stream gerado é checado antes da publicação, e não representa um limite de memória de pico do processo nem limita todas as alocações do builder de fontes instaladas
O cancelamento é cooperativo através da tokenização de conteúdo e dos loops do helper, com checagens em torno das chamadas existentes de geração de fontes; retenha o token até a chamada completar
Origem ausente, entrada inválida, colisões, plans velhos, conteúdo não suportado, orçamentos esgotados, cancelamento e falhas comuns retornam false com um status explícito e preservam o grafo original de objetos
Texto vertical ou singular selecionado, Forms cíclicas ou não resolvidas, tipos não suportados de XObjects pintados e documentos com campos de assinaturas são rejeitados; edição incremental que preserva 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 salva
Os runners dedicados de Delphi e FPC usam fixtures reais de PDFs carregados para parágrafos multibaseline, operands parciais, Forms aninhadas compartilhadas, texto de Forms clipado, mudanças de largura e fonte, tipos de colisões, cancelamento e rollback de grafos
Saves repetidos arquivo/arquivo e stream/arquivo preservam o grafo editado; documentos carregados novos e inalterados mantêm os bytes exatos da origem deles, e uma falha injetada de gravação de saída pode ser seguida de um retry bem-sucedido
Tests/Fixtures/ParagraphReflow/loaded-repeat-save.pdf isola a regressão de saves sem usar o helper de parágrafos: carregue, insira um marcador, salve duas vezes, e leia de forma independente o segundo arquivo
Execute Tests/Delphi/Run-ParagraphReflowTests.ps1 -Platform Win64 ou Tests/FPC/Run-ParagraphReflowTests.ps1 -Platform Win64, e selecione Win32 para a outra arquitetura
O verifier Python opcional Tests/Fixtures/ParagraphReflow/verify_output.py usa PyMuPDF para extrair o texto Unicode realmente salvo e renderizar páginas editadas; todo runner suprime a chamada automática de viewers