Dependencies:   mbed

myBMP/myBMP.cpp

Committer:
XkLi
Date:
2011-10-11
Revision:
0:c546b51ecf0b

File content as of revision 0:c546b51ecf0b:

#include "myBMP.h"

int BitDepth = 1;
int Width = 1;
int Height = 1;
RGBApixel *Colors;

bool SafeFread( char* buffer, int size, int number, FILE* fp )
{
 using namespace std;
 int ItemsRead;
 if( feof(fp) )
 { return false; }
 ItemsRead = (int) fread( buffer , size , number , fp );
 if( ItemsRead < number )
 { return false; }
 return true;
}

bool Read32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row, NokiaLCD *lcd)
{ 
 int i;
 char Colors[4];
 if( Width*4 > BufferSize )
 { return false; }
 for( i=0 ; i < Width ; i++ )
 {
    memcpy( (char*) &(Colors), (char*) Buffer+4*i, 4 );
     //Blue, Green, Red, Alpha
    int color = 0x00000000 | (Colors[2] << 16) | (Colors[1] << 8) | (Colors[0]);
    (*lcd).pixel((130-Width)/2+i,(130-Height)/2+Row,color);
 }
 return true;
}

bool Read24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row, NokiaLCD *lcd)
{ 
 int i;
 char Colors[4];
 if( Width*3 > BufferSize )
 { return false; }
 for( i=0 ; i < Width ; i++ )
 {
    memcpy( (char*) &(Colors), (char*) Buffer+3*i, 3 );
     //Blue, Green, Red, Alpha
    int color = 0x00000000 | (Colors[2] << 16) | (Colors[1] << 8) | (Colors[0]);
    (*lcd).pixel((130-Width)/2+i,(130-Height)/2+Row,color);
 }
 return true;
}

RGBApixel GetColor( int ColorNumber)
{ 
 RGBApixel Output;
 Output.Red   = 255;
 Output.Green = 255;
 Output.Blue  = 255;
 Output.Alpha = 0;
 
 if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
 {
  return Output;
 }
 if( !Colors )
 {
  return Output; 
 }
 Output = Colors[ColorNumber];
 return Output;
}

bool Read8bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row, NokiaLCD *lcd)
{
 int i;
 if( Width > BufferSize )
 { return false; }
 for( i=0 ; i < Width ; i++ )
 {
    int Index = Buffer[i];
     //Blue, Green, Red, Alpha
    RGBApixel colors = GetColor(Index);
    int color = 0x00000000 | (colors.Red<< 16) | (colors.Blue << 8) | (colors.Green);
    (*lcd).pixel((130-Width)/2+i,(130-Height)/2+Row,color);
 }
 return true;
}

bool Read4bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row, NokiaLCD *lcd)
{
 int Shifts[2] = {4  ,0 };
 int Masks[2]  = {240,15};
 
 int i=0;
 int j;
 int k=0;
 if( Width > 2*BufferSize )
 { return false; }
 while( i < Width )
 {
  j=0;
  while( j < 2 && i < Width )
  {
   int Index = (int) ( (Buffer[k]&Masks[j]) >> Shifts[j]);
   RGBApixel colors = GetColor(Index);
   int color = 0x00000000 | (colors.Red<< 16) | (colors.Blue << 8) | (colors.Green);
   (*lcd).pixel((130-Width)/2+i,(130-Height)/2+Row,color);
   i++; j++;   
  }
  k++;
 }
 return true;
}
bool Read1bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row, NokiaLCD *lcd)
{
 int Shifts[8] = {7  ,6 ,5 ,4 ,3,2,1,0};
 int Masks[8]  = {128,64,32,16,8,4,2,1};
 
 int i=0;
 int j;
 int k=0;
 
 if( Width > 8*BufferSize )
 { return false; }
 while( i < Width )
 {
  j=0;
  while( j < 8 && i < Width )
  {
   int Index = (int) ( (Buffer[k]&Masks[j]) >> Shifts[j]);
   RGBApixel colors = GetColor(Index);
   int color = 0x00000000 | (colors.Red<< 16) | (colors.Blue << 8) | (colors.Green);
   (*lcd).pixel((130-Width)/2+i,(130-Height)/2+Row,color);
   i++; j++;   
  }
  k++;
 }
 return true;
}

int TellNumberOfColors( int BitDepth )
{
 int output = 1 << BitDepth;
 if( BitDepth == 32 )
 { output = 1 << 24; }
 return output;
}

