Ir al contenido
getnextpdf.com

Fuentes: la parte difícil

Las fuentes son el punto donde un PDF puede parecer completamente correcto y, aun así, estar silenciosamente roto. Una página puede representar los glifos correctos y, al mismo tiempo, ser imposible de buscar, imposible de copiar como texto y no conforme con un perfil de archivo. Todo eso puede ocurrir a la vez, sin nada visible que lo advierta. Esta página trata de las tres cosas que tienen que salir bien —incrustación, subconjuntos, codificación— y de lo que NextPDF hace con cada una.

«Parece correcto» es la frase más peligrosa en el trabajo con PDF, y las fuentes son donde causa más daño. Tres cosas independientes deben cumplirse:

  1. Incrustación — el programa de fuente viaja dentro del archivo, de modo que se representa igual en una máquina que no tiene la fuente instalada.
  2. Subconjuntos — solo se transportan los glifos realmente usados, de modo que una fuente CJK de 20 MB no infla cada documento.
  3. Codificación — existe una correspondencia correcta desde los códigos de carácter de la página hasta Unicode, de modo que el texto se puede buscar, copiar, indexar y leer con tecnología de asistencia.

La representación visual solo demuestra parcialmente la primera. Un documento puede mostrar glifos perfectos y, aun así, fallar por completo en la tercera: el texto es una imagen de palabras, no palabras. Ese es el fallo que supera cualquier revisión de tipo «parece correcto» y luego no supera una auditoría de cumplimiento o una solicitud de exhibición de pruebas.

  • Una fuente en un PDF es un diccionario más, por lo general acompañado de un flujo de programa de fuente incrustado.
  • Subconjuntos reescribe ese programa para que contenga solo los glifos usados. El nombre de una fuente subconjunto recibe una etiqueta de seis letras mayúsculas y un + para que los lectores la traten como distinta.
  • Codificación es el problema aparte de asignar códigos de carácter a Unicode. Un CMap /ToUnicode es lo que hace que el texto se pueda buscar y copiar, y es independiente de si los glifos se ven bien.
  • Un texto de aspecto correcto sin /ToUnicode (o con uno erróneo) es el fallo silencioso clásico: perfecto en pantalla, imposible de buscar en la práctica.
  • NextPDF crea subconjuntos de fuentes TrueType, preserva la identidad de los glifos para una representación correcta y emite un CMap /ToUnicode para que la extracción funcione, y puede imponer la regla de incrustación de PDF 2.0 en lugar de solo advertir.

Subconjuntos. FontSubsetter (src/Typography/FontSubsetter.php) analiza el directorio de tablas TrueType original y lee el cmap para asignar puntos de código Unicode a identificadores de glifo. Gestiona tanto el formato 4 del BMP como el formato 12 de Unicode completo, que CJK necesita. Después realiza el paso que los subconjuntadores ingenuos omiten: resuelve las dependencias de glifos compuestos por cierre transitivo. Un glifo acentuado formado por una letra base más una marca de combinación referencia otros glifos como componentes. Si esos componentes se descartan, el glifo se representa mal. El subconjuntador recorre ese grafo hasta que no aparece ningún componente nuevo, con una protección contra ciclos para que una fuente malformada no pueda quedar en un bucle infinito.

Merece la pena destacar dos decisiones de ingeniería de ese archivo. Primera: los identificadores de glifo se preservan, no se reasignan — las posiciones no usadas se rellenan con ceros en glyf/loca para que los índices de glifo originales del flujo de contenido sigan siendo válidos bajo CIDToGIDMap /Identity. Reasignar produciría un archivo más pequeño, pero exigiría reescribir cada referencia de glifo. Preservar la identidad es correcto por construcción. Segunda: el recorrido está ordenado (por gid ascendente) para que el subconjunto sea determinista a nivel de bytes — la misma fuente y los mismos glifos usados producen los mismos bytes de subconjunto, que es lo que exigen las compilaciones reproducibles. Si crear el subconjunto ahorrara menos de ~10 % del archivo, se devuelve el original sin cambios. La sobrecarga no compensa una ganancia marginal.

