Getting pixels from Windows DIB with no BITMAPFILEHEADER?
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 14 of 14

Thread: Getting pixels from Windows DIB with no BITMAPFILEHEADER?

  1. #1
    Join Date
    Dec 2008
    Posts
    91

    Getting pixels from Windows DIB with no BITMAPFILEHEADER?

    Hi,

    I am new to Windows programming, but have been given a handle to a Windows DIB and am not sure how to use it. Basically, I just want to retrieve a char* holding the pixel data for an image such that the origin is the top left corner and scanlines are stored.

    Apparently, no BITMAPFILEHEADER is present and the data starts with BITMAPINFO:
    Code:
    HBITMAP mrDIB = (HBITMAP)GlobalLock(imageData);   //'imageData' is a HANDLE
    BITMAPINFO* mrDIBInfo = (BITMAPINFOHEADER*)mrDIB;
    mrDIBInfo gives me a structure as such:


    How can I get the start of the bitmap header data so I can assign its address to a char*?

    Thank you in advance and sorry if I am unclear as this is really new to me.

  2. #2
    Join Date
    Feb 2005
    Posts
    2,160

    Re: Getting pixels from Windows DIB with no BITMAPFILEHEADER?

    I think the cast to HBITMAP is superfluous and even incorrect. If you are calling GlobalLock, then the HANDLE is probably just a memory handle. You cast it to a BITMAPINFO struct and it appears to be valid. In this case, the memory immediately after the BITMAPINFO struct should be the raw bits. Try:
    Code:
    BITMAPINFO* mrDIBInfo = (BITMAPINFOHEADER*)GlobalLock(imageData);
    unsigned char *bits=((unsigned char *)mrDIBInfo)+sizeof(BITMAPINFOHEADER);
    It looks like a monochrome bitmap so each unsigned char in bits is 8 pixels.

  3. #3
    Join Date
    Nov 2007
    Posts
    613

    Re: Getting pixels from Windows DIB with no BITMAPFILEHEADER?

    Obviously, there is no BITMAPFILEHEADER structure because you didn't load the bitmap from a *.bmp file, you loaded it as a resource from your *.exe file.

    Only a *BITMAP FILE* has that header, that's why they named it BITMAPFILEHEADER.

    Bitmaps loaded from resources (using LoadBitmap, LoadImage) are device dependent. You cannot access directly the memory used to store the pixells of a device dependent bitmap.

    Only the memory of a device independent bitmap can be accessed directly. To have a device independent bitmap you have to create it using CreateDIBSection.
    First, load your bitmap into the memory, then use that data to call the function. After you have the HBITMAP handle, you can call SetDIBits to set directly the pixels from a buffer, and GetDIBits to get the pixels into a buffer.

  4. #4
    Join Date
    Feb 2005
    Posts
    2,160

    Re: Getting pixels from Windows DIB with no BITMAPFILEHEADER?

    I don't think the OP is getting the buffer from a RC file. The fact that it is being locked with GlobalLock indicates that it is some kind of memory block from a different process. The fact that it casts to a valid looking BITMAPINFOHEADER indicates that it is probably a raw DIB block from another process.

    OP, Please clarify.

  5. #5
    Join Date
    Dec 2008
    Posts
    91

    Re: Getting pixels from Windows DIB with no BITMAPFILEHEADER?

    Thanks for the responses everyone.

    The DIB I am getting is from EZTWAIN (an image acquired from a scanner).
    This is the function description they give:
    Code:
    HANDLE EZTAPI TWAIN_AcquireNative(HWND hwndApp, unsigned wPixTypes);
    // The minimal use of EZTWAIN.DLL is to just call this routine, with 0 for
    // both params.  EZTWAIN creates a window if hwndApp is 0.
    //
    // Acquires a single image, from the currently selected Data Source, using
    // Native-mode transfer. It waits until the source closes (if it's modal) or
    // forces the source closed if not.  The return value is a handle to the
    // acquired image.  Only one image can be acquired per call.
    //
    // Under Windows, the return value is a global memory handle - applying
    // GlobalLock to it will return a (huge) pointer to the DIB, which
    // starts with a BITMAPINFOHEADER.
    // NOTE: You are responsible for disposing of the returned DIB - these things
    // can eat up your Windows memory fast!  See TWAIN_FreeNative below.
    //
    // The image type can be restricted using the following masks.  A mask of 0
    // means 'any pixel type is welcome'.
    // Caution: You should not assume that the source will honor a pixel type
    // restriction!  If you care, check the parameters of the DIB.
    Sorry, this Windows DIB stuff is new and confusing for me.

  6. #6
    Join Date
    Feb 2005
    Posts
    2,160

    Re: Getting pixels from Windows DIB with no BITMAPFILEHEADER?

    What is it you want to do with the bitmap after you receive it form the TWAIN source? If you want to display it, you'll have to convert it to a DDB compatible with your display. If you just want to save it to a file, it's easy to add a file header, then save to disk.

  7. #7
    Join Date
    Dec 2008
    Posts
    91

    Re: Getting pixels from Windows DIB with no BITMAPFILEHEADER?

    Hi, I actually want to store it in an internal image class using char* format for additional processing.
    Because saving to disk and reading back is inefficient.

  8. #8
    Join Date
    Feb 2005
    Posts
    2,160

    Re: Getting pixels from Windows DIB with no BITMAPFILEHEADER?

    Then the method I showed above should point you to the raw bitmap buffer. The length of the buffer should be calculable from the info in the header: xres * yres * Bytes_per_pixel.

  9. #9
    Join Date
    Dec 2008
    Posts
    91

    Re: Getting pixels from Windows DIB with no BITMAPFILEHEADER?

    Quote Originally Posted by hoxsiew View Post
    Then the method I showed above should point you to the raw bitmap buffer. The length of the buffer should be calculable from the info in the header: xres * yres * Bytes_per_pixel.
    Okay, but I am confsued about a few more things:
    1. Do I need to account for 'RGBQUAD' having more than one index? Like will I need to add an extra sizeof(RGBQUAD) to the pointer? I also read about color-index array?
    2. I hear that DIB's are stored from bottom up or something. How do I deal with this?

  10. #10
    Join Date
    Dec 2008
    Posts
    91

    Re: Getting pixels from Windows DIB with no BITMAPFILEHEADER?

    Actually, I found this link.

    I'll post back if it doesn't work for me.


    Thanks!

  11. #11
    Join Date
    Aug 2013
    Location
    Florida
    Posts
    2

    Re: Getting pixels from Windows DIB with no BITMAPFILEHEADER?

    Maybe this will help, here is a function I have finished today just for a related purpose, this function will
    get the unpadded array pixels plus the width and height quick and painlessly. Most of this is tested because it came from a part of a program I'm making, so I took some stuff out and modified it to be stand-alone.
    This can be easily modified to get the pixels from just a normal BITMAPINFO struct pointer handed down from Windows through whatever means.


    LPARAM GetDIBPixelsFromClipboard(HWND clipboardOwnerWnd, COLORREF* returnPixels){
    //Open clipboard
    BOOL testOpen=OpenClipboard(clipboardOwnerWnd);
    if(testOpen==FALSE){
    cout<<"Could not open clipboard for some reason."<<endl;
    return 0;
    }
    //See if there's a DIB saved to the clipboard (MS Paint throws them up there in this format)
    HGLOBAL test=GetClipboardData(CF_DIB);
    if(test==NULL){
    cout<<"No bitmap saved to the clipboard."<<endl;
    return 0;
    }


    //Aquire BITMAPINFO struct
    const BITMAPINFO* bmi=(BITMAPINFO*)GlobalLock(test);

    //The packed pixel array is after the information for the BITMAPINFO struct, it must be referenced by incrimenting the memory spot for the BITMAPINFO pointer past the RGBQUAD[1] section.
    //That section is reached quickly by the bmiHeader.biSize member, this array of bytes is padded with zero-bytes of variable amount after each row of pixels, we will be filtering these
    //zero-bytes below.
    LPSTR colors=((LPSTR)bmi+bmi->bmiHeader.biSize);

    //This is the count of bytes that represent a row of pixels plus the padding bytes
    LONG limit=((((bmi->bmiHeader.biWidth*bmi->bmiHeader.biBitCount)+31)&~31)>>3);

    //This is the width of each row before it gets to the padding bytes, this is how many actual bytes represent the red, green, and blue color channels of each pixel in the row exclusively.
    LONG rowWidth=bmi->bmiHeader.biWidth*3;

    //The length of the padding bytes
    int padding=limit-rowWidth;

    //The length of the DIB in pixels (the size of the bitmap)
    LONG size=bmi->bmiHeader.biWidth*bmi->bmiHeader.biHeight;

    //Related stuff. Extents for height and width, and also an iterator for the loops below.
    LONG c=0;
    LONG xExt=bmi->bmiHeader.biWidth;
    LONG yExt=bmi->bmiHeader.biHeight;

    //Declare two COLORREF arrays, one to recieve the bytes upside down, and one to convert the upside down pixels to the correct way,
    //there may be a more efficient way to do this if necessary, but this way works just fine.
    COLORREF* upsideDownPixels=new COLORREF[size];
    COLORREF* pixels=new COLORREF[size];

    //Here is where you loop through the DIB section of the BITMAPINFO struct, which is referenced by (colors).
    for(LONG i=0;i<size;i++){
    //This is the part where the zero-bytes for the row-padding get filtered.
    if(c==rowWidth){
    for(int j=0;j<padding;j++)colors++;
    c=0;
    }
    c+=3;
    //Colors are assigned here by the individual color channel and then combined to represent a single pixel.
    //From here we aquire the upside down representation of the bitmap's pixels
    unsigned char r=*colors;colors++;
    unsigned char g=*colors;colors++;
    unsigned char b=*colors;colors++;
    upsideDownPixels[i]=RGB(r,g,b);
    }

    c=0;

    //Now that we have the upside down bitmap's pixels lets flip them vertically
    for(LONG y=bmi->bmiHeader.biHeight-1;y>-1;y--){
    for(LONG x=0;x<bmi->bmiHeader.biWidth;x++){
    LONG pos=
    pixels[c]=upsideDownPixels[(bmi->bmiHeader.biWidth*y)+x];
    c++;
    }
    }

    //Delete memory that is no longer necessary, unlock the locked clipboard variable, and close the clipboard.
    delete [] upsideDownPixels;
    GlobalUnlock(test);
    CloseClipboard();

    //Assign (returnPixels) to (pixels) so that they can be referenced after this function executes.
    returnPixels=pixels;

    //Return the width and height of the bitmap so that (returnPixels) can be looped through acurately.
    return MAKELPARAM(xExt,yExt); //You can reference the width and height by using LOWORD(returnValueOfThisFunction) and HIWORD(returnValueOfThisFunction) respectively.
    }

  12. #12
    Join Date
    Dec 2012
    Location
    England
    Posts
    2,370

    Re: Getting pixels from Windows DIB with no BITMAPFILEHEADER?

    Please before you post code format the code properly and use code tags to make it readable. Go Advanced, select the code and click '#'.
    All advice is offered in good faith only. You are ultimately responsible for effects of your programs and the integrity of the machines they run on.

  13. #13
    Join Date
    Aug 2013
    Location
    Florida
    Posts
    2

    Re: Getting pixels from Windows DIB with no BITMAPFILEHEADER?

    I should probably add real quick that the "LONG pos=" line is one that I forgot to take out, as it was not needed for this function. I didn't know how to edit it out from here so I'm just making this quick post, in case anyone tries that function and sees the syntax error.

    Also, I appologize for the lack of formatting in that, I'm new to posting code here and didn't realize what to do, but I will keep your advice in mind for next time.

  14. #14
    Join Date
    Aug 2013
    Posts
    8

    Re: Getting pixels from Windows DIB with no BITMAPFILEHEADER?

    If you are trying to process image in the future try to use OpenCV library, http://opencv.org/.
    It's easy and fun. Don't do it on your own.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center