I managed to find this code snippet and compile it with Cairo:
#define LIBCAIRO_EXPORTS
#include <cairo/cairo.h>
#include <cairo/cairo-win32.h>
int main(int argc, char** argv)
{
cairo_surface_t *surface;
cairo_t *cr;
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 240, 80);
cr = cairo_create (surface);
cairo_select_font_face (cr, "serif", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size (cr, 32.0);
cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
cairo_move_to (cr, 10.0, 50.0);
cairo_show_text (cr, "Hello, World");
cairo_destroy (cr);
cairo_surface_write_to_png (surface, "hello.png");
cairo_surface_destroy (surface);
return 0;
}
As you can see, it create an image with the text "Hello World" and saved it on the drive. How do I go about creating a win32 surface and draw to a window instead?
I am failing to use: cairo_win32_surface_create
It requires a hdc
and I don't know what that is. I tried to read a few tutorials but none seems to walk you through printing to a new window.
I found this link: http://windrealm.org/cairo-gdi/
It has a working demo but it uses int WINAPI WinMain
. I don't wish to use that.
There are several ways to get a handle to a device context in Windows. For instance it is typical that the WM_PAINT
handler will call BeginPaint
to acquire a device context, update the contents to the window and then call EndPaint
. In cases where BeginPaint
and EndPaint
cannot be used (e.g. outside of a WM_PAINT message) you can use GetDC
update the window and then call ReleaseDC
.
The device contexts returned by BeginPaint
and GetDC
allow you to draw directly to a window. Sometimes however you want to draw directly to a bitmap. In this case you would call CreateCompatibleDC
, select the bitmap you want to draw to, do your drawing and then call DeleteDC
.
In your case what you're looking for is something like the following:
HDC dc = GetDC(windowHandle);
cairo_win32_surface_create(dc);
ReleaseDC(windowHandle, dc);
If you do not want to create a window at this stage (since you are simply saving an image) you can probably get away with using the desktop window to acquire a device context.
HWND windowHandle = GetDesktopWindow();
HDC dc = GetDC(windowHandle);
cairo_win32_surface_create(dc);
ReleaseDC(windowHandle, dc);
There are other calls that can be used to acquire or create a device context. You can find a list of these and related functions here
Creating and using a window is a bit more involved so I'm going to provide you with the basic steps and some sample code that you can use to play around with. To create and use a window...
RegisterClass
CreateWindow
or CreateWindowEx
GetMessage
, TranslateMessage
and DispatchMessage
Additionally you will have to implement a function to handle processing of window messages such as WM_PAINT
.
NOTE: The following code is UNTESTED but should be correct.
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_PAINT)
{
HDC dc;
PAINTSTRUCT ps;
dc = BeginPaint(hwnd, &ps);
// do your drawing here
EndPaint(hwnd, &ps);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szClassName[] = TEXT("DrawSurfaceClass");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
///////////////////////////////////////////////////////////
// Register a window "class"
///////////////////////////////////////////////////////////
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground =(HBRUSH)COLOR_WINDOW;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szClassName;
if(!RegisterClass(&wndclass))
{
// error
return 1;
}
///////////////////////////////////////////////////////////
// Create the window and display it (if iCmdShow says so)
///////////////////////////////////////////////////////////
hwnd = CreateWindow(
szAppName,
TEXT("Draw Surface"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
///////////////////////////////////////////////////////////
// Run the message pump so the window proc recieves events
///////////////////////////////////////////////////////////
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
I found the easiest way for beginners to open a window and draw some lines into it, is downloading and setting up the gtk+ and using ZetCode's tutorials.
You will probably need to download GTK from here: http://gtk.hexchat.org/
Setting up Gtk+: Using GTK+ in Visual C++
Cairo tutorials: http://zetcode.com/gfx/cairo/
Remember to include all the GTK's dll files in the directory where your compiled executable is.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With