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