Comment travailler avec les graphiques PDF en C++
Aspose.PDF FOSS pour C++ comprend un petit API vectoriel pour dessiner des formes libres directement sur une page PDF — distinct des dispositifs de rendu raster de la bibliothèque (BmpDevice, JpegDevice, TiffDevice), qui convertissent le contenu existant de la page en images. Ce guide explique comment créer un conteneur Graph, ajouter des formes Circle, Ellipse et Line, styliser ces formes avec GraphInfo, et placer le Graph fini sur une page. La bibliothèque est ajoutée à un projet via CMake.
Guide étape par étape
Étape 1: Installer le paquet
Ajoutez la bibliothèque en tant que sous-répertoire CMake et liez-la à la cible aspose_pdf_foss:
add_subdirectory(aspose.pdf-foss-for-cpp)
target_link_libraries(your_app PRIVATE aspose_pdf_foss)Vérifiez que la chaîne d’outils et les en-têtes se résolvent en compilant un programme minimal:
#include <aspose/pdf/document.hpp>
#include <iostream>
int main() {
Aspose::Pdf::Document doc;
std::cout << "Linked OK — pages: " << doc.Pages().Count() << "\n";
}Une compilation réussie qui affiche pages: 0 confirme que la bibliothèque est correctement liée.
Étape 2 : Importer les classes requises
Inclure les en-têtes pour le document, le conteneur de formes, les trois formes concrètes et leurs types de style :
#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 et Line se trouvent dans l’espace de noms Aspose::Pdf::Drawing; GraphInfo, BorderInfo et Color se trouvent directement sous Aspose::Pdf.
Étape 3 : Créer un graphe et l’ajouter à une page
Graph est un conteneur qui se positionne sur la page via Left(), Top(), Width() et Height(), et qui contient les formes dessinées à l’intérieur via Shapes(). Une fois configuré, il est placé sur la page via Page.Paragraphs().Add(), la même collection utilisée pour le reste du contenu de la page :
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);Étape 4 : Dessiner un cercle et une ellipse
Circle décrit sa géométrie avec PosX(), PosY() et Radius(). Ellipse utilise à la place une boîte englobante — Left(), Bottom(), Width() et Height(). Les deux sont ajoutés au Graph en les ajoutant, en tant que pointeurs Shape, au vecteur renvoyé par 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));Les deux formes héritent de CheckBounds(containerWidth, containerHeight) depuis Shape, qui indique si la géométrie actuelle de la forme tient dans un conteneur de la taille donnée :
bool circleFits = circle->CheckBounds(graph->Width(), graph->Height());Étape 5: Dessiner une ligne
Line stocke sa géométrie différemment: PositionArray() contient un std::vector<float> plat de coordonnées — une paire x, y par point — plutôt que des propriétés nommées. Un segment à deux points nécessite quatre valeurs: x de départ, y de départ, x de fin, y de fin.
auto line = std::make_unique<Line>();
line->PositionArray({0.0f, 0.0f, 400.0f, 400.0f});
graph->Shapes().push_back(std::move(line));Étape 6: Styliser les formes avec GraphInfo et la bordure du conteneur
Le trait et le remplissage de chaque forme proviennent d’un GraphInfo, lus et définis via Shape.GraphInfo() / GraphInfo(value). Il expose la largeur du trait (LineWidth(), valeur par défaut 1.0f), la couleur du trait et du remplissage (Color(), FillColor()), ainsi qu’un motif de tirets (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));Le conteneur Graph lui-même possède un BorderInfo, défini via Border(), qui regroupe un GraphInfo par arête (Left(), Right(), Top(), Bottom()) ainsi qu’un RoundedBorderRadius() pour le cadre propre du conteneur:
BorderInfo border{BorderSide::All, 1.5f, Color::Black()};
border.RoundedBorderRadius(6.0);
graph->Border(border);Étape 7: Enregistrer le document
doc.Save("graphics.pdf");Problèmes courants et solutions
Une forme que j’ai construite n’apparaît jamais sur la page
Construire un Circle, Ellipse ou Line seul n’a aucun effet tant qu’il n’est pas ajouté au vecteur renvoyé par le Shapes() du Graph propriétaire, et que ce Graph est ajouté à une page via Page.Paragraphs().Add(). Les trois étapes — construire, ajouter, ajouter le Graph à la page — sont requises.
Les formes sont rendues à la mauvaise position
Graph.Left() et Graph.Top() positionnent le conteneur sur la page; les propriétés de la forme (Circle.PosX()/PosY(), Ellipse.Left()/Bottom(), coordonnées Line.PositionArray()) décrivent la géométrie à l’intérieur de ce conteneur. Vérifiez à la fois le placement du conteneur et les coordonnées propres à la forme lorsque le rendu semble décalé.
CheckBounds returns false unexpectedly
CheckBounds(containerWidth, containerHeight) vérifie la géométrie propre de la forme par rapport aux dimensions fournies — généralement les Width()/Height() du Graph propriétaire, et non la boîte média complète de la page. Fournir les mauvaises dimensions produit un faux négatif même lorsque la forme tiendrait réellement dans le Graph.
A Line n’apparaît pas, ou apparaît comme un point unique
PositionArray() nécessite au moins deux paires (x, y) — quatre valeurs float — pour décrire un segment visible. Un vecteur plus court ne forme pas une ligne.
Confusing Circle with AnnotationType::Circle or CircleAnnotation
La bibliothèque possède également un API d’annotations PDF distinct, où AnnotationType::Circle et CircleAnnotation représentent des annotations de marquage en forme de cercle. La classe Circle présentée dans ce guide n’est pas liée — elle se trouve dans Aspose::Pdf::Drawing et dessine directement dans le contenu de la page plutôt que d’ajouter un objet d’annotation.
Foire aux questions
Quelle est la différence entre GraphInfo et BorderInfo ?
GraphInfo définit le style d’une seule trace — épaisseur de ligne, couleur, couleur de remplissage et motif de tirets — et est utilisé à la fois sur des formes individuelles (via Shape.GraphInfo()) et par arête à l’intérieur d’un BorderInfo. BorderInfo regroupe quatre valeurs GraphInfo (Left(), Right(), Top(), Bottom()) plus un RoundedBorderRadius() pour décrire le cadre de bordure propre d’un conteneur Graph.
Puis-je remplir une forme avec une couleur unie ?
Oui. GraphInfo.FillColor() définit la couleur de remplissage utilisée lorsque la forme est dessinée via son Graph propriétaire.
Circle stocke-t-il une boîte englobante comme le fait Ellipse ?
N°. Circle expose PosX(), PosY() et Radius(); Ellipse expose Left(), Bottom(), Width() et Height(). Ils ne partagent pas de représentation géométrique commune au-delà de la base abstraite Shape et du style GraphInfo.
Un Graph peut-il contenir plus d’une forme?
Oui. Graph.Shapes() renvoie la collection complète d’objets Shape placés dans ce Graph— les cercles, ellipses et lignes peuvent tous être ajoutés au même conteneur.
Est-ce la même chose que de rendre une page sous forme d’image?
Non. BmpDevice, JpegDevice et TiffDevice rasterisent le contenu de page existant vers des formats d’image. Graph, Shape, Circle, Ellipse et Line construisent de nouvelles géométries vectorielles directement dans le contenu PDF pendant la création ou la modification d’un document.