Édition bornée de paragraphes
HPDFParagraphReflow sélectionne des centres de glyphes chargés dans un rectangle source explicite et écrit un paragraphe nouvellement mesuré dans un rectangle cible explicite de la même page
Le profil d’acceptation couvre Delphi Win32/Win64 et FPC/Lazarus Windows ; la génération de polices mesurées utilise le builder d’apparences de documents existant et sa prise en charge des polices installées
Sélection, layout et préservation
Les coordonnées sont des points en espace utilisateur de page PDF non pivotés, avec un axe y vers le haut ; les deux rectangles doivent être finis, avoir des dimensions positives d’au plus 14400 points et tenir dans le MediaBox de la page
La sélection peut couvrir plusieurs lignes de base originales et plusieurs flux de contenu de page ; les opérandes de texte literal, hexadécimal, TJ, guillemet simple et guillemet double sont réécrits aux frontières de codes de caractères sélectionnés
Les préfixes et suffixes retenus, les avances de texte et les ajustements de kerning numériques originaux restent en place ; le texte source est retiré des vrais opérandes plutôt que masqué par un rectangle d’arrière-plan
Les Form XObjects imbriqués utilisent leur Matrix et BBox ; chaque invocation sélectionnée et ses ressources ancêtres sont copiées en privé, en préservant les autres invocations et les autres pages qui partagent les Forms originaux
Les centres de glyphes hors du BBox d’un Form sont exclus ; des bornes de glyphes sources partielles rejettent par défaut, et RejectPartialSourceGlyphs = False autorise explicitement le retrait d’un code de caractère entier quand son centre est sélectionné
Appearance choisit la police installée, le style, la taille, la couleur, le padding, l’alignement et la politique de débordement ; la largeur cible contrôle le wrap, et shrink-to-fit rapporte la EffectiveFontSize réelle
La géométrie de glyphes générée est interprétée indépendamment et confrontée au rectangle cible ; la rotation est fixée à zéro et l’opacité à un pour ce helper borné
Un remplacement vide supprime le texte source sélectionné ; définissez RequireSourceText = False pour insérer un paragraphe dans une région source vide
Preuves de collisions
Le texte non sélectionné non blanc, les images XObject et inline, les bornes de chemins peints et les rectangles d’annotations sont comparés aux bornes de glyphes du remplacement généré
Chaque collision identifie son type, ses bornes en espace page, le texte voisin optionnel et un index de glyphe de remplacement ; le comptage total est conservé même quand la liste de collisions renvoyée atteint son plafond
Les points de contrôle de chemins, les bornes de clips de Forms transformés, la largeur de trait et les limites de miter produisent des boîtes conservatrices ; un ombrage d’étendue de peinture inconnue occupe conservatoirement tout le rectangle cible
Ce test géométrique peut surestimer les images transparentes, zones d’annotations non peintes, courbes, chemins clippés et enveloppes de Forms pivotés ; il ne prouve pas une séparation d’encre pixel-perfect et n’inspecte pas les chemins de clipping arbitraires, la composition de fusion ni les contours de polices
RejectCollisions = True rejette les remplacements qui se chevauchent sans mutation ; le définir à false conserve le rapport tout en laissant à l’appelant sa politique délibérée de chevauchement
Preview, commit et rollback
HPDFPreviewParagraphReflow renvoie un plan scellé possédé par l’appelant, un layout de remplacement sémantique, des empreintes et des preuves de collisions, puis restaure les objets de document générés
HPDFCommitParagraphReflow répète l’analyse bornée et applique le plan atomiquement seulement quand contenu source, bornes de Forms, géométrie d’annotations et géométrie de polices de remplacement correspondent toujours à la preview
Un plan appartient à la même instance de document vivante ; libérez-le quand vous avez terminé, gardez le document vivant pendant toute la durée et régénérez la preview après avoir chargé un autre document ou modifié le contenu sélectionné
THPDFParagraphReflowSession ajoute un état de revue appliqué : Apply expose le document édité pour extraction ou rendu, Commit le publie, et Rollback ou la destruction restaure le graphe original
Utilisez les sessions en série ; le document doit survivre à la session, et les autres transactions de graphe ou appels d’édition ne doivent pas s’intercaler tant que Pending est true
Le rollback restaure l’état du document en mémoire ; les fichiers externes déjà sauvegardés restent de la responsabilité de l’appelant
Travail fini et comportement d’échec
Les limites par défaut sont 64 Mio de contenu décodé, 64 Mio de flux générés, 100000000 unités de travail, 100000 glyphes, 250000 tokens, 12 niveaux de Forms, 256 invocations de Forms, 256 collisions renvoyées et 100000 nœuds de ressources clonés
Les octets de chaînes encodées sont vérifiés avant l’interprétation des glyphes contre la limite de glyphes restante, si bien que les encodages multi-octets peuvent consommer conservatoirement plus de budget que leur nombre de glyphes visibles
Les limites décodées et générées couvrent le contenu traité par le helper ; la taille de flux générée est vérifiée avant publication, et ne représente pas une limite de mémoire de pointe du process ni ne plafonne toutes les allocations du builder de polices installées
L’annulation est coopérative via la tokenisation du contenu et les boucles du helper, avec des vérifications autour des appels existants de génération de polices ; conservez le token jusqu’à la fin de l’appel
Source manquante, entrée invalide, collisions, plans périmés, contenu non pris en charge, budgets épuisés, annulation et échecs ordinaires renvoient false avec un statut explicite et préservent le graphe d’objets original
Le texte vertical ou singulier sélectionné, les Forms cycliques ou non résolus, les types de XObjects peints non pris en charge et les documents avec champs de signature sont rejetés ; l’édition incrémentale préservant les signatures exige un workflow séparé
Exemple
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;
Acceptation et sortie sauvegardée
Les runners Delphi et FPC dédiés utilisent de vraies fixtures de PDF chargés pour des paragraphes multi-lignes de base, des opérandes partiels, des Forms imbriqués partagés, du texte de Forms clippé, des changements de largeur et de police, des types de collisions, l’annulation et le rollback de graphe
Les sauvegardes répétées fichier/fichier et flux/fichier préservent le graphe édité ; les documents chargés frais et inchangés conservent leurs octets source exacts, et un échec d’écriture de sortie injecté peut être suivi d’un retry réussi
Tests/Fixtures/ParagraphReflow/loaded-repeat-save.pdf isole la régression de sauvegarde sans utiliser le helper de paragraphes : charger, insérer un marqueur, sauvegarder deux fois, puis relire le second fichier indépendamment
Exécutez Tests/Delphi/Run-ParagraphReflowTests.ps1 -Platform Win64 ou Tests/FPC/Run-ParagraphReflowTests.ps1 -Platform Win64, et choisissez Win32 pour l’autre architecture
Le vérificateur Python optionnel Tests/Fixtures/ParagraphReflow/verify_output.py utilise PyMuPDF pour extraire le vrai texte Unicode sauvegardé et rendre les pages éditées ; chaque runner supprime le lancement automatique de lecteur