|
-
August 22nd, 2011, 05:05 AM
#1
[RESOLVED] Loading bitmap without using MFC
A solution I got from a different thread has opened Pandora's Box for me. Now I'm going crazy trying to figure out a problem I'm having.
I have struggled to understand bitmaps for quite some time. Until now, I have heavily relied on MFC to do all the bitmap details, but now I want to understand more of what is happening. Specifically, I would like to create a function that loads a bitmap from a file using only C++ and the standard template library. Yes, I am aware this is reinventing the wheel, but until I understand what is happening with the load process, I will never be happy using code from another person or agency. I have tried finding this on the internet and through FAQs but have had marginal success in the process. If there is a place I should be looking, I would appreciate a pointer in the right direction.
The current version of the function I have is as follows. Its aim is to load the bitmap and then pass it to a CBitmap object. I am aware that CBitmap is used by MFC, but until I get this version to work, I will be hesitant to take further steps away from MFC.
Code:
// in CDynamicBitmapCreationDlg.h
class FileObject
{
FILE* m_pFile;
public:
FileObject( FILE *pFile ) : m_pFile( pFile ) {}
~FileObject() { if (m_pFile) fclose(m_pFile); }
};
// in CDynamicBitmapCreationDlg.cpp
int CDynamicBitmapCreationDlg::load_bitmap_from_file(char* file, CBitmap* p_newbitmap)
{
if(!p_newbitmap)
{
MessageBox("Error location 0");
return 0;
}
//First we open the file the binary mode
FILE* in = fopen(file,"rb");
FileObject fObject( in );
//Next we read the BITMAPFILEHEAR. . .
BITMAPFILEHEADER bmfh;
size_t result = fread(&bmfh,sizeof(BITMAPFILEHEADER),1,in);
if(result < 1)
{
MessageBox("Error location 1");
return 0;
}
if(bmfh.bfType != 19778)
{
MessageBox("Error location 2");
return 0;
}
//Then the BITMAPINFOHEADER. . .
BITMAPINFOHEADER bmih;
result = fread(&bmih,sizeof(BITMAPINFOHEADER),1,in);
if(result < 1)
{
MessageBox("Error location 3");
return 0;
}
//Next comes the palette
std::vector<RGBQUAD> colors;
//set the number of colours
int number_of_colors = 1 << bmih.biBitCount;
//load the palette if the bitmap has less than 24 bits per pixel
if(bmih.biBitCount < 24)
{
colors.resize(number_of_colors);
result = fread(&colors[0], sizeof(RGBQUAD), number_of_colors,in);
if(result < number_of_colors)
{
MessageBox("Error location 4");
return 0;
}
}
//Now we read in the pixel data
DWORD data_size = bmfh.bfSize - bmfh.bfOffBits;
std::vector<BYTE> p_initialdata(data_size);
result = fread(&p_initialdata[0],sizeof(BYTE),data_size,in);
if(result < data_size)
{
MessageBox("Error location 6");
return 0;
}
//The data has been read. First, check if padding is needed
//byteWidth is the width of the actual image in bytes
//padWidth is the width of the image plus the extra padding
LONG width_in_bytes = 0;
LONG width_plus_padding = 0;
width_in_bytes = width_plus_padding = (LONG)((float)bmih.biWidth*(float)bmih.biBitCount/8.0);
//add any extra space to bring each line to a DWORD boundary
while(width_plus_padding % 4 != 0)
{
width_plus_padding++;
}
//Second, we transfer the data from the temporary buffer to the final buffer,
// adjusting for padding and inversion, if necessary
DWORD actual_size;
int offset;
//set diff to the actual image size(no padding)
actual_size = bmih.biHeight * width_in_bytes;
//allocate memory for the image
BYTE* p_finaldata = new BYTE[actual_size];
if(bmih.biHeight > 0)
{
// The bitmap is inverted, so we'll need to reverse the image and remove the padding
int j = data_size - 3;
offset = width_plus_padding - width_in_bytes;
for( int i = 0 ; i < data_size ; i += 3 )
{
if( (i+offset) % width_plus_padding == 0 )
{
i += offset;
}
*(p_finaldata + j + 2) = p_initialdata[i];
*(p_finaldata + j + 1) = p_initialdata[i + 1];
*(p_finaldata + j) = p_initialdata[i + 2];
j -= 3;
}
}
else
{
// The bitmap is not inverted. We only need to remove the padding
LONG height = bmih.biHeight * -1;
offset = 0;
do
{
memcpy((p_finaldata+(offset*width_in_bytes)),(&p_initialdata[0] + (offset*width_plus_padding)),width_in_bytes);
offset++;
} while(offset < height);
}
/****************************************/
/* I BELIEVE THE PROBLEM IS HERE SOMEWHERE */
/****************************************/
//Here we begin to construct the BITMAP object
BITMAP bmp;
bmp.bmBitsPixel = bmih.biBitCount;
bmp.bmHeight = bmih.biHeight;
bmp.bmWidth = bmih.biWidth;
bmp.bmType = 0;
bmp.bmWidthBytes = width_in_bytes;
bmp.bmPlanes = bmih.biPlanes;
bmp.bmBits = p_finaldata;
if((p_newbitmap->CreateBitmapIndirect(&bmp)) == 0)
{
delete [] p_finaldata;
MessageBox("Error location 8");
return 0;
}
return 1;
}
As far as I know, the bitmap data is properly handled up until the BITMAP structure is filled in. The problem, I think, is with CreateBitmapIndirect. When I run it, the 'if' statement does not trigger, but the bitmap still doesn't show up in my dialog. I can load the same bitmap from file using LoadImage and it appears in the dialog, so I know that part works. Here is how the two implementations look in CDynamicBitmapDialog::OnInitDialog():
Code:
// THIS WORKS
m_bitmap = (HBITMAP)::LoadImage(0 ,_T("C:\\4by4bitmap.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION );
MainImage.ModifyStyle(0,SS_BITMAP);
if(m_bitmap)
MainImage.SetBitmap(m_bitmap);
versus. . .
Code:
// THIS DOES NOT WORK
CBitmap temp_bitmap;
load_bitmap_from_file(_T("C:\\4by4bitmap.bmp"),&temp_bitmap);
m_bitmap = (HBITMAP)temp_bitmap;
MainImage.ModifyStyle(0,SS_BITMAP);
if(m_bitmap)
MainImage.SetBitmap(m_bitmap);
(I comment out one method while I test the other)
I have tried SetBitmapBits and that also does nothing.
I would be very grateful to anyone able to help. I always try to leave good reputation feedback.
The bitmap in question can be found here: http://www.codeguru.com/forum/showthread.php?t=514930
error C2146a : syntax error : nebulizer stained in the tower floppy apple rider. Go rubble in flee smite. Bleeble snip snip.
Documentation says: error C2146a - This means there is an error somewhere in the course of human endeavor. Fix in the usual way.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|