-
Notifications
You must be signed in to change notification settings - Fork 0
/
convert_bmp_to_gb_vram_format.py
150 lines (118 loc) · 5.33 KB
/
convert_bmp_to_gb_vram_format.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
import os
import struct
import types
import hashlib
import sys
tileSizeInPixels = 8
def isValidBitmapFile(bitmapFileHandle):
#FK: Only support windows bmp for now
bitmapHeaderField = struct.unpack('h', bitmapFileHandle.read(2))[0]
if bitmapHeaderField != 0x4d42:
print("ERROR: Not a valid bmp file (must be Microsoft Windows bitmap file format)")
return False
#FK: Move to DIB header
bitmapFileHandle.seek(14, os.SEEK_SET)
dibHeaderSizeInBytes = struct.unpack('i', bitmapFileHandle.read(4))[0]
#FK: Only support windows bmp for now
if dibHeaderSizeInBytes != 40:
print("ERROR: Not a valid bmp file (must be Microsoft Windows bitmap file format)")
return False
#FK: Move to bpp
bitmapFileHandle.seek(28, os.SEEK_SET)
bitsPerPixel = struct.unpack('i', bitmapFileHandle.read(4))[0]
#FK: Only support RGB for now
if bitsPerPixel != 24:
print("ERROR: Not a valid bmp file (currently only bit-depth of 24bpp is supported)")
return False
compressionMethod = struct.unpack('i', bitmapFileHandle.read(4))[0]
BI_RGB = 0
if compressionMethod != BI_RGB:
print("ERROR: Not a valid bmp file (currently only compression method RGB is supported)")
return False
return True
def extractBitmapInformations(bitmapFileHandle):
#FK: offset to bitmap pixel data
bitmapFileHandle.seek(10, os.SEEK_SET)
bitmapPixelDataOffsetInBytes = struct.unpack('i', bitmapFileHandle.read(4))[0]
#FK: bitmap dimension
bitmapFileHandle.seek(18, os.SEEK_SET)
bitmapWidthInPixels = struct.unpack('i', bitmapFileHandle.read(4))[0]
bitmapHeightInPixels = struct.unpack('i', bitmapFileHandle.read(4))[0]
return types.SimpleNamespace(pixelDataOffsetInBytes=bitmapPixelDataOffsetInBytes, width=bitmapWidthInPixels, height=bitmapHeightInPixels)
def convertToVramPixelValue(brightness):
if brightness == 0:
return 3
elif brightness == 64:
return 2
elif brightness == 128:
return 1
return 0
def writeBitmapDataToCArray(vramDataFileHandle, bitmapInformations, bitmapFileHandle):
#FK: seek to beginning of pixel data
bitmapFileHandle.seek(bitmapInformations.pixelDataOffsetInBytes, os.SEEK_SET)
tileIndex = 0
tileCountHorizontal = bitmapInformations.width / tileSizeInPixels
tileCountVertical = bitmapInformations.height / tileSizeInPixels
totalTileCount = tileCountHorizontal * tileCountVertical
vramPixel = 0
shiftIndex = 0
tileHashes = []
tilePixels = []
while tileIndex < totalTileCount:
sha1Hash = hashlib.new("sha1")
startX = ( int( tileIndex % tileCountHorizontal ) * tileSizeInPixels )
startY = ( int( tileIndex / tileCountHorizontal ) * tileSizeInPixels )
endY = startY + 8
y = startY
while y < endY:
fixedY = ( bitmapInformations.height - 1 ) - y #FK: Bitmap data has it's origin in the lower left corner, we assume upper left
x = startX
endX = startX + 8
while x < endX:
pixelDataPosition = ( x + fixedY * bitmapInformations.width ) * 3
bitmapFileHandle.seek(bitmapInformations.pixelDataOffsetInBytes + pixelDataPosition)
pixelValue = int.from_bytes( bitmapFileHandle.read(1), "little" ) #FK: It's enough to only read the first value
vramPixelValue = convertToVramPixelValue( int( pixelValue ) )
lb = ( vramPixelValue >> 0 ) & 1
hb = ( vramPixelValue >> 1 ) & 1
vramPixel |= lb
vramPixel |= hb << 8
shiftIndex += 1
if shiftIndex == 8:
vramPixelInBytes = vramPixel.to_bytes(2, "little", signed=False)
sha1Hash.update( vramPixelInBytes )
tilePixels.append( vramPixel )
shiftIndex = 0
vramPixel = 0
else:
vramPixel <<= 1
x += 1
y += 1
tileIndex += 1
newTileHash = int.from_bytes( sha1Hash.digest(), byteorder="little" )
tileHashes.index()
tileAlreadyInCache = False
for tileHash in tileHashes:
if tileHash == newTileHash:
tileAlreadyInCache = True
break
if tileAlreadyInCache == False:
tileHashes.append( newTileHash )
for tilePixel in tilePixels:
pixelInBytes = tilePixel.to_bytes(2, "little")
vramDataFileHandle.write( pixelInBytes )
vramDataFileHandle.flush()
tilePixels.clear()
print( "Unique tiles: {}".format( len( tileHashes ) ) )
if len(sys.argv) < 3:
print("Too few arguments. Usage: convert_bmp_to_gb_vram_format input.bmp output.bin")
exit(-1)
bitmapFileHandle = open(sys.argv[1], "rb")
if not isValidBitmapFile(bitmapFileHandle):
exit(-1)
bitmapInformations = extractBitmapInformations(bitmapFileHandle)
if bitmapInformations.width % tileSizeInPixels != 0 or bitmapInformations.height % tileSizeInPixels != 0:
print( "BMP dimension has to be multiple of 8. Currently is {}x{}".format( bitmapInformations.width, bitmapInformations.height ) )
exit( -1 )
vramDataFileHandle = open(sys.argv[2], "wb")
writeBitmapDataToCArray(vramDataFileHandle, bitmapInformations, bitmapFileHandle)