/* showbmp.cxx **************************************************************************/
#include
#include "bmp.hxx"
#include "util.hxx"
using namespace std;
using namespace dzb_image;
int main(int argc, char *argv[])
{
CBmp my_bmp;
if( argc != 2 ) return FAILED;
if( my_bmp.read_file(argv[1]) == FAILED ) return FAILED;
my_bmp.dump_header();
my_bmp.convert_YCrCb();
return SUCCESSED;
}
/***********************************************************************************************************/
/* bmp.hxx ***********************************************************************************************/
#include
#include
#ifndef BMP_HXX
#define BMP_HXX
using namespace std;
namespace dzb_image {
typedef unsigned char UCHAR;
typedef unsigned long ULONG;
typedef unsigned short USHORT;
// struct RGBQuad
struct RGBQuad {
char blud;
char green;
char red;
char res;
};
// struct Palette
struct Palette {
int num;
struct RGBQuad pRGBQuads;
};
// struct BmpFileHeader
struct BmpFileHeader {
USHORT m_file_id;
ULONG m_file_size;
ULONG m_reserved;
ULONG m_bmp_data_offset;
} __attribute__ ((packed));
// struct BmpInfoHeader
struct BmpInfoHeader {
ULONG m_bmp_header_size;
ULONG m_width;
ULONG m_height;
USHORT m_planes;
USHORT m_bits_per_pixel;
ULONG m_compression;
ULONG m_bmp_data_size;
ULONG m_HResolution;
ULONG m_VResolution;
ULONG m_colors;
ULONG m_imp_colors;
} __attribute__ ((packed));
// class CBmp
class CBmp {
private:
#define FILE_NAME_LEN 63
enum { BM = 0x424d, BI_RGB = 0, BI_RLE8 = 1, BI_RLE4 = 2, BI_BITFIELDS = 3 };
char m_filename[FILE_NAME_LEN + 1];
ifstream m_bmpstream;
struct BmpFileHeader m_bmfh;
struct BmpInfoHeader m_bmih;
struct Palette m_palette;
UCHAR *m_bmpdata;
UCHAR *m_ycbcr;
public:
CBmp() {
memset(m_filename, 0, FILE_NAME_LEN + 1);
memset(&m_bmfh, 0, sizeof(m_bmfh));
memset(&m_bmih, 0, sizeof(m_bmih));
memset(&m_palette, 0, sizeof(m_palette));
m_bmpdata = NULL;
m_ycbcr = NULL;
}
~CBmp() {
m_bmpstream.close();
if( m_bmpdata != NULL ) delete []m_bmpdata;
if( m_ycbcr != NULL ) delete []m_ycbcr;
}
int read_file(char* file);
void convert_YCrCb();
void dump_header();
void dump_data();
};
}
/* bmp.cxx **********************************/
#include
#include
#include "bmp.hxx"
#include "util.hxx"
using namespace std;
using namespace dzb_image;
/*
* just deal with bmp file with:
* compression = 0
* bits per pixel = 24
* ( no palette )
*/
int CBmp::read_file(char *file)
{
int ret = SUCCESSED;
strncpy(m_filename, file, FILE_NAME_LEN);
m_bmpstream.open(m_filename, ios::in | ios::binary);
assert(m_bmpstream);
// read the bmp file header
m_bmpstream.read((char*)&m_bmfh, sizeof(m_bmfh));
BitOrder::ch_word(&m_bmfh.m_file_id);
if( m_bmfh.m_file_id != BM ) {
ret = FAILED;
return ret;
}
// read the bmp info header
m_bmpstream.read((char*)&m_bmih, sizeof(m_bmih));
// read the palette, if exist
// re-sum the Image size field
if( m_bmih.m_compression == BI_RGB ) {
switch (m_bmih.m_bits_per_pixel) {
case 1:
case 4:
case 8:
case 16:
case 24:
case 32:
m_bmih.m_bmp_data_size = ( ( (m_bmih.m_width * m_bmih.m_bits_per_pixel + 31) >> 5 ) << 2) * m_bmih.m_height;
// set palette
if( m_bmih.m_bits_per_pixel == 24 ) m_palette.num = 0;
break;
default:
cout << "Illegal bits per pixel: " << m_bmih.m_bits_per_pixel << endl;
exit(-1);
}
} else {
cout << "This bmp file is compressed, compression = " << ( m_bmih.m_compression == BI_RLE8 ? "BI_RLE8" : (m_bmih.m_compression == BI_RLE4 ? "BI_RLE4" : "BI_BITFIELDS") ) << endl;
}
// read the bitmap data
if( m_palette.num == 0 && m_bmih.m_compression == BI_RGB && m_bmih.m_bits_per_pixel == 24 ) {
if( m_bmpdata != NULL ) {
delete []m_bmpdata;
m_bmpdata = NULL;
}
if( m_ycbcr != NULL ) {
delete []m_ycbcr;
m_ycbcr = NULL;
}
m_bmpdata = new UCHAR[m_bmih.m_bmp_data_size];
assert(m_bmpdata);
m_bmpstream.read((char*)m_bmpdata, m_bmih.m_bmp_data_size);
} else {
cout << "Only deal with no compression, bits per pixel = 24 bmp file!" << endl;
exit(-1);
}
return ret;
}
void CBmp::dump_header()
{
cout << "File id: " << hex << "0x" << m_bmfh.m_file_id << endl;
cout << dec;
cout << "Total file size: " << m_bmfh.m_file_size << endl;
cout << "Bitmap data offset: " << m_bmfh.m_bmp_data_offset << endl;
cout << "Bmp info header size: " << m_bmih.m_bmp_header_size << endl;
cout << "Bmp width: " << m_bmih.m_width << endl;
cout << "Bmp height: " << m_bmih.m_height << endl;
cout << "Bmp Planes: " << m_bmih.m_planes << endl;
cout << "Bits per pixel: " << m_bmih.m_bits_per_pixel << endl;
cout << "Is compression: " << m_bmih.m_compression << endl;
cout << "Image size: " << m_bmih.m_bmp_data_size << endl;
cout << "H resolution: " << m_bmih.m_HResolution << " pixel/meter" << endl;
cout << "V resolution: " << m_bmih.m_VResolution << " pixel/meter" << endl;
cout << "Color used: " << m_bmih.m_colors << endl;
cout << "Important color number: " << m_bmih.m_imp_colors << endl;
}
void CBmp::dump_data()
{
UCHAR *data = m_bmpdata;
int i = 0;
if( data != NULL ) {
cout << endl;
cout << hex;
while( data <= m_bmpdata + m_bmih.m_bmp_data_size ) {
i++;
cout <<" 0x" << setw(4) << setfill('0') << (USHORT) *data;
if( i % 10 == 0 ) cout << endl;
data += sizeof(USHORT);
}
cout << endl;
}
}
/*
* convert bmp data array to YCrCb format
*/
void CBmp::convert_YCrCb()
{
int i, j, k;
if( m_ycbcr != NULL ) return;
m_ycbcr = new UCHAR[m_bmih.m_bmp_data_size];
assert(m_ycbcr);
k = 0;
for ( i = m_bmih.m_height - 1; i >= 0; i-- ) {
// locate the first pixel
for( j = 0; j < m_bmih.m_width; j++ ) {
// get red, blue, green component
UCHAR red, blue, green;
UCHAR *base;
base = &m_bmpdata[i * m_bmih.m_bmp_data_size / m_bmih.m_height + j * 3];
red = *base;
base++;
green = *base;
base++;
blue = *base;
// caculate Y, Cr, Cb for this pixel
m_ycbcr[k++] = (UCHAR)(0.299 * red + 0.587 * green + 0.114 * blue); // Y
m_ycbcr[k++] = (UCHAR)(-0.1687 * red - 0.3313 * green + 0.5 * blue + 128); // Cb
m_ycbcr[k++] = (UCHAR)(0.5 * red - 0.4187 * green - 0.0813 * blue + 128); // Cr
// cout << "Y = 0x" << hex << (USHORT)m_ycbcr[k-3] <<
// " cb = 0x" << (USHORT)m_ycbcr[k-2] <<
// " cr = 0x" << (USHORT)m_ycbcr[k-1] << endl;
}
}
}
/* util.hxx ***********************************************************************************************/
#include "bmp.hxx"
#ifndef UTIL_HXX
#define UTIL_HXX
#define SUCCESSED 0
#define FAILED 1
namespace dzb_image {
// class BitOrder
class BitOrder {
public:
static void ch_byte(UCHAR *c);
static void ch_word(USHORT *word);
static void ch_dword(ULONG *dword);
};
}
#endif
/*************************************************************************************************************/
#include "util.hxx"
using namespace dzb_image;
void BitOrder::ch_byte(UCHAR *c)
{
UCHAR lobyte = 0x0f;
lobyte = *c & lobyte;
*c = (*c >> 4) + (lobyte << 4);
}
void BitOrder::ch_word(USHORT *word)
{
USHORT lobyte = 0xff;
lobyte = *word & lobyte;
*word = (*word >> 8) + (lobyte << 8);
}
void BitOrder::ch_dword(ULONG *dword)
{
ULONG loword = 0xffff;
cout << hex << "0x" << *dword << endl;
loword = *dword & loword;
*dword = (*dword >> 16) + (loword << 16);
ch_word( (USHORT*)dword + 1 ); // low word
ch_word( (USHORT*)dword ); // high word
}
/**************************************************************************************************/
/* Makefile **************************************************************************************/
showbmp: showbmp.cxx util.o bmp.o
g++ -g showbmp.cxx bmp.o util.o -o showbmp
util.o: util.cxx util.hxx
g++ -g util.cxx -c -o util.o
bmp.o: bmp.cxx bmp.hxx
g++ -g bmp.cxx -c -o bmp.o
clean:
rm *.o showbmp