314 lines
12 KiB
Python
Executable File
314 lines
12 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# SPDX-License-Identifier: GPL-2.0 */
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from struct import unpack, pack
|
|
import sys
|
|
import getopt
|
|
|
|
|
|
class BMPFile:
|
|
|
|
def __init__(self, file_path, force_revers=0, force_swap=0):
|
|
self.file = open(file_path, "rb+")
|
|
# bmp head 14bit
|
|
self.bfType = unpack("<h", self.file.read(2))[0]
|
|
self.bfSize = unpack("<i", self.file.read(4))[0]
|
|
self.bfReserved1 = unpack("<h", self.file.read(2))[0]
|
|
self.bfReserved2 = unpack("<h", self.file.read(2))[0]
|
|
self.bfOffBits = unpack("<i", self.file.read(4))[0]
|
|
|
|
self.biSize = unpack("<i", self.file.read(4))[0]
|
|
self.biWidth = unpack("<i", self.file.read(4))[0]
|
|
self.biHeight = unpack("<i", self.file.read(4))[0]
|
|
self.biPlanes = unpack("<h", self.file.read(2))[0]
|
|
self.biBitCount = unpack("<h", self.file.read(2))[0]
|
|
# bmp parameter 40 bit normaally
|
|
self.biCompression = unpack("<i", self.file.read(4))[0]
|
|
self.biSizeImage = unpack("<i", self.file.read(4))[0]
|
|
self.biXPixelsPerMeter = unpack("<i", self.file.read(4))[0]
|
|
self.biYPixelsPerMeter = unpack("<i", self.file.read(4))[0]
|
|
self.biClrUsed = unpack("<i", self.file.read(4))[0]
|
|
self.biClrImportant = unpack("<i", self.file.read(4))[0]
|
|
self.head = []
|
|
self.color_map = []
|
|
self.bmp_data = []
|
|
self.bf_map = []
|
|
self.force_revers = force_revers
|
|
self.force_swap = force_swap
|
|
# some software change parameter size more than 40 bit
|
|
if self.biSize > 40:
|
|
self.read_other(self.biSize-40)
|
|
|
|
if self.biBitCount == 16 and self.biCompression == 3:
|
|
for i in range(4):
|
|
self.bf_map.append(
|
|
[unpack("<i", self.file.read(4))[0]]
|
|
)
|
|
if self.biBitCount == 24:
|
|
self.get_24bit_data()
|
|
elif self.biBitCount == 16:
|
|
if self.biCompression == 3:
|
|
self.bmp16bit_to_24bit_bf()
|
|
else:
|
|
self.bmp16bit_to_24bit()
|
|
elif self.biBitCount == 8:
|
|
# Not convert 8bit bmp logo to 24 bit
|
|
self.file.close()
|
|
return
|
|
else:
|
|
self.bmp32bit_to_24bit()
|
|
self.rb_swap = 0
|
|
if self.bfReserved1 != 8399 and self.biHeight > 0:
|
|
self.reverse_bmp_data()
|
|
print("reverse data at first time")
|
|
if self.force_revers:
|
|
self.reverse_bmp_data()
|
|
print("reverse data by force")
|
|
if self.force_swap:
|
|
self.rb_swap = 1
|
|
print("swap rb by force'")
|
|
|
|
if self.bfReserved1 == 8399:
|
|
self.file.close()
|
|
return
|
|
|
|
self.write_24bit(self.rb_swap)
|
|
self.file.close()
|
|
|
|
def read_other(self, n):
|
|
for i in range(n):
|
|
self.file.read(1)
|
|
|
|
def reverse_bmp_data(self):
|
|
self.bmp_data.reverse()
|
|
|
|
@staticmethod
|
|
def get_16bit_bgr_bf(pixel):
|
|
red = (pixel[1] & 0xf8) << 0
|
|
green = ((pixel[1] & 0x07) << 5) | ((pixel[0] & 0xe0) >> 3)
|
|
blue = ((pixel[0] & 0x1f) << 3)
|
|
new_pixel = [blue, green, red]
|
|
return new_pixel
|
|
|
|
def bmp32bit_to_24bit(self):
|
|
for height in range(abs(self.biHeight)):
|
|
bmp_data_row = []
|
|
# bmp file 4 align
|
|
count = 0
|
|
for width in range(self.biWidth):
|
|
bmp_data_row.append(
|
|
[unpack("<B", self.file.read(1))[0], unpack("<B", self.file.read(1))[0], unpack("<B", self.file.read(1))[0]])
|
|
self.file.read(1)
|
|
count = count + 4
|
|
while count % 4 != 0:
|
|
self.file.read(1)
|
|
count = count + 1
|
|
self.bmp_data.append(bmp_data_row)
|
|
|
|
def bmp16bit_to_24bit_bf(self):
|
|
self.get_16bit_data()
|
|
temp_data = self.bmp_data
|
|
self.bmp_data = []
|
|
for height in range(abs(self.biHeight)):
|
|
bmp_data_row = []
|
|
for width in range(self.biWidth):
|
|
bmp_data_row.append(
|
|
self.get_16bit_bgr_bf(temp_data[height][width])
|
|
)
|
|
self.bmp_data.append(bmp_data_row)
|
|
|
|
def bmp8bit_to_24bit_rle(self):
|
|
bmp_data_row = []
|
|
data_x = []
|
|
t_count = 0
|
|
loop = 1
|
|
while loop:
|
|
data1 = unpack("<B", self.file.read(1))[0]
|
|
if data1 > 0:
|
|
data2 = unpack("<B", self.file.read(1))[0]
|
|
for n in range(data1):
|
|
bmp_data_row.append(self.color_map[data2])
|
|
if data1 == 0:
|
|
data2 = unpack("<B", self.file.read(1))[0]
|
|
if data2 > 2:
|
|
data_count = data2
|
|
data_temp = unpack("<B", self.file.read(1))[0]
|
|
data_x.append(data_temp)
|
|
while data_temp != 0:
|
|
data_temp = unpack("<B", self.file.read(1))[0]
|
|
data_x.append(data_temp)
|
|
for m in range(data_count):
|
|
bmp_data_row.append(self.color_map[data_x[m]])
|
|
if data2 == 2:
|
|
print("data2 == 2")
|
|
if data2 == 0:
|
|
t_count += 1
|
|
self.bmp_data.append(bmp_data_row)
|
|
bmp_data_row = []
|
|
if data2 == 1:
|
|
print("encode over!")
|
|
loop = 0
|
|
|
|
def bmp8bit_to_24bit(self):
|
|
for height in range(abs(self.biHeight)):
|
|
bmp_data_row = []
|
|
count = 0
|
|
for width in range(self.biWidth):
|
|
bmp_data_row.append(
|
|
self.color_map[unpack("<B", self.file.read(1))[0]])
|
|
count = count + 1
|
|
while count % 4 != 0:
|
|
self.file.read(1)
|
|
count = count + 1
|
|
self.bmp_data.append(bmp_data_row)
|
|
|
|
@staticmethod
|
|
def get_16bit_bgr(pixel):
|
|
red = (pixel[1] & 0x7c) << 1
|
|
green = ((pixel[1] & 0x03) << 6) | ((pixel[0] & 0xe0) >> 2)
|
|
blue = ((pixel[0] & 0x1f) << 3)
|
|
new_pixel = [blue, green, red]
|
|
return new_pixel
|
|
|
|
def bmp16bit_to_24bit(self):
|
|
self.get_16bit_data()
|
|
temp_data = self.bmp_data
|
|
self.bmp_data = []
|
|
for height in range(abs(self.biHeight)):
|
|
bmp_data_row = []
|
|
for width in range(self.biWidth):
|
|
bmp_data_row.append(
|
|
self.get_16bit_bgr(temp_data[height][width])
|
|
)
|
|
self.bmp_data.append(bmp_data_row)
|
|
|
|
def get_head(self):
|
|
self.file.seek(0, 0)
|
|
for i in range(54):
|
|
self.head.append(unpack("<B", self.file.read(1))[0])
|
|
return self.head
|
|
|
|
def get_16bit_data(self):
|
|
for height in range(abs(self.biHeight)):
|
|
bmp_data_row = []
|
|
count = 0
|
|
for width in range(self.biWidth):
|
|
bmp_data_row.append(
|
|
[unpack("<B", self.file.read(1))[0], unpack("<B", self.file.read(1))[0]])
|
|
count = count + 2
|
|
while count % 4 != 0:
|
|
self.file.read(1)
|
|
count = count + 1
|
|
self.bmp_data.append(bmp_data_row)
|
|
|
|
def get_24bit_data(self):
|
|
for height in range(abs(self.biHeight)):
|
|
bmp_data_row = []
|
|
count = 0
|
|
for width in range(self.biWidth):
|
|
bmp_data_row.append(
|
|
[unpack("<B", self.file.read(1))[0], unpack("<B", self.file.read(1))[0], unpack("<B", self.file.read(1))[0]])
|
|
count = count + 3
|
|
while count % 4 != 0:
|
|
self.file.read(1)
|
|
count = count + 1
|
|
self.bmp_data.append(bmp_data_row)
|
|
|
|
def write_24bit(self,rb_swap):
|
|
self.file.seek(0, 0)
|
|
self.write_head_24bit()
|
|
self.write_data_24bit(rb_swap)
|
|
|
|
def write_head(self):
|
|
self.file.write(pack("<h", self.bfType))
|
|
self.file.write(pack("<i", self.bfSize))
|
|
self.file.write(pack("<h", self.bfReserved1))
|
|
self.file.write(pack("<h", self.bfReserved2))
|
|
self.file.write(pack("<i", self.bfOffBits)) # bfOffBits
|
|
self.file.write(pack("<i", self.biSize)) # biSize
|
|
self.file.write(pack("<i", self.biWidth))
|
|
|
|
self.file.write(pack("<i", self.biHeight))
|
|
self.file.write(pack("<h", self.biPlanes))
|
|
self.file.write(pack("<h", self.biBitCount)) # biBitCount
|
|
self.file.write(pack("<i", self.biCompression)) # biCompression
|
|
self.file.write(pack("<i", self.biSizeImage)) # biSizeImage
|
|
self.file.write(pack("<i", self.biXPixelsPerMeter)) # biXPixelsPerMeter
|
|
self.file.write(pack("<i", self.biYPixelsPerMeter)) # biYPixelsPerMeter
|
|
self.file.write(pack("<i", self.biClrUsed)) # biClrUsed
|
|
self.file.write(pack("<i", self.biClrImportant)) # biClrImportant try to mark whether is reversed
|
|
|
|
def write_head_24bit(self):
|
|
temp_bi_width = self.biWidth * 3
|
|
while temp_bi_width % 4 != 0:
|
|
temp_bi_width = temp_bi_width + 1
|
|
new_bf_size = temp_bi_width * abs(self.biHeight) + 54
|
|
self.file.write(pack("<h", self.bfType))
|
|
self.file.write(pack("<i", new_bf_size))
|
|
self.file.write(pack("<h", 8399)) # a mark for uboot dealing
|
|
self.file.write(pack("<h", self.bfReserved2))
|
|
self.file.write(pack("<i", 54)) # bfOffBits
|
|
self.file.write(pack("<i", 40)) # biSize
|
|
self.file.write(pack("<i", self.biWidth))
|
|
# force height to negative let logo show normal in windows
|
|
# the uboot code can deal with negative height
|
|
if self.biHeight < 0:
|
|
self.file.write(pack("<i", self.biHeight))
|
|
else:
|
|
self.file.write(pack("<i", self.biHeight * -1))
|
|
self.file.write(pack("<h", self.biPlanes))
|
|
self.file.write(pack("<h", 24)) # biBitCount
|
|
self.file.write(pack("<i", 0)) # biCompression
|
|
self.file.write(pack("<i", 0)) # biSizeImage
|
|
self.file.write(pack("<i", 0)) # biXPixelsPerMeter
|
|
self.file.write(pack("<i", 0)) # biYPixelsPerMeter
|
|
self.file.write(pack("<i", 0)) # biClrUsed
|
|
self.file.write(pack("<i", 0)) # biClrImportant try to mark whether is reversed
|
|
|
|
def write_data_24bit(self, rb_swap):
|
|
for hg in range(abs(self.biHeight)):
|
|
count = 0
|
|
for wd in range(self.biWidth):
|
|
if rb_swap:
|
|
self.file.write(pack("<B", self.bmp_data[hg][wd][2]))
|
|
self.file.write(pack("<B", self.bmp_data[hg][wd][1]))
|
|
self.file.write(pack("<B", self.bmp_data[hg][wd][0]))
|
|
else:
|
|
self.file.write(pack("<B", self.bmp_data[hg][wd][0]))
|
|
self.file.write(pack("<B", self.bmp_data[hg][wd][1]))
|
|
self.file.write(pack("<B", self.bmp_data[hg][wd][2]))
|
|
count = count + 3
|
|
while count % 4 != 0:
|
|
self.file.write(pack("<B", 0))
|
|
count = count + 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
swap = 0
|
|
revers = 0
|
|
par = len(sys.argv[1:])
|
|
if par == 1:
|
|
bmp = BMPFile(sys.argv[1])
|
|
elif par == 0:
|
|
print("This program is trying to convert different format of bmpfile to a same format"
|
|
"to make vop can handle bmpfile easily")
|
|
print("try such cmd to make it work python bmpconvert xxx/xxx.bmp")
|
|
else:
|
|
try:
|
|
opts, args = getopt.getopt(sys.argv[2:], "hrs", ["help", "reverse", "swap"])
|
|
for opt, arg in opts:
|
|
|
|
if opt in ('-h','--help'):
|
|
print("add -r option will force program to reverse data")
|
|
print("add -s option will force program to swap data of rb")
|
|
if opt in ("-r", "--reverse"):
|
|
revers = 1
|
|
if opt in ("-s", "--swap"):
|
|
swap = 1
|
|
bmp = BMPFile(sys.argv[1], revers, swap)
|
|
except getopt.GetoptError:
|
|
sys.exit(1)
|
|
|