• Not Answered

[solved]Converting 24 bit BMP to RGB565 application

SOLVED:

Now I have a working bmp24 to rgb565 converter. It both produces a binary file of the image and a header file which has the image information in a data structure.

Here is the code

/*

  FILE: bmp24_to_rgb565
  ....: takes a 24 bit bmp image as input and output a rgb565 image format binary file and a header file
  ....: which consists of the rgb565 data structre.
  ....: designed for LITTLE ENDIAN

*/


#include <stdio.h>
#include <string.h>
#include <windows.h>

#define RGB16(red, green, blue) ( ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3))
#define MAX_OSD_WIDTH 720 // Max Davinci OSD width
#define MAX_OSD_HEIGHT 576 // Max Davinci OSD height (for PAL support)
#define MAX_OSD_SIZE MAX_OSD_WIDTH*MAX_OSD_HEIGHT
#define NTSC_OSD_WIDTH 720
#define NTSC_OSD_HEIGHT 480


/*

  FUNCTION...: adjusts the given input character array and write to the given file stream.
  ...........: given input character array is 2 byte rgb565 data, and needed to be formatted properly
  ...........: to be written into file stream. (which is a header file)

*/
bool convert_bmp24_to_rgb16_in_array(FILE *rgb16SourceFile, char input_character_array[], int newline_flag )
{
 
 char len;
 
 char buffer_write[5];

 len = strlen(input_character_array);
 
 switch (len)
 {
         case 4:
              {   
                    buffer_write[0] = input_character_array[0];
                    buffer_write[1] = input_character_array[1];
                    buffer_write[2] = input_character_array[2];
                    buffer_write[3] = input_character_array[3];
                    buffer_write[4] = '\0'; 
                    //printf( "buffer write: %s\n", buffer_write );
              }
         break;
        
         case 3:
              {
                    buffer_write[0] = '0';
                    buffer_write[1] = input_character_array[0];
                    buffer_write[2] = input_character_array[1];
                    buffer_write[3] = input_character_array[2];
                    buffer_write[4] = '\0';
                    //printf( "buffer write: %s\n", buffer_write );         
              }
         break;
             
         case 2:
              {
                    buffer_write[0] = '0';
                    buffer_write[1] = '0';
                    buffer_write[2] = input_character_array[0];
                    buffer_write[3] = input_character_array[1];
                    buffer_write[4] = '\0'; 
                    //printf( "buffer write: %s\n", buffer_write );                           
              }
         break;
        
         case 1:
              {
                    buffer_write[0] = '0';
                    buffer_write[1] = '0';
                    buffer_write[2] = '0';
                    buffer_write[3] = input_character_array[0];
                    buffer_write[4] = '\0';
                    //printf( "buffer write: %s\n", buffer_write );                       
              }
         break;
        
         case 8: /* This case is only entered when no unsigned variables are used/ */
              {
                    buffer_write[0] = input_character_array[7];
                    buffer_write[1] = input_character_array[6];
                    buffer_write[2] = input_character_array[5];
                    buffer_write[3] = input_character_array[4];
                    buffer_write[4] = '\0';
                    //printf( "buffer write: %s\n", buffer_write );   
              }
         break;
        
         default:
          printf("Err: Unexpected strlen value. len: %d", len);
          return false;             
 }
 
 if( !(newline_flag % 2) )
  fprintf(rgb16SourceFile, "0x%s", buffer_write);
 else
  fprintf(rgb16SourceFile, "%s,\n", buffer_write);
 
  return true;

}


