Reemplazar Texto en PDF usando C++
A veces surge la tarea de corregir o reemplazar texto en un documento PDF. Intentar hacerlo manualmente será una tarea desalentadora, así que aquí está la solución a ese problema.
Honestamente, editar un archivo PDF no es una tarea fácil. Así que, una situación donde necesites encontrar y reemplazar una palabra por otra mientras editas un archivo PDF, será muy difícil ya que te tomará mucho tiempo hacerlo. Además, puedes encontrarte con muchos problemas con tu resultado, como problemas de formato o fuentes rotas. Si deseas encontrar y reemplazar texto fácilmente en archivos PDF, te recomendamos que utilices el software de la biblioteca Aspose.Pdf, ya que hará el trabajo en minutos.
En este artículo, te mostraremos cómo encontrar y reemplazar texto exitosamente en tus archivos PDF usando Aspose.PDF para C++.
Reemplazar texto en todas las páginas de un documento PDF
Para reemplazar texto en todas las páginas de un documento PDF, primero necesita usar TextFragmentAbsorber para encontrar la frase particular que desea reemplazar. Después de eso, debe pasar por todos los TextFragments para reemplazar el texto y cambiar cualquier otro atributo. Una vez hecho esto, solo necesita guardar el PDF de salida usando el método Save del objeto Document. El siguiente fragmento de código le muestra cómo reemplazar texto en todas las páginas de un documento PDF.
using namespace System;
using namespace Aspose::Pdf;
using namespace Aspose::Pdf::Text;
void ReplaceTextOnAllPages() {
String _dataDir("C:\\Samples\\");
auto document = MakeObject<Document>(_dataDir + u"sample.pdf");
// Crear objeto TextAbsorber para encontrar todas las instancias de la frase de búsqueda de entrada
auto textFragmentAbsorber = MakeObject<TextFragmentAbsorber>("Web");
// Aceptar el absorber para la primera página del documento
document->get_Pages()->Accept(textFragmentAbsorber);
// Obtener los fragmentos de texto extraídos en la colección
auto textFragmentCollection = textFragmentAbsorber->get_TextFragments();
// Recorrer los fragmentos
for (auto textFragment : textFragmentCollection) {
// Actualizar texto y otras propiedades
textFragment->set_Text(u"World Wide Web");
textFragment->get_TextState()->set_Font(FontRepository::FindFont(u"Verdana"));
textFragment->get_TextState()->set_FontSize(12);
textFragment->get_TextState()->set_ForegroundColor(Color::get_Blue());
textFragment->get_TextState()->set_BackgroundColor(Color::get_Gray());
}
// Guardar el archivo PDF actualizado
document->Save(_dataDir + u"Updated_Text.pdf");
}
Reemplazar texto en una región específica de la página
Para reemplazar texto en una región específica de la página, primero necesitamos instanciar el objeto TextFragmentAbsorber, especificar la región de la página usando la propiedad TextSearchOptions.Rectangle y luego iterar a través de todos los TextFragments para reemplazar el texto. Una vez completadas estas operaciones, solo necesitamos guardar el PDF de salida usando el método Save del objeto Document. El siguiente fragmento de código te muestra cómo reemplazar texto en todas las páginas de un documento PDF.
void ReplaceTextInParticularRegion() {
String _dataDir("C:\\Samples\\");
// cargar archivo PDF
auto document = MakeObject<Document>(_dataDir + u"sample.pdf");
// instanciar objeto TextFragment Absorber
auto textFragmentAbsorber = MakeObject<TextFragmentAbsorber>("PDF");
// buscar texto dentro del límite de la página
textFragmentAbsorber->get_TextSearchOptions()->set_LimitToPageBounds(true);
// especificar la región de la página para las opciones de búsqueda de texto
textFragmentAbsorber->get_TextSearchOptions()->set_Rectangle(new Rectangle(100, 700, 400, 770));
// buscar texto desde la primera página del archivo PDF
document->get_Pages()->idx_get(1)->Accept(textFragmentAbsorber);
// iterar a través de cada TextFragment
for (auto tf : textFragmentAbsorber->get_TextFragments()) {
// reemplazar texto con "---"
tf->set_Text(u"---");
}
// Guardar el archivo PDF actualizado
document->Save(_dataDir + u"Updated_Text.pdf");
}
Reemplazar Texto Basado en una Expresión Regular
Si deseas reemplazar algunas frases basadas en una expresión regular, primero necesitas encontrar todas las frases que coincidan con esa expresión regular en particular usando TextFragmentAbsorber. Tendrás que pasar la expresión regular como un parámetro al constructor de TextFragmentAbsorber. También necesitas crear un objeto TextSearchOptions que especifique si se está utilizando la expresión regular o no. Una vez que obtengas las frases coincidentes en TextFragments, necesitas iterar a través de todas ellas y actualizar según sea necesario. Finalmente, necesitas guardar el PDF actualizado utilizando el método Save del objeto Document. El siguiente fragmento de código te muestra cómo reemplazar texto basado en una expresión regular.
void ReplaceTextWithRegularExpression() {
String _dataDir("C:\\Samples\\");
// carga el archivo PDF
auto document = MakeObject<Document>(_dataDir + u"Sample.pdf");
// Crear objeto TextAbsorber para encontrar todas las instancias de la frase de búsqueda de entrada
auto textFragmentAbsorber = MakeObject<TextFragmentAbsorber>("\\d{4}-\\d{4}");
// como 1999-2000
// Establecer la opción de búsqueda de texto para especificar el uso de expresión regular
auto textSearchOptions = new TextSearchOptions(true);
textFragmentAbsorber->set_TextSearchOptions(textSearchOptions);
// Aceptar el absorbedor para la primera página del documento
document->get_Pages()->Accept(textFragmentAbsorber);
// Obtener los fragmentos de texto extraídos en la colección
auto textFragmentCollection = textFragmentAbsorber->get_TextFragments();
// Iterar a través de los fragmentos
for (auto textFragment : textFragmentCollection) {
// Actualizar texto y otras propiedades
textFragment->set_Text(u"ABCD-EFGH");
textFragment->get_TextState()->set_Font(FontRepository::FindFont(u"Verdana"));
textFragment->get_TextState()->set_FontSize(12);
textFragment->get_TextState()->set_ForegroundColor(Color::get_Blue());
textFragment->get_TextState()->set_BackgroundColor(Color::get_Gray());
}
// Guardar el archivo PDF actualizado
document->Save(_dataDir + u"Updated_Text.pdf");
}
Reemplazar fuentes en un archivo PDF existente
Aspose.PDF para C++ admite la capacidad de reemplazar texto en un documento PDF. Sin embargo, a veces tiene el requisito de solo reemplazar la fuente que se está utilizando dentro del documento PDF. Entonces, en lugar de reemplazar el texto, solo se reemplaza la fuente que se está utilizando. Una de las sobrecargas del constructor TextFragmentAbsorber acepta un objeto TextEditOptions como argumento y podemos usar el valor RemoveUnusedFonts de la enumeración TextEditOptions.FontReplace para cumplir con nuestros requisitos. El siguiente fragmento de código muestra cómo reemplazar la fuente dentro de un documento PDF.
void ReplaceFonts() {
String _dataDir("C:\\Samples\\");
// Instanciar objeto Document
auto document = MakeObject<Document>(_dataDir + u"sample.pdf");
// Buscar fragmentos de texto y establecer la opción de edición como eliminar fuentes no utilizadas
auto textFragmentAbsorber = MakeObject<TextFragmentAbsorber>(
MakeObject<TextEditOptions>(TextEditOptions::FontReplace::RemoveUnusedFonts));
// Aceptar el absorbedor para todas las páginas del documento
document->get_Pages()->Accept(textFragmentAbsorber);
// recorrer todos los TextFragments
auto textFragmentCollection = textFragmentAbsorber->get_TextFragments();
for (auto textFragment : textFragmentCollection) {
String fontName = textFragment->get_TextState()->get_Font()->get_FontName();
// si el nombre de la fuente es ArialMT, reemplazar el nombre de la fuente por Arial
if (fontName.Equals(u"ArialMT")) {
textFragment->get_TextState()->set_Font(FontRepository::FindFont(u"Arial"));
}
}
// Guardar el archivo PDF actualizado
document->Save(_dataDir + u"Updated_Text.pdf");
}
En el siguiente fragmento de código, verá cómo usar una fuente no inglesa al reemplazar texto:
void UseNonEnglishFontWhenReplacingText() {
String _dataDir("C:\\Samples\\");
// Instanciar objeto Documento
auto document = MakeObject<Document>(_dataDir + u"sample.pdf");
// Vamos a cambiar cada palabra "PDF" a algún texto en japonés con una fuente específica
// MSGothic que podría estar instalada en el sistema operativo
// Además, podría ser otra fuente que soporte jeroglíficos
auto textFragmentAbsorber = MakeObject<TextFragmentAbsorber>("PDF");
// Crear instancia de opciones de búsqueda de texto
auto searchOptions = MakeObject<TextSearchOptions>(true);
textFragmentAbsorber->set_TextSearchOptions(searchOptions);
// Aceptar el absorbedor para todas las páginas del documento
document->get_Pages()->Accept(textFragmentAbsorber);
// Obtener los fragmentos de texto extraídos en la colección
auto textFragmentCollection = textFragmentAbsorber->get_TextFragments();
// Recorrer los fragmentos
for (auto textFragment : textFragmentCollection) {
// Actualizar texto y otras propiedades
textFragment->set_Text(u"ファイル");
textFragment->get_TextState()->set_Font(FontRepository::FindFont(u"TakaoMincho"));
textFragment->get_TextState()->set_FontSize(12);
textFragment->get_TextState()->set_ForegroundColor(Color::get_Blue());
textFragment->get_TextState()->set_BackgroundColor(Color::get_Gray());
}
// Guardar el documento actualizado
document->Save(_dataDir + u"Japanese_Text.pdf");
}
El reemplazo de texto debe reorganizar automáticamente el contenido de la página
Aspose.PDF para C++ admite encontrar y reemplazar texto dentro de un archivo PDF. Sin embargo, recientemente, algunos clientes han tenido problemas al reemplazar texto, donde un TextFragment particular es reemplazado con contenido más pequeño y se muestra un espacio en blanco adicional en el PDF resultante, o si el TextFragment es reemplazado con una cadena más larga, las palabras se superponen al contenido existente de la página. Por lo tanto, fue necesario introducir un mecanismo que, después de reemplazar el texto dentro del documento PDF, reorganizara su contenido.
Para atender los escenarios mencionados, Aspose.PDF para C++ ha sido mejorado para que tales problemas no ocurran al reemplazar texto dentro de un archivo PDF. El siguiente fragmento de código demuestra cómo reemplazar texto dentro de un archivo PDF y el contenido de la página debe ser reordenado automáticamente.
void RearrangeContent() {
String _dataDir("C:\\Samples\\");
// Instanciar objeto Document
auto document = MakeObject<Document>(_dataDir + u"sample.pdf");
// Crear objeto TextFragment Absorber con expresión regular
auto textFragmentAbsorber = MakeObject<TextFragmentAbsorber>("[PDF,Web]");
auto textSearchOptions = MakeObject<TextSearchOptions>(true);
textFragmentAbsorber->set_TextSearchOptions(textSearchOptions);
// También puede especificar la opción ReplaceAdjustment.WholeWordsHyphenation para
// ajustar el texto en la siguiente o actual línea si la línea actual se vuelve demasiado larga o
// corta después del reemplazo:
//textFragmentAbsorber->get_TextReplaceOptions()->set_ReplaceAdjustmentAction(TextReplaceOptions::ReplaceAdjustment::WholeWordsHyphenation);
// Aceptar el absorbente para todas las páginas del documento
document->get_Pages()->Accept(textFragmentAbsorber);
// Obtener los fragmentos de texto extraídos en la colección
auto textFragmentCollection = textFragmentAbsorber->get_TextFragments();
// Reemplazar cada TextFragment
for (auto textFragment : textFragmentCollection) {
// Establecer fuente del fragmento de texto que se reemplaza
textFragment->get_TextState()->set_Font(FontRepository::FindFont(u"Arial"));
// Establecer tamaño de fuente
textFragment->get_TextState()->set_FontSize(10);
textFragment->get_TextState()->set_ForegroundColor(Color::get_Blue());
textFragment->get_TextState()->set_BackgroundColor(Color::get_Gray());
// Reemplazar el texto con una cadena más larga que el marcador de posición
textFragment->set_Text(u"This is a larger string for the testing of this feature");
}
// Guardar PDF resultante
document->Save(_dataDir + u"RearrangeContentsUsingTextReplacement_out.pdf");
}
Renderización de Símbolos Reemplazables durante la creación de PDF
Los símbolos reemplazables son símbolos especiales en una cadena de texto que pueden ser reemplazados con el contenido correspondiente en tiempo de ejecución. Los símbolos reemplazables actualmente soportados por el nuevo Modelo de Objeto de Documento del espacio de nombre Aspose.PDF son $P
, $p,
\n
, \r
. Los símbolos $p
y $P
se utilizan para manejar la numeración de páginas en tiempo de ejecución. $p
se reemplaza con el número de la página donde se encuentra la clase Paragraph actual. $P
se reemplaza con el número total de páginas en el documento. Al agregar TextFragment
a la colección de párrafos de documentos PDF, no soporta el salto de línea dentro del texto. Sin embargo, para agregar texto con un salto de línea, utilice TextFragment
con TextParagraph
:
- use “\r\n” o Environment.NewLine en TextFragment en lugar de un único “\n”;
- cree un objeto TextParagraph. Añadirá texto con división de líneas;
- agregue el TextFragment con TextParagraph.AppendLine;
- agregue el TextParagraph con TextBuilder.AppendParagraph.
Símbolos reemplazables en el área de Encabezado/Pie de página
El símbolo reemplazable también se puede colocar dentro de la sección de encabezado/pie de página del archivo PDF. Revise el siguiente fragmento de código para ver cómo agregar un símbolo reemplazable a una sección de pie de página.
void ReplaceableSymbolsInHeaderFooterArea() {
auto document = MakeObject<Document>();
auto page = doc.getPages().add();
auto marginInfo = MakeObject<MarginInfo>();
marginInfo->set_Top(90);
marginInfo->set_Bottom(50);
marginInfo->set_Left(50);
marginInfo->set_Right(50);
// Asignar la instancia de marginInfo a la propiedad Margin de PageInfo
page.getPageInfo()->set_Margin(marginInfo);
auto hfFirst = MakeObject<HeaderFooter>();
page->set_Header(hfFirst);
hfFirst->get_Margin()->set_Left(50);
hfFirst->get_Margin()->set_Right(50);
// Instanciar un párrafo de texto que almacenará el contenido para mostrar como encabezado
auto t1 = MakeObject<TextFragment>("título del informe");
t1->get_TextState()->set_Font(FontRepository::FindFont(u"Arial"));
t1->get_TextState()->set_FontSize(16);
t1->get_TextState()->set_ForegroundColor(Color::get_Black());
t1->get_TextState()->set_FontStyle(FontStyles::Bold);
t1->get_TextState()->set_HorizontalAlignment(HorizontalAlignment::Center);
t1->get_TextState()->set_LineSpacing(5.0f);
hfFirst->get_Paragraphs()->Add(t1);
auto t2 = MakeObject<TextFragment>("Nombre_Informe");
t2->get_TextState()->set_Font(FontRepository::FindFont(u"Arial"));
t2->get_TextState()->set_ForegroundColor(Color::get_Black());
t2->get_TextState()->set_HorizontalAlignment(HorizontalAlignment::Center);
t2->get_TextState()->set_LineSpacing(5.0f);
t2->get_TextState()->set_FontSize(12);
hfFirst->get_Paragraphs()->Add(t2);
// Crear un objeto HeaderFooter para la sección
auto hfFoot = MakeObject<HeaderFooter>();
// Establecer el objeto HeaderFooter para pie de página impar y par
page->set_Footer(hfFoot);
hfFoot->get_Margin()->set_Left(50);
hfFoot->get_Margin()->set_Right(50);
// Agregar un párrafo de texto que contenga el número de página actual del total de páginas
auto t3 = MakeObject<TextFragment>("Generado en fecha de prueba");
auto t4 = MakeObject<TextFragment>("nombre del informe ");
auto t5 = MakeObject<TextFragment>("Página $p de $P");
// Instanciar un objeto tabla
auto tab2 = MakeObject<Table>();
// Agregar la tabla en la colección de párrafos de la sección deseada
hfFoot->get_Paragraphs()->Add(tab2);
// Establecer anchos de columna de la tabla
tab2->set_ColumnWidths(u"165 172 165");
// Crear filas en la tabla y luego celdas en las filas
auto row3 = tab2->get_Rows()->Add();
row3->get_Cells()->Add();
row3->get_Cells()->Add();
row3->get_Cells()->Add();
// Establecer la alineación vertical del texto como centrada
row3->get_Cells()->idx_get(0)->set_Alignment(HorizontalAlignment::Left);
row3->get_Cells()->idx_get(1)->set_Alignment(HorizontalAlignment::Center);
row3->get_Cells()->idx_get(2)->set_Alignment(HorizontalAlignment::Right);
row3->get_Cells()->idx_get(0)->get_Paragraphs()->Add(t3);
row3->get_Cells()->idx_get(1)->get_Paragraphs()->Add(t4);
row3->get_Cells()->idx_get(2)->get_Paragraphs()->Add(t5);
auto table = MakeObject<Table>();
table->set_ColumnWidths(u"33% 33% 34%");
table->set_DefaultCellPadding(new MarginInfo());
table->get_DefaultCellPadding()->set_Top(10);
table->get_DefaultCellPadding()->set_Bottom(10);
// Agregar la tabla en la colección de párrafos de la sección deseada
page.getParagraphs().add(table);
// Establecer el borde de celda predeterminado usando el objeto BorderInfo
table->set_DefaultCellBorder(MakeObject<BorderInfo>(BorderSide::All, 0.1f));
// Establecer el borde de la tabla usando otro objeto BorderInfo personalizado
table->set_Border(MakeObject<BorderInfo>(BorderSide::All, 1.0f));
table->set_RepeatingRowsCount(1);
// Crear filas en la tabla y luego celdas en las filas
auto row1 = table->get_Rows()->Add();
row1->get_Cells()->Add(u"col1");
row1->get_Cells()->Add(u"col2");
row1->get_Cells()->Add(u"col3");
String CRLF ("\r\n");
for (int i = 0; i <= 10; i++) {
auto row = table->get_Rows()->Add();
row->set_IsRowBroken(true);
for (int c = 0; c <= 2; c++) {
SharedPtr<Cell> c1;
if (c == 2)
c1 = row->get_Cells()->Add(
u"Aspose.Total for C++ es una compilación de todos los componentes de Java ofrecidos por Aspose. Se compila en una"
+ CRLF
+ u"base diaria para asegurar que contiene las versiones más actualizadas de cada uno de nuestros componentes de Java. "
+ CRLF
+ u"base diaria para asegurar que contiene las versiones más actualizadas de cada uno de nuestros componentes de Java. "
+ CRLF
+ u"Usando Aspose.Total for C++ los desarrolladores pueden crear una amplia gama de aplicaciones.");
else
c1 = row->get_Cells()->Add(u"elemento1" + c);
c1->set_Margin(new MarginInfo());
c1->get_Margin()->set_Left(30);
c1->get_Margin()->set_Top(10);
c1->get_Margin()->set_Bottom(10);
}
}
_dataDir = _dataDir + "ReplaceableSymbolsInHeaderFooter_out.pdf";
doc.save(_dataDir);
}
Remove All Text from PDF Document
Remove All Text using Operators
En algunas operaciones de texto, necesitas eliminar todo el texto del documento PDF, y para eso, usualmente necesitas establecer el texto encontrado como un valor de cadena vacío. El hecho es que cambiar el texto para un conjunto de fragmentos de texto provoca una serie de operaciones para verificar y ajustar la posición del texto. Son necesarias en los scripts de edición de texto. La dificultad radica en el hecho de que no puedes determinar cuántos fragmentos de texto serán eliminados en el script donde se procesan en el bucle.
Por lo tanto, recomendamos usar un enfoque diferente para el escenario de eliminar todo el texto de las páginas PDF.
El siguiente fragmento de código muestra cómo resolver esta tarea rápidamente.
void RemoveAllTextUsingOperators() {
String _dataDir("C:\\Samples\\");
// Open document
auto document = MakeObject<Document>(_dataDir + u"sample.pdf");
// Loop through all pages of PDF Document
for (int i = 1; i <= document->get_Pages()->get_Count(); i++) {
auto page = document->get_Pages()->idx_get(i);
auto operatorSelector = MakeObject<OperatorSelector>(MakeObject<Aspose::Pdf::Operators::TextShowOperator>());
// Select all text on the page
page->get_Contents()->Accept(operatorSelector);
// Delete all text
page->get_Contents()->Delete(operatorSelector->get_Selected());
}
// Save the document
document->Save(_dataDir + u"RemoveAllText_out.pdf");
}