C++: how create a HBITMAP with a pixels pointer?

see how i create the HBITMAP after load the image using GDIPlus:
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
void FromFile(string strFile)
    {
        //clean all objects.. here i must update it, but i need test an object before delete it:
        Dispose();

        //Start GDIPlus:
        Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);

        //Create a GDIPlus image:
        img =new Bitmap(towstring(strFile).c_str());
        Width=img->GetWidth();
        Height=img->GetHeight();

        //Get Graphics from image:
        graphic= Graphics::FromImage(this->img);

        //Create the pixel vector pointer:
        unsigned int* pixels = (unsigned int*)malloc(Width*Height*sizeof(unsigned int));

        //Create the HDC for draw the image:
        ImageHDC = CreateCompatibleDC(GetDC(NULL));

        //Create the HBITMAP using the image size and pixels pointer:
        hBitmap=CreateBitmap(Width,Height,1,32,pixels);

        //Combine the HBITMAP the HDC:
        SelectObject(ImageHDC, hBitmap);

        //Get the Graphics from HDC and draw the image on HDC:
        Graphics *g;
        g=Graphics::FromHDC(ImageHDC);
        g->DrawImage(img,0,0);

    }

if i use the BitBlt(), using HDC, i can draw the image correctly.
i have 1 question before continue: i'm creating, correctly the pixels pointer?
Why do you mix GDI and GDI+ ?
A while ago I created this simple demo to deal with Pixels in the Bitmap class.
Have a look it might give you some ideas.
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
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <windows.h>
#include <gdiplus.h>
#include <cstdio>

#if defined(DEBUG) || defined(_DEBUG)
	#define LOG(fmt, ...) fprintf(stderr,fmt, __VA_ARGS__);
#else
	#define LOG(fmt, ...)
#endif


class GDI_Plus
{
public:
	GDI_Plus()
	{
		Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, nullptr);		
	}
	~GDI_Plus()
	{
		Gdiplus::GdiplusShutdown(m_gdiplusToken);
	}
private:
	ULONG_PTR m_gdiplusToken = 0;
	Gdiplus::GdiplusStartupInput gdiplusStartupInput = {0};
};

struct Pixel
{
  BYTE red,
          green,
          blue;
};