Incrustación. Una política explícita decide si un programa de fuente se transporta o no — nunca por conjeturas. Pdf20FontEmbeddingPolicy (src/Writer/Pdf20FontEmbeddingPolicy.php) tiene dos modos. Bajo el perfil PDF 2.0, Strict rechaza una referencia a una Type 1 estándar no incrustada («Base14») con una excepción tipada — el comportamiento correcto para la conformidad. AllowBase14 preserva la ruta consultiva histórica. Durante una ventana de migración, emite el descriptor de fuente mínimo que la norma todavía exige y genera una advertencia en lugar de lanzar una excepción. Quien invoca toma la decisión de forma explícita en el documento; nunca se infiere a partir de la fuente.

Codificación. Para las fuentes compuestas (Type 0), EmbeddedTtfFontDictBuilder (src/Writer/EmbeddedTtfFontDictBuilder.php) emite el descendiente CIDFontType2, el padre Type0 y un flujo de CMap /ToUnicode para que los códigos de carácter se resuelvan de vuelta a Unicode. El flujo /ToUnicode está legítimamente ausente en un único caso: cuando un CMap CJK predefinido y autodescriptivo ya proporciona al lector la correspondencia de carácter a Unicode. Ahí el CMap es la codificación, de modo que el perfil simple omite un flujo /ToUnicode redundante para ahorrar bytes. Fuera de ese caso, el flujo /ToUnicode es lo que mantiene el texto como texto.

AspectoQué garantizaQué no garantizaFallo silencioso si es incorrecto
IncrustaciónLa misma representación sin la fuente instaladaQue el texto sea buscableFuente sustituida; métricas incorrectas en otra máquina
SubconjuntosArchivo pequeño; solo los glifos usadosNada sobre la codificaciónFaltan componentes compuestos → glifos acentuados rotos
Codificación (/ToUnicode)Texto buscable, copiable y accesibleQue los glifos se representen correctamentePágina de aspecto perfecto, imposible de buscar / ilegible al copiar

Los tres aspectos de las fuentes son independientes. La incrustación y los subconjuntos tienen que ver con la apariencia y el tamaño; la codificación tiene que ver con el significado. Una página puede superar los dos primeros y fallar en el tercero sin nada visible que lo muestre.

Aquí están las dos mitades de una fuente compuesta correctamente incrustada, con subconjunto y buscable. La etiqueta de subconjunto sigue la regla de seis letras de la norma; la referencia /ToUnicode mantiene el texto extraíble.

% The Type 0 (composite) font dictionary
20 0 obj
<< /Type /Font /Subtype /Type0
/BaseFont /ABCDEF+NotoSans % six-letter subset tag + '+'
/Encoding /Identity-H
/DescendantFonts [21 0 R]
/ToUnicode 23 0 R >> % the map that makes text searchable
endobj
% The descendant CIDFontType2 (carries the subsetted program)
21 0 obj
<< /Type /Font /Subtype /CIDFontType2
/BaseFont /ABCDEF+NotoSans
/CIDToGIDMap /Identity % glyph IDs preserved, not remapped
/FontDescriptor 22 0 R >>
endobj

El /ToUnicode 23 0 R del objeto 20 es la diferencia entre un documento buscable y una imagen de uno. Al suprimirlo (fuera del caso del CMap predefinido), cada glifo se sigue pintando a la perfección, pero una búsqueda de cualquier palabra de la página no encuentra nada.

La trampa, dicha con claridad: que los glifos se representen correctamente no dice nada sobre si el texto es texto. La representación sigue la ruta de codificación a glifo. La búsqueda y la copia siguen la ruta de código a Unicode (/ToUnicode). Son mecanismos distintos que leen partes distintas del diccionario de fuente. Por tanto, un documento puede tener una salida visual impecable y un /ToUnicode ausente o erróneo. El resultado es una página que parece fiable y es funcionalmente imposible de buscar — el fallo que sobrevive a cualquier revisión visual, porque, por definición, no hay nada que ver.

