#!/usr/bin/python3 # =============================================================== # read a BMP file and paint it into a graphics window # # The graphics.py module is slow. That is OK because # this is an exercise in learning "stuff". # =============================================================== import graphics as gr import user_interface as ui # --------------------------------------------------------------- # ---- create graphics window # --------------------------------------------------------------- def create_graphics_window(width,height): win = gr.GraphWin('BMP Image',width,height) win.setBackground('white') return win # --------------------------------------------------------------- # ---- open BMP file and read it directly into a byte array # --------------------------------------------------------------- def load_bmp_to_array(bmp_file_path:str) -> bytearray: with open(bmp_file_path,'rb') as file: bmp_bytes = file.read() return bmp_bytes # --------------------------------------------------------------- # ---- calculate row padding # ---- # ---- Note: The pixel format is defined by the DIB header or # ---- extra bit masks. Each row in the Pixel array is # ---- padded to a multiple of 4 bytes in size. # --------------------------------------------------------------- def calculate_row_padding(width): match (width * 3) % 4: case 3: return 1 case 2: return 2 case 1: return 3 return 0 # --------------------------------------------------------------- # ---- copy pixels to the graphics window # --------------------------------------------------------------- def copy_image_to_window(win,width,height,offset,bary): # ---- byte array index padding for the end of each row padding = calculate_row_padding(width) print(f'padding = {padding}') # ---- byte array index byt_idx = offset # ---- image is upside down and should be reversed # ---- thus the -1 increment for y in range(height-1,0,-1): for x in range(width): # ---- RGB colors b = int.from_bytes(bary[byt_idx :byt_idx+1],'little') g = int.from_bytes(bary[byt_idx+1:byt_idx+2],'little') r = int.from_bytes(bary[byt_idx+2:byt_idx+3],'little') # ---- plot (draw) pixel color = gr.color_rgb(r,g,b) win.plotPixel(x,y,color) # ---- next pixel byt_idx += 3 # ---- end of row - add padding to get # ---- the start of next row byt_idx += padding return # --------------------------------------------------------------- # ---- main # --------------------------------------------------------------- if __name__ == '__main__': ##file_path = 'bmp_all_red.bmp' # 25 x 27 file_path = 'mona_lisa_small_a.bmp' # 100 x 149 ##file_path = 'mona_lisa_small_b.bmp' # 149 x 100 bmp_bytes = load_bmp_to_array(file_path) image_height = int.from_bytes(bmp_bytes[22:26],'little') image_size = int.from_bytes(bmp_bytes[34:38],'little') image_offset = int.from_bytes(bmp_bytes[10:14],'little') image_width = int.from_bytes(bmp_bytes[18:22],'little') print() print(f'{len(bmp_bytes)} from file {file_path}') print() print(f'image offset = {image_offset}') print(f'image width = {image_width}') print(f'image height = {image_height}') print(f'image size = {image_size}') win = create_graphics_window(image_width,image_height) copy_image_to_window(win,image_width,image_height, image_offset,bmp_bytes) ui.pause() print()