win32 - DIBs - can i use the a pixel array(HBITMAP), from 1 HDC, to another HDC(HBITMAP)?

ok.. using the GetCurrentObject() i can get the HBITMAP and the GetObject() give the BIMAP.
using once the GetDIBits(), without using the pixels array, from that HBITMAP, i can get the BITMAPINFO.
and using the GetDIBits(), we can get the pixels array.
now heres the function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
typedef std::vector<BYTE> PixelArray;
PixelArray GetImagePixel(HDC hdcImage)
{
    BITMAP bmp = {0};
    BITMAPINFO Info = {0};
    memset( &bmp, 0, sizeof(BITMAP) );// clear the BITMAP structure
    HBITMAP hBitmap =(HBITMAP) GetCurrentObject(hdcImage, OBJ_BITMAP);//get HBITMAP from HDC
    GetObject(hBitmap, sizeof(BITMAP), &bmp); //get the BITMAP from HBITMAP

    BITMAPINFO info { };
    //yes some info we must add manually:
    info.bmiHeader.biSize = sizeof(info.bmiHeader);//some structures need their size for work
    info.bmiHeader.biWidth = bmp.bmWidth;
    // pay attention to the sign, you most likely want a
    // top-down pixel array as it's easier to use
    info.bmiHeader.biHeight = -bmp.bmHeight;//don't forget that the image is from top to down, but DIB's is inverted
    info.bmiHeader.biPlanes = 1;
    info.bmiHeader.biBitCount = 32;
    info.bmiHeader.biCompression = BI_RGB;

    // the following calculations work for 16/24/32 bits bitmaps
    // but assume a byte pixel array
    size_t pixelSize = info.bmiHeader.biBitCount / 8;
    // the + 3 ) & ~3 part is there to ensure that each
    // scan line is 4 byte aligned
    size_t scanlineSize = (pixelSize * info.bmiHeader.biWidth + 3) & ~3;
    size_t bitmapSize = bmp.bmHeight * scanlineSize;

    PixelArray pixels(bitmapSize);
    GetDIBits(hdcImage, hBitmap, 0, bmp.bmHeight, &pixels[0], &info, DIB_RGB_COLORS);
    bmp.bmHeight = std::abs(bmp.bmHeight);
    return pixels;
}

and now heres the SetImageData():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void SetImageData(HDC hdcDestination, PixelArray pixels)
{
    BITMAP bmp = {0};
    BITMAPINFO Info = {0};
    memset( &bmp, 0, sizeof(BITMAP) );
    HBITMAP hBitmap =(HBITMAP) GetCurrentObject(hdcDestination, OBJ_BITMAP);
    GetObject(hBitmap, sizeof(BITMAP), &bmp);
    BITMAPINFO info { };
    info.bmiHeader.biSize = sizeof(info.bmiHeader);
    info.bmiHeader.biWidth = bmp.bmWidth;
    // pay attention to the sign, you most likely want a
    // top-down pixel array as it's easier to use
    info.bmiHeader.biHeight = -bmp.bmHeight;
    info.bmiHeader.biPlanes = 1;
    info.bmiHeader.biBitCount = 32;
    info.bmiHeader.biCompression = BI_RGB;

    SetDIBits(hdcDestination, hBitmap, 0, bmp.bmHeight, &pixels[0], &info, DIB_RGB_COLORS);
}

note: i'm update the code for get the image size and the bitcount:
1
2
3
4
5
6
7
struct PixelsArray
{
    int Bitcount = 0;
    int ImageWidth = 0;
    int ImageHeight = 0;
    PixelArray Pixels;
};

because we need calculate:
- the 'pixelSize', with 'bm.bmBitsPixel';
size_t pixelSize = bm.bmBitsPixel / 8;
- the 'scanlineSize' with 'pixelSize' and 'bm.bmWidth'(and more):
size_t scanlineSize = (pixelSize * bm.bmWidth + 3) & ~3;
- and the 'pixelOffset':
size_t pixelOffset = y * scanlineSize + x * pixelSize;
for we getting the pixels positions and the RGB separed:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//how use it
/*PixelArray pixels=GetImagePixel(imgImage);

size_t pixelSize = bm.bmBitsPixel / 8;
size_t scanlineSize = (pixelSize * bm.bmWidth + 3) & ~3;

int x=0, y=0;
for(y=0; y<imgImage.height(); y++)
{
    for(x=0; x<imgImage.width(); x++)
    {
        size_t pixelOffset = y * scanlineSize + x * pixelSize;

        COLORREF clrActualColor=RGB(pixels[pixelOffset+2],pixels[pixelOffset+1],pixels[pixelOffset+ 0]);
        if(clrActualColor ==RGB(0,0,0))
        {
            pixels[pixelOffset+2]=GetRValue(GetSysColor(COLOR_MENU));
            pixels[pixelOffset+1]=GetGValue(GetSysColor(COLOR_MENU));
            pixels[pixelOffset+0]=GetBValue(GetSysColor(COLOR_MENU));
        }
    }
}
SetImageData(hMemDC,pixels);*/

