lpcware

Convert Windows BMP (24bpp-BGR) to TFT (16bpp-RGB)

Discussion created by lpcware Employee on Jun 15, 2016
Content originally posted in LPCWare by Ex-Zero on Sun Jan 01 06:16:19 MST 2012
Playing with SWIM I was trying to load a simple 480x272 Windows BMP file from SD. Wasn't too difficult (with EA SD sample) to load a 24bpp file to SDRAM.
But SWIM is expecting 16bpp, so a conversion is needed. Picture data (width, height, picture data offset) are stored in BMP file and can be read there via offset as shown below:

<code>
//DRAM 2M Words x 32 Bits x 4 Banks (256-MBIT)
//at 0xA000 0000 - 0xA1FF FFFF range = 0x0200 0000
#define SDRAM_FRAME (SDRAM_BASE+0x10000)
#define SDRAM_PIC   (SDRAM_BASE+0x800000)
#define SDRAM_RAW   (SDRAM_BASE+0x1000000)


/***********************************************************************
* Function: draw_picture
*
* Purpose:  read Windows BMP (24bpp GBR) from SD and draw it (480x272)
*
* Parameters:
*     win  : Window identifier
*     filename : filename
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: this function is reading original 24bpp GBR files (Windows)
*
**********************************************************************/
static int draw_picture(SWIM_WINDOW_T *win, const char * filename)
{
uint8_t *raw24_ptr;//pointer to reading 24bpp BGR
COLOR_T *pic_ptr;//pointer to writing 16bpp RGB565
uint16_t p_col;//color bits
uint32_t p_off;//data offset
uint32_t p_w;//picture width
uint32_t p_h;//picture height

//set picture pointer pointer
pic_ptr = (COLOR_T *)SDRAM_PIC;
raw24_ptr = (uint8_t *)SDRAM_RAW;
swim_set_pen_color(win,BLACK);
res = f_open (&file, filename, FA_READ);
if (res)
{
  sprintf(buff, "Failed to open ip.txt: %d \n", res);
  swim_put_text(win,(const char*)&buff);
  return 0;
}
//read image
res = f_read (&file,(void*)raw24_ptr,Finfo.fsize, &numRead);/* Read data from a file */
if (res || numRead <= 0)
{
  sprintf(buff, "Failed to read file: %d \n", res);
  swim_put_text(win,(const char*)&buff);
  return 0;
}
sprintf(buff, "Read %d bytes\n",numRead);
// swim_put_text(win,(const char*)&buff);
// swim_put_text(win,(const char*)"Closing file\n");
res =  f_close (&file);
if (res)
{
  sprintf(buff, "Failed to close new.txt: %d \n", res);
  swim_put_text(win,(const char*)&buff);
  return 0;
}
raw24_ptr =(uint8_t *)SDRAM_RAW;
p_off = *(uint16_t*)(raw24_ptr +0x0A);
p_w = *(uint32_t*)(raw24_ptr +0x12);
p_h = *(uint32_t*)(raw24_ptr +0x16);
p_col = *(uint16_t*)(raw24_ptr +0x1C);
sprintf(buff, "Offset %d\nWidth %d - Height %d - Color %d\n",p_off,p_w,p_h,p_col);
// swim_put_text(win,(const char*)&buff);
raw24_ptr += p_off;//set pointer to data offset

pic_ptr = (COLOR_T *)SDRAM_PIC;

convert24to16(raw24_ptr,pic_ptr,p_w,p_h);

pic_ptr = (COLOR_T *)SDRAM_PIC;
//clear screen if necessary
// swim_clear_screen(win,BLACK);
//put image
swim_put_image(win,pic_ptr,p_w,p_h);
return 1;
}
</code>


Conversion is more than just changing size and color order. Mirroring must be done also:


<code>

/***********************************************************************
* Function: convert24to16
*
* Purpose:  convert Windows BMP (24bpp GBR) to 16bpp 565 RGB
*
* Parameters:
*     read_buffer : read from bmp data buffer (uint8) = bmp-file + data_offset
*     write_buffer: write to picture buffer (uint16)
*     width   : picture width
*     height      : picture height
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: this function is also changing byte order to avoid
*        wrong 'mirroring' of pictures
*
**********************************************************************/
static void convert24to16(uint8_t* read_buffer,uint16_t* write_buffer,uint32_t width,uint32_t height)
{
uint32_t p_x;//picture x position
uint32_t p_y;//picture y position
write_buffer += (width*height)-1-width;//start at last line
//read 24bit BGR to 16bit RGB
for(p_y=0;p_y<height;p_y++)//y = lines = height
{
  for(p_x=0;p_x<width;p_x++)//x = pixel = width
  {
//convert 3 byte data BGR (Windows BMP) to 2 byte data RBG 565
   *write_buffer = (*read_buffer & 0xF8)>>3;//read upper 5 bits blue
   read_buffer++;//next color byte
   *write_buffer |=((*read_buffer &0xFC)<<3);//read upper 6 bits green
   read_buffer++;//next color byte
   *write_buffer |=((*read_buffer & 0xF8)<<8);//add upper 5 bits red
   write_buffer++;//next picture int
   read_buffer++;//next color byte
  }//end pixel
  write_buffer-= 2*width;//2 lines back
}//end line
}//end function
</code>

Now BMP files from SD card can be shown:


<iframe width="420" height="315" src="http://www.youtube.com/embed/rjQXyU5zlnQ" frameborder="0" allowfullscreen></iframe>

Outcomes