在 PDF 页面上绘制矢量图形

在 PDF 页面上绘制矢量图形

在 PDF 页面上绘制矢量图形

Aspose.PDF FOSS for C++ 包含一个小型矢量图形 API,用于在构建文档的过程中直接在 PDF 页面上绘制形状。入口点是 Graph,它是放置在页面上的容器,保存一组 Shape 对象;三种具体形状——Circle、Ellipse 和 Line——继承自 Shape,并各自以不同方式表达其几何形状。每个形状的描边和填充样式来自 GraphInfo,而 Graph 容器本身携带一个用于框架的 BorderInfo。这与页面栅格化(BmpDevice、JpegDevice、TiffDevice)无关,后者将现有页面内容转换为栅格图像格式,而不是绘制新几何体。


图形容器及向页面添加形状

Graph 通过 Left()、Top()、Width() 和 Height() 在页面上定位并设定大小,其 IsChangePosition() 标志控制该位置是否可以相对于其他页面内容移动。它绘制的形状存放在由 Shapes() 返回的向量中——std::vector<std::unique_ptr<Shape>>——该向量通过构造形状、配置形状并将其移动到该向量中来填充。构建完成后,Graph 本身通过 Page.Paragraphs().Add() 放置在页面上,这与用于其他页面级内容的同一集合相同。

#include <aspose/pdf/document.hpp>
#include <aspose/pdf/drawing/graph.hpp>
#include <aspose/pdf/drawing/circle.hpp>

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

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

auto graph = std::make_shared<Graph>();
graph->Left(36.0);
graph->Top(36.0);
graph->Width(500.0);
graph->Height(300.0);

auto marker = std::make_unique<Circle>();
marker->PosX(60.0);
marker->PosY(60.0);
marker->Radius(30.0);
graph->Shapes().push_back(std::move(marker));

page.Paragraphs().Add(graph);
doc.Save("shapes.pdf");

绘制圆形和椭圆

Circle 和 Ellipse 都以纯数值属性而非共享的点或矩形类型来表达几何形状。Circle 是中心点和半径——PosX()、PosY()、Radius()——而 Ellipse 是边界框——Left()、Bottom()、Width()、Height()。两者都从 Shape 继承 CheckBounds(containerWidth, containerHeight),该属性报告形状当前的几何是否能够在给定尺寸的容器内适配,而不改变形状本身。

#include <aspose/pdf/drawing/circle.hpp>
#include <aspose/pdf/drawing/ellipse.hpp>

using namespace Aspose::Pdf::Drawing;

Circle circle;
circle.PosX(120.0);
circle.PosY(120.0);
circle.Radius(60.0);
bool circleFits = circle.CheckBounds(500.0, 300.0);

Ellipse ellipse;
ellipse.Left(220.0);
ellipse.Bottom(20.0);
ellipse.Width(250.0);
ellipse.Height(100.0);
bool ellipseFits = ellipse.CheckBounds(500.0, 300.0);

使用 PositionArray 绘制直线

Line 以不同于 Circle 和 Ellipse 的方式存储其几何信息:PositionArray() 返回一个扁平的 std::vector<float>,其中包含每个线段经过的点的 x、y 对,而不是一组固定的命名属性。两个点(四个值)绘制一条直线段;额外的点对按顺序绘制经过这些点的多段路径。和其他形状一样,Line 会覆盖来自 Shape 的 CheckBounds(containerWidth, containerHeight)。

#include <aspose/pdf/drawing/line.hpp>

using namespace Aspose::Pdf::Drawing;

Line path;
path.PositionArray({0.0f, 0.0f, 250.0f, 0.0f, 125.0f, 200.0f});
bool pathFits = path.CheckBounds(500.0, 300.0);

使用 GraphInfo 和 BorderInfo 对形状进行样式设置

每个形状通过 Shape.GraphInfo() / GraphInfo(value) 读取和写入其描边和填充样式。GraphInfo 默认使用 LineWidth() 为 1.0f,并且空的 DashArray(),同时还公开 Color()、FillColor()、DashArray()/DashPhase() 用于虚线描边,IsDoubled() 用于双线,以及 SkewAngleX()/SkewAngleY()、ScalingRateX()/ScalingRateY()、RotationAngle() 用于变换描边。Graph 本身携带一个通过 Border() 设置的 BorderInfo,它将每条边分组为一个 GraphInfo —— Left()、Right()、Top()、Bottom() —— 加上一个 RoundedBorderRadius(),并且可以通过使用 BorderSide 标志来指定要为哪些边设置样式(BorderSide::Left | BorderSide::Right,或对所有边使用 BorderSide::All)。

#include <aspose/pdf/graph_info.hpp>
#include <aspose/pdf/border_info.hpp>
#include <aspose/pdf/border_side.hpp>
#include <aspose/pdf/color.hpp>

using namespace Aspose::Pdf;

GraphInfo stroke;
stroke.LineWidth(2.5f);
stroke.Color(Color::FromRgb(1.0, 0.0, 0.0));
stroke.DashArray({3, 2});
stroke.DashPhase(1);
stroke.IsDoubled(true);