int main()
{
	GDI_Plus _ ;

	HWND consoleWindow = GetConsoleWindow();
	HDC consoleDC = GetDC(consoleWindow);
	Gdiplus::Graphics graphics(consoleDC);

	Gdiplus::Bitmap *bmp = Gdiplus::Bitmap::FromFile(L"D:\\Temp\\Demo.jpg");
	LOG("Bitmap Width:  %d\nBitmap Height: %d\n", bmp->GetWidth(), bmp->GetHeight());
	graphics.DrawImage(bmp, 100, 200, bmp->GetWidth(), bmp->GetHeight());

	Gdiplus::Rect rect(0,0, bmp->GetWidth(), bmp->GetHeight());
	Gdiplus::BitmapData data;
	auto status = bmp->LockBits(&rect, Gdiplus::ImageLockModeWrite, PixelFormat24bppRGB, &data); // 24 bit jpeg
	Pixel *pixel = static_cast<Pixel*>(data.Scan0);
	int numPixels = bmp->GetWidth() * bmp->GetHeight();
	for (int i = 0; i < numPixels; ++i)
	{
		pixel->blue = pixel->red = pixel->green = 125;
		++pixel;
	}

	bmp->UnlockBits(&data);	
	graphics.DrawImage(bmp, 400, 200, bmp->GetWidth(), bmp->GetHeight());
	ReleaseDC(consoleWindow, consoleDC);
}
thank you so much.. let me ask more:
1 - 'pixel' works after 'unlockbits'? yes i need it while the same image is used.
2 - can be updated for use alpha?
3 - how test GDIPLus objects for delete them without errors?(yes i can't delete a deleted object)
heres my actual result:
https://imgur.com/a/tKpAbmK
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
void FromFile(string strFile)
    {
        //clean all objects.. here i must update it, but i need test an object before delete it:
        Dispose();



        //Create a GDIPlus image:
        img =new Bitmap(towstring(strFile).c_str());
        Width=img->GetWidth();
        Height=img->GetHeight();

        //Get Graphics from image:
        graphic= Graphics::FromImage(img);
        Gdiplus::Rect rect(0,0, img->GetWidth(), img->GetHeight());
        Gdiplus::BitmapData data;
        auto status = img->LockBits(&rect, Gdiplus::ImageLockModeWrite, PixelFormat24bppRGB, &data); // 24 bit jpeg
        pixel = static_cast<Pixel*>(data.Scan0);
        int numPixels = img->GetWidth() * img->GetHeight();


        //Create the HDC for draw the image:
        ImageHDC = CreateCompatibleDC(GetDC(NULL));

        //Create the HBITMAP using the image size and pixels pointer:
        hBitmap=CreateBitmap(Width,Height,1,32,NULL);

        //Combine the HBITMAP the HDC:
        SelectObject(ImageHDC, hBitmap);

        //Get the Graphics from HDC and draw the image on HDC:
        Graphics *g;
        g=Graphics::FromHDC(ImageHDC);
        g->DrawImage(img,0,0);
        img->UnlockBits(&data);
    }

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
//Draw image pixel a pixel:
    void DrawImagePoint(HDC hdcDestination,point TopLeft,point TopRight,point BottomLeft,point BottomRight, angle angles={0,0,0})
    {
        //Obter os pontos das 2 linhas verticais:
        //Getting the Points of a line:
        vector<point> LeftLine;
        LeftLine = GetPointsLine(TopLeft,BottomLeft);

        vector<point> RgihtLine;
        RgihtLine = GetPointsLine(TopRight,BottomRight);

        int pixelposition=0;
        for(int PosX=0; PosX<LeftLine.size()-1; PosX++)
        {
            //Calcular os pontos da linha horizontal usando os pontos das linha verticais
            vector<point> PixelLine;
            PixelLine=GetPointsLine(LeftLine[PosX], RgihtLine[PosX]);

            for (int PosY=0; PosY<PixelLine.size()-1; PosY++)
            {
                //Obter o ponto da recto Horizontal:
                point Point=PixelLine[PosY];

                //Obter a cor do pixel:
                COLORREF clr;
                clr=RGB(pixel[pixelposition].red,pixel[pixelposition].green,pixel[pixelposition].green) ;

                //se os pontos são 3D, temos de usar a perspectiva
                point eyepoint={250,150,300};
                Point = perspective(Point,eyepoint);

                //Imprimir o pixel no Destino do HDC:
                ::SetPixel(hdcDestination,PosX,PosY,clr);
                pixelposition++;
            }
        }
    }
1 - 'pixel' works after 'unlockbits'? yes i need it while the same image is used.
No, you can't access the pixels after unlockbits.

2 - can be updated for use alpha?

Sure.
1
2
3
4
5
6
7
struct Pixel
{
  BYTE alpha,
          red,
          green,
          blue;
};
However you need to be sure that the bitmap supports alpha.

3 - how test GDIPLus objects for delete them without errors?(yes i can't delete a deleted object)
I am not sure what you mean. Best way to to create them on the stack, then you don't need to worry about that.
Thank you so much. You gived me more ideas.
I need ask: why i get bad pixels colors, like you see on image link?
clr=RGB(pixel[pixelposition].red,pixel[pixelposition].green,pixel[pixelposition].green) ;
This doesn't look right. pixel is a pointer to a struct or at least it should be. Look at my example line 53-57 how to set the individual values.
Yes its true. And I found another error: the function class accept the 4 points, and the points can me more big or small than the image, and the function must be updated for that too and for the transparent color too. On night I will test more. Thanks so much for all.
i did the change and works fine.. now i need understand something, but see the result:
https://imgur.com/SqJxQe1
- why i get the image horizontal?
- why part of image is down?
- and why i get that error after 1st print?
how use 'pixel' like an array?(instead ++pixel)
i belive the error: "Process returned -1073741819 (0xC0000005) execution time : 2.219 s
Press any key to continue."
is from 'DrawImagePoint' function('++pixel').... i don't know calculate the 'pixel' size and go back to zero.
when i do '++pixel' and 'pixel->red', i don't know the pointer position... maybe that's why the image seems drawed speared.
fixed.... for return the pointer to zero:
1
2
//in these case the pixelposition, is the last pixel position:
        for (int i=pixelposition; i!=0; i--) --pixel;

now works fine.. thanks.
in time i will update for don't use 'SetPixel()'
Note: i use the:
1
2
3
4
5
6
7
struct Pixel
{
  BYTE red,
          green,
          blue,
          alpha;
};

1
2
3
Gdiplus::BitmapData data;
        auto status = img->LockBits(&rect, Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, &data); // 24 bit jpeg
        pixel = static_cast<Pixel*>(data.Scan0);

i can use another format that accept any bit and ARGB/RGB?
I think the alpha value should be the first value in the struct.
Unfortunately there are many file formats for bitmaps.
.gif has 8 bit, .jpg has 24 bit, .png has 32 bit and there are many other bitmap formats as well.
So you need different Pixel type for each bitmap.
Good news is that Gdiplus::Bitmap supports many formats - for details see MS doc
"I think the alpha value should be the first value in the struct."
honestly i don't know:
1
2
3
4
5
6
7
struct Pixel
{
  BYTE red,
          green,
          blue,
          alpha;
};

from results, maybe i change the Blue to Red and Red to Blue.

"Unfortunately there are many file formats for bitmaps."
i know, but how i get the right for use it on 'LockBits'?

now i'm update for don't use the 'SetPixel()', but no luck :(
1
2
3
4
5
6
7
8
9
10
11
void GetPixelsFromHDC(HDC Destination, int *pixels)
{

    HBITMAP hBitmap = reinterpret_cast<HBITMAP>(GetCurrentObject(Destination, OBJ_BITMAP));
    DIBSECTION dibs;
    ::GetObject(hBitmap, sizeof(DIBSECTION), &dibs);
    BITMAPINFO bitinfo;
    ::GetObject(hBitmap, sizeof(BITMAPINFO), &bitinfo);
    pixels = (unsigned int*)malloc(dibs.dsBmih.biWidth*dibs.dsBmih.biHeight*sizeof(unsigned int));
    ::GetDIBits(Destination, hBitmap,0,0,&pixels,&bitinfo,dibs.dsBmih.biClrUsed);
}


how i use:
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
50
51
52
53
54
55
//Draw image pixel a pixel:
    void DrawImagePoint(HDC hdcDestination,point TopLeft,point TopRight,point BottomLeft,point BottomRight, angle angles={0,0,0})
    {
        //Obter os pontos das 2 linhas verticais:
        //Getting the Points of a line:
        vector<point> LeftLine;
        LeftLine = GetPointsLine(TopLeft,BottomLeft);

        vector<point> RgihtLine;
        RgihtLine = GetPointsLine(TopRight,BottomRight);

        int pixelposition=0;
        int PosX=0;
        int PosY=0;
        int *DestinationPixels;
        GetPixelsFromHDC(hdcDestination, DestinationPixels);
        for( PosX=0; PosX<LeftLine.size()-1; PosX++)
        {
            //Calcular os pontos da linha horizontal usando os pontos das linha verticais
            vector<point> PixelLine;
            PixelLine=GetPointsLine(LeftLine[PosX], RgihtLine[PosX]);
            for ( PosY=0; PosY<PixelLine.size()-1; PosY++)
            {
                //Obter o ponto da recto Horizontal:
                point Point=PixelLine[PosY];

                //Obter a cor do pixel:
                COLORREF clr;
                byte r =pixel->red;
                byte g = pixel->green;
                byte b=pixel->blue;
                byte a=pixel->alpha;
                clr=RGB(b,g,r) ;


                //se os pontos são 3D, temos de usar a perspectiva
                point eyepoint={250,150,300};
                Point = perspective(Point,eyepoint);

                //Imprimir o pixel no Destino do HDC:
                DestinationPixels=clr;
                //::SetPixel(hdcDestination,PosY,PosX,clr);
                ++pixel;
                ++pixelposition;
                ++DestinationPixels;
            }
        }
        //in these case the pixelposition, is the last pixel position:
        for (int i=pixelposition; i!=0; i--)
        {
            --pixel;
            --DestinationPixels;
        }
    }
};

the pixels, on hdcDestination, aren't changed :(
what i'm doing wrong?
Topic archived. No new replies allowed.