Agregue FPdfStyledEdit y proporcione un IPdfRegexEngine para planificar y ejecutar reemplazos sobre objetos nativos de texto de nivel superior
PlanStyledPdfRegexReplacements captura una instantánea reproducible del origen, concatena los glifos Unicode reales en orden de página y objeto, y mapea las coincidencias a anclas estables de objeto; excluye los espacios y saltos de línea generados por la extracción
ExecuteStyledPdfReplacements valida el SHA-256 de la instantánea, la identidad actual del origen, las anclas y los intervalos sin superposición antes de modificar un documento cargado por separado
La identidad de origen usa una serialización reproducible, con marcas de tiempo e identificadores normalizados, no los bytes del archivo original; el plan almacena los bytes reales de la instantánea y su SHA-256
Cuando es posible se reutilizan fuente nativa, tamaño de texto, color y matriz; los reemplazos que abarcan varios objetos o páginas mantienen el estilo del primer objeto y eliminan los caracteres consumidos de los posteriores, conservando el texto restante y el orden de páginas
FallbackFontName selecciona explícitamente una fuente PostScript estándar cuando no se puede reproducir el Unicode nativo; ForceFallbackFont solicita esa ruta directamente
El fallback conserva el orden de dibujo, la matriz, el modo de renderizado y los atributos de relleno y trazo; se rechazan los objetos recortados, transparentes, marcados o etiquetados en lugar de perder silenciosamente su semántica gráfica
El texto más ancho que sus límites de origen puede comprimirse horizontalmente si su matriz está vertical y sin sesgo; MinHorizontalScale es 0.5 de forma predeterminada, mientras que el texto de reemplazo más estrecho conserva la matriz original
Este flujo admite texto de reemplazo de una línea y ajuste horizontal limitado; no recorre Form XObjects anidados, no reescribe la semántica Tagged PDF ni redistribuye párrafos
Se rechazan documentos firmados o cifrados y XFA; la cancelación, los planes desactualizados, el UTF-16 inválido, las fuentes no compatibles y los límites agotados dejan intacto el documento del llamador
PreviewOnly devuelve el resultado reabierto por separado en PreviewPdf sin reemplazar al llamador; un commit exitoso solo reemplaza el documento después de verificar la extracción de glifos y el número de páginas tras guardar y reabrir
Todas las coincidencias se integran en el texto final de cada objeto antes de modificar objetos nativos; el ajuste y la escala mínima se comprueban una sola vez contra los límites originales, evitando que varias coincidencias acumulen una reducción excesiva
Un reemplazo vacío elimina un objeto de texto consumido por completo después de aplicar todas las ediciones ancladas; varios reemplazos se ejecutan hacia atrás para mantener válidos los offsets de origen anteriores
Los límites predeterminados son 256 MiB de bytes de documento, 10,000 páginas, 100,000 objetos de texto, 16,777,216 unidades UTF-16 y 100,000 reemplazos; el presupuesto de escaneo de texto es 67,108,864 visitas a caracteres nativos y unidades de copia UTF-16 durante la planificación
Los máximos absolutos conservan esos límites de páginas, objetos, caracteres y reemplazos, permiten 512 MiB de bytes de documento y 1,073,741,824 visitas de escaneo, y limitan el nombre de la fuente de fallback a 1,024 bytes
El informe incluye los SHA-256 del origen y de la salida, cantidades de reemplazos aplicados, fallbacks y ajustes de escala, y el texto y límites originales y finales de cada objeto en puntos del espacio de usuario PDF; los índices de página y objeto son índices de origen con base cero
Un reemplazo de texto no es un flujo de redacción de seguridad; para eliminar contenido sensible y los datos asociados del documento, use las API específicas de redacción
Options := TPdfStyledEditOptions.Default; Plan := PlanStyledPdfRegexReplacements(Pdf, Pattern, Replacement, Engine, Options); Options.PreviewOnly := True; if not ExecuteStyledPdfReplacements(Pdf, Plan, Options, PreviewPdf, Report) then raise EPdfProduction.Create(Report.ErrorMessage);
type
TPdfStyledEditOptions= record
MaxDocumentBytes: Integer;
MaxPages, MaxTextObjects, MaxCharacters, MaxReplacements: Integer;
MaxTextScanWork: Int64;
MinHorizontalScale: Double;
FallbackFontName: AnsiString;
ForceFallbackFont: Boolean;
PreviewOnly: Boolean;
CancellationToken: IPdfCancellationToken;
class function Default: TPdfStyledEditOptions; static;
end;
TPdfStyledEditPlan= record
SourceSha256: string;
SourceBytes: TBytes;
Spans: TPdfStyledSpans;
Replacements: TPdfStyledReplacements;
end;
TPdfStyledObjectChange= record
PageIndex, ObjectIndex: Integer;
BeforeText, AfterText: WideString;
BeforeBounds, AfterBounds: TPdfRectangle;
HorizontalScale: Double;
FontFallback: Boolean;
end;
TPdfStyledObjectChanges= array of TPdfStyledObjectChange;
TPdfStyledEditReport= record
Succeeded, Cancelled, PreviewOnly: Boolean;
AppliedReplacementCount, FontFallbackCount, ScaledObjectCount: Integer;
SourceSha256, OutputSha256, ErrorMessage: string;
Changes: TPdfStyledObjectChanges;
end;
function PlanStyledPdfRegexReplacements(Pdf: TPdf;
const Pattern, Replacement: WideString; Engine: IPdfRegexEngine;
const Options: TPdfStyledEditOptions): TPdfStyledEditPlan;
function ExecuteStyledPdfReplacements(Pdf: TPdf;
const Plan: TPdfStyledEditPlan; const Options: TPdfStyledEditOptions;
out PreviewPdf: TBytes; out Report: TPdfStyledEditReport): Boolean;