Optimize PDF using C++
Antes de tudo, qualquer otimização de PDF que você fizer é para o usuário. Em PDFs, a otimização do usuário é principalmente sobre reduzir o tamanho dos seus PDFs para aumentar a velocidade de carregamento deles. Esta é a tarefa mais popular. Podemos usar várias técnicas para otimizar PDF, mas o mais essencial:
- Otimizar o conteúdo da página para navegação online
- Reduzir ou comprimir todas as imagens
- Habilitar a reutilização do conteúdo da página
- Mesclar fluxos duplicados
- Remover fontes incorporadas
- Remover objetos não utilizados
- Remover campos de formulário achatados
- Remover ou achatar anotações
Otimizar Documento PDF para a Web
Quando você se depara com a tarefa de otimizar o conteúdo do seu documento PDF para melhor classificação em motores de busca, o Aspose.PDF para C++ tem uma solução.
- Abra o documento de entrada em um objeto Document.
- Use o método Optimize.
- Salve o documento otimizado usando o método Save.
O seguinte trecho de código mostra como otimizar um documento PDF para a web.
using namespace System;
using namespace Aspose::Pdf;
using namespace Aspose::Pdf::Text;
//Optimize PDF Document for the Web
void OptimizeForWeb() {
// String para nome do caminho
String _dataDir("C:\\Samples\\");
// String para nome do arquivo de saída
String outfilename("OptimizeDocument_out.pdf");
// Abrir documento
auto document = MakeObject<Document>();
// Fazer algumas operações (adicionar páginas, imagens, etc)
// ...
// Otimizar para web
document->Optimize();
// Salvar documento de saída
document->Save(_dataDir + outfilename);
}
Reduzir Tamanho do PDF
O método OptimizeResources() permite reduzir o tamanho do documento eliminando as informações desnecessárias. Por padrão, este método funciona da seguinte forma:
- Recursos que não são usados nas páginas do documento são removidos
- Recursos iguais são unidos em um único objeto
- Objetos não utilizados são deletados
O trecho abaixo é um exemplo. Note, porém, que este método não pode garantir a redução do documento.
void ReduceSizePDF() {
// String para nome do caminho
String _dataDir("C:\\Samples\\");
// String para nome do arquivo de entrada
String outfilename("ShrinkDocument_out.pdf");
// Abrir documento
auto document = MakeObject<Document>();
// Fazer algumas operações (adicionar páginas, imagens, etc.)
// ...
// Otimizar documento PDF. Note, porém, que este método não pode garantir a redução do documento
document->OptimizeResources();
// Salvar documento de saída
document->Save(_dataDir + outfilename);
}
Gerenciamento da Estratégia de Otimização
Também podemos personalizar a estratégia de otimização. Atualmente, o método OptimizeResources() usa 5 técnicas. Essas técnicas podem ser aplicadas usando o método OptimizeResources() com o parâmetro OptimizationOptions.
Encolhendo ou Compactando Todas as Imagens
Para otimizar imagens em seu documento PDF, usaremos Aspose.Pdf.Optimization. Para resolver o problema com a otimização de imagens, temos as seguintes opções: reduzir a qualidade da imagem e/ou alterar a resolução delas. Em qualquer caso, ImageCompressionOptions deve ser aplicado. No exemplo a seguir, reduzimos as imagens diminuindo ImageQuality para 50.
void CompressImage() {
// String para nome do caminho
String _dataDir("C:\\Samples\\");
// String para nome do arquivo de entrada
String infilename("ShrinkDocument.pdf");
String outfilename("ShrinkDocument_out.pdf");
// Abrir documento
auto document = MakeObject<Document>(_dataDir + infilename);
// Inicializar OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// Definir opção CompressImages
optimizationOptions->get_ImageCompressionOptions()->set_CompressImages(true);
// Definir opção ImageQuality
optimizationOptions->get_ImageCompressionOptions()->set_ImageQuality(50);
// Otimizar documento PDF usando OptimizationOptions
document->OptimizeResources(optimizationOptions);
// Salvar documento atualizado
document->Save(_dataDir + outfilename);
}
Para definir a imagem em uma resolução mais baixa, defina ResizeImages como verdadeiro e MaxResolution para o valor correspondente.
void ResizeImagesWithLowerResolution() {
// String para o nome do caminho
String _dataDir("C:\\Samples\\");
// String para o nome do arquivo de entrada
String infilename("ResizeImage.pdf");
String outfilename("ResizeImages_out.pdf");
// Abrir documento
auto document = MakeObject<Document>(_dataDir + infilename);
// Inicializar OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// Definir opção CompressImages
optimizationOptions->get_ImageCompressionOptions()->set_CompressImages(true);
// Definir opção ImageQuality
optimizationOptions->get_ImageCompressionOptions()->set_ImageQuality(75);
// Definir opção ResizeImage
optimizationOptions->get_ImageCompressionOptions()->set_ResizeImages(true);
// Definir opção MaxResolution
optimizationOptions->get_ImageCompressionOptions()->set_MaxResolution(300);
// Otimizar documento PDF usando OptimizationOptions
document->OptimizeResources(optimizationOptions);
// Salvar documento atualizado
document->Save(_dataDir + outfilename);
}
Aspose.PDF para C++ também oferece controle sobre a configuração em tempo de execução. Hoje, podemos usar dois algoritmos - Padrão e Rápido. Para controlar o tempo de execução, devemos definir uma propriedade Version.
O trecho a seguir demonstra o algoritmo Rápido:
void ResizeImagesWithLowerResolutionFast() {
auto time = System::DateTime::get_Now().get_Ticks();
// String para o nome do caminho
String _dataDir("C:\\Samples\\");
// String para o nome do arquivo de entrada
String infilename("ResizeImage.pdf");
String outfilename("ResizeImages_out.pdf");
// Abrir documento
auto document = MakeObject<Document>(_dataDir + infilename);
// Inicializar OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// Definir a opção CompressImages
optimizationOptions->get_ImageCompressionOptions()->set_CompressImages(true);
// Definir a opção ImageQuality
optimizationOptions->get_ImageCompressionOptions()->set_ImageQuality(75);
// Definir a opção ResizeImage
optimizationOptions->get_ImageCompressionOptions()->set_ResizeImages(true);
// Definir a versão de Compressão de Imagem para rápido
optimizationOptions->get_ImageCompressionOptions()->set_Version (Aspose::Pdf::Optimization::ImageCompressionVersion::Fast);
// Otimizar documento PDF usando OptimizationOptions
document->OptimizeResources(optimizationOptions);
// Salvar documento atualizado
document->Save(_dataDir + outfilename);
std::cout << "Ticks: " << System::DateTime::get_Now().get_Ticks() - time << std::endl;
}
Removendo Objetos Não Utilizados
Às vezes, você pode precisar remover alguns objetos não utilizados do seu documento PDF que não são referenciados nas páginas. Isso pode acontecer, por exemplo, quando uma página é removida da árvore de páginas do documento, mas o próprio objeto de página não é removido. Remover esses objetos não torna o documento inválido, mas sim o reduz. Confira o próximo trecho de código:
void RemovingUnusedObject() {
// String para o caminho do diretório
String _dataDir("C:\\Samples\\");
// String para o nome do arquivo de entrada
String infilename("ShrinkDocument.pdf");
String outfilename("ShrinkDocument_out.pdf");
// Abrir documento
auto document = MakeObject<Document>(_dataDir + infilename);
// Inicializar OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// Definir a opção RemoveUsedObject
optimizationOptions->set_RemoveUnusedObjects(true);
// Otimizar o documento PDF usando OptimizationOptions
document->OptimizeResources(optimizationOptions);
// Salvar documento atualizado
document->Save(_dataDir + outfilename);
}
Removendo Fluxos Não Utilizados
Às vezes, o documento contém fluxos de recursos não utilizados. Esses fluxos não são “objetos não utilizados” porque são referenciados a partir de um dicionário de recursos de página. Assim, eles não são removidos com um método de “remover objetos não utilizados”. Mas esses fluxos nunca são usados com o conteúdo da página. Isso pode acontecer em casos quando uma imagem foi removida da página, mas não dos recursos da página. Além disso, essa situação ocorre frequentemente quando páginas são extraídas do documento e as páginas do documento têm recursos “comuns”, ou seja, o mesmo objeto Resources. Os conteúdos da página são analisados para determinar se um fluxo de recurso é usado ou não. Fluxos não utilizados são removidos. Isso às vezes diminui o tamanho do documento. O uso dessa técnica é semelhante ao passo anterior:
void RemovingUnusedStreams() {
// String para nome do caminho
String _dataDir("C:\\Samples\\");
// String para nome do arquivo de entrada
String infilename("ShrinkDocument.pdf");
String outfilename("ShrinkDocument_out.pdf");
// Abrir documento
auto document = MakeObject<Document>();
// Inicializar OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// Definir opção RemoveUsedStreams
optimizationOptions->set_RemoveUnusedStreams(true);
// Otimizar documento PDF usando OptimizationOptions
document->OptimizeResources(optimizationOptions);
// Salvar documento atualizado
document->Save(_dataDir + outfilename);
}
Linking Duplicate Streams
Alguns documentos podem conter vários fluxos de recursos duplicados (como imagens, por exemplo). Isso pode acontecer, por exemplo, quando um documento é concatenado com ele mesmo. O documento de saída contém duas cópias independentes do mesmo fluxo de recursos. Analisamos todos os fluxos de recursos e os comparamos. Se os fluxos estão duplicados, eles são mesclados, ou seja, apenas uma cópia é mantida. As referências são alteradas apropriadamente, e as cópias do objeto são removidas. Em alguns casos, isso ajuda a diminuir o tamanho do documento.
void LinkingDuplicateStreams() {
// String para o nome do caminho
String _dataDir("C:\\Samples\\");
// String para o nome do arquivo de entrada
String infilename("ShrinkDocument.pdf");
String outfilename("ShrinkDocument_out.pdf");
// Abrir documento
auto document = MakeObject<Document>(_dataDir + infilename);
// Inicializar OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// Definir opção LinkDuplcateStreams
optimizationOptions->set_LinkDuplcateStreams(true);
// Otimizar documento PDF usando OptimizationOptions
document->OptimizeResources(optimizationOptions);
// Salvar documento atualizado
document->Save(_dataDir + outfilename);
}
Além disso, podemos usar as configurações AllowReusePageContent. Se esta propriedade for definida como true, o conteúdo da página será reutilizado ao otimizar o documento para páginas idênticas.
void AllowReusePageContent() {
// String para o nome do caminho
String _dataDir("C:\\Samples\\");
// String para o nome do arquivo de entrada
String infilename("ShrinkDocument.pdf");
String outfilename("ShrinkDocument_out.pdf");
// Abrir documento
auto document = MakeObject<Document>(_dataDir + infilename);
// Inicializar OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// Definir a opção AllowReusePageContent
optimizationOptions->set_AllowReusePageContent(true);
// Otimizar documento PDF usando OptimizationOptions
document->OptimizeResources(optimizationOptions);
// Salvar documento atualizado
document->Save(_dataDir + outfilename);
}
Desincorporar Fontes
Quando você cria uma versão PDF do seu arquivo de design pessoal, uma cópia de todas as fontes necessárias é adicionada ao próprio arquivo PDF. Isso é incorporação. Independentemente de onde este PDF seja aberto, seja no seu computador, no computador de um amigo ou no computador do seu provedor de impressão, todas as fontes corretas estarão lá e serão renderizadas corretamente.
Mas, se o documento usa fontes incorporadas, significa que todos os dados das fontes estão armazenados no documento. A vantagem é que o documento é visualizável independentemente de a fonte estar instalada na máquina do usuário ou não. Mas incorporar fontes torna o documento maior. O método de desincorporar fontes remove todas as fontes incorporadas. Assim, o tamanho do documento diminui, mas o próprio documento pode se tornar ilegível se a fonte correta não estiver instalada.
void UnembedFonts() {
// String para nome do caminho
String _dataDir("C:\\Samples\\");
// String para nome do arquivo de entrada
String infilename("ShrinkDocument.pdf");
String outfilename("ShrinkDocument_out.pdf");
// Abrir documento
auto document = MakeObject<Document>(_dataDir+infilename);
// Inicializar OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// Definir opção AllowReusePageContent
optimizationOptions->set_UnembedFonts(true);
// Otimizar documento PDF usando OptimizationOptions
document->OptimizeResources(optimizationOptions);
// Salvar documento atualizado
document->Save(_dataDir + outfilename);
}
Os recursos de otimização aplicam esses métodos ao documento. Se algum desses métodos for aplicado, o tamanho do documento provavelmente diminuirá. Se nenhum desses métodos for aplicado, o tamanho do documento não mudará, o que é óbvio.
Maneiras Adicionais de Reduzir o Tamanho do Documento PDF
Removendo ou Achatando Anotações
A presença de anotações no seu documento PDF aumenta naturalmente seu tamanho. As anotações podem ser deletadas quando são desnecessárias. Quando são necessárias mas não requerem edição adicional, podem ser achatadas. Ambas as técnicas reduzirão o tamanho do arquivo.
void FlatteningAnnotation() {
// String para caminho do diretório
String _dataDir("C:\\Samples\\");
// String para nome do arquivo de entrada
String infilename("OptimizeDocument.pdf");
// String para nome do arquivo de saída
String outfilename("OptimizeDocument_out.pdf");
// Abrir documento
auto document = MakeObject<Document>(_dataDir + infilename);
// Achar anotações
for(auto page : document->get_Pages())
{
for(auto annotation : page->get_Annotations())
{
annotation->Flatten();
}
}
// Salvar documento atualizado
document->Save(_dataDir + outfilename);
}
Removendo Campos de Formulário
Remover formulários do seu PDF também otimizará seu documento. Se o documento PDF contiver AcroForms, podemos tentar reduzir o tamanho do arquivo achatando os campos do formulário.
void FlatteningFormFields() {
// String para o caminho do diretório
String _dataDir("C:\\Samples\\");
// String para o nome do arquivo de entrada
String infilename("OptimizeFormField.pdf");
// String para o nome do arquivo de saída
String outfilename("OptimizeFormField_out.pdf");
// Abrir documento
auto document = MakeObject<Document>(_dataDir + infilename);
// Aplanar campos de formulário
// Aplanar Formulários
if (document->get_Form()->get_Fields()->get_Count() > 0)
{
for(auto item : document->get_Form()->get_Fields())
{
item->Flatten();
}
}
// Salvar documento atualizado
document->Save(_dataDir + outfilename);
}
Converter um PDF do espaço de cores RGB para tons de cinza
Um arquivo PDF é composto por Texto, Imagem, Anexo, Anotações, Gráficos e outros objetos. Você pode se deparar com a necessidade de converter um PDF do espaço de cores RGB para escala de cinza para que seja mais rápido ao imprimir esses arquivos PDF. Além disso, quando o arquivo é convertido para escala de cinza, o tamanho do documento é reduzido também, mas isso pode causar uma diminuição na qualidade do documento. Este recurso é atualmente suportado pelo recurso Pre-Flight do Adobe Acrobat, mas quando se fala em automação de escritório, Aspose.PDF é uma solução definitiva para fornecer tais vantagens para manipulações de documentos. Para realizar este requisito, o seguinte trecho de código pode ser usado.
void ConvertPDFfromColorspaceToGrayscale() {
// String para nome do caminho
String _dataDir("C:\\Samples\\");
// String para nome do arquivo de entrada
String infilename("OptimizeDocument.pdf");
// String para nome do arquivo de saída
String outfilename("Test-gray_out.pdf");
// Abrir documento
auto document = MakeObject<Document>(_dataDir + infilename);
auto strategy = MakeObject<Aspose::Pdf::RgbToDeviceGrayConversionStrategy>();
for (int idxPage = 1; idxPage <= document->get_Pages()->get_Count(); idxPage++)
{
// Obter instância de uma página específica dentro do PDF
auto page = document->get_Pages()->idx_get(idxPage);
// Converter a imagem do espaço de cores RGB para o espaço de cores GrayScale
strategy->Convert(page);
}
// Salvar arquivo resultante
document->Save(_dataDir + outfilename);
}
Compressão FlateDecode
Aspose.PDF para C++ oferece suporte à compressão FlateDecode para a funcionalidade de otimização de PDF. Para otimizar a imagem usando a compressão FlateDecode, defina as opções de otimização para Flate. O trecho de código a seguir mostra como usar a opção em Otimização para armazenar imagens com compressão FlateDecode:
void FlatDecodeCompression() {
// String para nome do caminho
String _dataDir("C:\\Samples\\");
// String para nome do arquivo de entrada
String infilename("FlateDecodeCompression.pdf");
// String para nome do arquivo de saída
String outfilename("FlateDecodeCompression_out.pdf");
// Abrir documento
auto document = MakeObject<Document>(_dataDir + infilename);
// Inicializar OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// Para otimizar a imagem usando a compressão FlateDecode, defina as opções de otimização para Flate
optimizationOptions->get_ImageCompressionOptions()->set_Encoding(Aspose::Pdf::Optimization::ImageEncoding::Flate);
// Otimizar documento PDF usando OptimizationOptions
document->OptimizeResources(optimizationOptions);
// Salvar documento atualizado
document->Save(_dataDir + outfilename);
}
Armazenar Imagem em XImageCollection
Aspose.PDF para C++ fornece a capacidade de armazenar novas imagens em XImageCollection com compressão FlateDecode. Para habilitar esta opção, você pode usar a flag ImageFilterType.Flate. O trecho de código a seguir mostra como usar esta funcionalidade:
void StoreImageInXImageCollection() {
// String para o nome do caminho
String _dataDir("C:\\Samples\\");
// String para o nome do arquivo de saída
String outfilename("FlateDecodeCompression_out.pdf");
// Abrir documento
auto document = MakeObject<Document>();
auto page = document->get_Pages()->Add();
auto imageStream = System::IO::File::OpenRead(_dataDir + u"aspose-logo.jpg");
page->get_Resources()->get_Images()->Add(imageStream, Aspose::Pdf::ImageFilterType::Flate);
auto ximage = page->get_Resources()->get_Images()->idx_get(page->get_Resources()->get_Images()->get_Count());
page->get_Contents()->Add(MakeObject<Aspose::Pdf::Operators::GSave>());
// Definir coordenadas
int lowerLeftX = 0;
int lowerLeftY = 0;
int upperRightX = 600;
int upperRightY = 600;
auto rectangle = MakeObject<Rectangle>(lowerLeftX, lowerLeftY, upperRightX, upperRightY);
auto matrix = MakeObject<Matrix>(new double[] {rectangle->get_URX() - rectangle->get_LLX(), 0, 0, rectangle->get_URY() - rectangle->get_LLY(), rectangle->get_LLX(), rectangle->get_LLY()});
// Usando o operador ConcatenateMatrix (concatenar matriz): define como a imagem deve ser colocada
page->get_Contents()->Add(MakeObject<Aspose::Pdf::Operators::ConcatenateMatrix>(matrix));
page->get_Contents()->Add(MakeObject<Aspose::Pdf::Operators::Do>(ximage->get_Name()));
page->get_Contents()->Add(MakeObject<Aspose::Pdf::Operators::GRestore>());
document->Save(_dataDir + outfilename);
}