Substituir Texto em PDF usando C++
Às vezes, surge a tarefa de corrigir ou substituir texto em um documento PDF. Tentar fazer isso manualmente será uma tarefa assustadora, então aqui está a solução para esse problema.
Honestamente, editar um arquivo PDF não é uma tarefa fácil. Portanto, uma situação em que você precisa encontrar e substituir uma palavra por outra enquanto edita um arquivo PDF será muito difícil, pois levará muito tempo para fazê-lo. Além disso, você pode encontrar muitos problemas com seu resultado, como formatação ou fontes quebradas. Se você deseja encontrar e substituir texto facilmente em arquivos PDF, recomendamos que use o software da biblioteca Aspose.Pdf, pois ele fará o trabalho em minutos.
Neste artigo, mostraremos como encontrar e substituir texto com sucesso em seus arquivos PDF usando o Aspose.PDF para C++.
Substituir Texto em todas as páginas do documento PDF
Para substituir texto em todas as páginas de um documento PDF, primeiro você precisa usar TextFragmentAbsorber para encontrar a frase específica que deseja substituir. Depois disso, você precisa percorrer todos os TextFragments para substituir o texto e alterar quaisquer outros atributos. Uma vez feito isso, você só precisa salvar o PDF de saída usando o método Save do objeto Document. O trecho de código a seguir mostra como substituir texto em todas as páginas de um 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");
// Criar objeto TextAbsorber para encontrar todas as instâncias da frase de pesquisa de entrada
auto textFragmentAbsorber = MakeObject<TextFragmentAbsorber>("Web");
// Aceitar o absorvedor para a primeira página do documento
document->get_Pages()->Accept(textFragmentAbsorber);
// Obter os fragmentos de texto extraídos na coleção
auto textFragmentCollection = textFragmentAbsorber->get_TextFragments();
// Percorrer os fragmentos
for (auto textFragment : textFragmentCollection) {
// Atualizar texto e outras propriedades
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());
}
// Salvar o arquivo PDF atualizado
document->Save(_dataDir + u"Updated_Text.pdf");
}
Substituir Texto em uma Região Específica da Página
Para substituir texto em uma região específica da página, primeiro precisamos instanciar o objeto TextFragmentAbsorber, especificar a região da página usando a propriedade TextSearchOptions.Rectangle e depois iterar por todos os TextFragments para substituir o texto. Uma vez que essas operações são concluídas, só precisamos salvar o PDF de saída usando o método Save do objeto Document. O código a seguir mostra como substituir texto em todas as páginas de um documento PDF.
void ReplaceTextInParticularRegion() {
String _dataDir("C:\\Samples\\");
// carregar arquivo PDF
auto document = MakeObject<Document>(_dataDir + u"sample.pdf");
// instanciar objeto TextFragment Absorber
auto textFragmentAbsorber = MakeObject<TextFragmentAbsorber>("PDF");
// procurar texto dentro dos limites da página
textFragmentAbsorber->get_TextSearchOptions()->set_LimitToPageBounds(true);
// especificar a região da página para Opções de Pesquisa de Texto
textFragmentAbsorber->get_TextSearchOptions()->set_Rectangle(new Rectangle(100, 700, 400, 770));
// procurar texto da primeira página do arquivo PDF
document->get_Pages()->idx_get(1)->Accept(textFragmentAbsorber);
// iterar por cada TextFragment
for (auto tf : textFragmentAbsorber->get_TextFragments()) {
// substituir texto por "---"
tf->set_Text(u"---");
}
// Salvar o arquivo PDF atualizado
document->Save(_dataDir + u"Updated_Text.pdf");
}
Substituir Texto com Base em uma Expressão Regular
Se você deseja substituir algumas frases com base em uma expressão regular, primeiro precisa encontrar todas as frases que correspondem a essa expressão regular específica usando TextFragmentAbsorber. Você terá que passar a expressão regular como um parâmetro para o construtor TextFragmentAbsorber. Você também precisa criar um objeto TextSearchOptions que especifica se a expressão regular está sendo usada ou não. Assim que você obtiver as frases correspondentes em TextFragments, você precisa percorrer todas elas e atualizar conforme necessário. Finalmente, você precisa salvar o PDF atualizado usando o método Save do objeto Document. O trecho de código a seguir mostra como substituir texto com base em uma expressão regular.
void ReplaceTextWithRegularExpression() {
String _dataDir("C:\\Samples\\");
// load PDF file
auto document = MakeObject<Document>(_dataDir + u"Sample.pdf");
// Create TextAbsorber object to find all instances of the input search phrase
auto textFragmentAbsorber = MakeObject<TextFragmentAbsorber>("\\d{4}-\\d{4}");
// like 1999-2000
// Set text search option to specify regular expression usage
auto textSearchOptions = new TextSearchOptions(true);
textFragmentAbsorber->set_TextSearchOptions(textSearchOptions);
// Accept the absorber for first page of document
document->get_Pages()->Accept(textFragmentAbsorber);
// Get the extracted text fragments into collection
auto textFragmentCollection = textFragmentAbsorber->get_TextFragments();
// Loop through the fragments
for (auto textFragment : textFragmentCollection) {
// Update text and other properties
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());
}
// Save the updated PDF file
document->Save(_dataDir + u"Updated_Text.pdf");
}
Substituir fontes em arquivo PDF existente
Aspose.PDF para C++ suporta a capacidade de substituir texto em um documento PDF. No entanto, às vezes você tem a necessidade de substituir apenas a fonte sendo usada dentro do documento PDF. Então, em vez de substituir o texto, apenas a fonte utilizada é substituída. Uma das sobrecargas do construtor TextFragmentAbsorber aceita um objeto TextEditOptions como argumento e podemos usar o valor RemoveUnusedFonts da enumeração TextEditOptions.FontReplace para atender aos nossos requisitos. O seguinte trecho de código mostra como substituir a fonte dentro do documento PDF.
void ReplaceFonts() {
String _dataDir("C:\\Samples\\");
// Instanciar objeto Document
auto document = MakeObject<Document>(_dataDir + u"sample.pdf");
// Procurar fragmentos de texto e definir a opção de edição como remover fontes não utilizadas
auto textFragmentAbsorber = MakeObject<TextFragmentAbsorber>(
MakeObject<TextEditOptions>(TextEditOptions::FontReplace::RemoveUnusedFonts));
// Aceitar o absorvedor para todas as páginas do documento
document->get_Pages()->Accept(textFragmentAbsorber);
// Percorrer todos os TextFragments
auto textFragmentCollection = textFragmentAbsorber->get_TextFragments();
for (auto textFragment : textFragmentCollection) {
String fontName = textFragment->get_TextState()->get_Font()->get_FontName();
// se o nome da fonte for ArialMT, substituir o nome da fonte por Arial
if (fontName.Equals(u"ArialMT")) {
textFragment->get_TextState()->set_Font(FontRepository::FindFont(u"Arial"));
}
}
// Salvar o arquivo PDF atualizado
document->Save(_dataDir + u"Updated_Text.pdf");
}
No próximo trecho de código, você verá como usar uma fonte não inglesa ao substituir texto:
void UseNonEnglishFontWhenReplacingText() {
String _dataDir("C:\\Samples\\");
// Instanciar objeto Documento
auto document = MakeObject<Document>(_dataDir + u"sample.pdf");
// Vamos mudar todas as palavras "PDF" para algum texto em japonês com fonte específica
// MSGothic que pode estar instalada no sistema operacional
// Além disso, pode ser outra fonte que suporte hieróglifos
auto textFragmentAbsorber = MakeObject<TextFragmentAbsorber>("PDF");
// Criar instância de opções de pesquisa de texto
auto searchOptions = MakeObject<TextSearchOptions>(true);
textFragmentAbsorber->set_TextSearchOptions(searchOptions);
// Aceitar o absorvedor para todas as páginas do documento
document->get_Pages()->Accept(textFragmentAbsorber);
// Obter os fragmentos de texto extraídos em uma coleção
auto textFragmentCollection = textFragmentAbsorber->get_TextFragments();
// Percorrer os fragmentos
for (auto textFragment : textFragmentCollection) {
// Atualizar texto e outras propriedades
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());
}
// Salvar o documento atualizado
document->Save(_dataDir + u"Japanese_Text.pdf");
}
A Substituição de Texto deve reorganizar automaticamente o Conteúdo da Página
Aspose.PDF para C++ suporta encontrar e substituir texto dentro de um arquivo PDF. Recentemente, no entanto, alguns clientes tiveram problemas ao substituir texto, onde um determinado TextFragment é substituído por um conteúdo menor e algum espaço em branco extra é exibido no PDF resultante, ou se o TextFragment for substituído por uma string mais longa, então as palavras se sobrepõem ao conteúdo existente da página. Assim, foi necessário introduzir um mecanismo que, após substituir o texto dentro do documento PDF, reorganizasse seu conteúdo.
Para atender aos cenários mencionados, o Aspose.PDF para C++ foi aprimorado para que tais problemas não ocorram ao substituir texto dentro de um arquivo PDF. O seguinte trecho de código demonstra como substituir texto dentro de um arquivo PDF e o conteúdo da página deve ser reordenado automaticamente.
void RearrangeContent() {
String _dataDir("C:\\Samples\\");
// Instanciar objeto Document
auto document = MakeObject<Document>(_dataDir + u"sample.pdf");
// Criar objeto TextFragment Absorber com expressão regular
auto textFragmentAbsorber = MakeObject<TextFragmentAbsorber>("[PDF,Web]");
auto textSearchOptions = MakeObject<TextSearchOptions>(true);
textFragmentAbsorber->set_TextSearchOptions(textSearchOptions);
// Você também pode especificar a opção ReplaceAdjustment.WholeWordsHyphenation para
// quebrar o texto na próxima linha ou na linha atual se a linha atual ficar muito longa ou
// curta após a substituição:
//textFragmentAbsorber->get_TextReplaceOptions()->set_ReplaceAdjustmentAction(TextReplaceOptions::ReplaceAdjustment::WholeWordsHyphenation);
// Aceitar o absorvedor para todas as páginas do documento
document->get_Pages()->Accept(textFragmentAbsorber);
// Obter os fragmentos de texto extraídos na coleção
auto textFragmentCollection = textFragmentAbsorber->get_TextFragments();
// Substituir cada TextFragment
for (auto textFragment : textFragmentCollection) {
// Definir fonte do fragmento de texto sendo substituído
textFragment->get_TextState()->set_Font(FontRepository::FindFont(u"Arial"));
// Definir tamanho da fonte
textFragment->get_TextState()->set_FontSize(10);
textFragment->get_TextState()->set_ForegroundColor(Color::get_Blue());
textFragment->get_TextState()->set_BackgroundColor(Color::get_Gray());
// Substituir o texto por uma string maior que o espaço reservado
textFragment->set_Text(u"Isto é uma string maior para o teste desta funcionalidade");
}
// Salvar PDF resultante
document->Save(_dataDir + u"RearrangeContentsUsingTextReplacement_out.pdf");
}
Renderização de Símbolos Substituíveis durante a criação de PDF
Símbolos substituíveis são símbolos especiais em uma string de texto que podem ser substituídos por conteúdo correspondente em tempo de execução. Os símbolos substituíveis atualmente suportados pelo novo Modelo de Objeto de Documento do namespace Aspose.PDF são $P
, $p,
\n
, \r
. O $p
e $P
são usados para lidar com a numeração de páginas em tempo de execução. $p
é substituído pelo número da página onde a classe atual Paragraph está. $P
é substituído pelo número total de páginas no documento. Ao adicionar TextFragment
à coleção de parágrafos de documentos PDF, ele não suporta quebra de linha dentro do texto. No entanto, para adicionar texto com uma quebra de linha, por favor, use TextFragment
com TextParagraph
:
- use “\r\n” ou Environment.NewLine em TextFragment em vez de um único “\n”;
- crie um objeto TextParagraph. Isso adicionará texto com divisão de linhas;
- adicione o TextFragment com TextParagraph.AppendLine;
- adicione o TextParagraph com TextBuilder.AppendParagraph.
void RenderingReplaceableSymbols() {
String _dataDir("C:\\Samples\\");
// carregar arquivo PDF
auto document = MakeObject<Document>(_dataDir + u"sample.pdf");
auto page = document->get_Pages()->Add();
// Inicializar novo TextFragment com texto contendo marcadores de nova linha necessários
auto textFragment = MakeObject<TextFragment>("Applicant Name: \r\n Joe Smoe");
// Definir propriedades do fragmento de texto, se necessário
textFragment->get_TextState()->set_FontSize(12);
textFragment->get_TextState()->set_Font(FontRepository::FindFont(u"TimesNewRoman"));
textFragment->get_TextState()->set_BackgroundColor(Color::get_LightGray());
textFragment->get_TextState()->set_ForegroundColor(Color::get_Red());
// Criar objeto TextParagraph
auto par = MakeObject<TextParagraph>();
// Adicionar novo TextFragment ao parágrafo
par->AppendLine(textFragment);
// Definir posição do parágrafo
par->set_Position(MakeObject<Position>(100, 600));
// Criar objeto TextBuilder
auto textBuilder = MakeObject<TextBuilder>(page);
// Adicionar o TextParagraph usando TextBuilder
textBuilder->AppendParagraph(par);
document->Save(_dataDir + u"RenderingReplaceableSymbols_out.pdf");
}
Símbolos substituíveis na área de Cabeçalho/Rodapé
O símbolo substituível também pode ser colocado dentro da seção de cabeçalho/rodapé do arquivo PDF. Revise o trecho de código a seguir para ver como adicionar um símbolo substituível a uma seção de rodapé.
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);
// Atribuir a instância marginInfo à propriedade Margin do 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 um parágrafo de texto que armazenará o conteúdo a ser exibido como cabeçalho
auto t1 = MakeObject<TextFragment>("título do relatório");
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>("Nome_Relatório");
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);
// Criar um objeto HeaderFooter para a seção
auto hfFoot = MakeObject<HeaderFooter>();
// Definir o objeto HeaderFooter para rodapé ímpar e par
page->set_Footer(hfFoot);
hfFoot->get_Margin()->set_Left(50);
hfFoot->get_Margin()->set_Right(50);
// Adicionar um parágrafo de texto contendo o número da página atual do total de páginas
auto t3 = MakeObject<TextFragment>("Gerado na data de teste");
auto t4 = MakeObject<TextFragment>("nome do relatório ");
auto t5 = MakeObject<TextFragment>("Página $p de $P");
// Instanciar um objeto Table
auto tab2 = MakeObject<Table>();
// Adicionar a tabela na coleção de parágrafos da seção desejada
hfFoot->get_Paragraphs()->Add(tab2);
// Definir as larguras das colunas da tabela
tab2->set_ColumnWidths(u"165 172 165");
// Criar linhas na tabela e depois células nas linhas
auto row3 = tab2->get_Rows()->Add();
row3->get_Cells()->Add();
row3->get_Cells()->Add();
row3->get_Cells()->Add();
// Definir o alinhamento vertical do texto como centralizado
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);
// Adicionar a tabela na coleção de parágrafos da seção desejada
page.getParagraphs().add(table);
// Definir a borda padrão da célula usando o objeto BorderInfo
table->set_DefaultCellBorder(MakeObject<BorderInfo>(BorderSide::All, 0.1f));
// Definir a borda da tabela usando outro objeto BorderInfo personalizado
table->set_Border(MakeObject<BorderInfo>(BorderSide::All, 1.0f));
table->set_RepeatingRowsCount(1);
// Criar linhas na tabela e depois células nas linhas
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 para C++ é uma compilação de todos os componentes Java oferecidos pela Aspose. É compilado em uma"
+ CRLF
+ u"base diária para garantir que contenha as versões mais atualizadas de cada um dos nossos componentes Java. "
+ CRLF
+ u"base diária para garantir que contenha as versões mais atualizadas de cada um dos nossos componentes Java. "
+ CRLF
+ u"Usando Aspose.Total para C++ desenvolvedores podem criar uma ampla gama de aplicações.");
else
c1 = row->get_Cells()->Add(u"item1" + 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);
}
Remover Todo o Texto do Documento PDF
Remover Todo o Texto usando Operadores
Em algumas operações de texto, você precisa remover todo o texto do documento PDF, e para isso, geralmente precisa definir o texto encontrado como um valor de string vazio. O fato é que alterar o texto para um conjunto de fragmentos de texto causa uma série de operações para verificar e ajustar a posição do texto. Elas são necessárias em scripts de edição de texto. A dificuldade reside no fato de que você não pode determinar quantos pedaços de texto serão deletados no script onde eles são processados no loop.
Portanto, recomendamos usar uma abordagem diferente para o cenário de remover todo o texto das páginas do PDF.
O seguinte trecho de código mostra como resolver essa tarefa rapidamente.
void RemoveAllTextUsingOperators() {
String _dataDir("C:\\Samples\\");
// Abrir documento
auto document = MakeObject<Document>(_dataDir + u"sample.pdf");
// Percorrer todas as páginas do Documento PDF
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>());
// Selecionar todo o texto na página
page->get_Contents()->Accept(operatorSelector);
// Excluir todo o texto
page->get_Contents()->Delete(operatorSelector->get_Selected());
}
// Salvar o documento
document->Save(_dataDir + u"RemoveAllText_out.pdf");
}