314 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			314 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env python3
 | |
| # 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)
 | |
| 
 |