如何在 C++ 中使用 PDF 图形

如何在 C++ 中使用 PDF 图形

Aspose.PDF FOSS for C++ 包含一个小型矢量图形 API,用于直接在 PDF 页面上绘制自由形状——它与库的光栅渲染设备 (BmpDevice, JpegDevice, TiffDevice) 分离,后者将现有页面内容转换为图像。本指南演示如何创建一个 Graph 容器,向其中添加 Circle、Ellipse 和 Line 形状,使用 GraphInfo 对这些形状进行样式设置,并将完成的 Graph 放置在页面上。该库通过 CMake 添加到项目中。

分步指南

步骤 1:安装软件包

将库添加为 CMake 子目录,并链接到 aspose_pdf_foss 目标:

add_subdirectory(aspose.pdf-foss-for-cpp)
target_link_libraries(your_app PRIVATE aspose_pdf_foss)

通过编译一个最小程序来验证工具链和头文件是否解析成功:

#include <aspose/pdf/document.hpp>
#include <iostream>

int main() {
    Aspose::Pdf::Document doc;
    std::cout << "Linked OK — pages: " << doc.Pages().Count() << "\n";
}

成功构建并打印 pages: 0 表明库已正确链接。


步骤 2:导入所需类

包含文档、形状容器、三个具体形状以及它们的样式类型的头文件:

#include <aspose/pdf/document.hpp>
#include <aspose/pdf/drawing/graph.hpp>
#include <aspose/pdf/drawing/circle.hpp>
#include <aspose/pdf/drawing/ellipse.hpp>
#include <aspose/pdf/drawing/line.hpp>
#include <aspose/pdf/graph_info.hpp>
#include <aspose/pdf/border_info.hpp>
#include <aspose/pdf/color.hpp>

using namespace Aspose::Pdf;
using namespace Aspose::Pdf::Drawing;

Graph、Shape、Circle、Ellipse 和 Line 位于 Aspose::Pdf::Drawing 命名空间;GraphInfo、BorderInfo 和 Color 直接位于 Aspose::Pdf 下。


步骤 3:创建图形并将其添加到页面

Graph 是一个容器,通过 Left()、Top()、Width() 和 Height() 将自身定位在页面上,并通过 Shapes() 保存内部绘制的形状。配置完成后,它通过 Page.Paragraphs().Add() 放置到页面上,该集合与其他页面内容使用的是同一个集合:

Document doc;
Page page = doc.Pages().Add();

auto graph = std::make_shared<Graph>();
graph->Left(50.0);
graph->Top(50.0);
graph->Width(400.0);
graph->Height(400.0);

page.Paragraphs().Add(graph);

步骤 4:绘制圆和椭圆

Circle 使用 PosX()、PosY() 和 Radius() 描述其几何形状。Ellipse 则使用边界框——Left()、Bottom()、Width() 和 Height()。两者都通过将它们作为 Shape 指针追加到 Shapes() 返回的向量中,从而添加到 Graph:

auto circle = std::make_unique<Circle>();
circle->PosX(150.0);
circle->PosY(150.0);
circle->Radius(75.0);
graph->Shapes().push_back(std::move(circle));

auto ellipse = std::make_unique<Ellipse>();
ellipse->Left(20.0);
ellipse->Bottom(20.0);
ellipse->Width(120.0);
ellipse->Height(60.0);
graph->Shapes().push_back(std::move(ellipse));

两种形状都从 Shape 继承 CheckBounds(containerWidth, containerHeight),该方法报告形状的当前几何形状是否适合给定大小的容器:

bool circleFits = circle->CheckBounds(graph->Width(), graph->Height());

步骤5:绘制线条

Line 以不同的方式存储其几何形状:PositionArray() 持有一个扁平的 std::vector<float> 坐标——每个点一个 x、y 对——而不是具名属性。一个两点线段需要四个值:起始 x、起始 y、结束 x、结束 y。

auto line = std::make_unique<Line>();
line->PositionArray({0.0f, 0.0f, 400.0f, 400.0f});
graph->Shapes().push_back(std::move(line));