bool ReadBMPFromFile( const char* FileName, RGBApixel *Colors, NokiaLCD *lcd)
{ 
 FILE* fp = fopen( FileName, "rb" );
 if( fp == NULL )
 {
  return false;
 }
 
 // read the file header 
 
 BMFH bmfh;
 bool NotCorrupted = true;
 
 NotCorrupted &= SafeFread( (char*) &(bmfh.bfType) , sizeof(ebmpWORD), 1, fp);
 
 bool IsBitmap = false;
 
 if( bmfh.bfType == 19778 )
 { IsBitmap = true; }
 
 if( !IsBitmap ) 
 {
  fclose( fp ); 
  return false;
 }

 NotCorrupted &= SafeFread( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1, fp); 
 NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1, fp);
 NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1, fp);
 NotCorrupted &= SafeFread( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp);
 
 // read the info header

 BMIH bmih; 
 
 NotCorrupted &= SafeFread( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp);
 NotCorrupted &= SafeFread( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp); 
 NotCorrupted &= SafeFread( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp);
 NotCorrupted &= SafeFread( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1, fp); 
 NotCorrupted &= SafeFread( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1, fp);

 NotCorrupted &= SafeFread( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp);
 NotCorrupted &= SafeFread( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp);
 NotCorrupted &= SafeFread( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
 NotCorrupted &= SafeFread( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
 NotCorrupted &= SafeFread( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp);
 NotCorrupted &= SafeFread( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp);
 
 // a safety catch: if any of the header information didn't read properly, abort
 // future idea: check to see if at least most is self-consistent
  
 if( !NotCorrupted )
 {
  fclose(fp);
  return false;
 } 
 
 // if bmih.biCompression 1 or 2, then the file is RLE compressed
 
 if( bmih.biCompression == 1 || bmih.biCompression == 2 )
 {
  fclose(fp);
  return false; 
 }
 
 // if bmih.biCompression > 3, then something strange is going on 
 // it's probably an OS2 bitmap file.
 
 if( bmih.biCompression > 3 )
 {
  fclose(fp);
  return false; 
 }
 
 if( bmih.biCompression == 3 && bmih.biBitCount != 16 )
 {
  fclose(fp);
  return false; 
 }

 // set the bit depth
 
 int TempBitDepth = (int) bmih.biBitCount;
 if(    TempBitDepth != 1  && TempBitDepth != 4 
     && TempBitDepth != 8  && TempBitDepth != 16
     && TempBitDepth != 24 && TempBitDepth != 32 )
 {
  fclose(fp);
  return false;
 }
 BitDepth = (int)bmih.biBitCount;
 // set the size

 if( (int) bmih.biWidth <= 0 || (int) bmih.biHeight <= 0 ) 
 {
  fclose(fp);
  return false;
 } 
 Width = (int) bmih.biWidth;
 Height = (int) bmih.biHeight;
 // some preliminaries
 
 double dBytesPerPixel = ( (double) BitDepth ) / 8.0;
 double dBytesPerRow = dBytesPerPixel * (Width+0.0);
 dBytesPerRow = ceil(dBytesPerRow);
  
 int BytePaddingPerRow = 4 - ( (int) (dBytesPerRow) )% 4;
 if( BytePaddingPerRow == 4 )
 { BytePaddingPerRow = 0; }  
 
 // if < 16 bits, read the palette
 
 if( BitDepth < 16 )
 {
  // determine the number of colors specified in the 
  // color table
  
  int NumberOfColorsToRead = ((int) bmfh.bfOffBits - 54 )/4;  
  if( NumberOfColorsToRead > (1 << BitDepth) )
  { NumberOfColorsToRead = (1 << BitDepth); }
 
  int n;
  for( n=0; n < NumberOfColorsToRead ; n++ )
  {
   SafeFread( (char*) &(Colors[n]) , 4 , 1 , fp);     
  }
  for( n=NumberOfColorsToRead ; n < TellNumberOfColors(BitDepth) ; n++ )
  {
   RGBApixel WHITE; 
   WHITE.Red = 255;
   WHITE.Green = 255;
   WHITE.Blue = 255;
   WHITE.Alpha = 0;
   Colors[n] = WHITE;
  }
 }
 
 // skip blank data if bfOffBits so indicates
 
 int BytesToSkip = bmfh.bfOffBits - 54;;
 if( BitDepth < 16 )
 { BytesToSkip -= 4*(1 << BitDepth); }
 if( BitDepth == 16 && bmih.biCompression == 3 )
 { BytesToSkip -= 3*4; }
 if( BytesToSkip < 0 )
 { BytesToSkip = 0; }
 if( BytesToSkip > 0 && BitDepth != 16 )
 {
  ebmpBYTE* TempSkipBYTE;
  TempSkipBYTE = new ebmpBYTE [BytesToSkip];
  SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);   
  delete [] TempSkipBYTE;
 } 
  
 // This code reads 1, 4, 8, 24, and 32-bpp files 
 // with a more-efficient buffered technique.

 int i,j;
 if( BitDepth != 16 )
 {
  int BufferSize = (int) ( (Width*BitDepth) / 8.0 );
  while( 8*BufferSize < Width*BitDepth )
  { BufferSize++; }
  while( BufferSize % 4 )
  { BufferSize++; }
  ebmpBYTE* Buffer;
  Buffer = new ebmpBYTE [BufferSize];
  j= Height-1;
  while( j > -1 )
  {
   int BytesRead = (int) fread( (char*) Buffer, 1, BufferSize, fp );
   if( BytesRead < BufferSize )
   {
    j = -1; 
   }
   else
   {
    bool Success = false;
    if( BitDepth == 1  )
    { Success = Read1bitRow(  Buffer, BufferSize, j , lcd); }
    if( BitDepth == 4  )
    { Success = Read4bitRow(  Buffer, BufferSize, j , lcd); }
    if( BitDepth == 8  )
    { Success = Read8bitRow(  Buffer, BufferSize, j , lcd); }
    if( BitDepth == 24 )
    { Success = Read24bitRow( Buffer, BufferSize, j , lcd); }
    if( BitDepth == 32 )
    { Success = Read32bitRow( Buffer, BufferSize, j , lcd); }
    if( !Success )
    {
     j = -1;
    }
   }   
   j--;
  }
  delete [] Buffer; 
 }

 if( BitDepth == 16 )
 {
  int DataBytes = Width*2;
  int PaddingBytes = ( 4 - DataBytes % 4 ) % 4;

  // set the default mask
  
  ebmpWORD BlueMask = 31; // bits 12-16
  ebmpWORD GreenMask = 992; // bits 7-11
  ebmpWORD RedMask = 31744; // bits 2-6

  // read the bit fields, if necessary, to 
  // override the default 5-5-5 mask
  
  if( bmih.biCompression != 0 )
  {
   // read the three bit masks

   ebmpWORD TempMaskWORD;
  
   SafeFread( (char*) &RedMask , 2 , 1 , fp );
   SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
  
   SafeFread( (char*) &GreenMask , 2 , 1 , fp );
   SafeFread( (char*) &TempMaskWORD , 2, 1, fp );

   SafeFread( (char*) &BlueMask , 2 , 1 , fp );
   SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
  }
  
  // read and skip any meta data

  if( BytesToSkip > 0 )
  {
   ebmpBYTE* TempSkipBYTE;
   TempSkipBYTE = new ebmpBYTE [BytesToSkip];
   SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);
   delete [] TempSkipBYTE;   
  } 
  
  // determine the red, green and blue shifts
  
  int GreenShift = 0; 
  ebmpWORD TempShiftWORD = GreenMask;
  while( TempShiftWORD > 31 )
  { TempShiftWORD = TempShiftWORD>>1; GreenShift++; }  
  int BlueShift = 0;
  TempShiftWORD = BlueMask;
  while( TempShiftWORD > 31 )
  { TempShiftWORD = TempShiftWORD>>1; BlueShift++; }  
  int RedShift = 0;  
  TempShiftWORD = RedMask;
  while( TempShiftWORD > 31 )
  { TempShiftWORD = TempShiftWORD>>1; RedShift++; }  
  
  // read the actual pixels
  
  for( j=Height-1 ; j >= 0 ; j-- )
  {
   i=0;
   int ReadNumber = 0;
   while( ReadNumber < DataBytes )
   {
    ebmpWORD TempWORD;
    SafeFread( (char*) &TempWORD , 2 , 1 , fp );
    ReadNumber += 2;
  
    ebmpWORD Red = RedMask & TempWORD;
    ebmpWORD Green = GreenMask & TempWORD;
    ebmpWORD Blue = BlueMask & TempWORD;
                
    ebmpBYTE BlueBYTE = (ebmpBYTE) 8*(Blue>>BlueShift);
    ebmpBYTE GreenBYTE = (ebmpBYTE) 8*(Green>>GreenShift);
    ebmpBYTE RedBYTE = (ebmpBYTE) 8*(Red>>RedShift);
        
    int color = 0x00000000 | (RedBYTE << 16) | (GreenBYTE << 8) | (BlueBYTE);
    (*lcd).pixel((130-Width)/2+i,(130-Height)/2+j,color);
    i++;
   }
   ReadNumber = 0;
   while( ReadNumber < PaddingBytes )
   {
    ebmpBYTE TempBYTE;
    SafeFread( (char*) &TempBYTE , 1, 1, fp);
    ReadNumber++;
   }
  }

 }
 
 fclose(fp);
 return true;
}


BMIH::BMIH()
{
 biPlanes = 1;
 biCompression = 0;
 biXPelsPerMeter = DefaultXPelsPerMeter;  
 biYPelsPerMeter = DefaultYPelsPerMeter;
 biClrUsed = 0;
 biClrImportant = 0;
}

BMFH::BMFH()
{
 bfType = 19778;
 bfReserved1 = 0;
 bfReserved2 = 0;
}