Lithographica

Un cuaderno más de Juan Antonio Fernández Madrigal

Las imágenes del ZX Spectrum

Julio25/2011

Pedazo de entrada retro-friqui que os espera ;)

De vez en cuando me da la nostalgia ochentera, habitualmente coincidiendo con la cercanía a las vacaciones de verano (no me preguntéis por qué), y con bastante probabilidad me da en lo relacionado con esa maravillosa máquina, el ZX Spectrum, con el que se nos descubrió un nuevo mundo a tantos niños y no tan niños de la época.

Normalmente la cosa se resuelve visitando una vez más WorldOfSpectrum, echando unas partidillas a mis adorados Xeno y Manic Miner, y pensando por enésima vez por qué aquel emulador de Spectrum que me hice en 1991 para un i286 no me dio por hacerlo diez años después, que seguro que podía haberlo terminado mejor (con mucha más documentación disponible de la que yo tuve); ahora podría estar incluido en la lista de emuladores.

En fin. Esta vez me ha dado la picá por otro lado. No sé cómo he acabado pensando que podría ser curiosón el poder convertir imágenes bitmap a la apariencia que tenían las imágenes en el ZX Spectrum, y, ya puestos, hacer un plug-in para el programa de diseño gráfico GIMP que haga esa transformación. Hay alguna utilidad por ahí relacionada con la conversión de imágenes del Spectrum, pero no algo como lo que propongo en forma de plug-in de GIMP. Así que, ni corto ni perezoso, me he puesto a la tarea :)

Las imágenes del ZX Spectrum en su modo gráfico original, es decir, sin usar hardware/software especial que consiguiera incrementar la resolución, eran bitmaps de 256×192 píxeles, con el píxel 0,0 en la esquina inferior izquierda si mal no recuerdo (estoy escribiendo de memoria). Estos píxeles no se podían poner a ningún color concreto, sólo a apagado (0) o encendido (1), lo que suponía 256×192/8=6144 bytes de información que estaban almacenados a partir de la dirección 16384 de la RAM, es decir, justo tras los primeros 16KB de la ROM del sistema.

El color era el verdadero meollo de la historia de los gráficos de Spectrum. La paleta del ZX (de la que ya hablamos por aquí) tenía 8 colores, algunos de los cuales se observan en la esquina inferior derecha de la carcasa de la foto de arriba. Si Sir Clive Sinclair hubiera querido que pudiéramos especificar uno de esos 8 colores por cada píxel del bitmap, a tres bits por píxel, hubiera gastado un total de 256x192x3/8=18432 bytes de memoria para la imagen de pantalla, en lugar de los 6144 del blanco y negro. Definitivamente, 18KB era algo prohibitivo para la época, especialmente teniendo en cuenta que la RAM del Spectrum era de 48KB: con esa capacidad gráfica sólo hubieran quedado 30KB para variables del sistema, programas del usuario y pila de la CPU. Pero mucho peor: hubiera habido bastantes problemas de rendimiento a la hora de que una CPU Z80A a 3.47MHz direccionara los píxeles y no digamos ya de que hiciera animación, por mucho que yo siga admirando a esa CPU.

La solución no pudo ser más ingeniosa, a la par que enrevesada a la hora de su uso posterior: dividamos los 256×192 píxeles en celdas de 64 píxeles cada una (de 8×8 píxeles, para ser exactos), y asignemos un byte extra a cada celda, llamado “atributo”, que indique el color que tienen los píxeles de esa celda que estén a 0 -píxeles de “papel”- y el que tienen los píxeles que estén a 1 -píxeles de “tinta”. Además, al dividir la imagen en celdas de 8×8 podemos montar un modo texto además del modo gráfico, con sus rutinas específicas: en cada celda se podrá dibujar un carácter, pudiendo tener en pantalla 24 líneas por 32 columnas de texto. Bondadoso que es el destino: si dedicamos 1 byte al atributo de cada celda, dado que especificar un color, ya sea el de tinta o el de papel, ocupa 3 bits, nos quedan todavía 2 bits libres para jugar. Uno de ellos se dedicó al “brillo”, y otro al “parpadeo”. El esquema final de un byte cualquiera de atributo quedó así:

Lo del brillo es otra genialidad: con ese bit a 1 cualquier atributo podía indicar que los colores de papel y tinta no vinieran de la paleta original, sino de otra que contenía los mismos colores pero con más brillo -excepto el negro, que era el mismo-, es decir, que con el bit de brillo prácticamente se duplicaban los colores disponibles en la pantalla, con la salvedad de que no se podía usar un color con brillo y otro sin brillo en la misma celda.

Lo del parpadeo tenía también su enjundia: con otro bit por celda se podía hacer que el color que en ésta estaba asignado a la tinta pasara a ser mostrado en los píxeles de papel, y viceversa, intermitentemente (con una frecuencia de 1Hz, si tampoco recuerdo mal), todo eso sin necesidad de que el programador cambiara nada en memoria, puesto que lo realizaba automáticamente la ULA (uncommitted logic array), la circuitería gráfica del Spectrum. Esto del parpadeo puede parecer una tontería de poca utilidad, pero imaginad qué pasa si relleno algunas celdas de la pantalla con todos sus píxeles en tinta, otras con todos sus píxeles en papel, y activo el parpadeo: puedo montarme un cartel -con poca resolución, eso sí- que va cambiando de apariencia intermitentemente, es decir, puedo tener dos imágenes que se turnan en pantalla alegremente.

