Un archivo PDF que se ve perfecto en su computadora y se renderiza como una fila de cuadros vacíos en la de otra persona es el defecto de fuente más común en el software de documentos, y casi nunca significa que el texto sea incorrecto. Los caracteres están intactos, la codificación está bien, los glifos simplemente no están allí. Lo que cambió entre las dos computadoras es qué fuentes tenía instaladas el sistema operativo, y la brecha entre un archivo portátil y uno frágil es una decisión tomada cuando se escribió la página: si la fuente viajó dentro del PDF o se asumió que estaba presente en el destino
Comprender por qué sucede eso y por qué una falla separada produce un texto que parece poder buscarse y que se copia como un galimatías, significa ver cómo PDF almacena el texto. No almacena oraciones. Almacena códigos de glifos más un programa de fuente más tablas que mapean uno al otro, y cada error de renderización o extracción vive en una brecha entre esos tres. Lo que sigue es un recorrido por esa maquinaria, basado en ISO 32000, con las llamadas de Delphi que lo controlan donde importan
Los caracteres, códigos y glifos son tres cosas diferentes
El vocabulario hace tropezar a la gente porque el habla cotidiana colapsa tres ideas distintas en la palabra "letra". Un carácter es una unidad abstracta de escritura, la idea de la A mayúscula, identificada en Unicode como U+0041. Un glifo es una forma dibujada, el contorno curvo y de tallo que usa una fuente en particular para representar ese carácter. Entre ellos se encuentra el código: el byte o bytes en el flujo de contenido que le dicen al visor qué glifo pintar en la fuente actual
PDF funciona con códigos. Cuando un flujo de contenido muestra una cadena, esos bytes son índices en la fuente activa, no en Unicode. La codificación de la fuente decide que un código de 65 significa "dibujar el glifo archivado bajo el 65", y nada en esa operación sabe que el resultado le parece una A a un humano. Eso es lo que hace que un PDF se renderice idénticamente en todas partes donde pueda encontrar los glifos, y también es la razón por la cual la extracción es un problema separado de la visualización: el dibujo solo necesita código a glifo, la lectura necesita código a Unicode, y esas son dos tablas diferentes que pueden no estar de acuerdo o desaparecer de forma independiente
Los tipos de fuentes que realmente encontrará
ISO 32000 define varios tipos de diccionarios de fuentes y, en la práctica, un documento que usted recibe o genera utiliza uno de tres. Saber cuál está viendo explica la mayor parte de lo que puede salir mal
Type 1 es el formato de contorno PostScript original de Adobe, construido a partir de curvas Bezier cúbicas. Las catorce fuentes estándar que todo lector compatible debe suministrar, las familias Helvetica, Times, Courier, Symbol y ZapfDingbats, son Type 1, y un diccionario de fuentes que nombre una de ellas puede omitir legalmente el programa de fuentes. Ese es el único caso en el que dejar una fuente sin incrustar es seguro por especificación en lugar de por suerte. Para cualquier otro tipo de letra Type 1, el programa debe estar incrustado o el visor sustituye algo, generalmente una fuente métricamente similar pero visiblemente diferente
TrueType utiliza curvas cuadráticas y proviene del mundo de Apple y Microsoft. Es lo que son la mayoría de las fuentes del sistema, y lo que incrustará con más frecuencia. Una fuente TrueType simple en PDF está limitada a códigos de un solo byte, por lo que una fuente de este tipo puede abordar como máximo 256 glifos a la vez. Ese límite es la razón estructural por la cual los caracteres CJK y otros scripts grandes no pueden viajar en una fuente simple
Type 0, la fuente compuesta o con clave CID, es la respuesta a ese límite. Utiliza códigos de varios bytes y un CMap para enrutarlos a través de un CIDFont descendiente, cuyos contornos son a su vez TrueType o CFF/Type 1. Este es el único tipo de fuente que puede transportar miles de glifos, por lo que cualquier archivo PDF que contenga chino, japonés, coreano o una amplia mezcla multilingüe utiliza Type 0, ya sea que el autor haya pensado en ello o no. El intercambio es la complejidad: más partes móviles, más de las cuales deben ser correctas tanto para la renderización como para la extracción