Una trampa relacionada: suponer que «la fuente está incrustada, así que vamos bien para el archivado a largo plazo». La incrustación es necesaria, pero no suficiente. Un perfil como PDF/A también espera subconjuntos nombrados según la regla de seis letras y una codificación correcta. Incrustado pero imposible de buscar sigue fallando.

El subconjuntador de NextPDF es específicamente un subconjuntador de TrueType. Requiere las tablas TrueType esenciales y devuelve la fuente original sin cambios cuando faltan o cuando la ganancia queda por debajo del umbral de ~10 %. Los subconjuntos y un CMap /ToUnicode hacen que el texto sea extraíble, pero no pueden rescatar una fuente de origen que carece de la información para asignar un glifo a un carácter significativo. Donde no se puede determinar ningún valor Unicode, no hay emisión de CMap que invente uno.

Esta página trata de producir una estructura de fuente correcta en los documentos que NextPDF escribe. No es una herramienta de reparación de fuentes para PDF entrantes arbitrarios. Y emitir un subconjunto y una codificación conformes no certifica por sí solo un documento frente a un perfil de archivo completo — esa es una comprobación aparte y más amplia.

¿Por qué la etiqueta de seis letras y no el nombre de la fuente? Para que un lector pueda distinguir dos subconjuntos distintos de la misma fuente y fusionar documentos sin que colisionen sus conjuntos de glifos. Subconjuntos distintos, etiquetas distintas, por norma.

¿Cuándo es aceptable no tener /ToUnicode? Cuando un CMap CJK predefinido y autodescriptivo ya proporciona la correspondencia de carácter a Unicode. Ahí el CMap es la codificación. Un /ToUnicode aparte sería redundante. Fuera de eso, su ausencia es un defecto.

¿Los subconjuntos perjudican alguna vez? Solo si se hacen mal. Descartar los componentes de un glifo compuesto rompe los glifos acentuados. Reasignar los identificadores de glifo sin reescribir las referencias rompe la representación. NextPDF evita ambos problemas al resolver el cierre de componentes y preservar la identidad de los glifos.

  • Flujos y filtros — los programas de fuente incrustados son objetos de flujo filtrados con su propio contrato de decodificación.
  • Qué es realmente un PDF — el modelo de objetos en el que viven los diccionarios de fuente y los flujos de programa.
  • PDF 2.0: qué ha cambiado — incluidas las expectativas más estrictas de incrustación de fuentes de la base de 2.0.
  • Programa de fuente incrustado — el archivo de fuente real (TrueType/CFF/Type 1) transportado dentro del PDF como un flujo, de modo que la representación no depende de las fuentes instaladas del lector.
  • Subconjuntos — reescribir un programa de fuente para que contenga solo los glifos que el documento usa, con el fin de reducir el tamaño.
  • Etiqueta de subconjunto — el prefijo obligatorio de seis letras mayúsculas más + en el nombre de una fuente subconjunto (por ejemplo, ABCDEF+NotoSans).
  • /ToUnicode — un flujo de CMap que asigna códigos de carácter a valores Unicode; lo que hace que el texto PDF sea buscable, copiable y accesible.
  • Glifo compuesto — un glifo construido referenciando otros glifos como componentes; sus componentes deben conservarse al crear el subconjunto.
  • CIDToGIDMap /Identity — el modo en el que los índices de glifo del flujo de contenido son los propios identificadores de glifo de la fuente sin cambios; NextPDF preserva la identidad de los glifos para mantener esto válido.
  • Base14 — las catorce fuentes Type 1 estándar; PDF 2.0 espera que las fuentes se incrusten en lugar de referenciarse por nombre.