Se puede ver precisamente este efecto del parpadeo a partir del segundo 10 del siguiente vídeo, grabado del juego ya mencionado Manic Miner. También se observa claramente el típico aspecto de los gráficos del ZX Spectrum. El pedazo de borde que rodea a la imagen de pantalla estaba en principio desperdiciado: sólo se podía poner a un color, aunque si variabas ese color lo suficientemente rápido, como por ejemplo hacía la ROM mientras cargaba un programa en memoria desde la cinta de cassette, podías conseguir efectos muy curiosos.

En resumen: tenemos 6144 bytes que guardan qué píxeles de la imagen son papel y cuáles son tinta, y además otros 768 bytes a continuación de éstos, correspondientes a las 768 celdas de 8×8 píxeles que hay en una imagen de 256×192 píxeles, los cuales definen los atributos de color. El total es 6912 bytes, casi 7KB, para toda la imagen (bueno, 3 bits más si contamos el color del borde ;P), lo cual es absolutamente óptimo en términos de tamaño en memoria, funcionalidad gráfica y potencia de procesamiento. El ZX Spectrum introdujo verdaderas genialidades para su época, y este modo gráfico, por muy ridículo que nos parezca hoy en día, fue una de ellas.

Respecto al plug-in de GIMP que he escrito para transformar el aspecto de cualquier bitmap al de una imagen del ZX Spectrum no hay tanto que contar… Es fácil hacer plug-ins para GIMP, especialmente sobre sistemas Linux (GIMP también tiene versiones para otros sistemas) y programando en C. Aquí hay un tutorial que demuestra lo sencilla de usar que es la API de GIMP: te da un entorno de ejecución bastante completo donde se puede acceder a la imagen en curso.

El plug-in requiere que la imagen original sea RGB (no lo he probado pero está supuestamente preparado para trabajar también con imágenes que tengan canal de transparencia). La resolución de ésta no importa, aunque para tener una experiencia cercana a la de un verdadero ZX Spectrum es interesante reducirla primero de tamaño, concretamente a 256 píxeles de ancho (el alto da bastante igual), antes de aplicar el filtro. El plug-in se instala a sí mismo en una nueva carpeta de filtros de GIMP llamada “ZX” y no requiere ningún parámetro antes de ejecutarse. Hace la conversión directamente sobre la imagen, y usa una paleta de colores que he comprobado que es bastante parecida a la original del ZX. Incluso lo he probado sobre capturas de pantalla de emuladores del Spectrum y he validado que no cambia su contenido.

El algoritmo tiene su intríngulis porque hay que tomar algunas decisiones a la hora de reducir la gama de colores de la imagen inicial. Para empezar, se trata cada celda de 8×8 de la imagen inicial por separado (pueden sobrar píxeles en los bordes si el tamaño de la imagen original no es múltiplo de 8; éstos se mostrarán en negro). Dentro de cada celda se calcula qué color de la paleta del ZX Spectrum es más cercano al color del píxel en la imagen original, usando para ello la distancia cartesiana en el espacio tridimensional de coordenadas RGB. Tras esa conversión de color se hace un histograma para ver qué color del Spectrum aparece más frecuentemente dentro de la celda, y también cuál es el segundo más frecuente. El primero será el de tinta y el segundo el de papel -esta elección es arbitraria. Todos los píxeles de la celda que no sean del color de tinta ni del de papel serán convertidos al color de esos dos que quede más cercano en el espacio RGB. Finalmente está la decisión sobre el brillo (el parpadeo no se trata). Si ambos colores de la celda tienen el mismo brillo no hay que hacer nada. Si no, hay que cambiar uno para que tenga el mismo brillo que el otro porque sólo está permitido tener los dos con brillo o los dos sin brillo. Si uno de ellos es negro se le cambia el brillo a ése para que coincida con el brillo del otro y ya está, ya que el negro con brillo es el mismo color que el negro sin brillo. Si no es el caso, se le cambia el brillo al color que sea menos frecuente en la celda, en nuestro caso al papel. Voilà :)

Obviamente, se puede enriquecer este algoritmo con muchísimas cosas, principalmente para tener en cuenta la imagen completa y no por celdas separadas, ya que esto podría mejorar mucho la apariencia final al tomar decisiones que dependieran de la distribución global de los colores. Esto lo dejo para cuando tenga ganas de escribir el paper “Back to eighties: a new approach to draw ZX Spectrum bitmaps from RGB images” y mandarlo a algún sitio donde me lo rechacen inmisericordemente por irrelevante XDD (lástima que no exista ninguna IEEE Transactions on Freak Stuff indexada para el currículum ;P).

En este enlace podéis descargar el código fuente del plug-in. No he tenido ningún cuidado con la estructura ni elegancia del programa (aunque está bastante documentado), así que no respondo si se os caen las pestañas pensando cómo he podido hacer tal guarrerida programatística. Era pa jugar un ratillo ;) Para instalarlo en una máquina con Linux sólo hay que instalar previamente la librería de desarrollo de GIMP (libgimp-dev, típicamente en los repositorios) y luego usar la herramienta “gimptool-2.0″ desde línea de comandos como se explica en el mismo código fuente del plug-in.

Aquí dejo algunos ejemplos de lo que se puede conseguir (el último está ligeramente manipulado ;P). Podéis darle al Ctrl+ varias veces en vuestro Firefox para apreciar mejor los detalles:









(Los comentarios están deshabilitados en este blog.)

 
  • Últimas lecturas:

  • Andanzas artísticas:

  • Criaturas:

  • Creative Commons License