IDE = Dev-C++ V 4.9.9.2
Operation System = Windows Vista
Hello, and good day to anyone who reads this.
I am a novice Win32 via C++ programmer. I have been trying to understand how CreateDIBSection(), SetDIBitsToDevice(), and DIB's in general work. I am trying to create a program that changes one color into another. More specifically - I am trying to create a program that scans each pixel and it's RGB values of a bitmap in search of a certain color. Whenever my program finds a pixel with a certain RGB value it will convert that pixel's RGB values into another RGB value.
My problem is that I do not know much about DIB's and bitmap bit manipulation. I have been searching through codeguru, the web, and my book "Microsoft Windows 2000 API SuperBible" trying to find examples that simplify and thoroughly explain DIB's and the process that I mentioned above. I have gotten a vague idea about DIB's and slowly but surely I will figure it out, but if someone could please help me out that would be so great!
I need a working example of a program that either does what I mentioned above(IF this is even feasible) or something remotely similar.
I also need comments within the program describing each part, please be descriptive(if that is alright). I am a complete novice so I need this example program to be as simple as possible.
In particular I need to see the array containing the actual RGB values of a bitmap, and I need to see the RGB values manipulated. I also need these things explicitly pointed out, otherwise I may not know what is what.
Also when looking at the examples that I have seen, which either were not complete or thorough enough, I found it hard to distguish the colors in the color pallete of the DIB from the RGB values of the pixels.
------Lastly, I just want to say thank you to anyone who even considers helping me. I have posted two questions in the past couple of weeks so I seriously don't deserve another answer. Those answers were great. They were thorough and complete, and my question was definitely resolved, thanks to the good people on this website. Even though I don't feel I deserve any more help I figured I would at least try, and see what happens...
---------Even if no one helps me I just want to say THANK YOU, THANK YOU, THANK YOU any way! You guys have done enough helping. Thank you for just helping anybody at all. I am happy just to see people helping one another. I will figure this stuff out eventually.
---------The very best of wishes to everyone in every edeavor, and the kindest of regards -- kmkkra!
DreamShore
July 5th, 2008, 02:23 PM
I suggest you read Bitmaps part in MSDN document. It's not something hard to understand.
kmkkra
July 5th, 2008, 02:51 PM
Yes DreamShore you are right I should search through MSDN in search for the information that I'm looking for. However, having givin' it a look already I see that as informative as it is it still seems to lack a thorough and yet simplistic example of how DIB's work or at least certain aspects of DIB manipulation. Of course, judging by past experience, even after meticulously searching MSDN and not finding what one is looking for -- there still always seems to be some piece of documentation that is, I geuss you could say, hidden, and which is also the answer... So maybe the example or information I need is clearly stated in MSDN, but I just haven't found yet. Nevertheless, I will figure this thing out eventually.
I will continue to search through MSDN just as you suggested. It is, indeed, helping me put the pieces together and make since of DIB's, but not quite enough though.
-----Thank you DreamShore for your suggestion. Have a great day, and the best of wishes to you sir.
DreamShore
July 5th, 2008, 04:26 PM
If you have read all of this chapter
Win32 and COM Development -> Graphics and Multimedia -> GDI -> Windows GDI -> Bitmaps
I forgot the details on use CreateDIBSection with file mapping... I usually load the file by myself.
Without file mapping you need only 3 parameters to be set
pbmi
It should be the BITMAPINFO in the bitmap file. Just read from the file.
iUsage
You surely want DIB_RGB_COLORS
ppvBits
You receive the array you want here, allocated by the function, empty. Copy what's in the file to this array and do what you want.
And I think there shouldn't any difficulty using SetDIBitsToDevice
kmkkra
July 5th, 2008, 05:24 PM
Yes DreamShore I have read this particular documentation that you mention. Although I still haven't completely made since out of it all yet. The information found on MSDN is indeed helpul, but it is not always simple enough to understand or maybe it just does not give, a much needed,simple example program. Or perhaps they just do not expound upon their examples enough. The documentation is definitely helping but it would really help to have a simple example which is thoroughly explained.
The pieces are coming together, and I will figure this thing out eventually, but man I wish I had some more specific examples and explanations.
-------Thank you for your help DreamShore, good tidings to you my friend.
Joeman
July 5th, 2008, 10:55 PM
I wanted to try this myself. I didn't have much experience in dibs, but I did work with them alittle. It took me sometime, but I came up with a program to do what you are asking. Sometimes msdn isn't very clear on how to use their functions, but there are alot of tutorials that can help. When I first tried to learn dibs, I was using vb6. For some simple examples on how to use win32 apis, use http://allapi.mentalis.org/apilist/apilist.php. I know this isn't in c++ coding, but they have lots of tutorials for lots of win32 apis. I took their code and converted to c++ and did more to it.
#include <windows.h>
#include <iostream>
struct RGB
{
BYTE Blue;
BYTE Green;
BYTE Red;
};
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
HWND Window = (FindWindow(NULL,"Calculator")); // find the handle to the calculator
if (Window == NULL)
{
ShellExecute(NULL, "open", "calc.exe", 0, 0, SW_SHOWNORMAL); // If we didn't find the handle, it isn't loaded. Let's load it.
}
while (Window == 0)
{
Window = (FindWindow(NULL,"Calculator")); // wait until there is a handle for the window
}
RECT Rect; // just a simple rect to hold the size of our window
HDC WindowDC = GetDC(Window); // grab a device content to it
GetWindowRect(Window, &Rect); // grab window size
BITMAPINFO bi24BitInfo; // We set this up to grab what we want
bi24BitInfo.bmiHeader.biBitCount = 24; // rgb 8 bytes for each component(3)
bi24BitInfo.bmiHeader.biCompression = BI_RGB;// rgb = 3 components
bi24BitInfo.bmiHeader.biPlanes = 1;
bi24BitInfo.bmiHeader.biSize = sizeof(bi24BitInfo.bmiHeader); // size of this struct
bi24BitInfo.bmiHeader.biWidth = Rect.right - Rect.left; // width of window
bi24BitInfo.bmiHeader.biHeight = Rect.bottom - Rect.top; // height of window
BYTE *bBytes = new BYTE[bi24BitInfo.bmiHeader.biWidth * bi24BitInfo.bmiHeader.biHeight * 3]; // create enough room. all pixels * each color component
HDC iDC = CreateCompatibleDC(0); // create dc to store the image
HBITMAP iBitmap = CreateDIBSection(iDC, &bi24BitInfo, DIB_RGB_COLORS, 0, 0, 0); // create a dib section for the dc
SelectObject(iDC, iBitmap); // assign the dib section to the dc
SetWindowPos(Window, HWND_TOPMOST, 0,0,0,0, SWP_NOSIZE); // bring to front to see it
SendMessage(Window, WM_PAINT, 0, 0); // send a paint message so it will paint before we try to paint to it
BitBlt(iDC, 0, 0, bi24BitInfo.bmiHeader.biWidth, bi24BitInfo.bmiHeader.biHeight, WindowDC, 0, 0, SRCCOPY); // copy hdc to our hdc
GetDIBits(iDC, iBitmap, 0, bi24BitInfo.bmiHeader.biHeight, &bBytes[0], &bi24BitInfo, DIB_RGB_COLORS); // grab the pixels in the dc
for (int Cnt = 0; Cnt < bi24BitInfo.bmiHeader.biWidth * bi24BitInfo.bmiHeader.biHeight * 3; Cnt+=3) // run through each pixel
{
RGB* Pixel = (RGB*)&bBytes[Cnt];
SetDIBitsToDevice(iDC, 0, 0, bi24BitInfo.bmiHeader.biWidth, bi24BitInfo.bmiHeader.biHeight, 0, 0, 0, bi24BitInfo.bmiHeader.biHeight, &bBytes[0], &bi24BitInfo, DIB_RGB_COLORS); // set the new dibs to the dc
BitBlt(WindowDC, 0, 0, bi24BitInfo.bmiHeader.biWidth, bi24BitInfo.bmiHeader.biHeight, iDC, 0, 0, SRCCOPY); // copy hdc to their hdc
DeleteDC(iDC); // delete dc
ReleaseDC(Window, WindowDC); // release our dc handle
DeleteObject(iBitmap); // delete object
delete [] bBytes;
return 0;
}
That wasn't so easy to do lol, but it was fun :D
I am sure there is a better way to process the rgb values, but I don't know a better way. I wanted to get them in x and y coords, but I couldn't. Can someone help me with this?
Edit:: Fixed correction in code to delete bBytes so no memory leaks
fred100
July 6th, 2008, 12:02 AM
it just does not give, a much needed,simple example program
Are you joking ?
There are hundreds of complete and detailed samples on DIBs in MSDN !
PSDK, KB, etc...
All Web samples are just copies/traductions of all these samples...
kmkkra
July 6th, 2008, 12:47 AM
Hello Joeman. I am at a loss for words... It is obvious you are a very kind person. Thank you so very, very much for this wonderful example. You have surprised me with your efforts and kindness. I am now looking at your example, and trying to figure out how DIB's work, and I know that your example will help me learn a lot.
I do confess though... The way you processed the RGB values was a little abstract for a complete novice such as myself - which you yourself seemed to admit to.That is quite allright though because I found another simple example on codeguru, and have learned a lot from it. I think it was written in VC++ so I had to modify it for plain Win32. The way the RGB values were processed was not entirely simple either, but I don't think that it can be done in a much simpler way . I got this example off of a thread titled:
"CreateDIBSection() for palette bitmaps (very confusing) ".
//CreateDIBSection() requires gdi32.dll or libgdi32.a which is MingW compiler
//compatible
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth = 500;
bi.bmiHeader.biHeight = 500; //positive number == bottom-up DIB
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 8;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biClrUsed = 256;/*There are 256 colors
in the palette. These are the colors you need to choose from out of the
256r * 256g * 256b different color intensities. These colors or color
intensities will be associated with the pixels you specify through the
void ** found in CreatDIBSection(). Although since
"bi.bmiHeader.biBitCount" was set to 8 bits you are limited to merely 256
different colors. There is another dimension of color called alpha that
you can also add to your bitmaps. Alpha adds transparency,and would
bring the total accumulated colors available to 256r * 256g * 256b *
256alpha. I think you can only use alpha (per pixel) if the
"bi.bmiHeader.biBitCount" is set to at least 32 bpp.
But to qoute from
MSDN > MSDN Library > Win32 and COM Development > Graphics and
Multimedia > Windows GDI > Bitmaps > About Bitmaps > Alpha Blending:
(http://msdn.microsoft.com/en-us/library/ms532274(VS.85).aspx)
Alpha values per pixel are only supported for 32-bpp BI_RGB......
Bitmaps may also be displayed with a transparency factor applied to the
entire bitmap. Any bitmap format can be displayed with a global constant
alpha value by setting SourceConstantAlpha in the BLENDFUNCTION
structure. The global constant alpha value has 256 levels of transparency,
from 0 (entire bitmap is completely transparent) to 255 (entire bitmap is
completely opaque). The global constant alpha value is combined with the
per-pixel alpha value. */
/*This loop is where you pick the different colors you will be
using. Take note that DIB's 16 bpp and greater do not have color tables
(RGBQAUD structure arrays)... Rather the void ** in CreateDIBSection() is
used to point directly to the color values themselves instead of a RGBQUAD
structure. */
for(int i=0 ; i< 256; i++)
{
bi.bmiColors[i].rgbRed = i;
bi.bmiColors[i].rgbGreen = i;
bi.bmiColors[i].rgbBlue = i;
bi.bmiColors[i].rgbReserved = 0;
}
This loop is where the pBits* associates a RGBQUAD structure with a
pixel. This loop can also be used to - directly associate a rgb value to a
pixel bypassing the use of a RGBQUAD structure altogether.*/
for( int iRow=0; iRow<500; ++iRow )
{
for( int iCol=0; iCol<500; ++iCol )
{
*pBits = iCol% 255;
This example is for any other novices who someday should happen to want to learn about DIB's and look for some examples. This example isn't much, and was written by myself, a compete novice, but maybe it can still help somebody in the future. If I have made any mistakes or if there is room for improvement - please - anybody - feel free to point them out.
------------Thank you so very much Joeman for writting this great example. I am actually now starting to understand how DIB's works. With your example I know I now have the first stepping stone I needed.
I am very pleased!!!
--------In honesty, and sincerity - I say thank you once again, and I really do wish the very best for you Joeman in every way. Please take care- friend...
kmkkra
July 6th, 2008, 10:57 AM
Are you joking ?
There are hundreds of complete and detailed samples on DIBs in MSDN !
PSDK, KB, etc...
All Web samples are just copies/traductions of all these samples...
Hello fred100. I am not familar with PSDK or KB but if you say that that is where the simple examples are located then I will definitely look into it. I can only assume that there must also be many other examples of the different aspects of Win32 api within the PSDK and KB. If this is true then I consider myself to have hit the jackpot!
When you say there are hundreds of complete examples - on - MSDN do you also mean the "http://forums.msdn.microsoft.com " website? If this is so then what search words were you using? Can you give any links?
------- I haven't thoroughly looked into what you suggested, but assuming that what you are saying is correct - I say thank you... Thank you very much for your advice. Good day to you buddy.
kmkkra
July 7th, 2008, 09:08 AM
Hello. I figured I would add a couple more resources to this thread for any future novices looking for info.
I found a really simple example of how to create a .bmp from DIB bits. This is a complete and working function.
void SaveBitmapToFile( BYTE* pBitmapBits, LONG lWidth, LONG lHeight,WORD wBitsPerPixel, LPCTSTR lpszFileName )
{
BITMAPINFOHEADER bmpInfoHeader = {0};
// Set the size
bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
// Bit count
bmpInfoHeader.biBitCount = wBitsPerPixel;
// Use all colors
bmpInfoHeader.biClrImportant = 0;
// Use as many colors according to bits per pixel
bmpInfoHeader.biClrUsed = 0;
// Store as un Compressed
bmpInfoHeader.biCompression = BI_RGB;
// Set the height in pixels
bmpInfoHeader.biHeight = lHeight;
// Width of the Image in pixels
bmpInfoHeader.biWidth = lWidth;
// Default number of planes
bmpInfoHeader.biPlanes = 1;
// Calculate the image size in bytes
bmpInfoHeader.biSizeImage = lWidth* lHeight * (wBitsPerPixel/8);
BITMAPFILEHEADER bfh = {0};
// This value should be values of BM letters i.e 0×4D42
// 0x4D = M 0x42 = B storing in reverse order to match with endian
bfh.bfType=0x4D42;
/* or
bfh.bfType = ‘B’+(’M’ << 8);
// <<8 used to shift ‘M’ to end
*/
// Offset to the RGBQUAD
bfh.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);
// Total size of image including size of headers
bfh.bfSize = bfh.bfOffBits + bmpInfoHeader.biSizeImage;
// Create the file in disk to write
HANDLE hFile = CreateFile( lpszFileName,GENERIC_WRITE, 0,NULL,
DWORD dwWritten = 0;
// Write the File header
WriteFile( hFile, &bfh, sizeof(bfh), &dwWritten , NULL );
// Write the bitmap info header
WriteFile( hFile, &bmpInfoHeader, sizeof(bmpInfoHeader), &dwWritten, NULL );
// Write the RGB Data
WriteFile( hFile, pBitmapBits, bmpInfoHeader.biSizeImage, &dwWritten, NULL );
// Close the file handle
CloseHandle( hFile );
}
I found this example from
http://sarathc.wordpress.com/2007/03/14/how-to-save-bitmap-to-file (http://sarathc.wordpress.com/2007/03/14/how-to-save-bitmap-to-file/)
codeguru.com
Copyright 2007 Jupitermedia Corporation All Rights Reserved.