步骤6:使用 GraphInfo 和容器边框为形状设定样式

每个形状的描边和填充来自一个 GraphInfo,通过 Shape.GraphInfo() / GraphInfo(value) 读取和设置。它公开了描边宽度(LineWidth(),默认值 1.0f)、描边和填充颜色(Color(),FillColor())以及虚线模式(DashArray(),DashPhase()):

GraphInfo stroke;
stroke.LineWidth(2.0f);
stroke.Color(Color::FromRgb(1.0, 0.0, 0.0));
stroke.FillColor(Color::FromRgb(1.0, 0.9, 0.9));

Graph 容器本身携带一个 BorderInfo,通过 Border() 设置,它为每条边分组一个 GraphInfo(Left()、Right()、Top()、Bottom()),以及一个用于容器自身框架的 RoundedBorderRadius():

BorderInfo border{BorderSide::All, 1.5f, Color::Black()};
border.RoundedBorderRadius(6.0);
graph->Border(border);

步骤7:保存文档

doc.Save("graphics.pdf");

常见问题及解决方案

我构造的形状从未出现在页面上

单独构造一个 Circle、Ellipse 或 Line 没有任何效果,除非它被追加到所属 Graph 的 Shapes() 返回的向量中,并且该 Graph 通过 Page.Paragraphs().Add() 添加到页面中。所有这三个步骤——构造、追加、将 Graph 添加到页面——都是必需的。

形状渲染在错误的位置

Graph.Left() 和 Graph.Top() 确定容器在页面上的位置;形状属性(Circle.PosX()/PosY()、Ellipse.Left()/Bottom()、Line.PositionArray() 坐标)描述该容器内部的几何形状。当输出看起来偏移时,请检查容器放置位置以及形状自身的坐标。

CheckBounds returns false unexpectedly

CheckBounds(containerWidth, containerHeight) 将形状自身的几何与传入的尺寸进行检查——通常是所属 Graph 的 Width()/Height(),而不是页面的完整媒体框。传入错误的尺寸会导致即使形状实际上能够放入 Graph,也会产生误判(假阴性)。

A Line 未出现,或仅显示为一个点

PositionArray() 至少需要两个 (x, y) 对——四个 float 值——才能描述可见的线段。更短的向量无法形成线条。

Confusing Circle with AnnotationType::Circle or CircleAnnotation

该库还有一个单独的 PDF 注释 API,其中 AnnotationType::Circle 和 CircleAnnotation 代表圆形标记注释。本文档中涉及的 Circle 类与之无关——它位于 Aspose::Pdf::Drawing,直接绘制到页面内容中,而不是添加注释对象。

常见问题

GraphInfo 和 BorderInfo 有什么区别?

GraphInfo 为单条笔画设置样式——线宽、颜色、填充颜色和虚线模式——可用于单个形状(通过 Shape.GraphInfo())以及 BorderInfo 内的每条边。BorderInfo 将四个 GraphInfo 值(Left()、Right()、Top()、Bottom())以及一个 RoundedBorderRadius() 组合起来,以描述 Graph 容器自身的边框框架。

我可以用纯色填充形状吗?

是的。GraphInfo.FillColor() 设置在通过其所属的 Graph 绘制形状时使用的填充颜色。

Circle 是否像 Ellipse 那样存储边界框?

不。Circle公开了PosX()、PosY()和Radius();Ellipse公开了Left()、Bottom()、Width()和Height()。它们除了抽象的Shape基础和GraphInfo样式外,没有共享的几何表示。

一个 Graph 能容纳多个形状吗?

是的。Graph.Shapes()返回放置在该Graph中的全部Shape对象——圆形、椭圆和直线都可以追加到同一个容器中。

这和将页面渲染为图像是同一回事吗?

不。BmpDevice、JpegDevice和TiffDevice将现有页面内容栅格化为图像格式。Graph、Shape、Circle、Ellipse和Line在文档构建或编辑时直接在 PDF 内容中构建新的矢量几何。

另请参阅

 中文