El blog personal de Morgul, donde escribe sobre sus aficiones, descubrimientos y actividades, compartiendo conocimientos.

30 de noviembre de 2008

Cómo usar fuentes TrueType en PDFLaTeX

El otro día estuve investigando el modo de poder utilizar fuentes tipográficas TrueType (con extensión de fichero .ttf) para los documentos PDF que genero desde LaTeX, mediante sus herramientas PDFLaTeX o PDFeLaTeX. Por cierto, mi distribución LaTeX es TeTeX, que está siendo sustituida hoy en día por TeX Live, puesto que su autor ha dejado de mantenerla.

La información que aparece al respecto en los primeros resultados de búsqueda de los buscadores web más conocidos está en gran parte obsoleta, puesto que fue redactada más de cinco años atrás y las herramientas que utilizaban en aquella época ya no funcionan del mismo modo (por ejemplo, aceptan distintos parámetros desde la línea de comandos).

Después de un buen rato probando distintos métodos antiguos en vano, al final encontré una página web que estaba más al día con respecto a las herramientas y versiones de LaTeX que existen actualmente (en inglés): http://tclab.kaist.ac.kr/ipe/pdftex.html

Gracias al tutorial 'Using a Truetype font in Pdflatex' sito en esa misma página, conseguí por fin utilizar fuentes TrueType desde LaTeX. Sin embardo, tuve que deducir a base de prueba y error el procedimiento preciso para conseguir esto, puesto que ese tutorial no muestra el suficiente detalle para poder reproducir la proeza. Por tanto, para que no se me olvide y por si a alguien más le resulta útil, redactaré aquí de un modo sencillo y paso por paso cómo hice para conseguir usar fuentes TTF con LaTeX.