int main(int argc, char *argv[])
{

 FILE *rgb24file; /* for bmp file */
 FILE *rgb16file; /* for rgb565 binary file */
 FILE *rgb16SourceFile; /* for header file which holds rgb565 data structure */
 unsigned char red, green, blue; //pixel bytes
 long fileSize;
 long x, y;
 int width=NTSC_OSD_WIDTH, height=NTSC_OSD_HEIGHT; //Default values
 char hexString[8];

 /* STARTUP ADJUSTMENTS */
 if (argc < 2)
 {
  printf("Usage: %s filename [width][height]\n", argv[0]);
  return -1;
 }
 else if ((argc > 2) && (argc != 4))
 {
  printf("Must specify both width and height or neither\n");
  printf("Usage: %s filename [width][height]\n", argv[0]);
 return -1;
 }
 else if ((argc == 4) && (atoi(argv[2]) > MAX_OSD_WIDTH))
 {
  printf("width cannot exceed %d pixels\n", MAX_OSD_WIDTH);
  return -1;
 }
 else if ((argc==4) && (atoi(argv[3]) > MAX_OSD_HEIGHT))
 {
  printf("height cannot exceed %d pixels\n", MAX_OSD_HEIGHT);
  return -1;
 }
 else if (argc==4)
 {
 //Valid width and Height were entered; therefore override defaults
  width = atoi(argv[2]);
  height = atoi(argv[3]);
 }

unsigned short osdData[width * height];

 /* CONVERSION PROCESS STARTING */
 printf("Preparing to convert %s (%d x %d)....\n", argv[1], width, height);
 // Open file in read-binary mode
 rgb24file = fopen(argv[1], "rb");
 if (rgb24file == NULL)
 {
 printf("could not find file %s \n", argv[1]);
 return -1;
 }
 // Get size of file
 fseek(rgb24file, 0, SEEK_END);
 fileSize = ftell(rgb24file);

 fseek(rgb24file, 0, SEEK_SET);
 printf("size %d\n", fileSize);

 //Skip BMP header information (which is 54 byte)
 fseek(rgb24file, 54, SEEK_SET);
 fileSize = fileSize - 54;

 //Ensure file size does not exceed Max supported OSD size
 if (fileSize > (MAX_OSD_SIZE*3))
 {
  printf("This file is too large, maximum supported size is 720x576x3\n");
 }

/*
 else if (((fileSize % 3) !=0)|| (fileSize != (width*height*3)))
 {
  printf("file size: %d\n", fileSize);
  printf("this file does not have the size expected \n");
 }
*/

 /* PROCESS PART */
 else
 {
            for( x=0; x < (width*height); x++)  //for every pixel, read the rgb values and store them in osdData[]
           {
           
            fread(&blue, sizeof(char), 1, rgb24file);
            fread(&green, sizeof(char), 1, rgb24file);
            fread(&red, sizeof(char), 1, rgb24file);
      
            osdData[x] = RGB16(red, green, blue);

           }
          
           // Open .h file
           rgb16SourceFile = fopen("rgb565_image.h", "w");
           // Open file in read-binary mode
           rgb16file = fopen("osd.r16", "wb");
          
           fprintf (rgb16SourceFile, "unsigned long rgb565_image_720x480[] = {\n");
          
           for (y= height -1; y >=0; y--)
           {
               for (x=0; x < width; x ++)
               {
               //write to osd.r16 file in a binary stream
               fwrite(&osdData[(width*y) + x], sizeof(short), 1, rgb16file);
                
               //call to write rgb565_image.h file in a structre format
               sprintf(hexString, "%X", osdData[(width*y) + x] );
               convert_bmp24_to_rgb16_in_array(rgb16SourceFile, hexString, x);
               }
            }
           
            fprintf (rgb16SourceFile, "};\n");
           
            fclose(rgb16file);
            fclose(rgb16SourceFile);
  }
 
 fclose(rgb24file);
 
 return 0;
}

 

Previous Message:

Hi,

I am using the bmp24 to rgb565 converter code from http://focus.ti.com/lit/an/spraad7/spraad7.pdf . 

This application saves the bitmap data in a file that is written in a binary manner.

-When I change the file extension .r16 to .raw and open the file with Photoshop or Paintshop, a black and white and corrupted image opens. Is this because of the media opener can not encode the image or is the converter code doesn't work right? I think writing to file operation (loops and the fwrite content) is a little awkward, like it is not writing properly, but I will check it tomorrow morning, and I also think the example of TI can't be wrong.

