Vektorgrafiken auf einer PDF-Seite zeichnen
Vektorgrafiken auf einer PDF-Seite zeichnen
Aspose.PDF FOSS für C++ enthält ein kleines Vektorgrafik-API zum direkten Zeichnen von Formen auf einer PDF-Seite, während ein Dokument erstellt wird. Der Einstiegspunkt ist Graph, ein Container, der auf einer Seite platziert wird und eine Sammlung von Shape-Objekten hält; drei konkrete Formen — Circle, Ellipse und Line — leiten von Shape ab und geben jeweils ihre Geometrie unterschiedlich wieder. Die Strich- und Füllstilistik pro Form stammt von GraphInfo, und der Graph-Container selbst trägt ein BorderInfo zum Rahmen. Dies ist nicht verwandt mit der Seitenrasterisierung (BmpDevice, JpegDevice, TiffDevice), die vorhandenen Seiteninhalt in Rasterbildformate konvertiert, anstatt neue Geometrie zu zeichnen.
Der Graph-Container und das Hinzufügen von Formen zu einer Seite
Graph positioniert und skaliert sich selbst auf der Seite über Left(), Top(), Width() und Height(), und sein IsChangePosition()-Flag steuert, ob diese Position relativ zu anderem Seiteninhalt verschoben werden kann. Die Formen, die es zeichnet, befinden sich im Vektor, der von Shapes() zurückgegeben wird — std::vector<std::unique_ptr<Shape>> — und werden gefüllt, indem man eine Form konstruiert, konfiguriert und auf diesen Vektor verschiebt. Sobald sie gebaut ist, wird der Graph selbst über Page.Paragraphs().Add() auf der Seite platziert, dieselbe Sammlung, die für anderen Seiteninhalt verwendet wird.
#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");Kreise und Ellipsen zeichnen
Circle und Ellipse geben jeweils die Geometrie als einfache numerische Eigenschaften wieder, anstatt einen gemeinsamen Punkt- oder Rechtecktyp zu verwenden. Circle ist ein Mittelpunkt und ein Radius — PosX(), PosY(), Radius() —, während Ellipse ein Begrenzungsrahmen ist — Left(), Bottom(), Width(), Height(). Beide erben CheckBounds(containerWidth, containerHeight) von Shape, das meldet, ob die aktuelle Geometrie der Form in einen Container der angegebenen Größe passt, ohne die Form selbst zu verändern.
#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);Linien zeichnen mit PositionArray
Line speichert seine Geometrie anders als Circle und Ellipse: PositionArray() liefert ein flaches std::vector<float>, das ein x-y-Paar für jeden Punkt enthält, den die Linie durchläuft, anstatt einer festen Menge benannter Eigenschaften. Zwei Punkte (vier Werte) erzeugen ein gerades Segment; zusätzliche Paare erzeugen einen mehrsegmentigen Pfad durch diese Punkte in der Reihenfolge. Wie die anderen Formen überschreibt Line CheckBounds(containerWidth, containerHeight) von Shape.
#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);Gestalten von Formen mit GraphInfo und BorderInfo
Jede Form liest und schreibt ihr Strich- und Füll-Styling über Shape.GraphInfo() / GraphInfo(value). GraphInfo verwendet standardmäßig ein LineWidth() von 1.0f mit einem leeren DashArray() und stellt außerdem Color(), FillColor(), DashArray()/DashPhase() für gestrichelte Striche, IsDoubled() für eine doppelte Linie sowie SkewAngleX()/SkewAngleY(), ScalingRateX()/ScalingRateY() und RotationAngle() für die Transformation des Strichs bereit. Graph selbst enthält ein BorderInfo, das über Border() gesetzt wird und ein GraphInfo pro Kante gruppiert – Left(), Right(), Top(), Bottom() – plus ein RoundedBorderRadius(), und kann erstellt werden, indem man angibt, welche Kanten mit einem BorderSide-Flag zu stylen sind (BorderSide::Left | BorderSide::Right oder BorderSide::All für jede Kante).
#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);Tipps und bewährte Verfahren
- Rufen Sie
CheckBoundsgegenüber dem eigenenWidth()/Height()des besitzendenGraphauf, nicht gegenüber der gesamten Medienbox der Seite — die Prüfung validiert die Geometrie einer Form gegen die von Ihnen übergebene Containergröße und betrachtet die Seite nicht automatisch. - Fügen Sie Formen zu
Shapes()hinzu, bevor Sie dasGraphzuPage.Paragraphs()hinzufügen — das Erstellen einesCircle,EllipseoderLinehat keine sichtbare Wirkung, bis es sowohl an sein besitzendesGraphangehängt wurde als auch diesesGrapheiner Seite hinzugefügt wird. - Gruppieren Sie verwandte Formen unter einem einzigen
Graphstatt je einemGraphpro Form;Left()/Top()/Width()/Height()positionieren den gesamten Container einmal, und jede Form inShapes()wird relativ zu ihm gezeichnet. - Setzen Sie
Shape.GraphInfo()explizit für Formen, die eine sichtbare Füllung oder einen nicht-Standard-Strich benötigen — das Standard-GraphInfohat eine1.0fLinienbreite, keine Füllung und ein leeresDashArray(). - Erstelle
Line.PositionArray()alsx0, y0, x1, y1, …-Paare in der Reihenfolge, in der der Pfad gezeichnet werden soll — ein Vektor ungerader Länge beschreibt einen unvollständigen Punkt.
Häufige Probleme
| Problem | Ursache | Lösung |
|---|---|---|
Ein Circle, Ellipse oder Line erscheint nie auf der gespeicherten Seite | Die Form wurde konstruiert, wurde aber nie an das Graphs Shapes() angehängt, oder das Graph wurde nie zur Seite hinzugefügt | Füge die Form zu graph->Shapes() hinzu und rufe page.Paragraphs().Add(graph) auf |
| Form wird mit einem standardmäßigen dünnen schwarzen Strich gezeichnet | Shape.GraphInfo() wurde nie gesetzt | Rufen Sie shape->GraphInfo(customGraphInfo) auf, bevor Sie die Form an Shapes() anhängen |
Line fehlt oder sieht aus wie ein einzelner Punkt | PositionArray() hat weniger als zwei (x, y)-Paare oder eine ungerade Anzahl von Werten | Geben Sie mindestens vier Werte als x0, y0, x1, y1 an |
| Nur einige Kanten des Containerrahmens sind gestylt | BorderInfo wurde mit einer BorderSide-Maske konstruiert, die einige Kanten ausschließt | Verwenden Sie BorderSide::All, oder ORen Sie alle benötigten BorderSide-Flags |
CheckBounds gibt unerwartet false zurück | Die an CheckBounds übergebenen Dimensionen stimmen nicht mit dem Container überein, in dem die Form tatsächlich gezeichnet wird | Übergib das aktuelle Width()/Height() des besitzenden Graph |
FAQ
Was ist der Unterschied zwischen Circle und AnnotationType::Circle?
Circle (dieser Leitfaden) ist eine Zeichenform, die direkt in den Seiteninhalt über ein Graph zeichnet. AnnotationType::Circle und CircleAnnotation gehören zu einem separaten Annotations API und stellen stattdessen eine kreisförmige Markup-Annotation dar — die beiden sind trotz des gemeinsamen Namens nicht miteinander verbunden.
Kann ein einzelner Graph mehr als eine Form enthalten?
Ja. Graph.Shapes() gibt das vollständige std::vector<std::unique_ptr<Shape>> für diesen Container zurück, und jede Mischung aus Circle, Ellipse und Line-Instanzen kann angehängt werden, bevor Graph zur Seite hinzugefügt wird.
Teilen Circle und Ellipse einen Geometrietyp?
Nr. Circle ist ein Mittelpunkt und Radius (PosX, PosY, Radius); Ellipse ist ein Begrenzungsrahmen (Left, Bottom, Width, Height). Beide leiten sich von Shape ab, aber keiner teilt einen gemeinsamen Punkt- oder Rechtecktyp mit dem anderen.
Ist das Zeichnen von Formen mit Graph dasselbe wie das Rendern einer Seite zu einem Bild?
Nein. Graph, Shape, Circle, Ellipse und Line erzeugen neue Vektorgeometrie im Seiteninhalt, während das Dokument erstellt wird. Das Konvertieren einer bestehenden Seite in ein Rasterbild ist eine separate Fähigkeit, die von BmpDevice, JpegDevice und TiffDevice übernommen wird.
Was macht GraphInfo.IsDoubled()?
Es markiert den Strich als doppelte Linie, anstatt irgendeine andere Strich-Eigenschaft zu ändern. Es ist ein boolesches Flag, das über IsDoubled() / IsDoubled(value) ausgelesen und gesetzt wird, zusammen mit den anderen GraphInfo Strich-Eigenschaften.
API Reference Zusammenfassung
| Klasse/Methode | Beschreibung |
|---|---|
Graph | Form-Container, der auf einer Seite platziert wird; positioniert sich mit Left(), Top(), Width(), Height() |
Graph.Shapes() | Gibt das von diesem Container gezeichnete std::vector<std::unique_ptr<Shape>> zurück |
Graph.GraphInfo() / GraphInfo(value) | Liest/Setzt das eigene Strich- und Füllstyling des Containers |
Graph.Border() / Border(value) | Liest/Setzt die BorderInfo, die den Container umrahmt |
Shape | Abstrakte Basisklasse für Circle, Ellipse und Line; stellt GraphInfo() und CheckBounds() bereit |
Shape.CheckBounds(w, h) | Gibt an, ob die Geometrie der Form in einen Container der angegebenen Breite/Höhe passt |
Circle | Kreisform: PosX(), PosY(), Radius() |
Ellipse | Ellipse-Form: Begrenzungsrahmen via Left(), Bottom(), Width(), Height() |
Line | Linien-/Pfadform: PositionArray(), ein flaches std::vector<float> aus x-, y-Koordinaten |
GraphInfo | Strich-/Füllstil: LineWidth(), Color(), FillColor(), DashArray(), DashPhase(), IsDoubled(), RotationAngle(), SkewAngleX()/SkewAngleY(), ScalingRateX()/ScalingRateY() |
BorderInfo | Pro-Kanten-Container-Rand: Left(), Right(), Top(), Bottom() (je ein GraphInfo), plus RoundedBorderRadius() |
BorderSide | Enum, das Kanten auswählt beim Erstellen eines BorderInfo: None, Left, Top, Right, Bottom, All, Box |