Wie man mit PDF-Grafiken in C++ arbeitet
Aspose.PDF FOSS für C++ enthält ein kleines Vektor-Grafik-API zum Zeichnen von Freiform-Formen direkt auf einer PDF-Seite — getrennt von den Raster-Rendering-Geräten der Bibliothek (BmpDevice, JpegDevice, TiffDevice), die vorhandenen Seiteninhalt in Bilder umwandeln. Dieser Leitfaden führt durch das Erstellen eines Graph-Containers, das Hinzufügen von Circle, Ellipse und Line Formen, das Stylen dieser Formen mit GraphInfo und das Platzieren des fertigen Graph auf einer Seite. Die Bibliothek wird über CMake zu einem Projekt hinzugefügt.
Schritt-für-Schritt-Anleitung
Schritt 1: Paket installieren
Füge die Bibliothek als CMake-Unterverzeichnis hinzu und linke gegen das aspose_pdf_foss-Ziel:
add_subdirectory(aspose.pdf-foss-for-cpp)
target_link_libraries(your_app PRIVATE aspose_pdf_foss)Überprüfe, ob die Toolchain und Header aufgelöst werden, indem du ein Minimalprogramm kompilierst:
#include <aspose/pdf/document.hpp>
#include <iostream>
int main() {
Aspose::Pdf::Document doc;
std::cout << "Linked OK — pages: " << doc.Pages().Count() << "\n";
}Ein erfolgreicher Build, der pages: 0 ausgibt, bestätigt, dass die Bibliothek korrekt verlinkt ist.
Schritt 2: Erforderliche Klassen importieren
Binden Sie die Header für das Dokument, den Form-Container, die drei konkreten Formen und deren Stiltypen ein:
#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 und Line befinden sich im Namensraum Aspose::Pdf::Drawing; GraphInfo, BorderInfo und Color befinden sich direkt unter Aspose::Pdf.
Schritt 3: Erstellen Sie ein Diagramm und fügen Sie es einer Seite hinzu
Graph ist ein Container, der sich auf der Seite über Left(), Top(), Width() und Height() positioniert und die darin gezeichneten Formen über Shapes() hält. Sobald er konfiguriert ist, wird er über Page.Paragraphs().Add() auf der Seite platziert, dieselbe Sammlung, die für anderen Seiteninhalt verwendet wird:
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);Schritt 4: Zeichnen Sie einen Kreis und eine Ellipse
Circle beschreibt seine Geometrie mit PosX(), PosY() und Radius(). Ellipse verwendet stattdessen eine Begrenzungsbox — Left(), Bottom(), Width() und Height(). Beide werden dem Graph hinzugefügt, indem sie als Shape-Zeiger an den von Shapes() zurückgegebenen Vektor angehängt werden:
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));Beide Formen erben CheckBounds(containerWidth, containerHeight) von Shape, das meldet, ob die aktuelle Geometrie der Form in einen Container der angegebenen Größe passt:
bool circleFits = circle->CheckBounds(graph->Width(), graph->Height());Schritt 5: Linie zeichnen
Line speichert seine Geometrie anders: PositionArray() enthält ein flaches std::vector<float> von Koordinaten — ein x, y-Paar pro Punkt — anstatt benannter Eigenschaften. Ein Segment mit zwei Punkten benötigt vier Werte: Start-x, Start-y, Ende-x, Ende-y.
auto line = std::make_unique<Line>();
line->PositionArray({0.0f, 0.0f, 400.0f, 400.0f});
graph->Shapes().push_back(std::move(line));Schritt 6: Formen mit GraphInfo und dem Container-Rand stylen
Der Strich und die Füllung jeder Form stammen aus einem GraphInfo, der über Shape.GraphInfo() / GraphInfo(value) gelesen und gesetzt wird. Er stellt die Strichbreite (LineWidth(), Standard 1.0f), Strich- und Füllfarbe (Color(), FillColor()) sowie ein Strichmuster (DashArray(), DashPhase()) bereit:
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));Der Graph-Container selbst enthält ein BorderInfo, das über Border() festgelegt wird und pro Kante ein GraphInfo gruppiert (Left(), Right(), Top(), Bottom()) sowie ein RoundedBorderRadius() für den eigenen Rahmen des Containers:
BorderInfo border{BorderSide::All, 1.5f, Color::Black()};
border.RoundedBorderRadius(6.0);
graph->Border(border);Schritt 7: Dokument speichern
doc.Save("graphics.pdf");Häufige Probleme und Lösungen
Eine von mir konstruierte Form erscheint nie auf der Seite
Das Erzeugen eines Circle, Ellipse oder Line allein hat keine Wirkung, bis es an den Vektor angehängt wird, der von dem Graphs Shapes() zurückgegeben wird, und dieses Graph über Page.Paragraphs().Add() einer Seite hinzugefügt wird. Alle drei Schritte — Erzeugen, Anhängen, das Graph zur Seite hinzufügen — sind erforderlich.
Formen werden an der falschen Position gerendert
Graph.Left() und Graph.Top() positionieren den Container auf der Seite; Formeigenschaften (Circle.PosX()/PosY(), Ellipse.Left()/Bottom(), Line.PositionArray()-Koordinaten) beschreiben die Geometrie innerhalb dieses Containers. Überprüfen Sie sowohl die Platzierung des Containers als auch die eigenen Koordinaten der Form, wenn die Ausgabe versetzt erscheint.
CheckBounds returns false unexpectedly
CheckBounds(containerWidth, containerHeight) prüft die eigene Geometrie der Form gegen die übergebenen Abmessungen — typischerweise die Width()/Height() des Graph, nicht die vollständige Media-Box der Seite. Das Übergeben falscher Abmessungen führt zu einem falschen Negativ, selbst wenn die Form tatsächlich in den Graph passen würde.
A Line erscheint nicht, oder erscheint als einzelner Punkt
PositionArray() benötigt mindestens zwei (x, y)-Paare — vier float-Werte — um ein sichtbares Segment zu beschreiben. Ein kürzerer Vektor bildet keine Linie.
Confusing Circle with AnnotationType::Circle or CircleAnnotation
Die Bibliothek verfügt außerdem über ein separates PDF-Anmerkungen API, bei dem AnnotationType::Circle und CircleAnnotation kreisförmige Markup-Annotationen darstellen. Die in diesem Leitfaden behandelte Klasse Circle ist nicht verwandt — sie befindet sich in Aspose::Pdf::Drawing und zeichnet direkt in den Seiteninhalt, anstatt ein Annotationsobjekt hinzuzufügen.
Häufig gestellte Fragen
Was ist der Unterschied zwischen GraphInfo und BorderInfo?
GraphInfo definiert einen einzelnen Strich — Linienstärke, Farbe, Füllfarbe und Strichmuster — und wird sowohl für einzelne Formen (über Shape.GraphInfo()) als auch für jede Kante innerhalb eines BorderInfo verwendet. BorderInfo fasst vier GraphInfo-Werte (Left(), Right(), Top(), Bottom()) plus ein RoundedBorderRadius() zusammen, um den eigenen Rahmen eines Graph-Containers zu beschreiben.
Kann ich eine Form mit einer einfarbigen Farbe füllen?
Ja. GraphInfo.FillColor() legt die Füllfarbe fest, die verwendet wird, wenn die Form über ihr zugehöriges Graph gezeichnet wird.
Speichert Circle eine Begrenzungsbox wie Ellipse?
Nein. Circle stellt PosX(), PosY() und Radius() bereit; Ellipse stellt Left(), Bottom(), Width() und Height() bereit. Sie teilen keine gemeinsame Geometrie-Darstellung über die abstrakte Shape-Basis und GraphInfo-Styling hinaus.
Kann ein Graph mehr als eine Form enthalten?
Ja. Graph.Shapes() gibt die vollständige Sammlung von Shape-Objekten zurück, die in diesem Graph platziert sind — Kreise, Ellipsen und Linien können alle an denselben Container angehängt werden.
Ist dies dasselbe wie das Rendern einer Seite in ein Bild?
Nein. BmpDevice, JpegDevice und TiffDevice rasterisieren vorhandenen Seiteninhalt in Bildformate. Graph, Shape, Circle, Ellipse und Line erzeugen neue Vektorgeometrie direkt im PDF-Inhalt, während ein Dokument erstellt oder bearbeitet wird.