Dibujando gráficos vectoriales en una página PDF

Dibujando gráficos vectoriales en una página PDF

Dibujar gráficos vectoriales en una página PDF

Aspose.PDF FOSS for C++ incluye un pequeño API de gráficos vectoriales para dibujar formas directamente sobre una página PDF mientras se construye un documento. El punto de entrada es Graph, un contenedor colocado en una página que alberga una colección de objetos Shape; tres formas concretas — Circle, Ellipse y Line — derivan de Shape y cada una expresa su geometría de manera diferente. El estilo de trazo y relleno por forma proviene de GraphInfo, y el propio contenedor Graph lleva un BorderInfo para encuadrar. Esto no está relacionado con la rasterización de página (BmpDevice, JpegDevice, TiffDevice), que convierte el contenido existente de la página a formatos de imagen raster en lugar de dibujar nueva geometría.


El contenedor de gráficos y la adición de formas a una página

Graph se posiciona y dimensiona en la página mediante Left(), Top(), Width() y Height(), y su bandera IsChangePosition() controla si esa posición puede desplazarse respecto al resto del contenido de la página. Las formas que dibuja residen en el vector devuelto por Shapes() — std::vector<std::unique_ptr<Shape>> — que se llena al crear una forma, configurarla y moverla a ese vector. Una vez construida, el propio Graph se coloca en la página mediante Page.Paragraphs().Add(), la misma colección utilizada para otro contenido a nivel de página.

#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");

Dibujar círculos y elipses

Circle y Ellipse expresan la geometría como propiedades numéricas simples en lugar de un tipo compartido de punto o rectángulo. Circle representa un punto central y un radio — PosX(), PosY(), Radius() — mientras que Ellipse es un cuadro delimitador — Left(), Bottom(), Width(), Height(). Ambos heredan CheckBounds(containerWidth, containerHeight) de Shape, que indica si la geometría actual de la forma cabe dentro de un contenedor del tamaño especificado sin modificar la propia forma.

#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);

Dibujar líneas con PositionArray

Line almacena su geometría de forma diferente a Circle y Ellipse: PositionArray() devuelve un std::vector<float> plano que contiene un par x, y para cada punto por el que la línea pasa, en lugar de un conjunto fijo de propiedades con nombre. Dos puntos (cuatro valores) dibujan un segmento recto; pares adicionales dibujan una ruta de varios segmentos a través de esos puntos en orden. Al igual que las otras formas, Line sobrescribe CheckBounds(containerWidth, containerHeight) de 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);

Estilizando formas con GraphInfo y BorderInfo

Cada forma lee y escribe su estilo de trazo y relleno a través de Shape.GraphInfo() / GraphInfo(value). GraphInfo por defecto es un LineWidth() de 1.0f con un DashArray() vacío, y también expone Color(), FillColor(), DashArray()/DashPhase() para trazos discontinuos, IsDoubled() para una línea duplicada, y SkewAngleX()/SkewAngleY(), ScalingRateX()/ScalingRateY(), y RotationAngle() para transformar el trazo. Graph lleva un BorderInfo, establecido mediante Border(), que agrupa un GraphInfo por borde — Left(), Right(), Top(), Bottom() — más un RoundedBorderRadius(), y puede construirse indicando qué bordes estilizar con una bandera BorderSide (BorderSide::Left | BorderSide::Right, o BorderSide::All para cada borde).

#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);

Consejos y buenas prácticas

  • Llama a CheckBounds contra el Width()/Height() propio del Graph, no contra el cuadro de medios completo de la página — la comprobación valida la geometría de una forma contra el tamaño del contenedor que proporciones, no mira la página automáticamente.
  • Agrega las formas a Shapes() antes de añadir el Graph a Page.Paragraphs() — crear un Circle, Ellipse o Line no tiene efecto visible hasta que se añada tanto a su Graph propietario como ese Graph se agregue a una página.
  • Agrupa formas relacionadas bajo un único Graph en lugar de un Graph por forma; Left()/Top()/Width()/Height() posicionan todo el contenedor una sola vez, y cada forma en Shapes() se dibuja en relación con él.
  • Establece Shape.GraphInfo() explícitamente para las formas que requieran un relleno visible o un trazo no predeterminado — el GraphInfo predeterminado tiene un ancho de línea 1.0f, sin relleno y un DashArray() vacío.
  • Construye Line.PositionArray() como pares x0, y0, x1, y1, … en el orden en que se debe dibujar la trayectoria — un vector de longitud impar describe un punto incompleto.

