
El formato de imagen PCX: Parte 2 Final
@retrotech-cuba
Posted 21h ago · 10 min read
El formato de imagen PCX: Parte 2 Final

Imagen creada usando Gemini
Introducción
En la parte anterior de este artículo, estuvimos viendo todo lo referente a la organización interna de un archivo de imagen PCX, lo cual como se comentó puede ser útil para comprender cómo están diseñados otros formatos de archivo de imagen de mapa de bits.
En muchos de estos formatos se utiliza la misma compresión RLE para reducir el tamaño del archivo de imagen en disco, y debido a la relativa simplicidad de un PCX resulta idóneo para empezar a estudiar estos contenidos.
En cambio, en esta segunda parte, vamos a dedicarnos a escribir código para mostrar una de estas imágenes en pantalla usando QuickBASIC.
Por si no lo recuerdan, existen distintas variantes o versiones de archivos ".pcx", casi todas pensadas para usar una paleta de colores debido a la práctica común de la época por las limitaciones de memoria de video, no obstante, como se comentó en la primera parte del texto, nosostros nos vamos a centrar en mostrar en pantalla una imagen ".pcx" con soporte para 16 colores (4 BPP).
En realidad no existen tantas diferencias entre las distintas variantes, además de la colocación dentro del archivo de imagen de la paleta de colores, o la ausencia de esta si se trata de la versión para color verdadero. Por eso el procedimiento va a ser bastante parecido en todas las versiones donde se usa una paleta de colores salvo por algunos detalles, puesto en este caso en particular para 16 colores cada byte de la zona de datos del archivo representa dos pixel consecutivos de la imagen en lugar de uno solo como sucede con la variante para 256 colores (8 BPP). Pero en la práctica es necesario tener presente estas diferencias y detectar la versión del archivo de imagen a partir de los datos guardados en la cabecera para ese cometido, porque a la hora de mostrar la imagen en pantalla es imprescindible tener presente hasta el más mínimo detalle o no nos será posible presentarla correctamente.
Nota: En el caso de la versión de PCX para una imagen en color verdadero las diferencia en la interpretación pueden resultar más importantes.
En resumen, para cuando terminemos de escribir este código en QuickBASIC, podremos mostrar en pantalla una imagen PCX de 16 colores como se expone en la siguiente captura de una ventana de DOSBox:

En la captura expuesta se muestra una foto de la cantante israelí Ofra Haza convertida a PCX de 4 BPP (usando IrfanView de IrfanSkiljan); en otro espacio mío compartí hace poco un comentario sobre una canción interpretada por esta artista ahora desaparecida y pueden escucharla en: @pcarballosa/musica-israeli-jerusalen-de-oro?referral=retrotech-cuba">🔗 Jerusalén de Oro
Nota: La pobre calidad de la imagen mostrada no se debe ni a la implementación ni a la imagen en sí misma, sino a la pérdida de calidad en ella cuando se la convierte desde una imagen de color verdadero (como era en principio) a una imagen de sólo 16 colores, debido a no disponer de imágenes originales de 16 colores en formato PCX.
Por cierto, me olvidaba de mencionarlo, para llevar a cabo esta tarea utilicé DOSBox y Microsoft QuickBASIC 4.5, si bien no es obligatorio hacerlo así, y se puede usar un entorno como QB64 para poder programar con código QuickBASIC directamente en un Windows moderno de 64 bits, dado estos Windows no tienen soporte para programas de MS-DOS de 16 bits.
De hecho, si descargan el código fuente disponible más adelante, podrán encontrar además de éste y de la imagen, el programa compilado tanto con QuickBASIC 4.5 para correr en un MS-DOS o en un emulador como DOSBox como un programa compilado con QB64 para correrlo directamente en un Windows de 64 bits.
Nota: En caso de necesidad para comprender detalles del formato de imagen PCX, la primera parte de este artículo pueden verla a partir del enlace: @retrotech-cuba/el-formato-de-imagen-pcx?referral=retrotech-cuba">🔗 Parte 1
El programa principal
Las líneas de código mostradas seguidamente resumen el programa principal hecho en QuickBASIC:
DefInt A-Z
DECLARE SUB GetBPCXData (PCXData AS STRING, FileNumber AS INTEGER)
DECLARE SUB ShowPCXRLE4Bits (FileName AS STRING, XResolution AS INTEGER, YResolution AS INTEGER)
Dim XResolution As Integer
Dim YResolution As Integer
Screen 12
XResolution = 640
YResolution = 480
On Error GoTo ErrorHandler
ShowPCXRLE4Bits "Ofra4BPP.pcx", XResolution, YResolution
While InKey$ = ""
Wend
End
ErrorHandler:
Screen 0
Select Case Err
Case 100
Print
Print "La imagen a cargar no parece estar en formato PCX (*.pcx)"
Print
End
Case 101
Print
Print "El programa espera una imagen PCX comprimida con RLE y con una profundidad de color de 16 colores"
Print
End
Case 105
Print
Print "El programa encontró un final inesperado del archivo de imagen PCX, es posible el archivo esté‚ dañado"
Print
End
Case Else
Print
Print "El programa terminó con un error inesperado"
Print
End
End Select
La líneas de código mostrada definen un par de subrutinas encargadas de llevar a cabo la tarea de interpretar y mostrar el ".pcx" en la pantalla, establecen un modo de video 12 de 640x480 pixel con 16 colores, y llaman a la subrutina ShowPCXRLE4Bits en la cual está el código capaz de interpretar una imagen de 4 Bits por pixel y comprimida usando RLE.
Por lo demás, el código se limita a tratar algunos errores lanzados por dichas subrutinas en caso de encontrar una anomalía.
La subrutina GetBPCXData
La subrutina GetBPCXData se dedica a leer un byte del archivo PCX, y es utilizada por la subrutina ShowPCXRLE4Bits para ir obteniendo los datos según los necesite.
El código a continuación pertenece a la implementación de esta subrutina:
Sub GetBPCXData (PCXData As String, FileNumber As Integer)
Dim Dat As String * 1
Get FileNumber, , Dat
If EOF(FileNumber) Then Error 105 'Final de archivo inesperado
PCXData = Dat
End Sub
En este caso se trata de una subrutina bastante simple, la cual devuelve el byte leído a través del parámetro por referencia PCXData, declarado como un String puesto QuickBASIC no dispone de un tipo de dato Byte y se suele emular con una cadena de caracteres de un solo caracter.
La subrutina ShowPCXRLE4Bits
El centro del proceso de mostrar el archivo ".pcx" en pantalla se encuentra en la subrutina ShowPCXRLE4Bits la cual se lista a continuación:
Sub ShowPCXRLE4Bits (FileName As String, XResolution As Integer, YResolution As Integer)
Dim FileNumber As Integer
Dim PCXId As Integer
Dim PCXVersion As Integer
Dim RLEEncode As Integer
Dim BitsPerPixel As Integer
Dim ImageWidth As Long
Dim ImageHeight As Long
Dim ColorPlanes As Integer
Dim BytesPerLine As Long
FileNumber = FreeFile
Open FileName For Binary As FileNumber
Dim PCXFileHeader(127) As String * 1
Dim i As Integer
'Los datos de la cabecera son leídos
For i = 0 To 127
GetBPCXData PCXFileHeader(i), FileNumber
Next
PCXId = Asc(PCXFileHeader(0))
PCXVersion = Asc(PCXFileHeader(1))
RLEEncode = Asc(PCXFileHeader(2))
BitsPerPixel = Asc(PCXFileHeader(3))
ImageWidth = Asc(PCXFileHeader(9)) * 2 ^ 8 + Asc(PCXFileHeader(8))
ImageHeight = Asc(PCXFileHeader(11)) * 2 ^ 8 + Asc(PCXFileHeader(10))
ColorPlanes = Asc(PCXFileHeader(65))
BytesPerLine = Asc(PCXFileHeader(67)) * 2 ^ 8 + Asc(PCXFileHeader(66))
If PCXId <> 10 Then Error 100 'No es un PCX
If PCXVersion <> 5 Or RLEEncode <> 1 Or BitsPerPixel <> 4 Or ColorPlanes <> 1 Then Error 101 'No es un PCX del formato esperado
'Cargar la paletta VGA de 16 colores de la cabecera
For i = 0 To 15
Palette i, Int(Asc(PCXFileHeader(i * 3 + 18)) / 4) * 65536 + Int(Asc(PCXFileHeader(i * 3 + 17)) / 4) * 256 + Int(Asc(PCXFileHeader(i * 3 + 16)) / 4)
Next i
Dim Dat As String * 1
Dim ColorCode As Integer
Dim Count As Integer
Dim OriginX As Integer
Dim OriginY As Integer
Dim x As Integer
Dim y As Integer
OriginX = XResolution / 2 - ImageWidth / 2
OriginY = YResolution / 2 - ImageHeight / 2
x = OriginX
y = OriginY
Do While y - OriginY < ImageHeight
GetBPCXData Dat, FileNumber
ColorCode = Asc(Dat)
Count = 1
If ColorCode > 192 Then
Count = ColorCode - 192
GetBPCXData Dat, FileNumber
ColorCode = Asc(Dat)
End If
For i = 1 To Count
PSet (x, y), (ColorCode And 240) / 16
x = x + 1
PSet (x, y), ColorCode And 15
x = x + 1
If x - OriginX > ImageWidth Then
y = y + 1
x = OriginX
End If
Next i
Loop
Close FileNumber
End Sub
En la subrutina primeramente se declaran una serie de variables para obtener valores claves de la cabecera de la imagen, si bien esto también se puede hacer usando una estructura con los elementos correspondientes de la cabecera, y así se podría leer toda la cabecera en una sola operación.
En este caso se lo hizo de manera distinta, y la cabecera se lee en un arreglo de 128 byte para posteriormente obtener los datos leídos en el arreglo y guardarlos en las variables correspondientes; estos datos se leen de byte en byte a través de la subrutina GetBPCXData, si bien también podrían leerse de una sola vez.
Los datos leídos en el arreglo, como se ha dicho, se guardan en las distintas variables, y para esto es necesario tener presente que cuando se trata de valores de más de un byte están guardados en la cabecera usando el formato conocido como punta delgada (Little Endian), por lo cual deben intercambiarse los byte como pueden ver se lo hace.
Nota: El alto y el ancho de la imagen se guardan en la cabecera usando un entero sin signo, pero como QuickBASIC no dispone de enteros sin signo, se usó un dato Long de modo no se produzcan errores debidos a una mala interpretación de los valores.
En lo adelante se leen los datos de la paleta de colores de la cabecera en el arreglo, puesto en los PCX de 16 colores esa es la paleta utilizada, la paleta de la cabecera del archivo de imagen, y después se interpretan sus valores a medida se va cargando la paleta VGA de QuickBASIC con la instrucción Palette.
Por fin se procesan los datos de la imagen usando un bucle Do While, obteniendo los byte de la zona de datos o mapa de bits del archivo de imagen, y se muestran en pantalla los pixeles en sus posiciones relativas usando una instrucción PSet.
Los bytes obtenidos deben distinguirse, porque como se supone se utiliza compresión, estos pueden ser tanto un indice de color de la paleta como un número de la cantidad de veces a repetir un color, y por eso se comparan los valores con 192.
En caso de ser un índice de un color en la paleta (valor del byte menor a 192), se tiene presente que cada byte leído contiene dos códigos de color, puesto cada color del un pixel en esta versión de un ".pcx" para 16 colores se represente con 4 bits (4 BPP).
Por lo demás todo debe estar bastante claro, si se conocen los detalles del formato PCX expuestos en la primera parte del texto, y se estudia con detenimiento el código presentado ahora en la implementación.
Código fuente
Los interesados pueden descargar el fuente de la implementación para mostrar una imagen PCX de 16 colores por medio de este enlace: 🔗 PCX4BPP.zip
Nota: El archivo comprimido también contiene el programa compilado con QuickBASIC 4.5 y con QB64 para poder correrlo directamente en un MS-DOS o un emulador o en un Windows de 64 bits respectivamente.
¿Qué te ha parecido esta última parte?
Tú participación aportando ideas, dando sugerencias, o expresando tu crítica constructiva a través de tus comentarios, es importante y fundamental para permitirnos crecer y crear contenidos con cada vez más calidad.
También es importante tu voto si crees vale la pena concederlo.
¡Nos vemos en otro artículo sobre retroinformática!
Estimated Payout
$0.85
Discussion
No comments yet. Be the first!