Un detalle detrás de esa imagen impulsa el tamaño del archivo. Una fuente es una biblioteca de contornos, no mapas de bits de tamaño fijo, por lo que el mismo programa incrustado sirve a cada tamaño de punto en la página. El escalado es una transformación aplicada en el momento del dibujo, por lo que un encabezado y su cuerpo de texto comparten un tipo de letra incrustado y el costo de incrustación es por fuente, no por tamaño
La incrustación es la diferencia entre portátil y frágil
La incrustación significa que el programa de fuentes, los datos reales del contorno, se escriben en el PDF como un flujo. Un lector en una computadora que nunca ha oído hablar de su fuente lee esos contornos directamente desde el archivo y dibuja glifos exactos. Si se omite la incrustación, se apuesta a que el destino tiene una fuente del mismo nombre; cuando no es así, el visor recurre a un sustituto. Para los catorce estándares, esa sustitución está definida y es benigna. Para todo lo demás, va desde un caso aproximado en un tipo de letra diferente hasta el resultado de cuadro vacío cuando ningún sustituto cubre el script en absoluto
Con HotPDF el control es una sola propiedad, que se establece antes de que se abra el documento. FontEmbedding le dice a la biblioteca que empaquete las tipografías con los que dibuja en el archivo:
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'report.pdf';
Pdf.Compression := cmFlateDecode;
Pdf.FontEmbedding := True; // los contornos viajan dentro del archivo
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('Calibri', [], 11);
Pdf.CurrentPage.TextOut(72, 760, 0, 'Esto se renderiza igual en una computadora sin Calibri.');
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
El orden no es cosmético. BeginDoc es donde HotPDF confirma la estructura del documento, por lo que FontEmbedding debe ser verdadero antes de esa llamada. Asígnelo después y no habrá ningún error, ninguna advertencia, solo un archivo que salió silenciosamente sin sus fuentes. Ese es el peor tipo de error: pasa cada prueba en la computadora del desarrollador, donde resulta que la fuente está instalada, y solo aparece en la de un cliente, donde no lo está
La incrustación también es donde las licencias se encuentran con la ingeniería. Un programa de fuentes lleva indicadores que describen si se puede incrustar libremente, solo para vista previa o no en absoluto. Respetar esos indicadores es su responsabilidad, no del renderizador, y "funcionó" no es lo mismo que "estaba permitido"
Subconjuntos: incrustar solo los glifos que usó
La incrustación completa escribe el programa de fuentes completo en el archivo. Una cara TrueType grande CJK puede abarcar varios megabytes, y incrustarla completa para mostrar una docena de caracteres es un desperdicio de una manera que se agrava en un documento de varias páginas. La creación de subconjuntos resuelve esto escribiendo solo los glifos a los que hace referencia el documento, para luego cambiar el nombre de la fuente con una etiqueta de seis letras y un signo más, la forma ABCDEF+Calibri en la lista de fuentes de cualquier PDF en subconjunto, para que un lector nunca confunda la cara parcial con una fuente completa del sistema con el mismo nombre
Para la mayoría de los documentos generados, el subconjunto es el valor predeterminado correcto. Mantiene el tamaño del archivo proporcional al contenido en lugar de a la fuente original, lo que es más importante para las fuentes multilingües grandes que de otro modo dominarían el archivo. La única advertencia es que un subconjunto solo contiene lo que se usó en el momento de la creación. Si un proceso posterior intenta agregar texto a una fuente con subconjuntos más adelante, los glifos que necesita pueden no estar en el archivo, una restricción real para la edición incremental del PDF de otra persona
Fuentes Unicode y el problema de las cajas CJK
Cuando el texto no es latino simple, el camino de la fuente simple se agota y la solución es registrar una fuente con capacidad Unicode explícitamente y permitir que HotPDF construya una fuente Type 0 a partir de ella. RegisterUnicodeTTF carga un archivo TrueType por ruta; a partir de ahí el nombre registrado se puede usar en SetFont como cualquier otro:
Pdf.FontEmbedding := True;
Pdf.RegisterUnicodeTTF('C:\Fonts\NotoSansCJKsc-Regular.ttf');
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('NotoSansCJKsc-Regular', [], 14);
Pdf.CurrentPage.TextOut(72, 720, 0, '你好,世界 こんにちは 안녕하세요');
Pdf.EndDoc;
Dos cosas deciden el éxito o el fracaso de esto. La fuente tiene que cubrir los scripts de la cadena: un TrueType solo latino no generará glifos chinos porque se lo pida, y el resultado vuelve a ser cuadros vacíos, esta vez porque el glifo genuinamente no existe en ese tipo de letra. Y la incrustación debe permanecer activada, porque una fuente Type 0 ensamblada a partir de un TTF registrado no tiene sentido para un lector que no puede encontrar los contornos. Para el contenido mixto, la opción duradera es un tipo de letra de amplia cobertura, siendo las familias Noto y Arial Unicode MS las respuestas habituales, incrustadas y en subconjuntos
Los scripts de derecha a izquierda y complejos agregan una capa de formato además de la cobertura. HotPDF expone RtLTextOut para árabe y hebreo, que maneja el reordenamiento direccional, de manera que usted pasa el orden lógico y deja que la biblioteca lo diseñe. Lograr un árabe correcto es cobertura más formato más dirección, tres cosas separadas, y una caja allí puede significar que cualquiera de ellas falló
La tabla ToUnicode: donde vive el copiar y pegar
Todo lo anterior concierne al dibujo. La extracción es la imagen especular y falla por sus propias razones. Un visor renderiza una página usando la asignación de código a glifo de la fuente, pero cuando un usuario selecciona texto y lo copia, el visor necesita convertir esos mismos códigos nuevamente en Unicode. Esa asignación inversa es el CMap ToUnicode, un flujo opcional adjunto a la fuente
Cuando está presente y es correcto, el texto copiado sale como los caracteres correctos. Cuando está ausente o es incorrecto, o la fuente fue subdividida con códigos de glifos personalizados y no se escribió ningún ToUnicode, la página se ve perfecta y el portapapeles se llena de basura: códigos de glifos que se leen como si fueran Unicode, que para un subconjunto con codificación personalizada no lo son. Esta es la razón por la que un documento escaneado con una capa de texto OCR puede permitir búsquedas mientras que un PDF nacido en formato digital de un generador descuidado no lo es. La renderización y la extracción se basan en tablas diferentes, por lo que un archivo puede satisfacer una y fallar en la otra. Si la extracción es importante para su resultado, trate un mapa ToUnicode correcto como un requisito y verifíquelo copiando texto de una muestra en lugar de confiar en que está allí
Cómo diagnosticar rápidamente un error de fuente
El modo de fallo le indica dónde buscar. Los cuadros vacíos en otra computadora casi siempre significan una fuente que no estaba incrustada, así que verifique primero la incrustación y en segundo lugar la cobertura de glifos. Los cuadros que aparecen incluso en su propia computadora apuntan a la cobertura: la fuente no contiene ese script, independientemente de la incrustación. El texto que se renderiza correctamente pero se copia como tonterías es un problema de ToUnicode, no un problema de renderización, y jugar con fuentes o incrustaciones no lo solucionará porque el dibujo nunca estuvo dañado. Para leer un archivo terminado, ábralo en Acrobat y mire en Propiedades del documento, Fuentes: una entrada en buen estado muestra el tipo, dice Incrustado o Subconjunto incrustado y nombra la codificación. Una fuente que debería estar incrustada y no lo está se anuncia allí antes de que lo haga un cliente
Nada de esto es exótico una vez que queda clara la división entre carácter, código y glifo. Incruste las fuentes con las que dibuja, cree subconjuntos para las grandes, busque un tipo de letra Unicode y use RegisterUnicodeTTF en el momento en que el texto deje de ser latino, y mantenga un mapa ToUnicode correcto si alguien va a extraer el texto. Si hace eso bien, las cajas dejan de aparecer. Para la mecánica circundante, la anatomía de un PDF mínimo muestra dónde se asienta el diccionario de fuentes en el árbol de objetos, y el recorrido de la estructura del documento cubre cómo se comparten los recursos entre páginas
Las llamadas SetFont, FontEmbedding y RegisterUnicodeTTF mostradas aquí son parte del Componente HotPDF para Delphi y C++Builder