Problemas comunes

ProblemaCausaSolución
Un Circle, Ellipse o Line nunca aparece en la página guardadaLa forma se construyó pero nunca se añadió a su Graph’s Shapes(), o el Graph nunca se agregó a la páginaEmpuje la forma a graph->Shapes() y llame a page.Paragraphs().Add(graph)
La forma se dibuja con un trazo negro delgado predeterminadoShape.GraphInfo() nunca se establecióLlame a shape->GraphInfo(customGraphInfo) antes de añadir la forma a Shapes()
Line falta o parece un punto únicoPositionArray() tiene menos de dos pares (x, y) o un número impar de valoresProporcione al menos cuatro valores como x0, y0, x1, y1
Solo algunos bordes del contorno del contenedor están estilizadosBorderInfo se construyó con una máscara BorderSide que excluye algunos bordesUtilice BorderSide::All, o combine con OR todos los indicadores BorderSide necesarios
CheckBounds devuelve inesperadamente falseLas dimensiones pasadas a CheckBounds no coinciden con el contenedor en el que realmente se dibuja la formaPasa el Width()/Height() actual del Graph propietario

FAQ

¿Cuál es la diferencia entre Circle y AnnotationType::Circle?

Circle (esta guía) es una forma de dibujo que se inserta directamente en el contenido de la página a través de un Graph. AnnotationType::Circle y CircleAnnotation pertenecen a un API de anotaciones independiente y representan una anotación de marcado con forma circular — ambos no están relacionados a pesar del nombre compartido.

¿Puede un único Graph contener más de una forma?

Sí. Graph.Shapes() devuelve el std::vector<std::unique_ptr<Shape>> completo para ese contenedor, y cualquier combinación de instancias Circle, Ellipse y Line puede añadirse antes de que se inserte el Graph en la página.

¿Comparten Circle y Ellipse un tipo de geometría?

No. Circle es un punto central y radio (PosX, PosY, Radius); Ellipse es una caja delimitadora (Left, Bottom, Width, Height). Ambos se derivan de Shape, pero ninguno comparte un punto o tipo de rectángulo con el otro.

¿Dibujar formas con Graph es lo mismo que representar una página como imagen?

No. Graph, Shape, Circle, Ellipse y Line incorporan nueva geometría vectorial al contenido de una página durante la generación del documento. Convertir una página existente a una imagen raster es una capacidad distinta, gestionada por BmpDevice, JpegDevice y TiffDevice.

¿Qué hace GraphInfo.IsDoubled()?

Marca el trazo como una línea doble sin modificar ninguna otra propiedad del trazo. Es una bandera booleana que se lee y establece a través de IsDoubled() / IsDoubled(value) junto con las demás propiedades de trazo GraphInfo.


Resumen de API Reference

Clase/MétodoDescripción
GraphContenedor de forma colocado en una página; se posiciona con Left(), Top(), Width(), Height()
Graph.Shapes()Devuelve el std::vector<std::unique_ptr<Shape>> dibujado por este contenedor
Graph.GraphInfo() / GraphInfo(value)Obtiene/establece el estilo de trazo y relleno propio del contenedor
Graph.Border() / Border(value)Obtiene/establece el BorderInfo que enmarca el contenedor
ShapeBase abstracta para Circle, Ellipse y Line; expone GraphInfo() y CheckBounds()
Shape.CheckBounds(w, h)Informa si la geometría de la figura cabe dentro de un contenedor con el ancho/alto especificado
CircleForma de círculo: PosX(), PosY(), Radius()
EllipseForma de elipse: caja delimitadora mediante Left(), Bottom(), Width(), Height()
LineForma de línea/ruta: PositionArray(), un plano std::vector<float> de coordenadas x, y
GraphInfoEstilo de trazo/relleno: LineWidth(), Color(), FillColor(), DashArray(), DashPhase(), IsDoubled(), RotationAngle(), SkewAngleX()/SkewAngleY(), ScalingRateX()/ScalingRateY()
BorderInfoBorde del contenedor por borde: Left(), Right(), Top(), Bottom() (cada uno es un GraphInfo), más RoundedBorderRadius()
BorderSideEnumeración que selecciona los bordes al crear un BorderInfo: None, Left, Top, Right, Bottom, All, Box

Ver también

 Español