forked from OpenDUNE/OpenDUNE
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathextracticn.py
executable file
·140 lines (131 loc) · 4.46 KB
/
extracticn.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
#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4 noexpandtab
#
# read ICON.ICN file (IFF)
from struct import *
import sys
from westwood_codecs import *
from save_pictures import *
def load_palette(filename):
with open(filename, 'rb') as pal_file:
return ''.join(map(lambda c: chr((ord(c) << 2) + (ord(c) >> 6)), list(pal_file.read())))
def load_icon_map(filename):
with open(filename, 'rb') as map_file:
s = map_file.read()
return [unpack_from('<H', s, i)[0] for i in range(0, len(s), 2)]
def parse_iff(data):
form = data[0:4]
if form != 'FORM':
return None
(form_len,) = unpack_from('>L', data, 4)
if ((form_len + 9)&~1) != ((len(data) + 1)&~1):
print "FORM len mismatch", form_len + 8, len(data)
iff_type = data[8:12]
print iff_type, form_len
offset = 12
iff_data = {}
while offset <= len(data)-8:
chunk = data[offset:offset+4]
(chunk_size,) = unpack_from('>L', data, offset + 4)
print '%06X %s %6d' % (offset, chunk, chunk_size)
offset += 8
iff_data[chunk] = data[offset:offset+chunk_size]
offset += (chunk_size + 1) & ~1
return (iff_type, iff_data)
def decode_sset(data):
(encoding,size,offset) = unpack_from('<HLH', data)
offset += 8
if encoding == 0:
return data[offset:offset+size]
elif encoding == 4: # format80
return decode_format80(data[offset:])
def decode_tile(data, pal, width, height):
rows = []
for y in range(height):
row = ''
for x in range(width/2):
v = ord(data[y*(width/2)+x])
left = pal[v >> 4]
right = pal[v & 0x0f]
row += left
row += right
#print row.encode('hex')
rows.append(row)
return rows
def save_tileset(filename, tiles, width, height, palette, tileset_width = 320):
count = len(tiles)
tileset_height = height * ((count + (tileset_width / width) - 1) / (tileset_width / width))
#print tileset_width, tileset_height
step = tileset_width / width
pixels = ''
for i in range(0, count, step):
chunk = reduce(lambda a, b: map(lambda x, y: x+y, a, b), tiles[i:i+step])
chunk = map(lambda s: s if len(s) >= tileset_width else s + (chr(0)*(tileset_width-len(s))), chunk)
pixels += ''.join(chunk)
save_pbm(filename, tileset_width, tileset_height, pixels, palette)
def extract_icn(filename, palette = None, icon_map = None):
with open(filename, 'rb') as icn_file:
icn = icn_file.read()
(icn_type, icn_data) = parse_iff(icn)
width = ord(icn_data['SINF'][0]) * 8
height = ord(icn_data['SINF'][1]) * 8
tile_bytes = width * height / 2
pixel_data = decode_sset(icn_data['SSET'])
count = len(pixel_data) / tile_bytes
print '%d tiles of %dx%d pixels, %d bytes' % (count, width, height, tile_bytes)
if len(icn_data['RTBL']) != count:
print 'RTBL size mismatch :', count, len(icn_data['RTBL'])
else:
tiles = []
for i in range(count):
pal_index = ord(icn_data['RTBL'][i])
pal = icn_data['RPAL'][pal_index*16:(pal_index+1)*16]
tile = decode_tile(pixel_data[tile_bytes*i:tile_bytes*(i+1)], pal, width, height)
istransparent = False
for line in tile:
for j in range(len(line)):
if ord(line[j]) == 0:
istransparent = True
break
if istransparent:
print 'Tile %3d (palette %2d) is transparent %02x' % (i, pal_index, ord(pal[0]))
tiles.append(tile)
save_tileset(filename + '.pbm', tiles, width, height, palette)
if icon_map is not None:
count = icon_map[0]
for i in range(count):
if icon_map[i+1] == 0:
icons = icon_map[icon_map[i]:]
else:
icons = icon_map[icon_map[i]:icon_map[i+1]]
#print i, icon_map[i], len(icons), icons
if len(icons) > 60 and i != 20:
tileset_width = 10 * width
elif (len(icons) % 3) == 0 and i != 12 and i != 26:
tileset_width = 3 * width
elif (len(icons) % 2) == 0:
tileset_width = 2 * width
elif len(icons) < 4:
tileset_width = width * len(icons)
else:
tileset_width = 4 * width
save_tileset("%s_%02d.pbm" % (filename, i), [tiles[j] for j in icons], width, height, palette, tileset_width)
palette_usage = ['0'] * 256
for c in icn_data['RPAL']:
palette_usage[ord(c)] = '1'
#print ''.join(palette_usage)
if len(sys.argv) <= 1:
print "usage : %s [-p palette.PAL] [-m icon.MAP] file.ICN" % sys.argv[0]
else:
palette = None
icon_map = None
args = sys.argv[1:]
while len(args) > 2 and args[0][0] == '-':
if args[0] == '-p':
palette = load_palette(args[1])
args = args[2:]
elif args[0] == '-m':
icon_map = load_icon_map(args[1])
args = args[2:]
for filename in args:
extract_icn(filename, palette, icon_map)