xref: /OK3568_Linux_fs/kernel/scripts/bmpconvert (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#!/usr/bin/env python
2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0 */
3*4882a593Smuzhiyun# -*- coding: utf-8 -*-
4*4882a593Smuzhiyun
5*4882a593Smuzhiyunfrom struct import unpack, pack
6*4882a593Smuzhiyunimport sys
7*4882a593Smuzhiyunimport getopt
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun
10*4882a593Smuzhiyunclass BMPFile:
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun    def __init__(self, file_path, force_revers=0, force_swap=0):
13*4882a593Smuzhiyun        self.file = open(file_path, "rb+")
14*4882a593Smuzhiyun        # bmp head 14bit
15*4882a593Smuzhiyun        self.bfType = unpack("<h", self.file.read(2))[0]
16*4882a593Smuzhiyun        self.bfSize = unpack("<i", self.file.read(4))[0]
17*4882a593Smuzhiyun        self.bfReserved1 = unpack("<h", self.file.read(2))[0]
18*4882a593Smuzhiyun        self.bfReserved2 = unpack("<h", self.file.read(2))[0]
19*4882a593Smuzhiyun        self.bfOffBits = unpack("<i", self.file.read(4))[0]
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun        self.biSize = unpack("<i", self.file.read(4))[0]
22*4882a593Smuzhiyun        self.biWidth = unpack("<i", self.file.read(4))[0]
23*4882a593Smuzhiyun        self.biHeight = unpack("<i", self.file.read(4))[0]
24*4882a593Smuzhiyun        self.biPlanes = unpack("<h", self.file.read(2))[0]
25*4882a593Smuzhiyun        self.biBitCount = unpack("<h", self.file.read(2))[0]
26*4882a593Smuzhiyun        # bmp parameter 40 bit normaally
27*4882a593Smuzhiyun        self.biCompression = unpack("<i", self.file.read(4))[0]
28*4882a593Smuzhiyun        self.biSizeImage = unpack("<i", self.file.read(4))[0]
29*4882a593Smuzhiyun        self.biXPixelsPerMeter = unpack("<i", self.file.read(4))[0]
30*4882a593Smuzhiyun        self.biYPixelsPerMeter = unpack("<i", self.file.read(4))[0]
31*4882a593Smuzhiyun        self.biClrUsed = unpack("<i", self.file.read(4))[0]
32*4882a593Smuzhiyun        self.biClrImportant = unpack("<i", self.file.read(4))[0]
33*4882a593Smuzhiyun        self.head = []
34*4882a593Smuzhiyun        self.color_map = []
35*4882a593Smuzhiyun        self.bmp_data = []
36*4882a593Smuzhiyun        self.bf_map = []
37*4882a593Smuzhiyun        self.force_revers = force_revers
38*4882a593Smuzhiyun        self.force_swap = force_swap
39*4882a593Smuzhiyun        # some software change parameter size more than 40 bit
40*4882a593Smuzhiyun        if self.biSize > 40:
41*4882a593Smuzhiyun            self.read_other(self.biSize-40)
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun        if self.biBitCount == 16 and self.biCompression == 3:
44*4882a593Smuzhiyun            for i in range(4):
45*4882a593Smuzhiyun                self.bf_map.append(
46*4882a593Smuzhiyun                    [unpack("<i", self.file.read(4))[0]]
47*4882a593Smuzhiyun                )
48*4882a593Smuzhiyun        if self.biBitCount == 24:
49*4882a593Smuzhiyun            self.get_24bit_data()
50*4882a593Smuzhiyun        elif self.biBitCount == 16:
51*4882a593Smuzhiyun            if self.biCompression == 3:
52*4882a593Smuzhiyun                self.bmp16bit_to_24bit_bf()
53*4882a593Smuzhiyun            else:
54*4882a593Smuzhiyun                self.bmp16bit_to_24bit()
55*4882a593Smuzhiyun        elif self.biBitCount == 8:
56*4882a593Smuzhiyun                # Not convert 8bit bmp logo to 24 bit
57*4882a593Smuzhiyun                self.file.close()
58*4882a593Smuzhiyun                return
59*4882a593Smuzhiyun        else:
60*4882a593Smuzhiyun            self.bmp32bit_to_24bit()
61*4882a593Smuzhiyun        self.rb_swap = 0
62*4882a593Smuzhiyun        if self.bfReserved1 != 8399 and self.biHeight > 0:
63*4882a593Smuzhiyun            self.reverse_bmp_data()
64*4882a593Smuzhiyun            print("reverse data at first time")
65*4882a593Smuzhiyun        if self.force_revers:
66*4882a593Smuzhiyun            self.reverse_bmp_data()
67*4882a593Smuzhiyun            print("reverse data by force")
68*4882a593Smuzhiyun        if self.force_swap:
69*4882a593Smuzhiyun            self.rb_swap = 1
70*4882a593Smuzhiyun            print("swap rb by force'")
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun        if self.bfReserved1 == 8399:
73*4882a593Smuzhiyun            self.file.close()
74*4882a593Smuzhiyun            return
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun        self.write_24bit(self.rb_swap)
77*4882a593Smuzhiyun        self.file.close()
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun    def read_other(self, n):
80*4882a593Smuzhiyun        for i in range(n):
81*4882a593Smuzhiyun            self.file.read(1)
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun    def reverse_bmp_data(self):
84*4882a593Smuzhiyun        self.bmp_data.reverse()
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun    @staticmethod
87*4882a593Smuzhiyun    def get_16bit_bgr_bf(pixel):
88*4882a593Smuzhiyun        red = (pixel[1] & 0xf8) << 0
89*4882a593Smuzhiyun        green = ((pixel[1] & 0x07) << 5) | ((pixel[0] & 0xe0) >> 3)
90*4882a593Smuzhiyun        blue = ((pixel[0] & 0x1f) << 3)
91*4882a593Smuzhiyun        new_pixel = [blue, green, red]
92*4882a593Smuzhiyun        return new_pixel
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun    def bmp32bit_to_24bit(self):
95*4882a593Smuzhiyun        for height in range(abs(self.biHeight)):
96*4882a593Smuzhiyun            bmp_data_row = []
97*4882a593Smuzhiyun            # bmp file 4 align
98*4882a593Smuzhiyun            count = 0
99*4882a593Smuzhiyun            for width in range(self.biWidth):
100*4882a593Smuzhiyun                bmp_data_row.append(
101*4882a593Smuzhiyun                    [unpack("<B", self.file.read(1))[0], unpack("<B", self.file.read(1))[0], unpack("<B", self.file.read(1))[0]])
102*4882a593Smuzhiyun                self.file.read(1)
103*4882a593Smuzhiyun                count = count + 4
104*4882a593Smuzhiyun            while count % 4 != 0:
105*4882a593Smuzhiyun                self.file.read(1)
106*4882a593Smuzhiyun                count = count + 1
107*4882a593Smuzhiyun            self.bmp_data.append(bmp_data_row)
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun    def bmp16bit_to_24bit_bf(self):
110*4882a593Smuzhiyun        self.get_16bit_data()
111*4882a593Smuzhiyun        temp_data = self.bmp_data
112*4882a593Smuzhiyun        self.bmp_data = []
113*4882a593Smuzhiyun        for height in range(abs(self.biHeight)):
114*4882a593Smuzhiyun            bmp_data_row = []
115*4882a593Smuzhiyun            for width in range(self.biWidth):
116*4882a593Smuzhiyun                bmp_data_row.append(
117*4882a593Smuzhiyun                    self.get_16bit_bgr_bf(temp_data[height][width])
118*4882a593Smuzhiyun                )
119*4882a593Smuzhiyun            self.bmp_data.append(bmp_data_row)
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun    def bmp8bit_to_24bit_rle(self):
122*4882a593Smuzhiyun        bmp_data_row = []
123*4882a593Smuzhiyun        data_x = []
124*4882a593Smuzhiyun        t_count = 0
125*4882a593Smuzhiyun        loop = 1
126*4882a593Smuzhiyun        while loop:
127*4882a593Smuzhiyun            data1 = unpack("<B", self.file.read(1))[0]
128*4882a593Smuzhiyun            if data1 > 0:
129*4882a593Smuzhiyun                data2 = unpack("<B", self.file.read(1))[0]
130*4882a593Smuzhiyun                for n in range(data1):
131*4882a593Smuzhiyun                    bmp_data_row.append(self.color_map[data2])
132*4882a593Smuzhiyun            if data1 == 0:
133*4882a593Smuzhiyun                data2 = unpack("<B", self.file.read(1))[0]
134*4882a593Smuzhiyun                if data2 > 2:
135*4882a593Smuzhiyun                    data_count = data2
136*4882a593Smuzhiyun                    data_temp = unpack("<B", self.file.read(1))[0]
137*4882a593Smuzhiyun                    data_x.append(data_temp)
138*4882a593Smuzhiyun                    while data_temp != 0:
139*4882a593Smuzhiyun                        data_temp = unpack("<B", self.file.read(1))[0]
140*4882a593Smuzhiyun                        data_x.append(data_temp)
141*4882a593Smuzhiyun                    for m in range(data_count):
142*4882a593Smuzhiyun                        bmp_data_row.append(self.color_map[data_x[m]])
143*4882a593Smuzhiyun                if data2 == 2:
144*4882a593Smuzhiyun                    print("data2 == 2")
145*4882a593Smuzhiyun                if data2 == 0:
146*4882a593Smuzhiyun                    t_count += 1
147*4882a593Smuzhiyun                    self.bmp_data.append(bmp_data_row)
148*4882a593Smuzhiyun                    bmp_data_row = []
149*4882a593Smuzhiyun                if data2 == 1:
150*4882a593Smuzhiyun                    print("encode over!")
151*4882a593Smuzhiyun                    loop = 0
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun    def bmp8bit_to_24bit(self):
154*4882a593Smuzhiyun        for height in range(abs(self.biHeight)):
155*4882a593Smuzhiyun            bmp_data_row = []
156*4882a593Smuzhiyun            count = 0
157*4882a593Smuzhiyun            for width in range(self.biWidth):
158*4882a593Smuzhiyun                bmp_data_row.append(
159*4882a593Smuzhiyun                    self.color_map[unpack("<B", self.file.read(1))[0]])
160*4882a593Smuzhiyun                count = count + 1
161*4882a593Smuzhiyun            while count % 4 != 0:
162*4882a593Smuzhiyun                self.file.read(1)
163*4882a593Smuzhiyun                count = count + 1
164*4882a593Smuzhiyun            self.bmp_data.append(bmp_data_row)
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun    @staticmethod
167*4882a593Smuzhiyun    def get_16bit_bgr(pixel):
168*4882a593Smuzhiyun        red = (pixel[1] & 0x7c) << 1
169*4882a593Smuzhiyun        green = ((pixel[1] & 0x03) << 6) | ((pixel[0] & 0xe0) >> 2)
170*4882a593Smuzhiyun        blue = ((pixel[0] & 0x1f) << 3)
171*4882a593Smuzhiyun        new_pixel = [blue, green, red]
172*4882a593Smuzhiyun        return new_pixel
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun    def bmp16bit_to_24bit(self):
175*4882a593Smuzhiyun        self.get_16bit_data()
176*4882a593Smuzhiyun        temp_data = self.bmp_data
177*4882a593Smuzhiyun        self.bmp_data = []
178*4882a593Smuzhiyun        for height in range(abs(self.biHeight)):
179*4882a593Smuzhiyun            bmp_data_row = []
180*4882a593Smuzhiyun            for width in range(self.biWidth):
181*4882a593Smuzhiyun                bmp_data_row.append(
182*4882a593Smuzhiyun                    self.get_16bit_bgr(temp_data[height][width])
183*4882a593Smuzhiyun                )
184*4882a593Smuzhiyun            self.bmp_data.append(bmp_data_row)
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun    def get_head(self):
187*4882a593Smuzhiyun        self.file.seek(0, 0)
188*4882a593Smuzhiyun        for i in range(54):
189*4882a593Smuzhiyun            self.head.append(unpack("<B", self.file.read(1))[0])
190*4882a593Smuzhiyun        return self.head
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun    def get_16bit_data(self):
193*4882a593Smuzhiyun        for height in range(abs(self.biHeight)):
194*4882a593Smuzhiyun            bmp_data_row = []
195*4882a593Smuzhiyun            count = 0
196*4882a593Smuzhiyun            for width in range(self.biWidth):
197*4882a593Smuzhiyun                bmp_data_row.append(
198*4882a593Smuzhiyun                    [unpack("<B", self.file.read(1))[0], unpack("<B", self.file.read(1))[0]])
199*4882a593Smuzhiyun                count = count + 2
200*4882a593Smuzhiyun            while count % 4 != 0:
201*4882a593Smuzhiyun                self.file.read(1)
202*4882a593Smuzhiyun                count = count + 1
203*4882a593Smuzhiyun            self.bmp_data.append(bmp_data_row)
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun    def get_24bit_data(self):
206*4882a593Smuzhiyun        for height in range(abs(self.biHeight)):
207*4882a593Smuzhiyun            bmp_data_row = []
208*4882a593Smuzhiyun            count = 0
209*4882a593Smuzhiyun            for width in range(self.biWidth):
210*4882a593Smuzhiyun                bmp_data_row.append(
211*4882a593Smuzhiyun                    [unpack("<B", self.file.read(1))[0], unpack("<B", self.file.read(1))[0], unpack("<B", self.file.read(1))[0]])
212*4882a593Smuzhiyun                count = count + 3
213*4882a593Smuzhiyun            while count % 4 != 0:
214*4882a593Smuzhiyun                self.file.read(1)
215*4882a593Smuzhiyun                count = count + 1
216*4882a593Smuzhiyun            self.bmp_data.append(bmp_data_row)
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun    def write_24bit(self,rb_swap):
219*4882a593Smuzhiyun        self.file.seek(0, 0)
220*4882a593Smuzhiyun        self.write_head_24bit()
221*4882a593Smuzhiyun        self.write_data_24bit(rb_swap)
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun    def write_head(self):
224*4882a593Smuzhiyun        self.file.write(pack("<h", self.bfType))
225*4882a593Smuzhiyun        self.file.write(pack("<i", self.bfSize))
226*4882a593Smuzhiyun        self.file.write(pack("<h", self.bfReserved1))
227*4882a593Smuzhiyun        self.file.write(pack("<h", self.bfReserved2))
228*4882a593Smuzhiyun        self.file.write(pack("<i", self.bfOffBits))  # bfOffBits
229*4882a593Smuzhiyun        self.file.write(pack("<i", self.biSize))  # biSize
230*4882a593Smuzhiyun        self.file.write(pack("<i", self.biWidth))
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun        self.file.write(pack("<i", self.biHeight))
233*4882a593Smuzhiyun        self.file.write(pack("<h", self.biPlanes))
234*4882a593Smuzhiyun        self.file.write(pack("<h", self.biBitCount))  # biBitCount
235*4882a593Smuzhiyun        self.file.write(pack("<i", self.biCompression))  # biCompression
236*4882a593Smuzhiyun        self.file.write(pack("<i", self.biSizeImage))  # biSizeImage
237*4882a593Smuzhiyun        self.file.write(pack("<i", self.biXPixelsPerMeter))  # biXPixelsPerMeter
238*4882a593Smuzhiyun        self.file.write(pack("<i", self.biYPixelsPerMeter))  # biYPixelsPerMeter
239*4882a593Smuzhiyun        self.file.write(pack("<i", self.biClrUsed))  # biClrUsed
240*4882a593Smuzhiyun        self.file.write(pack("<i", self.biClrImportant))  # biClrImportant try to mark whether is reversed
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun    def write_head_24bit(self):
243*4882a593Smuzhiyun        temp_bi_width = self.biWidth * 3
244*4882a593Smuzhiyun        while temp_bi_width % 4 != 0:
245*4882a593Smuzhiyun            temp_bi_width = temp_bi_width + 1
246*4882a593Smuzhiyun        new_bf_size = temp_bi_width * abs(self.biHeight) + 54
247*4882a593Smuzhiyun        self.file.write(pack("<h", self.bfType))
248*4882a593Smuzhiyun        self.file.write(pack("<i", new_bf_size))
249*4882a593Smuzhiyun        self.file.write(pack("<h", 8399)) # a mark for uboot dealing
250*4882a593Smuzhiyun        self.file.write(pack("<h", self.bfReserved2))
251*4882a593Smuzhiyun        self.file.write(pack("<i", 54))  # bfOffBits
252*4882a593Smuzhiyun        self.file.write(pack("<i", 40))  # biSize
253*4882a593Smuzhiyun        self.file.write(pack("<i", self.biWidth))
254*4882a593Smuzhiyun        # force height to negative let logo show normal in windows
255*4882a593Smuzhiyun        # the uboot code can deal with negative height
256*4882a593Smuzhiyun        if self.biHeight < 0:
257*4882a593Smuzhiyun            self.file.write(pack("<i", self.biHeight))
258*4882a593Smuzhiyun        else:
259*4882a593Smuzhiyun            self.file.write(pack("<i", self.biHeight * -1))
260*4882a593Smuzhiyun        self.file.write(pack("<h", self.biPlanes))
261*4882a593Smuzhiyun        self.file.write(pack("<h", 24))  # biBitCount
262*4882a593Smuzhiyun        self.file.write(pack("<i", 0))  # biCompression
263*4882a593Smuzhiyun        self.file.write(pack("<i", 0))  # biSizeImage
264*4882a593Smuzhiyun        self.file.write(pack("<i", 0))  # biXPixelsPerMeter
265*4882a593Smuzhiyun        self.file.write(pack("<i", 0))  # biYPixelsPerMeter
266*4882a593Smuzhiyun        self.file.write(pack("<i", 0))  # biClrUsed
267*4882a593Smuzhiyun        self.file.write(pack("<i", 0))  # biClrImportant try to mark whether is reversed
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun    def write_data_24bit(self, rb_swap):
270*4882a593Smuzhiyun        for hg in range(abs(self.biHeight)):
271*4882a593Smuzhiyun            count = 0
272*4882a593Smuzhiyun            for wd in range(self.biWidth):
273*4882a593Smuzhiyun                if rb_swap:
274*4882a593Smuzhiyun                    self.file.write(pack("<B", self.bmp_data[hg][wd][2]))
275*4882a593Smuzhiyun                    self.file.write(pack("<B", self.bmp_data[hg][wd][1]))
276*4882a593Smuzhiyun                    self.file.write(pack("<B", self.bmp_data[hg][wd][0]))
277*4882a593Smuzhiyun                else:
278*4882a593Smuzhiyun                    self.file.write(pack("<B", self.bmp_data[hg][wd][0]))
279*4882a593Smuzhiyun                    self.file.write(pack("<B", self.bmp_data[hg][wd][1]))
280*4882a593Smuzhiyun                    self.file.write(pack("<B", self.bmp_data[hg][wd][2]))
281*4882a593Smuzhiyun                count = count + 3
282*4882a593Smuzhiyun            while count % 4 != 0:
283*4882a593Smuzhiyun                self.file.write(pack("<B", 0))
284*4882a593Smuzhiyun                count = count + 1
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun
287*4882a593Smuzhiyunif __name__ == "__main__":
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun    swap = 0
290*4882a593Smuzhiyun    revers = 0
291*4882a593Smuzhiyun    par = len(sys.argv[1:])
292*4882a593Smuzhiyun    if par == 1:
293*4882a593Smuzhiyun        bmp = BMPFile(sys.argv[1])
294*4882a593Smuzhiyun    elif par == 0:
295*4882a593Smuzhiyun        print("This program is trying to convert different format of bmpfile to a same format"
296*4882a593Smuzhiyun                "to make vop can handle bmpfile easily")
297*4882a593Smuzhiyun        print("try such cmd to make it work python bmpconvert xxx/xxx.bmp")
298*4882a593Smuzhiyun    else:
299*4882a593Smuzhiyun        try:
300*4882a593Smuzhiyun            opts, args = getopt.getopt(sys.argv[2:], "hrs", ["help", "reverse", "swap"])
301*4882a593Smuzhiyun            for opt, arg in opts:
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun                if opt in ('-h','--help'):
304*4882a593Smuzhiyun                    print("add -r option will force program to reverse data")
305*4882a593Smuzhiyun                    print("add -s option will force program to swap data of rb")
306*4882a593Smuzhiyun                if opt in ("-r", "--reverse"):
307*4882a593Smuzhiyun                    revers = 1
308*4882a593Smuzhiyun                if opt in ("-s", "--swap"):
309*4882a593Smuzhiyun                    swap = 1
310*4882a593Smuzhiyun            bmp = BMPFile(sys.argv[1], revers, swap)
311*4882a593Smuzhiyun        except getopt.GetoptError:
312*4882a593Smuzhiyun            sys.exit(1)
313*4882a593Smuzhiyun
314