?
Solved

Reading bitmaps in C++

Posted on 2003-03-03
12
Medium Priority
?
644 Views
Last Modified: 2013-12-03
Okay, so I have looked around, read a few tutorials, and discovered ways of reading bitmap files into a DOS app, myself (no I don't want to use MFC or SDL or Windows functions - I'm talking pure C++)
Only problem is none of them work.
My program will load the first member variable of the Bitmap Header struct properly, but after that it gets messed up. I have been messing with it for quite some time but haven't yet been able to figure out whats wrong. I have lots of details I can post if you need them - but all I really want is working code to load the bitmap into memory, or else an eplanation of how C++ loads and saves classes using fstream.write and fstream.read, and how to make it work with the bitmap file.
I am using Windows XP, and have compiled the code under both MSVC++ 6.0 and DJGPP, with the same results.
0
Comment
Question by:Cobras2
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 4
  • 2
  • +2
12 Comments
 
LVL 1

Expert Comment

by:d_iego
ID: 8061997
I think I've got what you need.  Its on codeproject.com it is easy to understand and has examples that work, I hope it works, I'll give you the address:
www.codeproject.com/bitmap/gditutorial.asp


Diego Mendieta
   
 
0
 

Expert Comment

by:bolludobarbaro
ID: 8062475
this page
www.codeproject.com/bitmap/index.asp

is very helpful but in many tutorials (may be all of them) they use MFC. I had the same problem, becuase just like you, I wanted not to use MFC.
Here is a code that writes the bitmap into a file using plain c++ code. The only thing I can give you is a code that writes a bitmap into a file. I know you are looking for a code which reads from a file as well, but this may help you for the writing time.
The program captures the image of the current form and save it in a file (c:\dddd.bmp) in 16-bits. Good luck.


int captura()
{
HWND capture, hw;
char buf[1024];
LPCTSTR tit_ventana;
HDC hdc;

hw = GetForegroundWindow();
     GetWindowText(hw,buf,1023);
     tit_ventana = buf;

if ( (capture = FindWindow(NULL,tit_ventana)) == NULL)
         exit(1);

if ( (hdc = GetWindowDC(capture)) == NULL )  

// get window dimensions
RECT rect;
GetWindowRect(capture, &rect);

size_t dx = rect.right - rect.left;
size_t dy = rect.bottom - rect.top;

// create BITMAPINFO structure
// used by CreateDIBSection
BITMAPINFO info;
info.bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
info.bmiHeader.biWidth         = dx;
info.bmiHeader.biHeight        = dy;
info.bmiHeader.biPlanes        = 1;
info.bmiHeader.biBitCount      = 16;
info.bmiHeader.biCompression   = BI_RGB;
info.bmiHeader.biSizeImage     = 0;
info.bmiHeader.biXPelsPerMeter = 0;
info.bmiHeader.biYPelsPerMeter = 0;
info.bmiHeader.biClrUsed       = 0;
info.bmiHeader.biClrImportant  = 0;

// a bitmap handle and a pointer its bit data
HBITMAP bitmap = 0;
BYTE*   memory = 0;

// create bitmap
HDC device = GetDC(capture);
bitmap = CreateDIBSection(device, &info, DIB_RGB_COLORS, (void**)&memory, 0, 0);
ReleaseDC(capture, device);
if(!bitmap || !memory) return 0;

// blit the contents of the desktop (winDC)
// to the bitmap (selected in memDC)
HDC winDC = GetWindowDC(capture);
HDC memDC = CreateCompatibleDC(winDC);
SelectObject(memDC, bitmap);
BitBlt(memDC, 0, 0, dx, dy, winDC, 0, 0, SRCCOPY);
DeleteDC(memDC);
ReleaseDC(capture, winDC);

// create bitmap file
basic_ofstream<char> file("c:\\ddddddd.bmp", ios::binary);
if(!file) { DeleteObject(bitmap); return 0; }

// initialize bitmap file headers
BITMAPFILEHEADER fileHeader;
BITMAPINFOHEADER infoHeader;

fileHeader.bfType      = 0x4d42;
fileHeader.bfSize      = 0;
fileHeader.bfReserved1 = 0;
fileHeader.bfReserved2 = 0;
fileHeader.bfOffBits   = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

infoHeader.biSize          = sizeof(infoHeader);
infoHeader.biWidth         = dx;
infoHeader.biHeight        = dy;
infoHeader.biPlanes        = 1;
infoHeader.biBitCount      = 16;
infoHeader.biCompression   = BI_RGB;
infoHeader.biSizeImage     = 0;
infoHeader.biXPelsPerMeter = 0;
infoHeader.biYPelsPerMeter = 0;
infoHeader.biClrUsed       = 0;
infoHeader.biClrImportant  = 0;

     // Compute the size of the  infoheader and the color table
 DWORD               dwLen;
     int nColors = (1 << infoHeader.biBitCount);
     if( nColors > 256 )
          nColors = 0;
     dwLen  = infoHeader.biSize + nColors * sizeof(RGBQUAD);


// save file headers
file.write((char*)&fileHeader, sizeof(fileHeader));
file.write((char*)&infoHeader, sizeof(infoHeader));

// save 16-bit bitmap data
int wbytes = (((16*dx + 31) & (~31))/8);
int tbytes = (((16*dx + 31) & (~31))/8)*dy;
file.write((char*)memory, tbytes);
file.close();

// delete bitmap
DeleteObject(bitmap);
bitmap = 0;
memory = 0;


return 0;
}
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 8063155
Why your program probably fails is related to the fact that there are several different formats for the data in a BMP file -- specifically the color depth -- BPP (Bits Per Pixel) and that will throw you off if you are not expecting it.