-I modified the code a little to create a .h file and put the data into an array. (Because, all examples I have seen reads the image data into frame buffer using arrays.) But now I have a problem.

For example, in DSP/BIOS VPBE User Guide, the given example processes a yuv image CbCr.

The array is:

unsigned long yuv_imageCbCr_720x480[] =

{

0x7A756AA2,

...

0x74937C4B

};

Bits per pixel for this format is 16 bits, as RGB565. But in the array, every line is consisted of 4 bytes. Is this because of byte aligning?

My application produces an array like:

unsigned long rgb565_image_720x480[] = {
0x862,
0x10A3,
0x10C3,
...

0x0,

};

 

Here, every line is 2 bytes. Is that a problem? Do I have to align them to four bytes? If yes, how?

 

And here is the application code of the BMP24 to RGB565 converter.

 

#include <stdio.h>
#include <string.h>
#include <windows.h>

#define RGB16(red, green, blue) ( ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3))
#define MAX_OSD_WIDTH 720 // Max Davinci OSD width
#define MAX_OSD_HEIGHT 576 // Max Davinci OSD height (for PAL support)
#define MAX_OSD_SIZE MAX_OSD_WIDTH*MAX_OSD_HEIGHT
#define NTSC_OSD_WIDTH 720
#define NTSC_OSD_HEIGHT 480

int main(int argc, char *argv[])
{
 unsigned short osdData[720 * 480];
 FILE *rgb24file;
 FILE *rgb16file;
 FILE *rgb16SourceFile;
 unsigned char red, green, blue; //pixel bytes
 long fileSize;
 int x, y;
 int width=NTSC_OSD_WIDTH, height=NTSC_OSD_HEIGHT; //Default values

 /* STARTUP ADJUSTMENTS */
 if (argc < 2)
 {
  printf("Usage: %s filename [width][height]\n", argv[0]);
  return -1;
 }
 else if ((argc > 2) && (argc != 4))
 {
  printf("Must specify both width and height or neither\n");
  printf("Usage: %s filename [width][height]\n", argv[0]);
 return -1;
 }
 else if ((argc == 4) && (atoi(argv[2]) > MAX_OSD_WIDTH))
 {
  printf("width cannot exceed %d pixels\n", MAX_OSD_WIDTH);
  return -1;
 }
 else if ((argc==4) && (atoi(argv[3]) > MAX_OSD_HEIGHT))
 {
  printf("height cannot exceed %d pixels\n", MAX_OSD_HEIGHT);
  return -1;
 }
 else if (argc==4)
 {
 //Valid width and Height were entered; therefore override defaults
  width = atoi(argv[2]);
  height = atoi(argv[3]);
 }


 /* CONVERSION PROCESS STARTING */
 printf("Preparing to convert %s (%d x %d)....\n", argv[1], width, height);
 // Open file in read-binary mode
 rgb24file = fopen(argv[1], "rb");
 if (rgb24file == NULL)
 {
 printf("could not find file %s \n", argv[1]);
 return -1;
 }
 // Get size of file
 fseek(rgb24file, 0, SEEK_END);
 fileSize = ftell(rgb24file);

 fseek(rgb24file, 0, SEEK_SET);
 printf("size %d\n", fileSize);

 //Skip BMP header information (which is 54 byte)
 fseek(rgb24file, 54, SEEK_SET);
 fileSize = fileSize - 54;

 //Ensure file size does not exceed Max supported OSD size
 if (fileSize > (MAX_OSD_SIZE*3))
 {
  printf("This file is too large, maximum supported size is 720x576x3\n");
 }

 else if (((fileSize % 3) !=0)|| (fileSize != (width*height*3)))
 {
  printf("this file does not have the size expected \n");
 }

 /* PROCESS PART */
 else
 {
            for( x=0; x < (width*height); x++)  //for every pixel, read the rgb values and store them in osdData[]
           {
            fread(&blue, sizeof(char), 1, rgb24file);
            fread(&green, sizeof(char), 1, rgb24file);
            fread(&red, sizeof(char), 1, rgb24file);
            osdData[x] = RGB16(red, green, blue);
           }
          
           // Open .h file
           rgb16SourceFile = fopen("rgb565_image.h", "w");
           fprintf (rgb16SourceFile, "unsigned long rgb565_image_720x480[] = {\n");
          

           // Open file in read-binary mode
           rgb16file = fopen("osd.r16", "wb");
           for (y= height -1; y >=0; y--)
           {
               for (x=0; x < width; x ++)
               {
               fprintf(rgb16SourceFile, "0x%X,\n", osdData[(width*y) + x]);
               //printf(" %X\n", osdData[(width*y) + x]);
               //write to osd.r16 file in a binary stream
               fwrite(&osdData[(width*y) + x], sizeof(short), 1, rgb16file);
              
               }
            }
            fprintf (rgb16SourceFile, "};\n");
           
            fclose(rgb16file);
            fclose(rgb16SourceFile);
  }
 
 fclose(rgb24file);

 return 0;
}

 

