acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

bmp2array4bit.py (8335B)

      1 '''
      2 
      3     This script takes in a bitmap and outputs a text file that is a
      4     byte array used in Arduino files.
      5 
      6     It is loosely based on Spark Fun's bmp2array script.
      7 
      8     You'll need python 3.6 (the original use Python 2.7)
      9 
     10     usage: python fourbitbmp2array.py [-v] star.bmp [-o myfile.c]
     11     
     12     Create the bmp file in Gimp by :
     13 
     14     . Remove the alpha channel (if it has one) Layer -> Transparency -> Remove Alpha Channel
     15     . Set the mode to indexed.  Image -> Mode -> Indexed...
     16     . Select Generate optimum palette with 16 colors (max)
     17     . Export the file with a .bmp extension. Options are:
     18         . Run-Length Encoded: not selected
     19         . Compatibility Options: "Do not write color space information" not selected
     20         . There are no Advanced Options available with these settings
     21 
     22 
     23     
     24 
     25 '''
     26 
     27 import sys
     28 import struct
     29 import math
     30 import argparse
     31 import os
     32 
     33 debug = None
     34 
     35 def debugOut(s):
     36     if debug:
     37         print(s)
     38 
     39 # look at arguments
     40 parser = argparse.ArgumentParser(description="Convert bmp file to C array")
     41 parser.add_argument("-v", "--verbose", help="debug output", action="store_true")
     42 parser.add_argument("input", help="input file name")
     43 parser.add_argument("-o", "--output", help="output file name")
     44 args = parser.parse_args()
     45 
     46 if not os.path.exists(args.input):
     47     parser.print_help()
     48     print("The input file {} does not exist".format(args.input))
     49     sys.exit(1)
     50 
     51 if args.output == None:
     52     output = os.path.basename(args.input).replace(".bmp", ".c")
     53 else:
     54     output = args.output
     55 
     56 debug = args.verbose
     57 
     58 try:
     59     #Open our input file which is defined by the first commandline argument
     60     #then dump it into a list of bytes
     61     infile = open(args.input,"rb") #b is for binary
     62     contents = bytearray(infile.read())
     63     infile.close()
     64 except:
     65     print("could not read input file {}".format(args.input))
     66     sys.exit(1)
     67 
     68 # first two bytes should be "BM"
     69 upto = 2
     70 #Get the size of this image
     71 data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3])
     72 fileSize = struct.unpack("I", bytearray(data))
     73 
     74 upto += 4
     75 # four bytes are reserved
     76 
     77 upto += 4
     78 
     79 debugOut("Size of file: {}".format(fileSize[0]))
     80 
     81 #Get the header offset amount
     82 data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3])
     83 offset = struct.unpack("I", bytearray(data))
     84 
     85 debugOut("Offset: {}".format(offset[0]))
     86 upto += 4
     87 
     88 data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3])
     89 headersize = struct.unpack("I", bytearray(data))
     90 headerLength = headersize[0]
     91 startOfDefinitions = headerLength + upto
     92 debugOut("header size: {}, up to {}, startOfDefinitions {}".format(headersize[0], upto, startOfDefinitions))
     93 upto += 4
     94 
     95 data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3])
     96 t = struct.unpack("I", bytearray(data))
     97 debugOut("width: {}".format(t[0]))
     98 width = t[0]
     99 
    100 upto += 4
    101 data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3])
    102 t = struct.unpack("I", bytearray(data))
    103 debugOut("height: {}".format(t[0]))
    104 height = t[0]
    105 
    106 # 26
    107 upto += 4
    108 
    109 data = struct.pack("BB", contents[upto], contents[upto+1])
    110 t = struct.unpack("H", bytearray(data))
    111 debugOut("planes: {}".format(t[0]))
    112 
    113 upto = upto + 2
    114 data = struct.pack("BB", contents[upto], contents[upto+1])
    115 t = struct.unpack("H", bytearray(data))
    116 debugOut("bits per pixel: {}".format(t[0]))
    117 bitsPerPixel = t[0]
    118 
    119 upto = upto + 2
    120 data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3])
    121 t = struct.unpack("I", bytearray(data))
    122 debugOut("biCompression: {}".format(t[0]))
    123 
    124 upto = upto + 4
    125 data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3])
    126 t = struct.unpack("I", bytearray(data))
    127 debugOut("biSizeImage: {}".format(t[0]))
    128 
    129 upto = upto + 4
    130 data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3])
    131 t = struct.unpack("I", bytearray(data))
    132 debugOut("biXPelsPerMeter: {}".format(t[0]))
    133 
    134 upto = upto + 4
    135 data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3])
    136 t = struct.unpack("I", bytearray(data))
    137 debugOut("biYPelsPerMeter: {}".format(t[0]))
    138 
    139 upto = upto + 4
    140 data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3])
    141 t = struct.unpack("I", bytearray(data))
    142 debugOut("biClrUsed: {}".format(t[0]))
    143 colorsUsed = t
    144 
    145 upto = upto + 4
    146 data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3])
    147 t = struct.unpack("I", bytearray(data))
    148 debugOut("biClrImportant: {}".format(t[0]))
    149 
    150 upto += 4
    151 
    152 debugOut("Upto: {} Number of colors used: {} definitions start at: {}".format(upto, colorsUsed[0],  startOfDefinitions))
    153 
    154 #Create color definition array and init the array of color values
    155 colorIndex = [] #(colorsUsed[0])
    156 for i in range(colorsUsed[0]):
    157     colorIndex.append(0)
    158 
    159 #Assign the colors to the array.  upto = 54
    160 # startOfDefinitions = upto
    161 for i in range(colorsUsed[0]):
    162     upto =  startOfDefinitions + (i * 4)
    163     blue = contents[upto]
    164     green = contents[upto + 1]
    165     red = contents[upto + 2]
    166     # ignore the alpha channel.
    167 
    168     # data = struct.pack("BBBB", contents[upto], contents[upto+1], contents[upto+2], contents[upto+3])
    169     # t = struct.unpack("I", bytearray(data))
    170     # colorIndex[i] = t[0]
    171 
    172     colorIndex[i] = (((red & 0xf8)<<8) + ((green & 0xfc)<<3)+(blue>>3))
    173     debugOut("color at index {0} is {1:04x}, (r,g,b,a) = ({2:02x}, {3:02x}, {4:02x}, {5:02x})".format(i,  colorIndex[i], red, green, blue, contents[upto+3]))
    174 
    175 #debugOut(the color definitions
    176 # for i in range(colorsUsed[0]):    
    177 #     print hex(colorIndex[i])
    178 
    179 # perfect, except upside down.
    180 
    181 #Make a string to hold the output of our script
    182 arraySize = (len(contents) - offset[0]) 
    183 outputString = "/* This was generated using a script based on the SparkFun BMPtoArray python script" + '\n'
    184 outputString += " See https://github.com/sparkfun/BMPtoArray for more info */" + '\n\n'
    185 outputString += "static const uint16_t palette[" + str(colorsUsed[0]) + "] = {";
    186 for i in range(colorsUsed[0]): 
    187     # print hexlify(colorIndex[i])
    188     if i % 4 == 0:
    189         outputString += "\n\t"
    190     outputString += "0x{:04x}, ".format(colorIndex[i])
    191 
    192 outputString = outputString[:-2]
    193 outputString += "\n};\n\n"
    194 outputString += "// width is " + str(width) + ", height is " + str(height) + "\n"
    195 outputString += "static const uint8_t myGraphic[" + str(arraySize) + "] PROGMEM = {" + '\n'
    196 
    197 if bitsPerPixel != 4:
    198     print("Expected 4 bits per pixel; found {}".format(bitsPerPixel))
    199     sys.exit(1)
    200     
    201 #Start converting spots to values
    202 #Start at the offset and go to the end of the file
    203 dropLastNumber = True #(width % 4) == 2 or (width % 4) == 1
    204 paddedWidth = int(math.ceil(bitsPerPixel * width / 32.0) * 4)
    205 debugOut("array range is {} {} len(contents) is {} paddedWidth is {} width is {}".format(offset[0], fileSize[0], len(contents), paddedWidth, width))
    206 
    207 r = 0
    208 width = int(width / 2)
    209 #for i in range(offset[0], fileSize[0]):                 # close but image is upside down.  Each row is correct but need to swap columns.
    210 #for i in range(fileSize[0], offset[0], -1):
    211 
    212 for col in range(height-1, -1, -1):
    213     i = 0
    214     for row in range(width):
    215         colorCode1 = contents[row + col*paddedWidth + offset[0]]  
    216 
    217         if r > 0 and r % width == 0:
    218             i = 0
    219             outputString += '\n\n'
    220         elif (i + 1) % 12 == 0 :
    221             outputString += '\n'
    222             i = 0
    223         
    224         #debugOut("cell ({0}, {1})".format(row, col)
    225 
    226         r = r + 1
    227         i = i + 1
    228         outputString += "0x{:02x}, ".format(colorCode1)
    229 
    230 
    231     
    232 #Once we've reached the end of our input string, pull the last two
    233 #characters off (the last comma and space) since we don't need
    234 #them. Top it off with a closing bracket and a semicolon.
    235 outputString = outputString[:-2]
    236 outputString += "};"
    237 
    238 try:
    239     #Write the output string to our output file
    240     outfile = open(output, "w")
    241     outfile.write(outputString)
    242     outfile.close()
    243 except:
    244     print("could not write output to file {}".format(output))
    245     sys.exit(1)
    246 
    247 debugOut("{} complete".format(output))
    248 debugOut("Copy and paste this array into a image.h or other header file")
    249 
    250 if not debug:
    251     print("Completed; the output is in {}".format(output))