El sistema con el que he trabajado es una Gentoo Linux, con la distribución (de LaTeX) TeTeX, versión 3.0 (versión del ebuild de Gentoo: 3.0_p1-r6). Sin lugar a duda, la metodología que voy a describir servirá para otras versiones de TeTeX, posiblemente también sirva para otras distribuciones de LaTeX (si os funciona en otra, hacédmelo saber) y, por supuesto, será independiente de la distribución de Linux.
  1. Crea un carpeta de trabajo temporal, copia en ella el fichero con el tipo de letra TrueType que quieras utilizar con LaTeX. Desde ahora supondremos que este fichero se llama fuente.ttf
  2. Comprueba si tu sistema dispone de la herramienta ttf2tfm. Por ejemplo, intenta ejecutarla desde la línea de comandos, con la orden ttf2tfm. Si ya dispones de ella, descarga el fichero T1-WGL4.enc desde esta URL hasta la carpeta de trabajo temporal y salta al paso 12.
  3. Comprueba que tienes la herramienta de control de versiones CVS instalada, así como un entorno de desarrollo GCC funcional. Esto es un requisito, por lo que será necesario que instales lo que le falte a tu sistema.
  4. Desde la consola, cambia a un directorio de tu elección donde tengas permisos de escritura.
  5. Descarga el código fuente de la versión 1 de la librería FreeType desde su repositorio CVS, con el siguiente comando: cvs -z3 -d:pserver:anonymous@cvs.savannah.nongnu.org:/sources/freetype co freetype
  6. Accede al nuevo directorio freetype con: cd freetype
  7. Descarga el código fuente de las herramientas adicionales para la versión 1 de la librería FreeType desde su repositorio CVS, con el siguiente comando: cvs -z3 -d:pserver:anonymous@cvs.savannah.nongnu.org:/sources/freetype co freetype1-contrib
  8. Dale permisos de ejecución a los dos ficheros configure que utilizaremos, con la orden: chmod +x configure freetype1-contrib/ttf2pk/configure
  9. Compila la librería FreeType 1, con: ./configure y a continuación: make
  10. Compila la herramienta ttf2tfm, cambiando primero al directorio donde se encuentra: cd freetype1-contrib/ttf2pk y ejecutando: ./configure y a continuación: make. Si todo ha ido bien, el ejecutable de la herramienta ttf2tfm estará en esta carpeta.
  11. Copia a la carpeta de trabajo temporal el fichero T1-WGL4.enc, que estará en el directorio .../freetype/freetype1-contrib/ttf2pk/data
  12. Accede a la carpeta de trabajo temporal y convierte el fichero de tipo de letra TrueType al formato tfm, ejecutando la orden: ttf2tfm fuente.ttf -p T1-WGL4.enc (debes añadir la ruta al ejecutable ttf2tfm en caso necesario).
  13. Crea un fichero de texto con nombre t1fuente.fd (cambia fuente según corresponda), con el siguiente contenido:
    \DeclareFontFamily{T1}{fuente}{}
    \DeclareFontShape{T1}{fuente}{m}{n}{
    <-> lhandw
    }{}
    \DeclareFontShape{T1}{fuente}{bx}{n}{<->ssub * fuente/m/n}{}
    \DeclareFontShape{T1}{fuente}{m}{it}{<->ssub * ptm/m/it}{}
    \DeclareFontShape{T1}{fuente}{m}{sl}{<->ssub * ptm/m/sl}{}
    \DeclareFontShape{T1}{fuente}{m}{sc}{<->ssub * ptm/m/sc}{}
    \DeclareFontShape{T1}{fuente}{bx}{it}{<->ssub * ptm/b/it}{}
    \DeclareFontShape{T1}{fuente}{bx}{sl}{<->ssub * ptm/b/sl}{}
    \DeclareFontShape{T1}{fuente}{bx}{sc}{<->ssub * ptm/b/sc}{}
    \pdfmapline{+fuente\space
  14. Copia desde la carpeta de trabajo los ficheros fuente.ttf, fuente.tfm, t1fuente.fd y T1-WGL4.enc a la carpeta donde se encuentre el código fuente de tu documento LaTeX. El resto ficheros en la carpeta de trabajo temporal ya pueden eliminarse, así como también el código fuente de FreeType, a menos que quieras aplicar el proceso a más fuentes TrueType.
Con esto, ya podrás utilizar esta fuente TrueType como cualquier otra fuente incluida en tu distribución LaTeX, teniendo en cuenta que su codificación es T1. Por ejemplo, puedes usar la fuente temporalmente en una sola frase usando el siguiente código LaTeX:
{{\fontencoding{T1}\fontfamily{fuente}\selectfont Esto es una prueba tipográfica.}}

¿Te ha gustado esta entrada? Vótala en Bitacoras.com: Votar

23 de noviembre de 2008

MUnDoCAAD MUD Engine: pasado y presente

Se ha notado muchísimo que he sido el único desarrollador del motor del MUD para nuestro 'MUnDoCAAD' (el MUnDoCAAD MUD Engine), así como que no tenía mucha idea de cómo implementar un MUD... muestra de ello ha sido el largo tiempo que me ha llevado programar algo funcional, elegante y potente.

MUnDoCAAD MUD Engine nació en enero de 2003 (edito: aunque partes de él fueron programadas en 2002), escrito en C++ y usando tanto sockets POSIX como WinSocks (que eran un churro, puesto que se comían toda la CPU con madalenas al esperar en las llamadas select), según la plataforma de compilación usada (UNIX o Windows, respectivamente). Más tarde descubrí que la librería Qt proporcionaba manejo de sockets y otras abstracciones del sistema operativo que harían el código compatible no sólo en sistemas UNIX y Windows sino también para Mac OS, así que reescribí parte del código para hacerlo más portable utilizando la Qt.

La pega de la Qt - versión 3 en aquél entonces - era que requería enlazar con las librerías de interfaz gráfica, y ejecutarse desde X Window en sistemas UNIX, a pesar de que el motor del MUD no era más que una aplicación de consola.

Luego salió la versión 4 de la librería Qt, que permitía por fin independizarse de las librerías de interfaz gráfica. Mejoró mucho el código del motor del MUD por aquél entonces, pero sobre todo mejoró mi comprensión de qué debería tener el motor funcionalmente para manejar un MUD. Gracias a la Qt, ya me despreocupaba en gran medida del aspecto de comunicaciones en red, y mis ideas de diseño giraban en torno al almacenamiento de la base de datos del MUD y su cacheo en memoria (para evitar tener en memoria toda la base de datos se utilice o no, y no tener que estar guardando a disco constantemente las modificaciones realizadas).

Desde los inicios, pensé usar XML para almacenar las entidades (objetos, localidades, personajes y demás) del MUD en la base de datos. Creo recordar que llegué a implementar completamente la carga y almacenamiento de entidades con la librería libxml2, aunque revisando el historial del repositorio CVS de nuestro proyecto en SourceForge no encuentro dicha evidencia. En cuanto empecé a usar la librería Qt para el motor, me aproveché de las clases para el manejo de documentos XML que trae esta, de manera bastante similar a como se hacía con la libxml2.

Sin embargo, era relativamente lento cargar y escribir documentos XML para el poco contenido que tenía cada uno (los datos propios de cada entidad del MUD, pues pensé en almacenar cada una en un fichero aparte). No obstante, al tener el sistema de caché ya implementado (de nombre Archivero, en memoria de El Viejo Archivero), este amortiguaba un poco este impacto de coste temporal.

Llegué al punto en que tuve que plantearme cómo implementar la librería base, también llamada el modelo de mundo. No podía implementarla como el resto del motor, usando C++, puesto que cualquier cambio implicaría tener que recompilar y reiniciar el motor del MUD para que surtiera efecto. Debía utilizar algún lenguaje interpretado, que fuera ejecutado desde el motor del MUD. Pero yo no sabía ni quería embarcarme en la costosa tarea de inventar un lenguaje para el MUD.

Más tarde, descubría la librería QSA: Qt Scripting for Applications. Esta me proporcionaba un lenguaje interpretado y un intérprete para ejecutar su código desde aplicaciones que usaran la librería Qt. "Genial" - pensé, y me puse a implementar la librería base del MUD con este lenguaje, muy similar a C++ (el lenguaje era un subconjunto de ECMAScript, íntimamente relacionado con JavaScript).

Pronto descubrí limitaciones en esta forma de implementación del motor del MUD. Al parecer, QSA por aquella época tenía ciertos fallos al convertir variables y objetos del lenguaje QSA a variables Qt, y tuve que hacer apaños para solventar dichos problemas. Para colmo, QSA hacía que tuviera que volver a enlazar con librerías de interfaz gráfica, aunque esta vez no me obligaba a ejecutar el motor del MUD desde X Window en mi entorno de desarrollo Linux.

Por todo esto, y por la infactibilidad de la ejecución de código almacenado en las entidades de la base de datos (código relacionado con la reacción de las entidades ante acciones de los personajes o del modelo de mundo) de manera elegante y potente, abandoné por completo el desarrollo del MUD.

Por suerte, durante los dos siguientes años a este abandono, he descubierto el lenguaje Python y lo fácil y rápido que es programar en él. Era cuestión de tiempo que me planteara intentar reescribir MUnDoCAAD MUD Engine por completo en Python, así como usar Python mismo como el lenguaje interpretado embebido en las entidades del MUD.

Y así fue, hace unos pocos meses atrás ya estaba implementando una caché LRU para almacenar las entidades. Después vino la implementación del módulo Archivero (reutilicé el nombre de su predecesor en C++/Qt), utilizando mi flamante caché LRU en Python. Esta vez descarté usar XML como formato de los ficheros de entidad, a pesar de tener buen soporte en Python, porque no quería que fuera costosa la lectura y escritura de cada entidad de la base de datos, y utilicé en su lugar las ventajas del módulo cPickle de Python.

Los resultados eran más que satisfactorios: código sencillo, funcional y rápido de desarrollar. El mismo código que empezaba a escribir como prueba (en plan chapucilla) de la funcionalidad que quería, terminaba convirtiéndose en poco tiempo en código correcto y completo funcionalmente.

Hace unas pocas semanas, empecé a escribir lo que sería el nuevo módulo Servidor del mud, usando la implementación de sockets que trae Python. Tan sencillo empezó siendo este módulo, que sólo permitía una conexión simultánea al MUD, y durante bastante tiempo siguió así, como un motor para aventuras conversacionales tradicionales (de un sólo jugador) que requería conectarse por Telnet para jugar.

Se me ocurrió implementar la aventura conversacional del tutorial 'La Torre - Contruye tu propia aventura' creado por Uto para NMP y adaptado a InformATE! por Zak, porque quería comprobar si el nuevo motor en Python era capaz de dar vida a algo jugable. Inicié una base de datos de MUD con las entidades de la aventura de este tutorial, así como un parser (analizador sintáctico) muy sencillo de tipo VERBO + NOMBRE, y una librería modelo de mundo con vistas a que el juego eventualmente pudiera ser utilizado por varios jugadores a la vez.

Estaba tan contento de ver que todo funcionaba bien y que el motor Python era perfectamente capaz, que quería enseñárselo a mis colegas del CAAD, y les hablé de él en el canal de IRC y de su posible futura evolución. Esto ocurría ya hace menos de una semana. Para poder enseñar mi creación tenía que hacer que pudiera conectarse más de un jugador a la vez, así que implementé un módulo Servidor que atendiera las conexiones de red del MUD, para lo cual utilicé el módulo asyncore de Python en lugar de trabajar con los sockets directamente.

Aumenté la librería base y el parser para que los jugadores pudieran ver cómo los personajes cambiaban de localidad y añadí el comando decir, para que pudieran hablar entre ellos. Hice una invitación en el IRC, y se apuntaron unos cuantos a probar el nuevo MUD. Inmediatamente relució un fallo en el código de la librería base, ya que nombraba a los personajes así: "Aquí está un Juan, un Pepe y un Jacinto", en lugar de decir: "Aquí está Juan, Pepe y Jacinto". Corregí este fallo en un periquete, y descubrí que conforme estaba implementado el motor, para que la corrección surtiera efecto sólo podía reiniciar el MUD.

Estando el MUD con jugadores conectados, no es una opción factible echarlos a todos cada vez que se haga una corrección a la librería del modelo de mundo o a alguna otra parte del motor. Así que investigué un poco e implementé un módulo (Restaurador) que recarga a petición del administrador los módulos del motor del MUD que se deseen, incluido él mismo. Desde entonces el MUD puede mejorarse dinámicamente, sin necesidad de reinicios.

Algunos jugadores tenían problemas para leer y escribir tildes y eñes en el MUD, debido a que ellos usan la codificación de caracteres UTF-8 y el motor trabaja con ISO-8859-15. Así que también añadí a MUnDoCAAD MUD Engine la capacidad de realizar conversión de código de caracteres para aquellos jugadores que así lo deseen.

Básicamente, el motor del MUD en Python cuenta con toda la funcionalidad de su predecesor en C++/Qt, además de tener nuevas características que difícilmente habría podido implementar en aquél (ahora obsoleto) motor. Podría decir que este es el mejor MUD que he creado nunca :)

Por cierto, el código fuente del nuevo motor Python es GPL versión 2 (igual que el antiguo), y ya está disponible en el repositorio Subversion del proyecto en SourceForge: https://sourceforge.net/projects/mundocaad

¿Te ha gustado esta entrada? Vótala en Bitacoras.com: Votar