Optimize PDF using C++
首先,您所做的任何PDF优化都是为了用户。在PDF中,用户优化主要是通过减少PDF的大小来提高其加载速度。这是最受欢迎的任务。
我们可以使用几种技术来优化PDF,但最基本的是:
- 为在线浏览优化页面内容
- 缩小或压缩所有图像
- 启用重用页面内容
- 合并重复的流
- 取消嵌入字体
- 删除未使用的对象
- 删除平面化表单字段
- 删除或平面化注释
为网络优化PDF文档
当您面临优化PDF文档内容以在搜索引擎中获得更好排名的任务时,Aspose.PDF for C++提供了解决方案。
以下代码片段展示了如何为网络优化 PDF 文档。
using namespace System;
using namespace Aspose::Pdf;
using namespace Aspose::Pdf::Text;
//为网络优化 PDF 文档
void OptimizeForWeb() {
// 路径名称的字符串
String _dataDir("C:\\Samples\\");
// 输入文件名的字符串
String outfilename("OptimizeDocument_out.pdf");
// 打开文档
auto document = MakeObject<Document>();
// 进行一些操作(添加页面、图像等)
// ...
// 为网络优化
document->Optimize();
// 保存输出文档
document->Save(_dataDir + outfilename);
}
减少 PDF 大小
OptimizeResources() 方法允许您通过清除不必要的信息来减少文档大小。 默认情况下,此方法的工作原理如下:
- 未在文档页面上使用的资源将被移除
- 相同的资源将合并为一个对象
- 未使用的对象将被删除
下面的代码片段是一个示例。但请注意,此方法不能保证文档缩小。
void ReduceSizePDF() {
// 路径名称的字符串
String _dataDir("C:\\Samples\\");
// 输入文件名的字符串
String outfilename("ShrinkDocument_out.pdf");
// 打开文档
auto document = MakeObject<Document>();
// 进行一些操作(添加页面、图像等)
// ...
// 优化PDF文档。但请注意,此方法不能保证文档缩小
document->OptimizeResources();
// 保存输出文档
document->Save(_dataDir + outfilename);
}
优化策略管理
我们还可以自定义优化策略。 目前,OptimizeResources() 方法使用了5种技术。这些技术可以通过使用 OptimizationOptions 参数的 OptimizeResources() 方法来应用。
缩小或压缩所有图像
要优化 PDF 文档中的图像,我们将使用 Aspose.Pdf.Optimization。 为了解决图像优化问题,我们有以下选项:降低图像质量和/或更改其分辨率。 在任何情况下,都应该应用ImageCompressionOptions。在下面的例子中,我们通过将ImageQuality减少到50来缩小图像。
void CompressImage() {
// 路径名称的字符串
String _dataDir("C:\\Samples\\");
// 输入文件名称的字符串
String infilename("ShrinkDocument.pdf");
String outfilename("ShrinkDocument_out.pdf");
// 打开文档
auto document = MakeObject<Document>(_dataDir + infilename);
// 初始化OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// 设置CompressImages选项
optimizationOptions->get_ImageCompressionOptions()->set_CompressImages(true);
// 设置ImageQuality选项
optimizationOptions->get_ImageCompressionOptions()->set_ImageQuality(50);
// 使用OptimizationOptions优化PDF文档
document->OptimizeResources(optimizationOptions);
// 保存更新的文档
document->Save(_dataDir + outfilename);
}
要将图像设置为较低分辨率,请将ResizeImages设置为true,并将MaxResolution设置为相应的值。
void ResizeImagesWithLowerResolution() {
// 路径名称的字符串
String _dataDir("C:\\Samples\\");
// 输入文件名的字符串
String infilename("ResizeImage.pdf");
String outfilename("ResizeImages_out.pdf");
// 打开文档
auto document = MakeObject<Document>(_dataDir + infilename);
// 初始化OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// 设置CompressImages选项
optimizationOptions->get_ImageCompressionOptions()->set_CompressImages(true);
// 设置ImageQuality选项
optimizationOptions->get_ImageCompressionOptions()->set_ImageQuality(75);
// 设置ResizeImage选项
optimizationOptions->get_ImageCompressionOptions()->set_ResizeImages(true);
// 设置MaxResolution选项
optimizationOptions->get_ImageCompressionOptions()->set_MaxResolution(300);
// 使用OptimizationOptions优化PDF文档
document->OptimizeResources(optimizationOptions);
// 保存更新后的文档
document->Save(_dataDir + outfilename);
}
Aspose.PDF for C++ 还为您提供了对运行时设置的控制。今天,我们可以使用两种算法 - 标准和快速。为了控制执行时间,我们应该设置一个 Version 属性。
以下代码片段演示了快速算法:
void ResizeImagesWithLowerResolutionFast() {
auto time = System::DateTime::get_Now().get_Ticks();
// 路径名称的字符串
String _dataDir("C:\\Samples\\");
// 输入文件名的字符串
String infilename("ResizeImage.pdf");
String outfilename("ResizeImages_out.pdf");
// 打开文档
auto document = MakeObject<Document>(_dataDir + infilename);
// 初始化 OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// 设置 CompressImages 选项
optimizationOptions->get_ImageCompressionOptions()->set_CompressImages(true);
// 设置 ImageQuality 选项
optimizationOptions->get_ImageCompressionOptions()->set_ImageQuality(75);
// 设置 ResizeImage 选项
optimizationOptions->get_ImageCompressionOptions()->set_ResizeImages(true);
// 将图像压缩版本设置为快速
optimizationOptions->get_ImageCompressionOptions()->set_Version (Aspose::Pdf::Optimization::ImageCompressionVersion::Fast);
// 使用 OptimizationOptions 优化 PDF 文档
document->OptimizeResources(optimizationOptions);
// 保存更新的文档
document->Save(_dataDir + outfilename);
std::cout << "Ticks: " << System::DateTime::get_Now().get_Ticks() - time << std::endl;
}
删除未使用的对象
有时,您可能需要从PDF文档中删除某些未使用的对象,这些对象在页面上没有被引用。例如,当一个页面从文档页面树中删除,但页面对象本身没有被删除时,就可能发生这种情况。删除这些对象不会使文档无效,而是会缩小文档的大小。请查看以下代码片段:
void RemovingUnusedObject() {
// 路径名的字符串
String _dataDir("C:\\Samples\\");
// 输入文件名的字符串
String infilename("ShrinkDocument.pdf");
String outfilename("ShrinkDocument_out.pdf");
// 打开文档
auto document = MakeObject<Document>(_dataDir + infilename);
// 初始化OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// 设置RemoveUsedObject选项
optimizationOptions->set_RemoveUnusedObjects(true);
// 使用OptimizationOptions优化PDF文档
document->OptimizeResources(optimizationOptions);
// 保存更新后的文档
document->Save(_dataDir + outfilename);
}
删除未使用的流
有时文档包含未使用的资源流。这些流不是“未使用的对象”,因为它们是从页面资源字典中引用的。因此,它们不会通过“删除未使用对象”方法被删除。但这些流从未与页面内容一起使用。当某个图像已从页面中删除但未从页面资源中删除时,可能会发生这种情况。此外,当从文档中提取页面并且文档页面具有“公共”资源(即相同的资源对象)时,这种情况经常发生。分析页面内容以确定资源流是否被使用。未使用的流被删除。这有时会减少文档的大小。使用此技术与上一步类似:
void RemovingUnusedStreams() {
// String for path name
String _dataDir("C:\\Samples\\");
// String for input file name
String infilename("ShrinkDocument.pdf");
String outfilename("ShrinkDocument_out.pdf");
// Open document
auto document = MakeObject<Document>();
// Initialize OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// Set RemoveUsedStreams option
optimizationOptions->set_RemoveUnusedStreams(true);
// Optimize PDF document using OptimizationOptions
document->OptimizeResources(optimizationOptions);
// Save updated document
document->Save(_dataDir + outfilename);
}
链接重复的流
一些文档可能包含多个重复的资源流(例如图像)。这种情况可能发生在一个文档与自身连接时。输出文档包含相同资源流的两个独立副本。我们分析所有资源流并进行比较。如果流是重复的,它们将被合并,也就是说,只保留一个副本。引用会被适当地更改,并且对象的副本将被移除。在某些情况下,这有助于减少文档的大小。
void LinkingDuplicateStreams() {
// 路径名称的字符串
String _dataDir("C:\\Samples\\");
// 输入文件名的字符串
String infilename("ShrinkDocument.pdf");
String outfilename("ShrinkDocument_out.pdf");
// 打开文档
auto document = MakeObject<Document>(_dataDir + infilename);
// 初始化优化选项
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// 设置 LinkDuplcateStreams 选项
optimizationOptions->set_LinkDuplcateStreams(true);
// 使用优化选项优化 PDF 文档
document->OptimizeResources(optimizationOptions);
// 保存更新的文档
document->Save(_dataDir + outfilename);
}
另外,我们可以使用 AllowReusePageContent 设置。如果此属性设置为 true,则在优化相同页面的文档时,页面内容将被重用。
void AllowReusePageContent() {
// 路径名称的字符串
String _dataDir("C:\\Samples\\");
// 输入文件名的字符串
String infilename("ShrinkDocument.pdf");
String outfilename("ShrinkDocument_out.pdf");
// 打开文档
auto document = MakeObject<Document>(_dataDir + infilename);
// 初始化 OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// 设置 AllowReusePageContent 选项
optimizationOptions->set_AllowReusePageContent(true);
// 使用 OptimizationOptions 优化 PDF 文档
document->OptimizeResources(optimizationOptions);
// 保存更新后的文档
document->Save(_dataDir + outfilename);
}
解除字体嵌入
当您创建个人设计文件的 PDF 版本时,所有必要字体的副本会被添加到 PDF 文件本身。这就是嵌入。无论在何处打开此 PDF,无论是在您的计算机上、朋友的计算机上还是在您的打印供应商的计算机上,所有的正确字体都会存在并正确呈现。
但是,如果文档使用了嵌入的字体,这意味着所有字体数据都存储在文档中。优点是无论用户的机器上是否安装了字体,该文档都可以查看。但是嵌入字体会使文档变大。解除嵌入字体的方法会移除所有嵌入的字体。因此,文档的大小会减少,但如果没有安装正确的字体,文档本身可能会变得不可读。
void UnembedFonts() {
// String for path name
String _dataDir("C:\\Samples\\");
// String for input file name
String infilename("ShrinkDocument.pdf");
String outfilename("ShrinkDocument_out.pdf");
// Open document
auto document = MakeObject<Document>(_dataDir+infilename);
// Initialize OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// Set AllowReusePageContent option
optimizationOptions->set_UnembedFonts(true);
// Optimize PDF document using OptimizationOptions
document->OptimizeResources(optimizationOptions);
// Save updated document
document->Save(_dataDir + outfilename);
}
优化资源将这些方法应用于文档。如果应用了这些方法,文档大小很可能会减小。如果这些方法都没有应用,文档大小将不会改变,这是显而易见的。
其他减少 PDF 文档大小的方法
删除或扁平化注释
PDF 文档中存在的注释自然会增加其大小。当注释不必要时可以删除。当需要注释但不需要额外编辑时,可以将其扁平化。这两种技术都可以减少文件大小。
void FlatteningAnnotation() {
// 路径名称的字符串
String _dataDir("C:\\Samples\\");
// 输入文件名称的字符串
String infilename("OptimizeDocument.pdf");
// 输出文件名称的字符串
String outfilename("OptimizeDocument_out.pdf");
// 打开文档
auto document = MakeObject<Document>(_dataDir + infilename);
// 扁平化注释
for(auto page : document->get_Pages())
{
for(auto annotation : page->get_Annotations())
{
annotation->Flatten();
}
}
// 保存更新的文档
document->Save(_dataDir + outfilename);
}
删除表单字段
从您的 PDF 中删除表单也将优化您的文档。 如果 PDF 文档包含 AcroForms,我们可以通过展平表单字段来尝试减小文件大小。
void FlatteningFormFields() {
// 用于路径名称的字符串
String _dataDir("C:\\Samples\\");
// 输入文件名的字符串
String infilename("OptimizeFormField.pdf");
// 输出文件名的字符串
String outfilename("OptimizeFormField_out.pdf");
// 打开文档
auto document = MakeObject<Document>(_dataDir + infilename);
// 展平表单字段
// 展平表单
if (document->get_Form()->get_Fields()->get_Count() > 0)
{
for(auto item : document->get_Form()->get_Fields())
{
item->Flatten();
}
}
// 保存更新的文档
document->Save(_dataDir + outfilename);
}
将 PDF 从 RGB 颜色空间转换为灰度
PDF 文件包含文本、图像、附件、注释、图形和其他对象。 您可能会遇到需要将 PDF 从 RGB 颜色空间转换为灰度的要求,以便在打印这些 PDF 文件时速度更快。此外,当文件转换为灰度时,文档大小也会减少,但这也可能导致文档质量下降。这个功能目前被 Adobe Acrobat 的预检功能支持,但在谈到 Office 自动化时,Aspose.PDF 是提供此类文档操作便利的终极解决方案。为了实现这个需求,可以使用以下代码片段。
void ConvertPDFfromColorspaceToGrayscale() {
// 路径名称的字符串
String _dataDir("C:\\Samples\\");
// 输入文件名的字符串
String infilename("OptimizeDocument.pdf");
// 输出文件名的字符串
String outfilename("Test-gray_out.pdf");
// 打开文档
auto document = MakeObject<Document>(_dataDir + infilename);
auto strategy = MakeObject<Aspose::Pdf::RgbToDeviceGrayConversionStrategy>();
for (int idxPage = 1; idxPage <= document->get_Pages()->get_Count(); idxPage++)
{
// 获取 PDF 中特定页面的实例
auto page = document->get_Pages()->idx_get(idxPage);
// 将 RGB 颜色空间图像转换为灰度颜色空间
strategy->Convert(page);
}
// 保存结果文件
document->Save(_dataDir + outfilename);
}
FlateDecode 压缩
Aspose.PDF for C++ 提供了对 PDF 优化功能的 FlateDecode 压缩支持。 要使用 FlateDecode 压缩优化图像,请将优化选项设置为 Flate。 下面的代码片段演示了如何在优化中使用选项以 FlateDecode 压缩存储图像:
void FlatDecodeCompression() {
// 路径名称的字符串
String _dataDir("C:\\Samples\\");
// 输入文件名称的字符串
String infilename("FlateDecodeCompression.pdf");
// 输出文件名称的字符串
String outfilename("FlateDecodeCompression_out.pdf");
// 打开文档
auto document = MakeObject<Document>(_dataDir + infilename);
// 初始化 OptimizationOptions
auto optimizationOptions = MakeObject<Aspose::Pdf::Optimization::OptimizationOptions>();
// 要使用 FlateDecode 压缩优化图像,请将优化选项设置为 Flate
optimizationOptions->get_ImageCompressionOptions()->set_Encoding(Aspose::Pdf::Optimization::ImageEncoding::Flate);
// 使用 OptimizationOptions 优化 PDF 文档
document->OptimizeResources(optimizationOptions);
// 保存更新的文档
document->Save(_dataDir + outfilename);
}
在 XImageCollection 中存储图像
Aspose.PDF for C++ 提供了将新图像存储到 XImageCollection 中并使用 FlateDecode 压缩的功能。要启用此选项,您可以使用 ImageFilterType.Flate 标志。 以下代码片段展示了如何使用此功能:
void StoreImageInXImageCollection() {
// 路径名称的字符串
String _dataDir("C:\\Samples\\");
// 输出文件名的字符串
String outfilename("FlateDecodeCompression_out.pdf");
// 打开文档
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>());
// 设置坐标
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()});
// 使用 ConcatenateMatrix(连接矩阵)操作符:定义图像如何放置
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);
}