// Style only the left and right edges of the container border.
BorderInfo border{BorderSide::Left | BorderSide::Right, 3.0f};
border.RoundedBorderRadius(4.0);

graph->GraphInfo(stroke);
graph->Border(border);

技巧与最佳实践

  • 对所属的 Graph 的自身 Width()/Height() 调用 CheckBounds,而不是页面的完整媒体框——此检查会根据你传入的容器尺寸验证形状的几何,而不会自动查看页面。
  • 在将 Graph 添加到 Page.Paragraphs() 之前先将形状加入 Shapes()——构造 Circle、Ellipse 或 Line 在它们被追加到所属的 Graph 并且该 Graph 被添加到页面之前不会产生可见效果。
  • 将相关形状归入单个 Graph 而不是每个形状使用一个 Graph;Left()/Top()/Width()/Height() 只需要定位一次整个容器,而 Shapes() 中的每个形状均相对于该容器绘制。
  • 为需要可见填充或非默认描边的形状显式设置 Shape.GraphInfo()——默认的 GraphInfo 具有 1.0f 的线宽、无填充且空的 DashArray()。
  • 按路径应绘制的顺序将 Line.PositionArray() 构建为 x0, y0, x1, y1, … 对——奇数长度的向量描述了一个不完整的点。

常见问题

问题原因修复
一个 Circle、Ellipse 或 Line 从未出现在已保存的页面上形状已构建,但从未追加到其 Graph 的 Shapes(),或者 Graph 从未添加到页面将形状推入 graph->Shapes() 并调用 page.Paragraphs().Add(graph)
形状使用默认的细黑色描边绘制Shape.GraphInfo() 从未设置在将形状追加到 Shapes() 之前调用 shape->GraphInfo(customGraphInfo)
Line 缺失或看起来像单个点PositionArray() 的 (x, y) 对少于两个,或值的数量为奇数提供至少四个值作为 x0, y0, x1, y1
仅对容器边框的部分边缘设置了样式BorderInfo 是使用排除某些边缘的 BorderSide 掩码构建的使用 BorderSide::All,或将所有所需的 BorderSide 标志进行按位或
CheckBounds 意外返回了 false传递给 CheckBounds 的尺寸与实际绘制形状的容器不匹配传递拥有者 Graph 当前的 Width()/Height()

FAQ

Circle 与 AnnotationType::Circle 有何区别?

Circle(本指南)是一种绘图形状,通过 Graph 直接绘制到页面内容中。AnnotationType::Circle 和 CircleAnnotation 属于另一个注释 API,并表示圆形标记注释——尽管名称相同,但两者并不相关。

单个 Graph 能包含多个形状吗?

是的。Graph.Shapes() 返回该容器的完整 std::vector<std::unique_ptr<Shape>>,并且在将 Graph 添加到页面之前,可以向其中追加任意组合的 Circle、Ellipse 和 Line 实例。

Circle 与 Ellipse 共享几何类型吗?

否。Circle 是中心点和半径(PosX, PosY, Radius);Ellipse 是边界框(Left, Bottom, Width, Height)。两者都源自 Shape,但彼此之间既不共享相同的点,也不共享相同的矩形类型。

使用 Graph 绘制形状与将页面渲染为图像是同一回事吗?

否。Graph、Shape、Circle、Ellipse 和 Line 在生成文档时向页面内容中构建新的矢量几何。将已有页面转换为光栅图像是另一项功能,由 BmpDevice、JpegDevice 和 TiffDevice 处理。

GraphInfo.IsDoubled() 是做什么的?

它将笔画标记为双线,而不改变其他任何笔画属性。它是一个布尔标志,通过 IsDoubled() / IsDoubled(value) 与其他 GraphInfo 笔画属性一起读取和设置。


API Reference 摘要

类/方法描述
Graph放置在页面上的形状容器;使用 Left()、Top()、Width()、Height() 来定位自身
Graph.Shapes()返回此容器绘制的 std::vector<std::unique_ptr<Shape>>
Graph.GraphInfo() / GraphInfo(value)获取/设置容器自身的描边和填充样式
Graph.Border() / Border(value)获取/设置围绕容器的 BorderInfo
Shape用于 Circle、Ellipse 和 Line 的抽象基类;公开 GraphInfo() 和 CheckBounds()
Shape.CheckBounds(w, h)报告形状的几何是否适合放入给定宽度/高度的容器中
Circle圆形: PosX(), PosY(), Radius()
Ellipse椭圆形: 边界框通过 Left(), Bottom(), Width(), Height()
Line线/路径形状:PositionArray(),一个平面std::vector<float>,由 x、y 坐标构成
GraphInfo描边/填充样式:LineWidth(),Color(),FillColor(),DashArray(),DashPhase(),IsDoubled(),RotationAngle(),SkewAngleX()/SkewAngleY(),ScalingRateX()/ScalingRateY()
BorderInfo每条边的容器边框:Left(),Right(),Top(),Bottom()(每个都是GraphInfo),以及RoundedBorderRadius()
BorderSide在构建BorderInfo时选择边的枚举:None,Left,Top,Right,Bottom,All,Box

另请参阅

 中文