-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathextrae_pics_v1.py
executable file
·307 lines (278 loc) · 12 KB
/
extrae_pics_v1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# NAPS: The New Age PAW-like System - Herramientas para sistemas PAW-like
#
# Extrae gráficos de bases de datos gráficas de DAAD, en el formato de las primeras versiones de DAAD
# Copyright (C) 2008, 2018-2022 José Manuel Ferrer Ortiz
#
# *****************************************************************************
# * *
# * This program is free software; you can redistribute it and/or modify it *
# * under the terms of the GNU General Public License version 2, as *
# * published by the Free Software Foundation. *
# * *
# * This program is distributed in the hope that it will be useful, but *
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
# * General Public License version 2 for more details. *
# * *
# * You should have received a copy of the GNU General Public License *
# * version 2 along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
# * *
# *****************************************************************************
import os
import sys
from bajo_nivel import *
from prn_func import prn
try:
import png
except:
try:
import pygame.display
import pygame.image
prn ('Si quieres guardar las imágenes en formato de paleta indexada (necesario para crea_bd_pics), instala la librería PyPNG')
except:
prn ('Se necesita o bien la librería PyPNG (preferiblemente), o la librería pygame')
sys.exit()
if len (sys.argv) < 3:
prn ('Uso:', sys.argv[0], 'base_de_datos_imágenes carpeta_destino')
sys.exit()
try:
import progressbar
hayProgreso = True
except:
hayProgreso = False
bbddimg = sys.argv[1] # Ruta a base de datos DAAD de imágenes CGA/EGA/PCW
destino = sys.argv[2] # Ruta de destino de las imágenes extraídas
# Paletas CGA (1 y 2 con brillo) en el orden necesario
paleta1b = ((0, 0, 0), (85, 255, 255), (255, 85, 255), (255, 255, 255))
paleta2b = ((0, 0, 0), (85, 255, 85), (255, 85, 85), (255, 255, 85))
# Paleta EGA en el orden necesario
paletaEGA = (( 0, 0, 0), ( 0, 0, 170), ( 0, 170, 0), ( 0, 170, 170),
(170, 0, 0), (170, 0, 170), (170, 85, 0), (170, 170, 170),
( 85, 85, 85), ( 85, 85, 255), ( 85, 255, 85), ( 85, 255, 255),
(255, 85, 85), (255, 85, 255), (255, 255, 85), (255, 255, 255))
# Paleta PCW en el orden necesario, negro y verde
paletaPCW = ((0, 0, 0), (0, 255, 0))
if 'pygame' in sys.modules:
pygame.display.init() # Necesario para poner la paleta de la imagen
fichero = open (bbddimg, 'rb') # Fichero de base de datos DAAD de imágenes CGA/EGA
extension = bbddimg[-4:].lower()
bajo_nivel_cambia_ent (fichero)
le = True # Si es Little Endian
longCabeceraImg = 10 # Longitud de la cabecera de imagen
fichero.seek (2)
modo = carga_int1()
if modo == 4:
if extension in ('.dat', '.pcw'):
bpp = 1
modo = 'PCW'
else:
bpp = 2
modo = 'CGA'
elif modo == 13:
bpp = 4
modo = 'EGA'
elif modo == 0 and extension == '.dat':
bpp = 4
le = False
modo = 'ST'
longCabeceraImg = 44
else:
prn ('El fichero de entrada no es una base de datos de imágenes de DAAD de formato conocido')
sys.exit()
if le:
carga_int2 = carga_int2_le
carga_int4 = carga_int4_le
else:
carga_int2 = carga_int2_be
carga_int4 = carga_int4_be
try:
os.mkdir (destino)
except:
pass # Asumimos que ese directorio ya existe
rango = range (256) # Recorremos todas las imágenes posibles
if hayProgreso:
progreso = progressbar.ProgressBar()
rango = progreso (range (256))
for numImg in rango:
fichero.seek (6 + (longCabeceraImg * numImg)) # Parte de cabecera de la imagen
posicion = carga_int4()
if not posicion:
continue # Ninguna imagen con ese número
# Obtenemos la paleta de la imagen
if modo == 'CGA':
if carga_int1() & 128:
paleta = paleta1b
else:
paleta = paleta2b
elif modo == 'ST':
fichero.seek (8, 1) # El segundo parámetro indica posición relativa
paleta = []
for color in range (16):
# TODO: calcular valores exactos
rojo = carga_int1()
rojo = (rojo & 7) << 5
# rojo = rojo & 4 + ((rojo & 3) << 4)
veaz = carga_int1()
verde = ((veaz >> 4) & 7) << 5
azul = (veaz & 7) << 5
paleta.append ((rojo, verde, azul))
elif modo == 'PCW':
paleta = paletaPCW
else:
paleta = paletaEGA
fichero.seek (posicion) # Saltamos a donde está la imagen
if le:
ancho = carga_int1() # LSB de la anchura de la imagen
valor = carga_int1()
else:
valor = carga_int1()
ancho = carga_int1() # LSB de la anchura de la imagen
ancho += (valor & 127) * 256
if ancho == 0 or ancho % 4:
prn ('El ancho de la imagen', numImg, 'no es mayor que 0 y múltiplo de 4, vale', ancho)
ancho /= 4 # Anchura de la imagen (en bloques de 4 píxeles)
rle = valor & 128
alto = carga_int2() # Altura de la imagen (en número de filas)
if alto == 0 or alto % 8:
prn ('El alto de la imagen', numImg, 'no es mayor que 0 y múltiplo de 8, vale', alto)
if 0 in (ancho, alto):
continue
repetir = []
fichero.seek (2, 1) # Saltamos valor de longitud de la imagen
if rle:
if modo == 'ST':
bits = carga_int2() # Máscara de colores que se repetirán
for indiceBit in range (16):
if bits & (2 ** indiceBit):
repetir.append (indiceBit)
else:
b = carga_int1() # Número de secuencias que se repetirán
if b > 4:
prn ('Valor inesperado para el número de secuencias que se repetirán:', b, 'para la imagen:', numImg)
for i in range (4):
if i < b:
repetir.append (carga_int1())
else:
fichero.seek (1, 1)
strImg = '' # Cadena que representa toda la imagen
fila = '' # Cadena que representa la fila actual
izqAder = True # Sentido de procesado de píxeles de la fila actual
tamFila = ancho * 4 # Tamaño en píxeles (y bytes) que tendrá cada fila
tamImg = tamFila * alto # Tamaño en píxeles (y bytes) que tendrá la imagen
if modo == 'CGA':
while len (strImg) < tamImg: # Mientras quede imagen por procesar
b = carga_int1() # Byte actual
if b in repetir:
repeticiones = carga_int1()
else:
repeticiones = 1
pixels = chr (b >> 6) + chr ((b >> 4) & 3) + chr ((b >> 2) & 3) + chr (b & 3) # Número de color de los cuatro píxeles
if izqAder: # Sentido de izquierda a derecha
fila += pixels * repeticiones # Añadimos al final
else: # Sentido de derecha a izquierda
fila = (pixels * repeticiones) + fila # Añadimos al principio
while len (fila) >= tamFila: # Al repetirse, se puede exceder la longitud de una fila
if izqAder: # Sentido de izquierda a derecha
strImg += fila[0:tamFila]
fila = fila[tamFila:]
else: # Sentido de derecha a izquierda
strImg += fila[-tamFila:]
fila = fila[:-tamFila]
if rle:
izqAder = not izqAder
elif modo != 'ST':
# Modos PCW monocromo y EGA en orden planar con cuatro planos de bit de color enteros consecutivos
resolucion = ancho * 4 * alto
colores = ([0] * resolucion)
numPlanos = 1 if modo == 'PCW' else 4
repeticiones = 0
for plano in range (numPlanos):
bitsFila = []
numFila = 0
while numFila < alto:
if not repeticiones:
try:
b = carga_int1() # Byte actual
if b in repetir:
repeticiones = carga_int1()
if repeticiones < 1:
prn ('Valor inesperado (' + str (repeticiones) + ') para el número de repeticiones de RLE, en la imagen', numImg)
else:
repeticiones = 1
except:
prn ('Imagen', numImg, 'incompleta. ¿Formato incorrecto?')
bits = [] # Bits del byte actual
for indiceBit in range (7, -1, -1): # Cada bit del byte actual
bits.append (1 if b & (2 ** indiceBit) else 0)
cuantas = min (repeticiones, (tamFila - len (bitsFila)) / 8) # Evitamos exceder la longitud de una fila
if izqAder: # Sentido de izquierda a derecha
bitsFila.extend (bits * cuantas) # Añadimos al final
else: # Sentido de derecha a izquierda
bitsReversa = bits[::-1]
bitsFila.extend (bitsReversa * cuantas) # Añadimos al final, pero con los bits invertidos
repeticiones -= cuantas
if len (bitsFila) == tamFila: # Al repetir no se excede la longitud de una fila
if modo == 'PCW' and not rle:
bytesEnFila = tamFila / 8
bloquesEnFila = bytesEnFila / 8 # Bloques de 8 bytes por cada fila
for indiceByte in range (bytesEnFila):
byte = bitsFila[indiceByte * 8 : (indiceByte * 8) + 8]
numBloqueDest = numFila // 8 # Índice del bloque de 8 filas, en destino
numFilaDest = (indiceByte % 8) # Índice de fila dentro del bloque, en destino
numByteDest = ((numFila % 8) * bloquesEnFila) + (indiceByte // 8) # Índice del byte dentro de la fila, en destino
primerPixel = (numBloqueDest * tamFila * 8) + (numFilaDest * tamFila) + (numByteDest * 8) # Índice del primer píxel del byte, en destino
for indiceBit in range (8):
bit = byte[indiceBit]
colores[primerPixel + indiceBit] += (2 ** plano) if bit else 0
elif izqAder: # Sentido de izquierda a derecha
primerPixel = (numFila * tamFila) # Índice del primer píxel del byte
for indiceBit in range (tamFila):
bit = bitsFila[indiceBit]
colores[primerPixel + indiceBit] += (2 ** plano) if bit else 0
else: # Sentido de derecha a izquierda
ultimoPixel = (numFila * tamFila) + tamFila - 1 # Índice del último píxel del byte
for indiceBit in range (tamFila):
bit = bitsFila[indiceBit]
colores[ultimoPixel - indiceBit] += (2 ** plano) if bit else 0
bitsFila = []
if rle:
izqAder = not izqAder
numFila += 1
for pixel in range (resolucion): # Cada píxel en la imagen
strImg += chr (colores[pixel])
else: # Modo de Amiga/Atari ST
color = None # Índice de color del píxel actual
numPlanos = 4
while len (strImg) < tamImg: # Mientras quede imagen por procesar
colores = ([0] * 8)
for plano in range (numPlanos):
b = carga_int1() # Byte actual
for indiceBit in range (8):
bit = b & (2 ** indiceBit)
colores[7 - indiceBit] += (2 ** plano) if bit else 0
for pixel in range (8): # Cada píxel en el grupo
if color == None:
color = colores[pixel]
if rle and color in repetir:
continue # El número de repeticiones vendrá en el valor del siguiente píxel
if rle and color in repetir:
repeticiones = colores[pixel] + 1
else:
repeticiones = 1
strImg += chr (color) * repeticiones
color = None
if 'png' in sys.modules:
listaImg = []
for numFila in range (alto):
listaImg.append (strImg[numFila * ancho * 4 : (numFila + 1) * ancho * 4])
escritor = png.Writer (ancho * 4, alto, palette = paleta, bitdepth = bpp)
salida = open ('%s/pic%03d.png' % (destino, numImg), 'wb')
escritor.write (salida, listaImg)
else:
# OJO: pygame no guarda las imágenes como paleta indexada
imagen = pygame.image.fromstring (strImg, (ancho * 4, alto), 'P')
imagen.set_palette (paleta)
pygame.image.save (imagen, '%s/pic%03d.png' % (destino, numImg))