การจัดการไฟล์ bitmap เพื่อแสดงผลบนจอ TFT

ซื้อจอ TFT แบบในรูปมา เพื่อจะใช้กับ Arduino โปรแกรมแรกที่ใช้กับจอนี้เป็น example ที่มากับ library ของ adafruit ก็ใช้งานได้ดี เห็นที่จอมีช่อง sd card อยู่ ก็เลยลองให้แสดงรูปใน sd card วนๆ ไปดู แก้ไขจากตัวอย่างโปรแกรมแสดงรูปที่อยู่ใน library ของ adafruit เช่นเดียวกัน ปรากฏว่าทำงานได้ แต่ช้ามากๆ โดยรูปที่จะเอาขึ้นจอต้องเป็นไฟล์ BMP ด้วย ค้นพบว่ารูปแบบการแสดงผลของจอเป็นแบบ 16 บิต คือ สีแดง 5 บิต สีเชียว 6 บิต สี น้ำเงิน 5 บิต

จอ TFT แบบ SPI

รูปแบบการเรียงบิตของ RGB565

ถ้าจะให้แสดงผลเร็วขึ้นก็ต้องแปลงไฟล์ BMP แบบ 24 บิต เป็น 16 บิต ก่อน ซึ่งอ่านดูหลายที่เขาแนะให้ใช้ GIMP (GIMP.org) แปลงไฟล์ โดยเลือก save ไฟล์ เป็น BMP 16 บิต แต่เราก็ไม่อยากลง GIMP เพราะว่าไม่ได้ใช้งานมันทำอย่างอื่น นึกไปนึกมา python น่าจะทำได้นะ ก็เจอว่า SciPy มี function สำหรับอ่านไฟล์รูปภาพด้วย ถ้าอ่านไฟล์ได้ค่าสีของแต่ละ pixel ได้เราก็แปลงเป็น 16 บิต และ save ลงเป็นไฟล์ข้อมูลเฉยๆ ได้ แล้วเอาไปเขียนขึ้นจอตรงๆ เลย

Code แปลงค่าสี

def RGB(r,g,b):
    return  (((r&0xF8)<<8)|((g&0xFC)<<3)|((b&0xF8)>>3)) #5 red | 6 green | 5 blue

def RGBfromArray(pixel):
    return RGB(pixel[0],pixel[1],pixel[2])


with open(outputfile, 'bw') as f:      # then use shell command 'xxd file' to see hex dump
        image= misc.imread(os.path.join(inputfile), flatten= 0)
        for m in range(len(image)): # m row index
            for n in range(len(image[0])):  # n col index
                color = RGBfromArray(image[m][n])
                hiByte = (color & 0xFF00) >> 8
                loByte = color & 0x00FF
                f.write(bytes([loByte,hiByte])) 

ผลก็คือทำงานได้เร็วกว่าไฟล์ BMP เดิมๆ มาก

คราวนี้พอได้ไฟล์ข้อมูล pixel ดิบๆ แล้ว อยากได้เป็น BMP แบบ 16 บิตล่ะ ก็เจอว่ามีโปรแกรมแปลงไฟล์ให้โหลดฟรีๆ ที่ https://www.displaymodule.com/pages/imageconverter เป็นบริษัทขายจอสำหรับ embedded system เลยลองแปลงไฟล์เพื่อที่จะแกะ header ของไฟล์ BMP ดู และเทียบกับไฟล์ BMP ที่ยังไม่ได้แปลงด้วย โดยอ้างอิงข้อมูลจาก https://en.wikipedia.org/wiki/BMP_file_format

ได้ข้อมูลแล้วก็เอาไปเขียนโปรแกรมเติม header ให้กับไฟล์ข้อมูล pixel ให้กลายเป็น BMP ซะ Code python สำหรับส่วนสร้าง header ก็ตามนี้

def genBMP16header(width,height):

    id = bytes("BM",'UTF-8')
    size = 70 + width*height*2
    dummy1 = 0
    dummp2 = 0
    bitmapOffset = 70
    sizeofDIB = 56
    bitmapWidth = width
    bitmapHeight = -1*height
    colorPlane = 1
    colorDepth = 16 # 16 bit / pixel
    compression = 3 # BI_Bitfields 
    sizeofBitmapArray = width*height*2
    h_resolution = 3780 # 96DPI
    v_resolution = 3780 
    colorPalette = 0
    importantColors = 0
    redbitmask = 0x0000F800
    greenbitmask = 0x000007E0
    bluebitmask = 0x0000001F
    alphabitmask = 0

    header = struct.pack('<2sLHHLLLlHHLLLLLLLLLL',id,size,dummy1,dummp2,bitmapOffset, \
                   sizeofDIB,bitmapWidth,bitmapHeight,colorPlane,colorDepth,compression, \
                   sizeofBitmapArray,h_resolution,v_resolution,colorPalette,importantColors, \
                   redbitmask,greenbitmask,bluebitmask,alphabitmask)

    return header
หลังจากเขียน python เสร็จ ทำงานได้อย่างที่ต้องการ สร้างไฟล์ BMP ได้ถูกต้อง อยากลองเขียนภาษา C บ้าง ให้ทำงานอย่างเดียวกัน ผลคือโปรแกรมภาษา C ทำงานเร็วกว่า python ประมาณ 3 เท่า