C++ Image Upload Problem

Started by
12 comments, last by neob 17 years, 2 months ago
----EDITED for accuracy and new error.---- In dev cpp, compiler errors.
if (bmfh.bfType != 'MB') return 2;
112:19 [Warning] multi-character character constant [Linker error] undefined reference to `SetDIBitsToDevice@48' 112:19 Id returned 1 exit status If I make if (bmfh.bfType != 'MB') return 2; into comments I still get, [Linker error] undefined reference to `SetDIBitsToDevice@48' 112:19 Any help is appriciated.

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

using namespace std;

char szAppName [] = "BMPLoad";

LRESULT CALLBACK WindowProc (HWND, UINT, WPARAM, LPARAM);

// **********
// class CRaster
//   - Generic class for BMP raster images.
class CRaster {
	public:
		int Width,Height;		// Dimensions
		int BPP;				// Bits Per Pixel.
		char * Raster;			// Bits of the Image.
		RGBQUAD * Palette;		// RGB Palette for the image.
		int BytesPerRow;		// Row Width (in bytes).
		BITMAPINFO * pbmi;		// BITMAPINFO structure

		// Member functions (defined later):
		int LoadBMP (char * szFile);
		int GDIPaint (HDC hdc,int x,int y);
};

// **********
// Windows Main Function. 
//   - Here starts our demo program
int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,
					LPSTR lpCmdLine, int nCmdShow )
{
	HWND hwnd;
	MSG msg;

	WNDCLASS wc;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	wc.lpfnWndProc = WindowProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor (NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = szAppName;

	RegisterClass (&wc);

	hwnd = CreateWindow (szAppName,"BMP Load",WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
		0,0,hInstance,0);

	ShowWindow (hwnd,nCmdShow);
	UpdateWindow (hwnd);

	while (GetMessage(&msg,0,0,0))
	{
		TranslateMessage (&msg);
		DispatchMessage (&msg);
	}

	return msg.wParam;
}

// **********
// Main Window Procedure.
//   - Processes Window Messages
LRESULT CALLBACK WindowProc
	(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static CRaster bmp;
	HDC hdc;
	PAINTSTRUCT ps;

	switch (message)
	{
		case WM_CREATE:
			bmp.LoadBMP ("example.bmp");
			return 0;
		case WM_PAINT:
			hdc=BeginPaint (hwnd,&ps);
			bmp.GDIPaint (hdc,10,10);
			EndPaint (hwnd,&ps);
			return 0;
		case WM_DESTROY:
			PostQuitMessage (0);
			return 0;
	}
	return DefWindowProc (hwnd,message,wParam,lParam);
}

// **********
// CRaster::LoadBMPFile (FileName);
//   - loads a BMP file into a CRaster object
//   * supports non-RLE-compressed files of 1, 2, 4, 8 & 24 bits-per-pixel
int CRaster::LoadBMP (char * szFile)
{
	BITMAPFILEHEADER bmfh;
	BITMAPINFOHEADER bmih;

	// Open file.
	ifstream bmpfile(szFile , ios::in | ios::binary);
	if (! bmpfile.is_open()) return 1;		// Error opening file

	// Load bitmap fileheader & infoheader
	bmpfile.read ((char*)&bmfh,sizeof (BITMAPFILEHEADER));
	bmpfile.read ((char*)&bmih,sizeof (BITMAPINFOHEADER));

	// Check filetype signature
	if (bmfh.bfType != 'MB') return 2;		// File is not BMP

	// Assign some short variables:
	BPP=bmih.biBitCount;
	Width=bmih.biWidth;
	Height= (bmih.biHeight>0) ? bmih.biHeight : -bmih.biHeight; // absoulte value
	BytesPerRow = Width * BPP / 8;
	BytesPerRow += (4-BytesPerRow%4) % 4;	// int alignment

	// If BPP aren't 24, load Palette:
	if (BPP==24) pbmi=(BITMAPINFO*)new char [sizeof(BITMAPINFO)];
	else
	{
		pbmi=(BITMAPINFO*) new char[sizeof(BITMAPINFOHEADER)+(1<<BPP)*sizeof(RGBQUAD)];
		Palette=(RGBQUAD*)((char*)pbmi+sizeof(BITMAPINFOHEADER));
		bmpfile.read ((char*)Palette,sizeof (RGBQUAD) * (1<<BPP));
	}
	pbmi->bmiHeader=bmih;

	// Load Raster
	bmpfile.seekg (bmfh.bfOffBits,ios::beg);

	Raster= new char[BytesPerRow*Height];

	// (if height is positive the bmp is bottom-up, read it reversed)
	if (bmih.biHeight>0)
		for (int n=Height-1;n>=0;n--)
			bmpfile.read (Raster+BytesPerRow*n,BytesPerRow);
	else
		bmpfile.read (Raster,BytesPerRow*Height);

	// so, we always have a up-bottom raster (that is negative height for windows):
	pbmi->bmiHeader.biHeight=-Height;

	bmpfile.close();

	return 0;
}

// **********
// CRaster::GDIPaint (hdc,x,y);
// * Paints Raster to a Windows DC.
int CRaster::GDIPaint (HDC hdc,int x=0,int y=0)
{
	// Paint the image to the device.
	return SetDIBitsToDevice (hdc,x,y,Width,Height,0,0,
		0,Height,(LPVOID)Raster,pbmi,0);
}


[Edited by - neob on January 31, 2007 4:07:12 PM]
Advertisement
The errors tell you pretty much all you need to know: <fstream.h> isn't a C++ header. You want to #include <fstream>.

There's a little bit more, though. Since ifstream is in the std:: namespace, you need to prepend it with "std::" to use it. There are other ways of getting a workable result, but this will build good habits. The same goes for ios. So, this line:
ifstream bmpfile(szFile , ios::in | ios::binary);
should look like this:
std::ifstream bmpfile(strFile.c_str( ), std::ios::in | std::ios::binary);
Now, you may have picked up on another little change: "strFile.c_str( )." That's because it's highly recommended that, rather than chars, C++ programmers use std::strings. (You'll need to #include <string>.) A quick google can get you started with strings, after you switch headers and get some "std::" action going.

Also, here's a handy reference for file I/O in C++.

Best of luck!
-jouley
First thank you very much for replying and pointing out many improvements to the code :)

I changed the
#include <fstream>
and
std::ifstream bmpfile(strFile.c_str( ), std::ios::in | std::ios::binary);


After I get it to compile I will replace the chars to strings.

On top I edited the code to what it looks like now, but now I get a new compile error.

In member function `int CRaster::LoadBMP(char*)': `strFile' undeclared (first use this function)   (Each undeclared identifier is reported only once for each function it appears in.) [Warning] multi-character character constant 

When I indicated the changed variable name, it was only to show that you std::strings are much simpler, easier, and safer than char*s. So, you'll still need to use the parameter you pass to int CRaster::LoadBMP (char * szFile). Change the strFile.c_str( ) back to szFile and you should be good to go.

Even after you change to std::strings, you can name the variable whatever you like, though, by convention, "sz-" refers to a char* type, and "str-" refers to a string type.

Best of luck!
-jouley
hmm lol silly me.
Ok now I get this;

if (bmfh.bfType!='MB') return 2;

112:19 [Warning] multi-character character constant
[Linker error] undefined reference to `SetDIBitsToDevice@48' 112:19
Id returned 1 exit status
Quote:Original post by neob
if (bmfh.bfType!='MB') return 2;


When you use single quotes around something, it means it's a character. "MB" is two characters ;). Also, you can't compare character strings that way (you can, though, with std::strings!). Make sure that's actually what you want that line to do, then either make the switch, or google strcmp.

-jouley
Quote:
When you use single quotes around something, it means it's a character. "MB" is two characters ;).


I think I miss understood you, but do you mean that I can only use 'M' and it cannot be 'MB' - that makes no sense to me.
Out of curiosity, where did you find this gem?

To fix the current error, you'll need to add the library "Gdi32.lib" in your project settings. I can't help you with that as far as Dev-C++ goes, but I'm sure google can.
http://www.cplusplus.com/src/
do you know a better "bitmap upload to program" source code?

This topic is closed to new replies.

Advertisement