HotPDF importa un archivo SVG a un PDF cargado o creado como un Form XObject reutilizable mediante ImportSVGFormXObject, que devuelve el nombre de recurso del formulario creado. Colocarlo es una llamada aparte, DrawSVGFormXObject, de modo que una sola importación puede estamparse en muchas páginas con distintos tamaños sin duplicar un solo byte del arte
Esa separación importa más de lo que parece. Un logotipo rasterizado a 300 DPI y colocado en 400 páginas son 400 copias de un mapa de bits. El mismo logotipo como Form XObject es un solo objeto referenciado 400 veces, se mantiene nítido a cualquier nivel de zoom, e imprime a la resolución del dispositivo en lugar de al DPI que pareció suficiente en el momento de la compilación
¿Por qué usar un Form XObject en lugar de dibujar el SVG cada vez?
Un Form XObject es el mecanismo propio de PDF para contenido reutilizable: un flujo de contenido autocontenido con su propio cuadro delimitador y su propio diccionario de recursos, invocado por nombre. Importar un SVG a uno le da tres propiedades que el dibujo directo no ofrece. El arte existe una sola vez en el archivo. Cada colocación es una pequeña matriz y una invocación. Y las formas siguen siendo vectores, de modo que un visor con 800 % de zoom dibuja curvas, no píxeles
El detalle sutil está en los recursos. Las fuentes y los estados gráficos de un formulario deben vivir en el propio diccionario /Resources del formulario, no en los recursos de la página que resultara estar activa en el momento de la importación. HotPDF escribe las fuentes Base 14 y las entradas ExtGState que necesita un formulario dentro del propio formulario, porque un formulario que toma prestado un nombre de su primera página anfitriona se renderiza correctamente allí, pero produce un nombre de recurso sin resolver en cualquier otra página donde se coloque después
Dos inversiones: una para la geometría y otra para los glifos
El sistema de coordenadas de SVG crece hacia abajo desde la esquina superior izquierda; un Form XObject de PDF usa el espacio de usuario de PDF, que crece hacia arriba desde la esquina inferior izquierda. La transformación del viewBox raíz realiza una inversión del eje Y para que la geometría quede colocada correctamente. El texto necesita entonces una segunda inversión local, porque un glifo dibujado dentro de un marco ya invertido quedaría al revés
Esta es la misma corrección que aparece en sentido inverso cuando una página PDF se exporta como SVG, descrita en exportar páginas PDF a SVG. Un error aquí es fácil de detectar en arte con texto y casi invisible en arte sin texto, razón por la cual un logotipo con eslogan es una prueba de humo mejor que un logotipo solo
uses
HPDFDoc;
var
Pdf: THotPDF;
SvgBytes: TBytes;
FormName: AnsiString;
Stats: THPDFSVGImportStatistics;
I: Integer;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'catalogue.pdf';
Pdf.BeginDoc;
SvgBytes := LoadFileBytes('brand-logo.svg');
FormName := Pdf.ImportSVGFormXObject(SvgBytes, Stats);
if FormName = '' then
raise Exception.Create('SVG rejected - see the import statistics');
// Una importación, muchas colocaciones: los bytes del arte existen una sola vez
for I := 1 to 40 do
begin
if I > 1 then
Pdf.AddPage;
Pdf.CurrentPage.DrawSVGFormXObject(FormName, 40, 780, 120, 40);
end;
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
¿Cómo sobreviven los hipervínculos al proceso?
No pueden sobrevivir dentro del formulario, porque un Form XObject es contenido y los destinos de enlace en PDF son anotaciones, que pertenecen a una página. Por lo tanto, un elemento <a> del SVG de origen no puede simplemente copiarse al flujo de contenido del formulario
HotPDF resuelve esto conservando los rectángulos de enlace como metadatos en el espacio del formulario durante el análisis, y materializándolos como anotaciones de enlace a nivel de página en cada colocación. DrawSVGFormXObject mapea esos rectángulos a través del rectángulo destino que usted pasa, de modo que un formulario colocado dos veces con tamaños distintos obtiene dos conjuntos de áreas activas con el tamaño correcto. Los rectángulos de enlace se mapean únicamente a través del tamaño raíz y nunca entran al flujo de contenido, lo cual mantiene el arte dibujado idéntico sin importar cuántos enlaces contenga. Pase AddLinks = False cuando quiera el arte sin la interactividad, por ejemplo en una página solo para impresión
Qué rechaza el importador, y por qué ese es el punto
SVG es un dialecto de XML con scripting, referencias externas y expansión de entidades, lo cual hace que un archivo SVG arbitrario sea una entrada tan hostil como lo sería un archivo HTML arbitrario. El perfil de importación es fail-closed (falla de forma segura) ante todo lo que se extienda fuera del documento: referencias a recursos externos, scripts, atributos de manejo de eventos, DTD y cualquier url() que no sea una referencia a un fragmento local
Fail-closed significa que la importación falla en lugar de descartar en silencio la construcción problemática. Esa distinción importa en un pipeline por lotes, porque un descarte silencioso produce un documento al que le falta algo que nadie sabe que falta, mientras que un rechazo produce un archivo que se puede poner en cuarentena e inspeccionar. Si usted acepta cargas de SVG provenientes de usuarios, este es el comportamiento que quiere, y se complementa con el aislamiento a nivel de proceso descrito en aislamiento de procesos de códec para imágenes no confiables
Hay un límite interno que vale la pena conocer si usted también renderiza fuentes a color. El subconjunto estricto de SVG usado para los glifos de color OpenType SVG pasa por un punto de entrada separado y conserva su comportamiento de falla original, más restringido. La importación de arte general es una ruta distinta, de modo que añadir soporte de arcos, transparencia y CSS al arte importado no amplió lo que un glifo de fuente puede contener
Degradados, máscaras y la regla de no rasterizar
Los degradados se importan como bandas de color vectoriales acotadas por la ruta de recorte de la geometría original, no como una imagen rasterizada. Las máscaras usan el mismo enfoque: el contorno de la máscara se convierte en una ruta de recorte vectorial. El resultado es que una ilustración cargada de degradados se mantiene independiente de la resolución y se mantiene pequeña, mientras que un importador que rasterizara produciría un objeto de imagen grande cuya calidad queda fija en el momento de la importación
La contrapartida es la fidelidad en los casos extremos. Una aproximación por bandas de un degradado suave no es matemáticamente idéntica al degradado SVG, y el arte con docenas de máscaras suaves superpuestas se verá más cercano al original si en su lugar se renderiza como una imagen de alta resolución. Para conocer los modelos de sombreado que PDF admite de forma nativa, y cuándo recurrir a ellos directamente, consulte renderizar sombreados axiales y radiales
// Leer las estadísticas de importación le indica qué se procesó realmente
Writeln(Format('nodes=%d css rules=%d gradients=%d masks=%d',
[Stats.NodeCount, Stats.CSSRuleCount, Stats.GradientCount,
Stats.MaskCount]));
Writeln(Format('text runs=%d links=%d form bytes=%d',
[Stats.TextRunCount, Stats.LinkCount, Stats.OutputBytes]));
// Colocar el mismo formulario en dos tamaños produce dos conjuntos de enlaces correctos
Pdf.CurrentPage.DrawSVGFormXObject(FormName, 40, 700, 240, 80);
Pdf.CurrentPage.DrawSVGFormXObject(FormName, 320, 700, 120, 40);
// Colocación solo para impresión: arte sin las áreas activas
Pdf.CurrentPage.DrawSVGFormXObject(FormName, 40, 60, 120, 40, False);
Dónde encaja la importación de SVG junto a las demás rutas vectoriales
Existen tres rutas de importación vectorial y no son intercambiables. La importación de SVG es adecuada para arte producido por herramientas de diseño y para todo lo que llega desde un pipeline web. La importación de metarchivos, cubierta en importación vectorial de EMF y WMF, es adecuada para contenido generado por aplicaciones de Windows y por componentes de gráficos que dibujan sobre un contexto de dispositivo. El dibujo directo mediante la API de página es adecuado para arte que su propio código calcula, donde no existe ningún formato intermedio
El argumento de la reutilización favorece a la importación de SVG específicamente para elementos repetidos. Los membretes, logotipos, marcas de agua, sellos de certificación y líneas decorativas se dibujan de forma idéntica en muchas páginas, y cada uno de ellos es un solo objeto de formulario más una invocación por página. Mida la diferencia de tamaño de archivo en un documento real antes de decidir que no importa: en un catálogo de 500 páginas con un logotipo vectorial por página, la diferencia entre un formulario y 500 copias inline suele ser de varios megabytes
La importación de SVG, la importación de metarchivos y el dibujo vectorial directo comparten el mismo escritor de flujo de contenido para Delphi y C++Builder; la lista completa de funciones está en la página del componente PDF para Delphi de HotPDF