Desenhando Gráficos Vetoriais em uma Página PDF

Desenhando Gráficos Vetoriais em uma Página PDF

Desenhando Gráficos Vetoriais em uma Página PDF

Aspose.PDF FOSS para C++ inclui um pequeno API de gráficos vetoriais para desenhar formas diretamente em uma página PDF enquanto o documento está sendo construído. O ponto de entrada é Graph, um contêiner colocado em uma página que contém uma coleção de objetos Shape; três formas concretas — Circle, Ellipse e Line — derivam de Shape e cada uma expressa sua geometria de maneira diferente. O estilo de traçado e preenchimento por forma vem de GraphInfo, e o próprio contêiner Graph possui um BorderInfo para enquadramento. Isso não tem relação com a rasterização de página (BmpDevice, JpegDevice, TiffDevice), que converte o conteúdo existente da página em formatos de imagem raster ao invés de desenhar nova geometria.


O Contêiner de Gráficos e Adicionando Formas a uma Página

Graph posiciona e dimensiona a si mesmo na página por meio de Left(), Top(), Width() e Height(), e sua bandeira IsChangePosition() controla se essa posição pode mudar em relação a outros conteúdos da página. As formas que ele desenha vivem no vetor retornado por Shapes() — std::vector<std::unique_ptr<Shape>> — preenchido ao construir uma forma, configurá-la e movê-la para esse vetor. Uma vez construído, o próprio Graph é colocado na página através de Page.Paragraphs().Add(), a mesma coleção usada para outros conteúdos ao nível da 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");

Desenhando Círculos e Elipses

Circle e Ellipse expressam a geometria como propriedades numéricas simples, em vez de um tipo compartilhado de ponto ou retângulo. Circle é um ponto central e raio — PosX(), PosY(), Radius() — enquanto Ellipse é uma caixa delimitadora — Left(), Bottom(), Width(), Height(). Ambos herdam CheckBounds(containerWidth, containerHeight) de Shape, que relata se a geometria atual da forma cabe dentro de um contêiner do tamanho especificado sem alterar a própria 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);

Desenhando Linhas com PositionArray

Line armazena sua geometria de forma diferente de Circle e Ellipse: PositionArray() devolve um std::vector<float> plano contendo um par x, y para cada ponto que a linha atravessa, em vez de um conjunto fixo de propriedades nomeadas. Dois pontos (quatro valores) desenham um segmento reto; pares adicionais desenham um caminho de múltiplos segmentos através desses pontos na ordem. Como as outras formas, Line sobrescreve 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 com GraphInfo e BorderInfo

Cada forma lê e grava sua estilização de traço e preenchimento através de Shape.GraphInfo() / GraphInfo(value). GraphInfo tem como padrão um LineWidth() de 1.0f com um DashArray() vazio, e também expõe Color(), FillColor(), DashArray()/DashPhase() para traços tracejados, IsDoubled() para uma linha dupla, e SkewAngleX()/SkewAngleY(), ScalingRateX()/ScalingRateY() e RotationAngle() para transformar o traço. Graph por si só contém um BorderInfo, definido através de Border(), que agrupa um GraphInfo por aresta — Left(), Right(), Top(), Bottom() — mais um RoundedBorderRadius(), e pode ser construído nomeando quais arestas estilizar com uma flag BorderSide (BorderSide::Left | BorderSide::Right, ou BorderSide::All para cada aresta).

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

Dicas e Melhores Práticas

  • Chame CheckBounds contra o próprio Width()/Height() do Graph, não contra a caixa de mídia completa da página — a verificação valida a geometria de uma forma em relação ao tamanho do contêiner que você fornece, não analisa a página automaticamente.
  • Adicione formas a Shapes() antes de adicionar o Graph a Page.Paragraphs() — a construção de um Circle, Ellipse ou Line não tem efeito visível até que seja anexado ao seu Graph proprietário e que esse Graph seja adicionado a uma página.
  • Agrupe formas relacionadas sob um único Graph em vez de um Graph por forma; Left()/Top()/Width()/Height() posicionam todo o contêiner de uma vez, e cada forma em Shapes() é desenhada em relação a ele.
  • Defina Shape.GraphInfo() explicitamente para formas que precisam de preenchimento visível ou de um traço não padrão — o GraphInfo padrão tem uma largura de linha 1.0f, sem preenchimento e um DashArray() vazio.
  • Construa Line.PositionArray() como pares x0, y0, x1, y1, … na ordem em que o caminho deve ser desenhado — um vetor de comprimento ímpar descreve um ponto incompleto.

