Конвертер монохромных BMP файлов в формат файлов MKL

| рубрика «Калькуляторы» | автор Vitasam
Метки:

Программа "Китайский год" стимулировала меня посидеть пару вечеров с интернет-планшеткой.

В результате получился скрипт на языке Python (v2.7), преобразующий монохромный BMP файл в некое подобие исходного текста программы формата MKL программируемых калькуляторов МК-152/161.

#
# BMP to MKL converter.
# Version 1.0
#
#coding=ascii
import array
import sys

#When 1, extra dumps to console
debug_dump = 0

#1 - invert pixels
invert_pixel = 1

file_to_open = sys.argv[1]
file_to_write = file_to_open + ".txt"
print "--------------------------"
print "File to open: ", file_to_open
print "File to write: ", file_to_write

img_file = open(file_to_open,"rb")
values = array.array('B') #Array of unsigned char type
values.read(img_file, 60)
img_file.close()

s_of = 0x02   #Start of data size
d_of = 0x0A   #Start of data offset
dib_of = 0x0E #Start of DIB header size
w_of = 0x12   #Width of BMP
h_of = 0x16   #Height of BMP
ncp_of = 0x1A #Number of color planes
nbpp_of = 0x1C #Number of bits per pixel
cmpr_of = 0x1E #Type of compression
is_of = 0x22  #Raw bitmap data size
num_col_pal_of = 0x2E #Number of colors in the palette
imp_col_of = 0x32  #Number of important colors used
color_tbl_of = 0x36 #Color table = 4 * colors_palette bytes. Present only if num_bpp <= 8

bmp_size = values[s_of]|(values[s_of+1]<<8)|(values[s_of+2]<<16)|(values[s_of+3]<<24)
data_start = values[d_of]|(values[d_of+1]<<8)|(values[d_of+2]<<16)|(values[d_of+3]<<24)
dib_size = values[dib_of]|(values[dib_of+1]<<8)|(values[dib_of+2]<<16)|(values[dib_of+3]<<24)
bmp_width = values[w_of]|(values[w_of+1]<<8)|(values[w_of+2]<<16)|(values[w_of+3]<<24)
bmp_height = values[h_of]|(values[h_of+1]<<8)|(values[h_of+2]<<16)|(values[h_of+3]<<24)
num_col_planes = values[ncp_of]|(values[ncp_of+1]<<8)
num_bpp = values[nbpp_of]|(values[nbpp_of+1]<<8)
compression_type = values[cmpr_of]|(values[cmpr_of+1]<<8)|(values[cmpr_of+2]<<16)|(values[cmpr_of+3]<<24)
raw_size = values[is_of]|(values[is_of+1]<<8)|(values[is_of+2]<<16)|(values[is_of+3]<<24)
colors_palette = values[num_col_pal_of]|(values[num_col_pal_of+1]<<8)|(values[num_col_pal_of+2]<<16)|(values[num_col_pal_of+3]<<24)
col_used = values[imp_col_of]|(values[imp_col_of+1]<<8)|(values[imp_col_of+2]<<16)|(values[imp_col_of+3]<<24)

print "BMP file size: ", bmp_size, " bytes"
print "Data start offset: ", data_start, " 0x%2X" % data_start
print "DIB header size: ", dib_size, " bytes"
print "BMP width: ", bmp_width, "pixels"
print "BMP height: ", bmp_height, "pixels"
print "Num of color planes: ", num_col_planes
print "Num of bits per pixel: ", num_bpp
print "Type of compression: ", compression_type
print "Raw bitmap size: ", raw_size, "bytes"
print "Colors in the palette: ", colors_palette
print "Colors used: ", col_used

txt_file = open(file_to_write, "w")
txt_file.write(";\n; BEGIN bitmap file: " + file_to_write.rstrip(".txt") + "\n;")

#Read bitmap data
img_file = open(file_to_open,"rb")
raw_values = array.array('B')    #Array of unsigned char type
raw_values.read(img_file, bmp_size)
img_file.close()

