Rysowanie grafiki wektorowej na stronie PDF
Rysowanie grafiki wektorowej na stronie PDF
Aspose.PDF FOSS dla C++ zawiera małą bibliotekę grafiki wektorowej API umożliwiającą rysowanie kształtów bezpośrednio na stronie PDF podczas budowania dokumentu. Punktem wejścia jest Graph, kontener umieszczony na stronie, który przechowuje kolekcję obiektów Shape; trzy konkretne kształty — Circle, Ellipse i Line — dziedziczą po Shape i każdy wyraża swoją geometrię inaczej. Stylizacja obrysu i wypełnienia dla każdego kształtu pochodzi z GraphInfo, a sam kontener Graph posiada BorderInfo służący do ramkowania. Nie ma to związku z rasteryzacją strony (BmpDevice, JpegDevice, TiffDevice), która konwertuje istniejącą zawartość strony na formaty obrazów rastrowych zamiast rysować nową geometrię.
Kontener wykresu i dodawanie kształtów do strony
Graph pozycjonuje się i określa swój rozmiar na stronie za pomocą Left(), Top(), Width() i Height(), a jego flaga IsChangePosition() kontroluje, czy ta pozycja może się przesuwać względem innej zawartości strony. Kształty, które rysuje, znajdują się w wektorze zwracanym przez Shapes() — std::vector<std::unique_ptr<Shape>> — wypełnionym poprzez utworzenie kształtu, skonfigurowanie go i przeniesienie na ten wektor. Po zbudowaniu, sam Graph jest umieszczany na stronie za pomocą Page.Paragraphs().Add(), tej samej kolekcji używanej dla innych treści na poziomie strony.
#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");Rysowanie okręgów i elips
Circle i Ellipse wyrażają geometrię jako proste właściwości liczbowe, a nie jako wspólny typ punktu lub prostokąta. Circle to punkt środkowy i promień — PosX(), PosY(), Radius() — natomiast Ellipse to ramka ograniczająca — Left(), Bottom(), Width(), Height(). Oba dziedziczą CheckBounds(containerWidth, containerHeight) z Shape, które informuje, czy bieżąca geometria kształtu mieści się w kontenerze o podanym rozmiarze bez modyfikacji samego kształtu.
#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);Rysowanie linii za pomocą PositionArray
Line przechowuje swoją geometrię inaczej niż Circle i Ellipse: PositionArray() zwraca płaską std::vector<float> zawierającą parę x, y dla każdego punktu, przez który przechodzi linia, zamiast stałego zestawu nazwanych własności. Dwa punkty (cztery wartości) rysują prosty odcinek; dodatkowe pary rysują wielosegmentową ścieżkę przez te punkty w kolejności. Podobnie jak inne kształty, Line nadpisuje CheckBounds(containerWidth, containerHeight) z 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);Stylowanie kształtów przy użyciu GraphInfo i BorderInfo
Każdy kształt odczytuje i zapisuje styl obrysu i wypełnienia poprzez Shape.GraphInfo() / GraphInfo(value). GraphInfo domyślnie ma LineWidth() 1.0f z pustym DashArray(), a także udostępnia Color(), FillColor(), DashArray()/DashPhase() dla przerywanych obrysów, IsDoubled() dla podwójnej linii oraz SkewAngleX()/SkewAngleY(), ScalingRateX()/ScalingRateY() i RotationAngle() do transformacji obrysu. Graph sam zawiera BorderInfo, ustawiany przez Border(), który grupuje po jednym GraphInfo na krawędź — Left(), Right(), Top(), Bottom() — plus RoundedBorderRadius(), i może być skonstruowany przez określenie, które krawędzie stylizować przy użyciu flagi BorderSide (BorderSide::Left | BorderSide::Right lub BorderSide::All dla każdej krawędzi).
#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);Wskazówki i najlepsze praktyki
- Wywołaj
CheckBoundswzględem własnegoWidth()/Height()własnegoGraph, a nie pełnego pola mediów strony — sprawdzenie waliduje geometrię kształtu względem podanego rozmiaru kontenera, nie patrzy automatycznie na stronę. - Dodaj kształty do
Shapes()przed dodaniemGraphdoPage.Paragraphs()— stworzenieCircle,EllipselubLinenie ma widzialnego efektu, dopóki nie zostanie zarówno dołączone do swojego właścicielaGraph, jak i tenGraphnie zostanie dodany do strony. - Grupuj powiązane kształty pod jednym
Graphzamiast jednegoGraphna każdy kształt;Left()/Top()/Width()/Height()pozycjonują cały kontener jednorazowo, a każdy kształt wShapes()jest rysowany względem niego. - Ustaw
Shape.GraphInfo()explicite dla kształtów, które potrzebują widocznego wypełnienia lub niestandardowego obrysu — domyślnyGraphInfoma szerokość linii1.0f, brak wypełnienia i pustyDashArray(). - Zbuduj
Line.PositionArray()jako paryx0, y0, x1, y1, …w kolejności, w jakiej ścieżka powinna być rysowana — wektor o nieparzystej długości opisuje niekompletny punkt.
Typowe problemy
| Problem | Przyczyna | Naprawa |
|---|---|---|
Circle, Ellipse lub Line nigdy nie pojawia się na zapisanej stronie | Kształt został zbudowany, ale nigdy nie został dołączony do Graph’s Shapes(), lub Graph nigdy nie został dodany do strony | Umieść kształt na graph->Shapes() i wywołaj page.Paragraphs().Add(graph) |
| Kształt rysuje się domyślnym cienkim czarnym obrysem | Shape.GraphInfo() nigdy nie został ustawiony | Wywołaj shape->GraphInfo(customGraphInfo) przed dodaniem kształtu do Shapes() |
Line jest brakujący lub wygląda jak pojedynczy punkt | PositionArray() ma mniej niż dwie pary (x, y) lub nieparzystą liczbę wartości | Podaj co najmniej cztery wartości jako x0, y0, x1, y1 |
| Tylko niektóre krawędzie obramowania kontenera są stylizowane | BorderInfo został skonstruowany z maską BorderSide, która wyklucza niektóre krawędzie | Użyj BorderSide::All, lub OR razem wszystkie potrzebne flagi BorderSide |
CheckBounds nieoczekiwanie zwraca false | Wymiary przekazane do CheckBounds nie pasują do kontenera, w którym kształt jest faktycznie rysowany | Przekaż bieżące Width()/Height() właściciela Graph |
FAQ
Jaka jest różnica między Circle a AnnotationType::Circle?
Circle (ten przewodnik) jest kształtem rysunkowym, który rysuje bezpośrednio w treści strony za pomocą Graph. AnnotationType::Circle i CircleAnnotation należą do oddzielnego API adnotacji i reprezentują adnotację znacznikową w kształcie koła — te dwa elementy nie są ze sobą powiązane mimo wspólnej nazwy.
Czy pojedynczy Graph może zawierać więcej niż jeden kształt?
Tak. Graph.Shapes() zwraca pełny std::vector<std::unique_ptr<Shape>> dla tego kontenera, a dowolna mieszanka instancji Circle, Ellipse i Line może zostać do niego dołączona przed dodaniem Graph do strony.
Czy Circle i Ellipse dzielą ten sam typ geometrii?
Nie. Circle jest punktem środkowym i promieniem (PosX, PosY, Radius); Ellipse jest prostokątem ograniczającym (Left, Bottom, Width, Height). Oba pochodzą od Shape, ale żaden z nich nie ma wspólnego punktu ani typu prostokąta z drugim.
Czy rysowanie kształtów za pomocą Graph jest tym samym co renderowanie strony do obrazu?
Nie. Graph, Shape, Circle, Ellipse i Line tworzą nową geometrię wektorową w treści strony podczas generowania dokumentu. Konwersja istniejącej strony na obraz rastrowy jest oddzielną funkcją, obsługiwaną przez BmpDevice, JpegDevice i TiffDevice.
Co robi GraphInfo.IsDoubled()?
Oznacza ona stroke jako podwójną linię, zamiast zmieniać jakąkolwiek inną właściwość stroke. Jest to flaga boolowska odczytywana i ustawiana przez IsDoubled() / IsDoubled(value) wraz z innymi właściwościami stroke GraphInfo.
API Reference Podsumowanie
| Klasa/Metoda | Opis |
|---|---|
Graph | Kontener kształtu umieszczony na stronie; pozycjonuje się przy użyciu Left(), Top(), Width(), Height() |
Graph.Shapes() | Zwraca std::vector<std::unique_ptr<Shape>> rysowany przez ten kontener |
Graph.GraphInfo() / GraphInfo(value) | Pobiera/ustawia własny styl obrysu i wypełnienia kontenera |
Graph.Border() / Border(value) | Pobiera/ustawia BorderInfo ramujący kontener |
Shape | Abstrakcyjna baza dla Circle, Ellipse i Line; udostępnia GraphInfo() i CheckBounds() |
Shape.CheckBounds(w, h) | Raportuje, czy geometria kształtu mieści się w kontenerze o podanej szerokości/wysokości |
Circle | Kształt koła: PosX(), PosY(), Radius() |
Ellipse | Kształt elipsy: ramka ograniczająca przez Left(), Bottom(), Width(), Height() |
Line | Kształt linii/ścieżki: PositionArray(), płaska std::vector<float> współrzędnych x, y |
GraphInfo | Styl obrysu/wypełnienia: LineWidth(), Color(), FillColor(), DashArray(), DashPhase(), IsDoubled(), RotationAngle(), SkewAngleX()/SkewAngleY(), ScalingRateX()/ScalingRateY() |
BorderInfo | Obramowanie kontenera per krawędź: Left(), Right(), Top(), Bottom() (każde jako GraphInfo), plus RoundedBorderRadius() |
BorderSide | Wyliczenie wybierające krawędzie przy konstruowaniu BorderInfo: None, Left, Top, Right, Bottom, All, Box |