#1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    USA
    Posts
    144
    Rep Power
    12

    manipulating pixels in bitmap array (avoiding SetPixel())


    Hello,

    I was trying to make an image filter but have hit the SetPixel road block, it's real slow and I've been struggling to find a good tutorial on how to manipulate a pixel as a value in the bitmap array in memory, thus avoiding using SetPixel. If anyone has a good tutorial I'd really appreciate it, and here's what I was doing so far in case anyone wants to see,

    //Load a bitmap file into the app view
    CString szFilename("C:\\Documents and Settings\\Me\\Desktop\\s7.bmp");
    HBITMAP hBmp = (HBITMAP)::LoadImage (NULL,szFilename, IMAGE_BITMAP,0,0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);

    CBitmap bmp;
    bmp.Attach(hBmp);

    CClientDC clientDC(this);
    CDC bmDC;
    bmDC.CreateCompatibleDC(&clientDC);
    CBitmap *pOldbmp = bmDC.SelectObject(&bmp);

    BITMAP bi;
    bmp.GetBitmap(&bi);

    //just do something simple like set every pixel in the box to be red
    for(int x=0; x<400; x++)
    {
    for(int y=0; y<400; y++)
    {
    //painfully slow!
    bmDC.SetPixel(x,y, 255)
    }
    }

    //put it on screen
    clientDC.BitBlt(0,0,bi.bmWidth,bi.bmHeight,&bmDC,0,0,SRCCOPY);

    bmDC.SelectObject(pOldbmp);

    (the bitmap load chunk is from codeguru.com's site on simple method's for loading a bitmap, thanks to them!)
  2. #2
  3. Doggie
    Devshed Novice (500 - 999 posts)

    Join Date
    Jul 2003
    Location
    Seattle, WA
    Posts
    751
    Rep Power
    13
    I haven't tried before, but is a bitmap in memory in the same format as a bitmap file? If so, the structure is very simple and easy to modify.

    http://www.wotsit.org/ has good documentation on file formats. Do a search for "bmp" and pick their 17K download. (Windows BMP Format (MS Word)) It's the most helpfull and one I've used in my programs where I want to output an image.
  4. #3
  5. jasondoucette.com
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    Canada
    Posts
    378
    Rep Power
    12
    Originally posted by dog135
    I haven't tried before, but is a bitmap in memory in the same format as a bitmap file? If so, the structure is very simple and easy to modify.
    Yes, it is, with the exception of the first header in the bitmap format. I would take a look at the CreateDIBSection function (although, it appears the code he uses loads a bitmap from a file into a DIB section).

    The CreateDIBSection function creates a DIB that you can write to directly. It gives you a pointer to the location of the raw color data. If you are using 24 or 32-bit bitmaps, then the values are VERY easy to change. Remember that each row of the bitmap is appended with empty bytes to make it a multiple of 4, if it is not already. Also remember that most bitmaps are stored upside down.

    Let me know if this helps. I'll show you some code if you need help. I'd try messing with this function first, and then use the LoadImage function after you are used to handling the bitmaps in memory.
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    USA
    Posts
    144
    Rep Power
    12
    thanks guys for your responses -

    I've been reading all day on CreateDIBSection especially, it seems that changing the value of one pixel should be easy (24 bit bmp, from a file or in memory, either way will work for me) I just need to find one solid example (that isn't fragmented!!)in actual use and I'll be set!!

    My main confusion is after creating the bitmap header, you can use the CreateDIBSection function to get the array of the pixel values (4th parameter of CreateDIBSection?) - and that's what the goal is, to be able to manipulate the array that was passed by the 4th parameter of CreateDIBSection?

    After manipulating that data you can then copy the changes back to screen or save it to a file again, is that correct?

    Thanks for your help again!!
  8. #5
  9. jasondoucette.com
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    Canada
    Posts
    378
    Rep Power
    12
    There should really be a tutorial on this somewhere, since most people just want a canvas to write on that doesn't disappear when the window is covered and then uncovered by another window, or minimized and maximized. It doesn't take that much code to do this, and it's way easier than jumping into DirectDraw. If there is enough demand for this, then I will write one.

    I learned the code from Programming Windows, Fifth Edition by Charles Petzold, which is highly recommended, as it has over 300 pages on dealing with bitmaps, BUT if you do not care about modes < 24 bit, then you needn't know 90% of it. Basically, this is what I do:

    Call CreateDIBSection() like so:
    Code:
    	hBitmap = CreateDIBSection (
    		NULL,
    		(BITMAPINFO*)&bmih,
    		DIB_RGB_COLORS,
    		(VOID**)&pBits,
    		NULL,
    		0);
    1st param is NULL, you don't need a hdc.

    Notice the 2nd parameter can just be a BITMAPINFOHEADER struct, and is type cast into the type required. This is the first field of the structure it is expecting, as it doesn't need the second field for 24 or 32 bit bitmaps. Look into the structs, and you'll know what I mean.

    After the call, pBits BECOMES a pointer to the raw data. This is what you use to modify the pixels.

    The rest of the parameters are 0, as they are not needed.

    Fill in this data of this struct before the above call:
    Code:
    	bmih.biSize = sizeof (BITMAPINFOHEADER);
    	bmih.biWidth = cx;
    	bmih.biHeight = cy;
    	bmih.biPlanes = 1;
    	bmih.biBitCount = BitCount;
    	bmih.biCompression = BI_RGB;
    	bmih.biSizeImage = 0;
    	bmih.biXPelsPerMeter = 0;
    	bmih.biYPelsPerMeter = 0;
    	bmih.biClrUsed = 0;
    	bmih.biClrImportant = 0;
    cx,cy = size of image. bitcount = 24 or 32. Pretty simple.




    Each row of the bitmap is a multiple of 4 bytes. So, it is appended with blanks to make it a multiple of 4 if it is not already.

    Most bitmaps are upsidedown. Unless you specify a negative height, this one will be as well.

    Basically, use the pBits pointer to modify the data. Petzold makes an array of pointers, so that you have the pointer to the first byte of every row, and can access the array (and thus the row) from 0..height-1, and you can forget about the bitmap being upside down if you set them this way. This is what I use, as well.

    Also, if you use GDI functions on this bitmap, check into the GdiFlush() function.

    To draw the bitmap, make a memory DC with CreateCompatibleDC() passing it the DC from the client area obtained with GetDC() or BeginPaint(). Select the bitmap into the memory DC with SelectObject(). BitBlt() it to the screen. Delete the memory DC. (As far as I know there is no memory leak, as you need not remove the bitmap from the memory DC by calling SelectObject() again.)

    This should be enough info to get you started.
    Last edited by Jason Doucette; August 6th, 2003 at 09:17 AM.
  10. #6
  11. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    USA
    Posts
    144
    Rep Power
    12
    Thanks a ton Jason this is very excellent!

    Thanks for the book recommendation too, sadly I couldn't find any good books about this by me so I'm going to see if I can get that one now.

IMN logo majestic logo threadwatch logo seochat tools logo