cnt = 0
binl = bmp_width/8 #Bytes in line
for i in range (0, bmp_height): #For each line
    str_out = "\n .DB "
    for j in range (0, binl, 4): #For each 4 bytes in the line
        off1 = data_start + raw_size
        off2 =  binl * i
        if invert_pixel: #Invert pixel values
            str_out = str_out + "%Xh," % (0xFF&(~raw_values[off1 - 4 - j - off2]))
            str_out = str_out + "%Xh," % (0xFF&(~raw_values[off1 - 3 - j - off2]))
            str_out = str_out + "%Xh," % (0xFF&(~raw_values[off1 - 2 - j - off2]))
            str_out = str_out + "%Xh," % (0xFF&(~raw_values[off1 - 1 - j - off2]))
        else:
            str_out = str_out + "%Xh," % raw_values[off1 - 4 - j - off2]
            str_out = str_out + "%Xh," % raw_values[off1 - 3 - j - off2]
            str_out = str_out + "%Xh," % raw_values[off1 - 2 - j - off2]
            str_out = str_out + "%Xh," % raw_values[off1 - 1 - j - off2]

        if debug_dump:
            print "-4 (%d) from[%Xh]: %Xh," % (cnt+0,off1 - 4 - j - off2,raw_values[off1 - 4 - j - off2])
            print "-3 (%d) from[%Xh]: %Xh," % (cnt+1,off1 - 3 - j - off2,raw_values[off1 - 3 - j - off2])
            print "-2 (%d) from[%Xh]: %Xh," % (cnt+2,off1 - 2 - j - off2,raw_values[off1 - 2 - j - off2])
            print "-1 (%d) from[%Xh]: %Xh," % (cnt+3,off1 - 1 - j - off2,raw_values[off1 - 1 - j - off2])

        cnt = cnt + 4

    txt_file.write(str_out.rstrip(","))

txt_file.write("\n;\n; END bitmap file: " + file_to_write.rstrip(".txt") + "\n;")
txt_file.close()
print "-----"
print "File converted"
print "Ok"

Увеличенный в 4x4 раза исходный BMP файл bw_32x32_face.bmp:

BMP файл

Для упрощения скрипта (а также из-за отсутствия времени) присутствует ряд ограничений:

  • Ширина монохромного файла должна быть кратна 4;
  • Минимальная ширина файла должна быть не меньше 16 пиксел (может, и при 16 будут глюки, не проверял)

Запускаем в консоли питон-скрипт:

> python bmp2mkl.py bw_32x32_face.bmp
--------------------------
File to open:  bw_32x32_face.bmp
File to write:  bw_32x32_face.bmp.txt
BMP file size:  190  bytes
Data start offset:  62  0x3E
DIB header size:  40  bytes
BMP width:  32 pixels
BMP height:  32 pixels
Num of color planes:  1
Num of bits per pixel:  1
Type of compression:  0
Raw bitmap size:  128 bytes
Colors in the palette:  0
Colors used:  0
-----
File converted
Ok

Скрипт создает текстовый файл bw_32x32_face.bmp.txt

;
; BEGIN bitmap file: bw_32x32_face.bmp
;
 .DB FFh,FFh,FFh,FFh
 .DB 80h,0h,0h,1h
 .DB 80h,3Fh,E0h,1h
 .DB 80h,FFh,FCh,1h
 .DB 83h,E0h,Fh,1h
 .DB 87h,80h,7h,81h
 .DB 8Eh,0h,1h,C1h
 .DB 8Ch,0h,0h,C1h
 .DB 98h,Ch,0h,61h
 .DB B8h,33h,0h,71h
 .DB B0h,40h,80h,31h
 .DB 60h,40h,80h,19h
 .DB 60h,80h,40h,19h
 .DB 60h,80h,42h,19h
 .DB 60h,40h,8Dh,99h
 .DB 60h,40h,88h,99h
 .DB 60h,33h,8h,99h
 .DB 60h,Ch,Dh,99h
 .DB 60h,0h,2h,19h
 .DB 60h,0h,0h,19h
 .DB 60h,3h,C0h,19h
 .DB B0h,7Ch,38h,31h
 .DB B9h,80h,0h,71h
 .DB 98h,0h,0h,61h
 .DB 8Ch,0h,0h,C1h
 .DB 8Eh,0h,1h,C1h
 .DB 87h,80h,7h,81h
 .DB 83h,E0h,Fh,1h
 .DB 80h,FFh,FCh,1h
 .DB 80h,3Fh,E0h,1h
 .DB 80h,0h,0h,1h
 .DB FFh,FFh,FFh,FFh
;
; END bitmap file: bw_32x32_face.bmp
;

Путем замены символов в notepad-е и преобразования из шестнадцатеричных чисел в двоичные получаем такой битмап:

11111111111111111111111111111111
1                              1
1         111111111            1
1       11111111111111         1
1     11111         1111       1
1    1111            1111      1
1   111                111     1
1   11                  11     1
1  11       11           11    1
1 111     11  11         111   1
1 11     1      1         11   1
 11      1      1          11  1
 11     1        1         11  1
 11     1        1    1    11  1
 11      1      1   11 11  11  1
 11      1      1   1   1  11  1
 11       11  11    1   1  11  1
 11         11      11 11  11  1
 11                   1    11  1
 11                        11  1
 11           1111         11  1
1 11     11111    111     11   1
1 111  11                111   1
1  11                    11    1
1   11                  11     1
1   111                111     1
1    1111            1111      1
1     11111         1111       1
1       11111111111111         1
1         111111111            1
1                              1
11111111111111111111111111111111