将图像添加到 PDF 使用 C++
在现有 PDF 文件中添加图像
每个 PDF 页面包含资源和内容属性。资源可以是图像和表单,例如,而内容由一组 PDF 操作符表示。每个操作符都有其名称和参数。此示例使用操作符将图像添加到 PDF 文件。
要将图像添加到现有 PDF 文件中:
-
创建一个 Document 对象并打开输入 PDF 文档。
-
获取您想要添加图像的页面。
-
将图像添加到页面的资源集合中。
-
使用操作符将图像放置在页面上:
-
使用 GSave 操作符 保存当前图形状态。
-
使用 ConcatenateMatrix 操作符 指定图像要放置的位置。
-
使用 Do 操作符 在页面上绘制图像。
-
最后,使用 GRestore 操作符 保存更新后的图形状态。
-
保存文件。 以下代码片段显示了如何在 PDF 文档中添加图像。
using namespace System;
using namespace Aspose::Pdf;
using namespace Aspose::Pdf::Text;
void WorkingWithImages::AddImageToExistingPDF()
{
String _dataDir("C:\\Samples\\");
// 打开文档
auto document = MakeObject<Document>(_dataDir + u"AddImage.pdf");
// 设置坐标
int lowerLeftX = 50;
int lowerLeftY = 750;
int upperRightX = 100;
int upperRightY = 800;
// 获取要添加图像的页面
auto page = document->get_Pages()->idx_get(1);
// 将图像加载到流中
auto imageStream = System::IO::File::OpenRead(_dataDir + u"logo.png");
// 将图像添加到页面资源的 Images 集合中
page->get_Resources()->get_Images()->Add(imageStream);
// 使用 GSave 操作符:该操作符保存当前图形状态
page->get_Contents()->Add(MakeObject<Aspose::Pdf::Operators::GSave>());
// 创建 Rectangle 和 Matrix 对象
auto rectangle = MakeObject<Rectangle>(lowerLeftX, lowerLeftY, upperRightX, upperRightY);
auto matrix = MakeObject<Matrix>(
MakeArray<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));
auto ximage = page->get_Resources()->get_Images()->idx_get(page->get_Resources()->get_Images()->get_Count());
// 使用 Do 操作符:该操作符绘制图像
page->get_Contents()->Add(MakeObject<Aspose::Pdf::Operators::Do>(ximage->get_Name()));
// 使用 GRestore 操作符:该操作符恢复图形状态
page->get_Contents()->Add(MakeObject<Aspose::Pdf::Operators::GRestore>());
// 保存新的 PDF
document->Save(_dataDir + u"updated_document.pdf");
// 关闭图像流
imageStream->Close();
}
在 PDF 文档中多次添加单个图像的引用
有时我们需要在 PDF 文档中多次使用相同的图像。添加新的实例会增加生成的 PDF 文档的大小。XImageCollection.Add(XImage) 方法允许添加对相同 PDF 对象的引用作为原始图像,从而优化 PDF 文档的大小。
void WorkingWithImages::AddReferenceOfaSingleImageMultipleTimes() {
String _dataDir("C:\\Samples\\");
auto imageRectangle = MakeObject<Rectangle>(0, 0, 30, 15);
auto document = MakeObject<Document>(_dataDir + u"sample.pdf");
document->get_Pages()->Add();
document->get_Pages()->Add();
auto imageStream = System::IO::File::OpenRead(_dataDir + u"aspose-logo.png");
SharedPtr<Aspose::Pdf::XImage> image;
for (auto page : document->get_Pages()) {
auto annotation = MakeObject<Aspose::Pdf::Annotations::WatermarkAnnotation>(page, page->get_Rect());
auto form = annotation->get_Appearance()->idx_get(u"N");
form->set_BBox(page->get_Rect());
String name;
if (image != nullptr) {
name = form->get_Resources()->get_Images()->Add(imageStream);
image = form->get_Resources()->get_Images()->idx_get(name);
}
else {
form->get_Resources()->get_Images()->AddWithName(image);
}
form->get_Contents()->Add(MakeObject<Aspose::Pdf::Operators::GSave>());
form->get_Contents()->Add(
MakeObject<Aspose::Pdf::Operators::ConcatenateMatrix>(
MakeObject<Matrix>(imageRectangle->get_Width(), 0, 0, imageRectangle->get_Height(), 0, 0)));
form->get_Contents()->Add(MakeObject<Aspose::Pdf::Operators::Do>(name));
form->get_Contents()->Add(MakeObject<Aspose::Pdf::Operators::GRestore>());
page->get_Annotations()->Add(annotation, false);
imageRectangle = MakeObject<Rectangle>(0, 0, imageRectangle->get_Width() * 1.01, imageRectangle->get_Height() * 1.01);
}
document->Save(_dataDir + u"AddReferenceOfaSingleImageMultipleTimes_out.pdf");
}
将图像放置在页面上并保持(控制)纵横比
如果我们不知道图像的尺寸,那么页面上很有可能会得到一个失真的图像。以下示例显示了避免这种情况的方法之一。
void WorkingWithImages::AddingImageAndPreserveAspectRatioIntoPDF() {
String _dataDir("C:\\Samples\\");
auto bitmap = System::Drawing::Image::FromFile(_dataDir + u"3410492.jpg");
int width;
int height;
width = bitmap->get_Width();
height = bitmap->get_Height();
auto document = MakeObject<Document>();
auto page = document->get_Pages()->Add();
int scaledWidth = 400;
int scaledHeight = scaledWidth * height / width;
page->AddImage(_dataDir + u"3410492.jpg", new Rectangle(10, 10, scaledWidth, scaledHeight));
document->Save(_dataDir + u"sample_image.pdf");
}
确定PDF中的图像是彩色还是黑白
为了减少图像的大小,您需要压缩它。 在您确定图像的压缩类型之前,您需要知道它是彩色还是黑白。
图像应用的压缩类型取决于原始图像的ColorSpace,即如果图像是彩色(RGB),则使用JPEG2000压缩,如果是黑白,则使用JBIG2 / JBIG2000压缩。
PDF文件可以包含文本、图像、图形、附件、注释等元素,如果源PDF文件包含图像,我们可以确定图像的色彩空间并应用适当的压缩来减少PDF文件的大小。
以下代码片段显示了识别PDF内图像是彩色还是黑白的步骤。
void WorkingWithImages::CheckColors() {
String _dataDir("C:\\Samples\\");
auto document = MakeObject<Document>(_dataDir + u"test4.pdf");
try {
// 遍历PDF文件的所有页面
for (auto page : document->get_Pages()) {
// 创建图像放置吸收器实例
auto abs = MakeObject<ImagePlacementAbsorber>();
page->Accept(abs);
for (auto ia : abs->get_ImagePlacements()) {
/* ColorType */
auto colorType = ia->get_Image()->GetColorType();
switch (colorType) {
case ColorType::Grayscale:
Console::WriteLine(u"灰度图像");
break;
case ColorType::Rgb:
Console::WriteLine(u"彩色图像");
break;
}
}
}
}
catch (Exception ex) {
Console::WriteLine(u"读取文件错误 = {0}", document->get_FileName());
}
}
控制图像质量
可以控制添加到 PDF 文件中的图像质量。使用 XImageCollection 类中的重载 Replace 方法。
以下代码片段演示了如何将所有文档图像转换为使用 80% 质量进行压缩的 JPEG 格式。
void WorkingWithImages::ControlImageQuality() {
String _dataDir("C:\\Samples\\");
auto document = MakeObject<Document>(_dataDir + u"sample_with_images.pdf");
for (auto page : document->get_Pages())
{
int idx = 1;
for (auto image : page->get_Resources()->get_Images())
{
auto imageStream = MakeObject<System::IO::MemoryStream>();
image->Save(imageStream, System::Drawing::Imaging::ImageFormat::get_Jpeg());
page->get_Resources()->get_Images()->Replace(idx, imageStream, 80);
idx = idx + 1;
}
}
document->Save(_dataDir + u"sample_with_images_out.pdf");
}