パレットindex 0修正(必須): ImageMagickの-colors 16量子化ではパレットの並び順が保証されず、index 0が#00FF00にならないことが多い。GBAスプライトではindex 0が透過色として扱われるため、BMP3変換後に必ずパレットindex 0を#00FF00に修正すること。
import struct
def fix_sprite_palette_index0(bmp_path):
with open(bmp_path, 'rb') as f:
data = bytearray(f.read())
w = struct.unpack_from('<i', data, 18)[0]
h = abs(struct.unpack_from('<i', data, 22)[0])
bpp = struct.unpack_from('<H', data, 28)[0]
data_offset = struct.unpack_from('<I', data, 10)[0]
n_colors = 1 << bpp
pal = []
for i in range(n_colors):
off = 54 + i * 4
b, g, r = data[off], data[off+1], data[off+2]
pal.append((r, g, b))
green_idx = next((i for i, c in enumerate(pal) if c == (0, 255, 0)), None)
if green_idx is None:
green_idx = min(range(n_colors), key=lambda i: pal[i][0]**2 + (255-pal[i][1])**2 + pal[i][2]**2)
if green_idx == 0:
data[54], data[55], data[56] = 0, 255, 0
else:
old0 = pal[0]
data[54], data[55], data[56], data[57] = 0, 255, 0, 0
offg = 54 + green_idx * 4
data[offg], data[offg+1], data[offg+2], data[offg+3] = old0[2], old0[1], old0[0], 0
row_bytes = (w * bpp + 31) // 32 * 4
for row in range(h):
row_start = data_offset + row * row_bytes
for col in range(w):
byte_off = row_start + col // 2
hi = (data[byte_off] >> 4) & 0x0F
lo = data[byte_off] & 0x0F
if col % 2 == 0:
if hi == 0: hi = green_idx
elif hi == green_idx: hi = 0
data[byte_off] = (hi << 4) | lo
else:
if lo == 0: lo = green_idx
elif lo == green_idx: lo = 0
data[byte_off] = (hi << 4) | lo
with open(bmp_path, 'wb') as f:
f.write(data)
この関数を全スプライトBMPに対して実行する。省略するとGBA上でスプライトの透過が効かず、緑色の矩形が表示される。