Problemas comuns

ProblemaCausaCorreção
Um Circle, Ellipse ou Line nunca aparece na página salvaA forma foi construída, mas nunca foi anexada ao Graph’s Shapes(), ou o Graph nunca foi adicionado à páginaEmpurre a forma para graph->Shapes() e chame page.Paragraphs().Add(graph)
A forma é desenhada com um traço fino preto padrãoShape.GraphInfo() nunca foi definidoChame shape->GraphInfo(customGraphInfo) antes de anexar a forma a Shapes()
Line está ausente ou parece um ponto únicoPositionArray() tem menos de dois pares (x, y) ou um número ímpar de valoresForneça pelo menos quatro valores como x0, y0, x1, y1
Apenas algumas arestas da borda do contêiner estão estilizadasBorderInfo foi construído com uma máscara BorderSide que exclui algumas arestasUse BorderSide::All, ou faça OR de todas as bandeiras BorderSide necessárias
CheckBounds inesperadamente retorna falseAs dimensões passadas para CheckBounds não correspondem ao contêiner em que a forma realmente é desenhadaPasse o Width()/Height() atual do Graph proprietário

FAQ

Qual é a diferença entre Circle e AnnotationType::Circle?

Circle (este guia) é uma forma de desenho que desenha diretamente no conteúdo da página através de um Graph. AnnotationType::Circle e CircleAnnotation pertencem a um API de anotações separado e representam, em vez disso, uma anotação de marcação em forma de círculo — os dois não estão relacionados apesar do nome compartilhado.

Um único Graph pode conter mais de uma forma?

Sim. Graph.Shapes() devolve o std::vector<std::unique_ptr<Shape>> completo para esse contêiner, e qualquer combinação de instâncias de Circle, Ellipse e Line pode ser acrescentada a ele antes que o Graph seja adicionado à página.

Circle e Ellipse compartilham um tipo de geometria?

Não. Circle é um ponto central e raio (PosX, PosY, Radius); Ellipse é uma caixa delimitadora (Left, Bottom, Width, Height). Ambos derivam de Shape, mas nenhum compartilha um ponto ou tipo de retângulo comum com o outro.

Desenhar formas com Graph é o mesmo que renderizar uma página para uma imagem?

Não. Graph, Shape, Circle, Ellipse e Line constroem nova geometria vetorial no conteúdo de uma página enquanto o documento é gerado. Converter uma página existente em uma imagem raster é uma capacidade separada, tratada por BmpDevice, JpegDevice e TiffDevice.

O que GraphInfo.IsDoubled() faz?

Ele marca o traço como uma linha dupla ao invés de mudar qualquer outra propriedade do traço. É uma flag booleana lida e definida através de IsDoubled() / IsDoubled(value) juntamente com as outras propriedades de traço GraphInfo.


API Reference Resumo

Classe/MétodoDescrição
GraphContêiner de forma colocado em uma página; posiciona-se com Left(), Top(), Width(), Height()
Graph.Shapes()Retorna o std::vector<std::unique_ptr<Shape>> desenhado por este contêiner
Graph.GraphInfo() / GraphInfo(value)Obtém/define o estilo de traço e preenchimento próprio do contêiner
Graph.Border() / Border(value)Obtém/define o BorderInfo que enquadra o contêiner
ShapeBase abstrata para Circle, Ellipse e Line; expõe GraphInfo() e CheckBounds()
Shape.CheckBounds(w, h)Informa se a geometria da forma cabe dentro de um contêiner de largura/altura dada
CircleForma de círculo: PosX(), PosY(), Radius()
EllipseForma de elipse: caixa delimitadora via Left(), Bottom(), Width(), Height()
LineForma de linha/caminho: PositionArray(), um std::vector<float> plano de coordenadas x, y
GraphInfoEstilização de traço/preenchimento: LineWidth(), Color(), FillColor(), DashArray(), DashPhase(), IsDoubled(), RotationAngle(), SkewAngleX()/SkewAngleY(), ScalingRateX()/ScalingRateY()
BorderInfoBorda de contêiner por borda: Left(), Right(), Top(), Bottom() (cada um um GraphInfo), mais RoundedBorderRadius()
BorderSideEnum que seleciona bordas ao construir um BorderInfo: None, Left, Top, Right, Bottom, All, Box

Ver também

 Português