Thank you in advance,

A. Erman Kulunyar

 

2 Replies

  • Erman,

    I was out that week, but am familiar with the App Note (I authored it) if you have any additional questions.  Based on the status of the post, it appears you have a working solution.

  • In reply to Juan Gonzales:

    By the way, I've found an interesting link: http://www.swview.org/node/165

    Basically this guy uses FFMPEG (http://ffmpeg.mplayerhq.hu/) to convert RGB565 to any other image format (JPG, PNG, etc.):

    e.g.

    ffmpeg -vcodec rawvideo -f rawvideo -pix_fmt rgb565 -s 1024x768 -i image.raw -f image2 -vcodec png image.png

    I used FFMPEG to check my RGB888 to RGB565 conversion.

    Just in case, a small code snippet to convert RGB888 RAW Interlaced data (RGBRGBRGB) to RGB565 format in C#, based on SPRAAD7:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;

    namespace DaVinciImageTools
    {
        class Program
        {

            static short RGB16(byte red, byte green, byte blue)
            {
                short rgb16_value = (short) (((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3));
                return rgb16_value;
            }

            // arguments:
            //  0: image source filename
            //  1: image destination filename
            //  2: width
            //  3: height
            static void Main(string[] args)
            {
                if (args.Length != 4)
                {
                    Console.WriteLine("Wrong number of arguments !");
                    return;
                }

                string sourceFilename = args[0];
                string destinationFilename = args[1];
                string sWidth = args[2];
                string sHeight = args[3];

                short width = Int16.Parse(sWidth);
                short height = Int16.Parse(sHeight);

                if ((width == 0) || (height == 0))
                {
                    Console.WriteLine("Unknown resolution");
                    return;
                }

                FileStream strmSource;

                // read source file
                try
                {
                    strmSource = File.Open(sourceFilename, FileMode.Open);
                }
                catch (FileNotFoundException e)
                {
                    Console.WriteLine("Source file not found");
                    return;
                }

                int sourceLength = (int)strmSource.Length;

                // attach a binary reader
                BinaryReader brSource = new BinaryReader(strmSource);
                byte[] data = brSource.ReadBytes(sourceLength);
                strmSource.Close();
                brSource.Close();

                // perform RGB888 to RGB565 conversion
                int counter = 0;
                short[] destinationData = new short[width * height];
                // format is RGBRGBRGB
                for (int x = 0; x < sourceLength; x = x + 3)
                {
                    byte red = data[x];
                    byte green = data[x + 1];
                    byte blue = data[x + 2];

                    short rgb16_val = RGB16(red, green, blue);
                    destinationData[counter] = rgb16_val;
                    counter++;
                }

                // write to destination file
                FileStream strmDestination;

                // read source file
                strmDestination = File.Open(destinationFilename, FileMode.Create);

                BinaryWriter bwDestination = new BinaryWriter(strmDestination);

                for (int x = 0; x < (int)destinationData.Length; x++)
                {
                    bwDestination.Write(destinationData[x]);
                }

                bwDestination.Close();
                strmDestination.Close();
            }
        }
    }