but i need ask: the GetImagePixel() use 1 HDC and the SetImageData() use a different HDC\HBITMAP but the same pixel array(i mean from GetImagePixel()):
so the SetDIBits() can't combine the pixel array on the HDC\HBITMAP destination?
did i miss something on SetImageData()?
(i get a black result... well... no result. for now i'm not testing the function returns)
note: these code works fine when i use the same HDC\HBITMAP.
Last edited on
I think you need to bitblt from one to the other.
maybe i need recreate another pixel array for do the pixel changes ;)
using these way, i can use differents HDC's without problems.
Last edited on
from
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
typedef std::vector<BYTE> PixelArray;

struct PixelsArray
{
    int Bitcount = 0;
    int ImageWidth = 0;
    int ImageHeight = 0;
    PixelArray Pixels;
    operator const void*()
    {
        return &Pixels[0];
    }
};

PixelsArray GetImagePixel(HDC hdcImage)
{
    BITMAP bmp = {0};
    memset( &bmp, 0, sizeof(BITMAP) );
    HBITMAP hBitmap =(HBITMAP) GetCurrentObject(hdcImage, OBJ_BITMAP);
    GetObject(hBitmap, sizeof(BITMAP), &bmp);

    BITMAPINFO info { };
    info.bmiHeader.biSize = sizeof(info.bmiHeader);
    info.bmiHeader.biWidth = bmp.bmWidth;
    // pay attention to the sign, you most likely want a
    // top-down pixel array as it's easier to use
    info.bmiHeader.biHeight = -bmp.bmHeight;
    info.bmiHeader.biPlanes = 1;
    info.bmiHeader.biBitCount = 32;
    info.bmiHeader.biCompression = BI_RGB;

    // the following calculations work for 16/24/32 bits bitmaps
    // but assume a byte pixel array
    size_t pixelSize = info.bmiHeader.biBitCount / 8;
    // the + 3 ) & ~3 part is there to ensure that each
    // scan line is 4 byte aligned
    size_t scanlineSize = (pixelSize * info.bmiHeader.biWidth + 3) & ~3;
    size_t bitmapSize = bmp.bmHeight * scanlineSize;

    PixelsArray Pixels;
    Pixels.Pixels.resize (bitmapSize);
    GetDIBits(hdcImage, hBitmap, 0, bmp.bmHeight, &Pixels.Pixels[0], &info, DIB_RGB_COLORS);
    bmp.bmHeight = std::abs(bmp.bmHeight);
    Pixels.Bitcount=info.bmiHeader.biBitCount;
    Pixels.ImageHeight=bmp.bmHeight;
    Pixels.ImageWidth=bmp.bmWidth;

    return   Pixels;
}

why seems that i get an empty pixels array?
i'm testing:
- i fill the surface using the FillRect(), the rectangle is drawed;
- then i get the pixels.. i can draw a line.. but the surface isn't showed... just a black secreen... i'm getting the DIBs correctly or i did something wrong and i'm getting an empty surface?
Last edited on
CreateCompatibleDC, but that doesn't copy the bitmap. It creates a second handle to the same bitmap.

https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createcompatibledc

If you want a copy of the bitmap to manipulate independently you need to copy the bitmap and set up a separate DC for that 2nd bitmap.

How you'd do that is easily searchable on the internet.
i found the problem lol
when i Drawed the FillRectangle, nothing is changed... ;)
i must update the pixels ;)
1
2
3
4
void Update()
    {
        pixels=GetImagePixel(ImageHDC);
    }

tested and works fine.. thanks.
Last edited on
now i can draw a line with a texture.. tomorrow, i will update it for draw a 3D line ;)

jonnin: i belive the problem was not update the image after change it... everytime that we change the pixel array, we must set it on HBITMAP\HDC.


George P: yes.. maybe that was my problem too.
for now i'm update it for draw a Line3D with a texture ;)
thanks for all to all
Last edited on
Topic archived. No new replies allowed.