Як працювати з графікою PDF у C++
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(). Обидва додаються до Graph, додаючи їх як вказівники Shape до вектора, який повертає Shapes():
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));Обидві форми успадковують CheckBounds(containerWidth, containerHeight) від Shape, який повідомляє, чи поточна геометрія форми підходить до контейнера заданого розміру:
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 окремо не має жодного ефекту, доки воно не буде додано до вектора, який повертає Shapes() власного Graph, і цей Graph не буде доданий до сторінки через Page.Paragraphs().Add(). Потрібні всі три кроки — створити, додати, додати Graph до сторінки.
Форми відображаються в неправильному положенні
Graph.Left() і Graph.Top() розташовують контейнер на сторінці; властивості форми (Circle.PosX()/PosY(), Ellipse.Left()/Bottom(), координати Line.PositionArray()) описують геометрію всередині цього контейнера. Перевірте як розташування контейнера, так і власні координати форми, коли результат виглядає зміщеним.
CheckBounds returns false unexpectedly
CheckBounds(containerWidth, containerHeight) перевіряє власну геометрію форми щодо переданих розмірів — зазвичай це Width()/Height() власного Graph, а не повна медіа-картка сторінки. Передача неправильних розмірів призводить до хибного негативу, навіть коли форма насправді вписується у Graph.
A Line не з’являється, або з’являється як єдина точка
PositionArray() потребує щонайменше двох пар (x, y) — чотирьох значень float — щоб описати видимий сегмент. Коротший вектор не утворює лінію.
Confusing Circle with AnnotationType::Circle or CircleAnnotation
Бібліотека також має окремий API для PDF-анотацій, де 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() повертає повну колекцію об’єктів Shape, розташованих у цьому Graph — кола, еліпси та лінії можна додати до одного контейнера.
Чи це те саме, що рендеринг сторінки в зображення?
Ні. BmpDevice, JpegDevice і TiffDevice растризують існуючий вміст сторінки у формати зображень. Graph, Shape, Circle, Ellipse і Line створюють нову векторну геометрію безпосередньо в PDF-вмісті під час створення або редагування документа.