Rysowanie grafiki wektorowej na stronie PDF

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 CheckBounds względem własnego Width()/Height() własnego Graph, 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 dodaniem Graph do Page.Paragraphs() — stworzenie Circle, Ellipse lub Line nie ma widzialnego efektu, dopóki nie zostanie zarówno dołączone do swojego właściciela Graph, jak i ten Graph nie zostanie dodany do strony.
  • Grupuj powiązane kształty pod jednym Graph zamiast jednego Graph na każdy kształt; Left()/Top()/Width()/Height() pozycjonują cały kontener jednorazowo, a każdy kształt w Shapes() jest rysowany względem niego.
  • Ustaw Shape.GraphInfo() explicite dla kształtów, które potrzebują widocznego wypełnienia lub niestandardowego obrysu — domyślny GraphInfo ma szerokość linii 1.0f, brak wypełnienia i pusty DashArray().
  • Zbuduj Line.PositionArray() jako pary x0, y0, x1, y1, … w kolejności, w jakiej ścieżka powinna być rysowana — wektor o nieparzystej długości opisuje niekompletny punkt.

Typowe problemy

ProblemPrzyczynaNaprawa
Circle, Ellipse lub Line nigdy nie pojawia się na zapisanej stronieKształt został zbudowany, ale nigdy nie został dołączony do Graph’s Shapes(), lub Graph nigdy nie został dodany do stronyUmieść kształt na graph->Shapes() i wywołaj page.Paragraphs().Add(graph)
Kształt rysuje się domyślnym cienkim czarnym obrysemShape.GraphInfo() nigdy nie został ustawionyWywołaj shape->GraphInfo(customGraphInfo) przed dodaniem kształtu do Shapes()
Line jest brakujący lub wygląda jak pojedynczy punktPositionArray() ma mniej niż dwie pary (x, y) lub nieparzystą liczbę wartościPodaj co najmniej cztery wartości jako x0, y0, x1, y1
Tylko niektóre krawędzie obramowania kontenera są stylizowaneBorderInfo został skonstruowany z maską BorderSide, która wyklucza niektóre krawędzieUżyj BorderSide::All, lub OR razem wszystkie potrzebne flagi BorderSide
CheckBounds nieoczekiwanie zwraca falseWymiary przekazane do CheckBounds nie pasują do kontenera, w którym kształt jest faktycznie rysowanyPrzekaż 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/MetodaOpis
GraphKontener 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
ShapeAbstrakcyjna 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
CircleKształt koła: PosX(), PosY(), Radius()
EllipseKształt elipsy: ramka ograniczająca przez Left(), Bottom(), Width(), Height()
LineKształt linii/ścieżki: PositionArray(), płaska std::vector<float> współrzędnych x, y
GraphInfoStyl obrysu/wypełnienia: LineWidth(), Color(), FillColor(), DashArray(), DashPhase(), IsDoubled(), RotationAngle(), SkewAngleX()/SkewAngleY(), ScalingRateX()/ScalingRateY()
BorderInfoObramowanie kontenera per krawędź: Left(), Right(), Top(), Bottom() (każde jako GraphInfo), plus RoundedBorderRadius()
BorderSideWyliczenie wybierające krawędzie przy konstruowaniu BorderInfo: None, Left, Top, Right, Bottom, All, Box

Zobacz także

 Polski