Ir al contenido

Dibujar gráficos vectoriales: formas, colores y estilos de línea

Esta receta dibuja primitivas con relleno y contorno: rectángulos, rectángulos redondeados, círculos, elipses y líneas. Para cada una se define el color de relleno, el color de trazo (dibujo) y el ancho de línea. La receta sigue examples/06-colors-and-drawing.php.

Cada primitiva corresponde a un objeto de trazado de ISO 32000-2. Un objeto de trazado es una forma construida a partir de segmentos de línea y de curva. Termina con un operador de pintado que decide si la forma se traza, se rellena o ambas cosas.

Ventana de terminal
composer require nextpdf/core:^3

No se requiere ninguna extensión opcional. La API de dibujo y color es estable desde la 1.0.0 y se ejecuta en la matriz de backport 8.1–8.4.

Primero se establece el estado y luego se dibuja. setFillColor(), setDrawColor() y setLineWidth() actualizan el estado gráfico. El siguiente rect(), circle(), ellipse(), roundedRect() o line() consume ese estado. Los métodos de forma reciben un argumento de estilo: 'F' rellena, 'S' traza (el valor predeterminado) y 'DF'/'FD' hacen ambas cosas. Internamente, un rectángulo relleno se representa como el operador de construcción de trazado re seguido del operador de pintado de relleno. ISO 32000-2 §8.5.3 especifica S para trazar y f para rellenar como operadores principales de pintado de trazado.

Los colores son colores de dispositivo. setFillColor(r, g, b) selecciona DeviceRGB. ISO 32000-2 §8.6.4.3 define rg como el operador que establece el color de DeviceRGB para operaciones distintas del trazo, y g como el equivalente de DeviceGray. Un setFillColor($v) con un solo argumento define un nivel de gris. El ancho de línea tiene como valor predeterminado 1.0 y el patrón de guiones tiene como valor predeterminado una línea continua (§8.4.3.6).

La superficie de la API se genera automáticamente a partir de PHPDoc. Esta receta usa los siguientes métodos:

  • rect(float $x, float $y, float $w, float $h, string $style = 'S'): static
  • roundedRect(float $x, float $y, float $w, float $h, float $r, string $style = 'S'): static
  • circle(float $x, float $y, float $r, string $style = 'S'): static
  • ellipse(float $x, float $y, float $rx, float $ry, string $style = 'S'): static
  • line(float $x1, float $y1, float $x2, float $y2): static
  • setFillColor(int $r, int $g = -1, int $b = -1): static / setDrawColor(...)
  • setLineWidth(float $width): static
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->addPage();
$doc->setFillColor(30, 58, 138);
$doc->rect(20, 30, 60, 40, 'F'); // filled rectangle
$doc->setDrawColor(217, 119, 6);
$doc->setLineWidth(1.0);
$doc->circle(140, 50, 20, 'S'); // stroked circle
$doc->setLineWidth(0.3);
$doc->line(20, 90, 190, 90); // thin rule
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/vector.pdf');

Este es el ejemplo completo, listo para el arnés. Respeta NEXTPDF_COOKBOOK_OUTPUT y no añade entropía propia.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Colors and Drawing');
$doc->addPage();
$doc->setFont('helvetica', 'B', 18);
$doc->cell(0, 12, 'Colors and Drawing', newLine: true);
$doc->ln(5);
// --- Filled rectangles: set fill colour, then draw with style 'F' ---
$palette = [
[30, 58, 138], [217, 119, 6], [30, 27, 75],
[239, 66, 35], [21, 128, 61],
];
$x = 15.0;
$rowY = $doc->getY();
foreach ($palette as [$r, $g, $b]) {
$doc->setFillColor($r, $g, $b);
$doc->rect($x, $rowY, 30, 20, 'F');
$x += 35.0;
}
$doc->ln(28);
// --- Outlined shapes: set draw colour + line width, draw with 'S' ---
$doc->setDrawColor(30, 58, 138);
$doc->setLineWidth(0.5);
$y = $doc->getY();
$doc->rect(15, $y, 30, 25, 'S');
$doc->roundedRect(55, $y, 30, 25, 5, 'S');
$doc->circle(110, $y + 12.5, 12.5, 'S');
$doc->ellipse(150, $y + 12.5, 18, 10, 'S');
$doc->ln(33);
// --- Lines at three widths ---
$y = $doc->getY();
$doc->setDrawColor(0);
$doc->setLineWidth(0.2);
$doc->line(15, $y, 195, $y);
$doc->setLineWidth(0.8);
$doc->line(15, $y + 5, 195, $y + 5);
$doc->setLineWidth(1.5);
$doc->line(15, $y + 12, 195, $y + 12);
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/vector.pdf';
$doc->save($out);
echo "Created vector.pdf\n";
  • El estilo predeterminado es trazar. Si se omite el argumento de estilo, la forma se traza ('S'). Una forma que parece invisible suele dibujarse sin un color de trazo establecido, o rellenarse con el color de fondo de la página. Usar 'F' para rellenarla.
  • El estado del color persiste. setFillColor() sigue activo hasta que se cambia. Conviene restablecerlo (por ejemplo, setFillColor(255)) antes del siguiente bloque no relacionado, o el color se arrastrará al bloque siguiente.
  • Gris frente a la sobrecarga RGB. setFillColor(128) es un nivel de gris. setFillColor(128, 0, 0) es RGB. La forma de un solo argumento no es «rojo 128».
  • El eje Y va de arriba abajo en la API. Los métodos auxiliares de dibujo usan el origen superior izquierdo del documento. El motor lo asigna automáticamente al espacio de usuario inferior izquierdo del PDF.

Cada primitiva se traduce en unos pocos operadores del flujo de contenido. Miles de formas por página se mantienen holgadamente dentro del presupuesto de 2000 ms / 64 MB. El costo crece de forma lineal con la cantidad de primitivas. No hay rasterización, así que la salida sigue siendo vectorial.

Esta receta dibuja únicamente la geometría especificada por el código. No analiza ninguna entrada ni realiza ningún acceso a la red. Comprobar el rango de cualquier coordenada que provenga de datos no confiables. Una comprobación de rango impide que un valor hostil coloque marcas muy fuera de la página.

DeclaraciónEspecificaciónCláusulareference_id
Un objeto de trazado se compone de líneas, rectángulos y curvas de Bézier, y termina en un operador de pintado.ISO 32000-2§8.5
S traza y f rellena un trazado.ISO 32000-2§8.5.3
rg establece el color de DeviceRGB para operaciones distintas del trazo; g establece DeviceGray.ISO 32000-2§8.6.4.3
El valor inicial del patrón de guiones es [] 0, una línea continua.ISO 32000-2§8.4.3.6

Perfil de reproducibilidad: estructural. El dibujo vectorial no tiene entropía propia. Aun así, cada documento guardado incluye un /ID en el tráiler y átomos de fecha. ISO 32000-2 §8.3.4 también establece que la disposición exacta de los operadores del estado gráfico no tiene significado semántico, por lo que un normalizador puede reordenar el estado equivalente. Lo honesto es afirmar la igualdad estructural tras la normalización con qpdf. Esta receta describe cómo NextPDF produce la estructura. No afirma la conformidad con ISO 32000-2 como una declaración general.

No aplica. El dibujo vectorial es una capacidad del núcleo, sin restricción de Premium.