The good news is that tHere is no need to twiddle the bits manually!  To read a .BMP file from disk into memoru, use the Win32 API function
     LoadImage()
You can use that function (and most other Win32 API functions) even if you are running "Plain old DOS code" in a Win32 Console window.  That will not help you in a Unix environment, but you did not specify Unix compatibility as a criteria in your question.

-- Dan
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 

Expert Comment

by:vijay_rangaraj
ID: 8063953
Hi
  If you can wait till 8th (if that is not troubling you), I can give you full turbo C code that displays BMP's in true color (24bpp). It also displays the video card vendor and amount of actual video memory available. It is a DOS based program.

  My home is far away from the place I work, and I visit only in weekends. If you need them, also tell me how to mail you the code (5 kb)

--Vijay
0
 

Author Comment

by:Cobras2
ID: 8068935
Actually, most of the above examples use either MFC or the Win32 API.
I said DOS not console :)
I don't want functions that use any Win32 API functions at all, and yes I have accounted for the variations in the way the bitmap structure is stored, however none of it has helped.
It seems that when the program tries to read a structure like this:

struct Bitmap {
unsigned short type;
long Size, Reserved, OffBits;
<..etc>
and the bitmap file itself(look for yourself with a hex editor..) has the following:
2 bytes for type

2 bytes for Size
2 more bytes for Size

2 bytes for Reserved
2 more bytes for Reserved

2 bytes for OffBits
2 more bytes for OffBits

the code reads the first value (unsigned short type) properly, but then assumes that the next 2 bytes are somehow to be disregarded. It ignores them. I have no idea why, but it does, and then picks up reading the file after those two bytes, which are *supposed* to be two of the bytes belonging to (long Size); so what it actually puts into (long Size) are the last two bytes that are supposed to be in it, and then the first two bytes of (long Reserved) !!
this of course messes everything up.
What I need to know is: how can I load it without having this happen?
and also, a much better solution would be, *why* is this happening? I am using the same method that others have used, it worked for them, but it doesn't work for me.
0
 

Expert Comment

by:vijay_rangaraj
ID: 8069499
The following links may help you!!!

http://members.fortunecity.com/shetzl/bmpffrmt.html
http://www.wotsit.org/search.asp?s=graphics

www.wotsit.org is great!!
By the way, you must not read the size bytes as 2+2. You must read them as a 4 byte unsigned integer.
0
 
LVL 49

Accepted Solution

by:
DanRollins earned 800 total points
ID: 8070034
Your problem is related to the way the compiler is organizing your structure defintions.  It is inserting padding between fields so that they each line up on 32-bit boundaries (it is a default optimization performed by most modern compilers).  In VC++, you can override this behavior by adding this:

   #pragma pack(1)

to the top of the header that defines your structure.

-- Dan
0
 

Author Comment

by:Cobras2
ID: 8074257
DanRollins -
That is *exactly* right on, man :) thanks for the help. I'll tag that as the answer.. however, if it wouldn't be too much trouble, do you have any idea *why* they decided to do that, especially when it affects things like loading bitmaps so much? and why I haven't been able to find any mention of it anywhere before?
0
 

Author Comment

by:Cobras2
ID: 8074273
If it wouldn't be too much trouble, could you tell me(if you have any idea) why it is that they changed that? esp. when it makes so much difference to things like bitmap loading? and why I haven't been able to find any mention of that anywhere else? It would really help - but thanks muchly for the answer, man :)
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 8074353
Why add padding?  It is because with most CPUs there is a significant speed improvement in accessing the fields of structures when they are aligned on 32-bit boundaries.  For instance grabbing a 4-byte DWORD that starts at some address like 0x0000081F will require (internal to the CPU) a 1-byte read and a 3-byte read.  If that data happens to align on the edge of an L1 cache bountadry, it (also internally) will require a fetch of a new cache line from the L2 Cache, which could in turn require a fetch from main memory.

Furthermore, other than a few bytes of 'wasted' RAM, there is *normally* no downside -- a program shouldn't care if field 2 is directly adjacent to field 1.  The one exception is in the very case that you hit -- when reading a pre-defined structure directly from disk.

Thanks for the points.
-- Dan

P.S.  Idle curiousity: Why on earth do you want to read BMP files into a DOS program?
0
 

Author Comment

by:Cobras2
ID: 8074788
actually the only reason I'm doing it is to get a better base in my skills. I know nobody uses DOS programs anymore, but rather than just doing the abstract calling some BMP-loader in Win32 API, or DirectX, or etc, I thought it would be a good idea to get down and learn how to do it myself.. even if I never actually do that in a real project. basically just a learning experience - and hey, I learned something :)
That makes sense, now that I think of it, that it should be alot easier for the CPU that way, since the modern CPUs are 32bit. I just find it a bit strange that those graphic file format sites wouldn't bother to mention that. I guess maybe they all just haven't been updated in a while?
Anyway, you're welcome for the points, I've been trying to figure this out for awhile now, and although it's not like it's all that important to load bitmaps in DOS, I really did want to know *why* it didn't work. Just bugs me to not ever find the solution to an interesting(even if it's not really worht it) problem ;)
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 8074990
Some example code that reads a BMP might read it a piece at a time.  For instance:  Read two bytes, store a 16-bit word... read one byte, store it... read four bytes, store a DWORD.  That would would work, regardless of alignment padding.   But looking at that code, one might say to oneself "self, that's silly to make three seperate reads... why not just read all seven bytes at once?"  And so it goes. :-)

-- Dan
0

Featured Post

On Demand Webinar: Networking for the Cloud Era

Ready to improve network connectivity? Watch this webinar to learn how SD-WANs and a one-click instant connect tool can boost provisions, deployment, and management of your cloud connection.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…

764 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question