Discussion:
GDI GradientFill not working on offscreen bitmap
(too old to reply)
Leith
2010-01-27 20:50:27 UTC
Permalink
Hi,

I am trying to use the GDI GradientFill function to draw on a
offscreen bitmap, then BitBlt that to the screen.

But I always get a black bitmap... if I GradientFill directly to the
screen it works.

Below is a sample app to see what I mean.

#pragma comment(lib, "msimg32.lib")
#include <windows.h>

const CHAR c_szWndClass[] = "GradientTestWnd";
const CHAR c_szWndTitle[] = "GradientTest";
const int c_nWndWidth = 1024;
const int c_nWndHeight = 768;

int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
WNDCLASSEX wcx;
ZeroMemory(&wcx, sizeof(wcx));
wcx.cbSize = sizeof(wcx);
wcx.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcx.lpfnWndProc = DefWindowProc;
wcx.hInstance = hInstance;
wcx.lpszClassName = c_szWndClass;

RegisterClassEx(&wcx);

HWND hwndMain = CreateWindowEx(
0,
c_szWndClass,
c_szWndTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
c_nWndWidth,
c_nWndHeight,
NULL,
NULL,
hInstance,
NULL);

ShowWindow(hwndMain, SW_SHOW);

HDC hdc;
hdc = GetDC(hwndMain);

HDC hdcOffscreen = CreateCompatibleDC(hdc);
HBITMAP bitmap = CreateCompatibleBitmap(hdcOffscreen, c_nWndWidth,
c_nWndHeight);
HBITMAP old_bitmap = (HBITMAP) SelectObject(hdcOffscreen, bitmap);

TRIVERTEX vertices[2];
ZeroMemory(&vertices, sizeof(vertices));
vertices[0].Red = 0xFF00;
vertices[0].Green = 0x0000;
vertices[0].Blue = 0x0000;
vertices[0].x = 0;
vertices[0].y = 0;

vertices[1].Red = 0x0000;
vertices[1].Green = 0x0000;
vertices[1].Blue = 0xFF00;
vertices[1].x = c_nWndWidth;
vertices[1].y = c_nWndHeight;

GRADIENT_RECT rects[1];
ZeroMemory(&rects, sizeof(rects));
rects[0].UpperLeft = 0;
rects[0].LowerRight = 1;

// This works
//GradientFill(hdc, vertices, 2, rects, 1, GRADIENT_FILL_RECT_V);

// This doesn't
GradientFill(hdcOffscreen, vertices, 2, rects, 1,
GRADIENT_FILL_RECT_V);
BitBlt(hdc, 0, 0, c_nWndWidth, c_nWndHeight, hdcOffscreen, 0, 0,
SRCCOPY);

Sleep(5000);

SelectObject(hdcOffscreen, old_bitmap);
DeleteObject(bitmap);
DeleteDC(hdcOffscreen);

return 0;
}
Jon Potter
2010-01-29 01:29:58 UTC
Permalink
CreateCompatibleDC automatically creates a monochrome bitmap; then when you
call CreateCompatibleBitmap, it makes another monochrome bitmap.
Instead you should pass the window's DC (hdc in your example code) to
CreateCompatibleBitmap.
Post by Leith
Hi,
I am trying to use the GDI GradientFill function to draw on a
offscreen bitmap, then BitBlt that to the screen.
But I always get a black bitmap... if I GradientFill directly to the
screen it works.
Below is a sample app to see what I mean.
#pragma comment(lib, "msimg32.lib")
#include <windows.h>
const CHAR c_szWndClass[] = "GradientTestWnd";
const CHAR c_szWndTitle[] = "GradientTest";
const int c_nWndWidth = 1024;
const int c_nWndHeight = 768;
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
WNDCLASSEX wcx;
ZeroMemory(&wcx, sizeof(wcx));
wcx.cbSize = sizeof(wcx);
wcx.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcx.lpfnWndProc = DefWindowProc;
wcx.hInstance = hInstance;
wcx.lpszClassName = c_szWndClass;
RegisterClassEx(&wcx);
HWND hwndMain = CreateWindowEx(
0,
c_szWndClass,
c_szWndTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
c_nWndWidth,
c_nWndHeight,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwndMain, SW_SHOW);
HDC hdc;
hdc = GetDC(hwndMain);
HDC hdcOffscreen = CreateCompatibleDC(hdc);
HBITMAP bitmap = CreateCompatibleBitmap(hdcOffscreen, c_nWndWidth,
c_nWndHeight);
HBITMAP old_bitmap = (HBITMAP) SelectObject(hdcOffscreen, bitmap);
TRIVERTEX vertices[2];
ZeroMemory(&vertices, sizeof(vertices));
vertices[0].Red = 0xFF00;
vertices[0].Green = 0x0000;
vertices[0].Blue = 0x0000;
vertices[0].x = 0;
vertices[0].y = 0;
vertices[1].Red = 0x0000;
vertices[1].Green = 0x0000;
vertices[1].Blue = 0xFF00;
vertices[1].x = c_nWndWidth;
vertices[1].y = c_nWndHeight;
GRADIENT_RECT rects[1];
ZeroMemory(&rects, sizeof(rects));
rects[0].UpperLeft = 0;
rects[0].LowerRight = 1;
// This works
//GradientFill(hdc, vertices, 2, rects, 1, GRADIENT_FILL_RECT_V);
// This doesn't
GradientFill(hdcOffscreen, vertices, 2, rects, 1,
GRADIENT_FILL_RECT_V);
BitBlt(hdc, 0, 0, c_nWndWidth, c_nWndHeight, hdcOffscreen, 0, 0,
SRCCOPY);
Sleep(5000);
SelectObject(hdcOffscreen, old_bitmap);
DeleteObject(bitmap);
DeleteDC(hdcOffscreen);
return 0;
}
Leith
2010-01-29 01:59:59 UTC
Permalink
Thanks, that worked.

Damn GDI and it's backwards API.
paulbo
2010-03-18 14:44:31 UTC
Permalink
Hi Leith,

Your problem is that when you create a compatible DC, it has a 1 x 1
monochrome bitmap selected into it by default. When you create a compatible
bitmap on that memory DC, that bitmap will also be monochrome. Create the
bitmap compatible with the display's DC (hdc), and it should work.

- Paul.

Loading...