1
votes

I need to draw PNG images with transparency. I use GDI, GDI+, and WinApi.

To load and draw images, I always used GDI+, but now I'm using more "native" GDI algorithms (StretchBlt, etc).

The problem is that GDI can't load PNG. I searched the internet and found 2 ways:

  • loading via GDI+
  • using WIC.

WIC seems to be too difficult (but what did I expect?), so I choose the first one.

It's easy to load a PNG image using GDI+, just create a Bitmap object passing the file path to the constructor, then call the getHBITMAP() method to receive an HBITMAP handle, and that's all.

The problem is that the HBITMAP produced by Bitmap loses transparency.

I searched how to fix it. There are different ways - like passing Color::Black as first argument, etc. But it doesn't work.

So, how can I Ioad a PNG image and convert it to HBITMAP with transparency?

I don't use DrawImage method, because it's slow, GDI is faster

I pinned the code:

I understood my mistake: I have to blit hdc_mem to hdcc firstly, and then blit the image. I've did it, but i have a new problem¬_¬

I made a class to manage uploaded images, here the code:

class Imagee
{
HDC hdc; HBITMAP bm;
Imagee(HDC hdc, HBITMAP bm, another args)
{
this->hdc=CreateCompatibleDC(hdc);
this->bm=bm;
SelectObject(this->hdc,this->bm);
}
void draw(int hdcc, int x,int y, int cx, int cy)
{
**StretchBlt(this->hdc,0,0,cx,cy,hdcc,x,y,cx,cy,SRCCOPY); //I'VE ADDED THIS
SelectObject(this->hdc,this->bm); //AND THIS **

StretchBlt(this->hdcc,x,y,cx,cy,hdc,0,0,cx,cy,SRCCOPY); 
};
};
Imagee *image;

void render()
{
for(;;)
{
//some draws

//Loading a bitmap via Gdi+, calling a GetHBITMAP function, HBITMAP variable named hbm

if(image==0)
image=new Imagee(hdc_mem, hbm, x, y etc..);

image->draw(hdc_mem, x, y etc..);

StretchBlt(hdc_main,0,0,1920,1080,hdc_mem,0,0,1920,1080,SRCCOPY);
}

I have a black screen. It seems I can't call SelectObject again, yes?

1
Why do you need to resort to GDI for drawing? You can create a Graphics object for an HDC and then pass the Bitmap to Graphics::DrawImage(). See Loading and Displaying Bitmaps in the GDI+ documentation. If you have to resort to GDI, see How would I load a PNG image using Win32/GDI (no GDI+ if possible)?.Remy Lebeau
GDI+ will draw the png with transparency. You haven't shown what problems you are having. GDI functions don't understand alpha, but you can use GetHBITMAP(Gdiplus::Color::Transparent, &hBitmap) for some special cases.Barmak Shemirani
@Remy Lebeau Gdi draws image faster than DrawImage methodАртур Клочко
@Barmak Shemirani I've tried Color::Transparent too, it didn't work(I mean there wasn't transparency)Артур Клочко
SRCCOPY doesn't perform alpha blending. A simple block transfer (which SRCCOPY does) is a lot faster than alpha blending. Given the code, it's unclear, what you really need. The code (like its formatting) is severely broken. Get a copy of Petzold's Programming Windows®.IInspectable

1 Answers

0
votes

Solve

class Imagee
{
HDC hdc; HBITMAP bm;

Imagee(HDC hdc, HBITMAP bm, another args)
{
this->hdc=CreateCompatibleDC(hdc);
this->bm=bm;
SelectObject(this->hdc,this->bm);
}

void draw(int hdcc, int x,int y, int cx, int cy)
{

BITMAP btm;

GetObject(bm,sizeof(BITMAP),&btm)

BLENDFUNCTION bf
//initialize bf

AlphaBlend(hdcc,x,y,cx,cy,his->hdcc,0,0,btm.bmWidth,btm.bmHeight,bf); 
};

};

Imagee *image;

void render()
{
for(;;)
{

//здесь я загружая через гди+ битмам, конвертирую его в хбитмап, записывая в перменную HBITMAP hbm

if(image==0)
image=new Imagee(hdc_mem, hbm, x, y и т.д.);

image->draw(hdc_mem, x, y и т.д.);

StretchBlt(hdc_main,0,0,1920,1080,hdc_mem,0,0,1920,1080,SRCCOPY); //hdc_main главный дс, hdc_mem буфер

}
}

Thanks to ru.stackoverflow.com