1 /*
2 Sample usage of GD on windows. This little program opens a window, fetch its DIB
3 and assigns to a GD truecolor image.
4 
5 Thanks to Mateusz Loskot (http://mateusz.loskot.net) for the AttachBuffer function!
6 */
7 #include <windows.h>
8 #include <gd.h>
9 #include <gdfontg.h>
10 #include <gdfontl.h>
11 
12 
gdImageTrueColorAttachBuffer(int * buffer,int sx,int sy,int stride)13 gdImagePtr gdImageTrueColorAttachBuffer(int* buffer, int sx, int sy, int stride)
14 {
15 	int i;
16 	int height;
17 	int* rowptr;
18 	gdImagePtr im;
19 	im = (gdImage *) malloc (sizeof (gdImage));
20 	if (!im) {
21 		return 0;
22 	}
23 	memset (im, 0, sizeof (gdImage));
24 
25 #if 0
26 	if (overflow2(sizeof (int *), sy)) {
27 		return 0;
28 	}
29 #endif
30 
31 	im->tpixels = (int **) malloc (sizeof (int *) * sy);
32 	if (!im->tpixels) {
33 		free(im);
34 		return 0;
35 	}
36 
37 	im->polyInts = 0;
38 	im->polyAllocated = 0;
39 	im->brush = 0;
40 	im->tile = 0;
41 	im->style = 0;
42 
43 	height = sy;
44 	rowptr = buffer;
45 	if (stride < 0) {
46 		int startoff = (height - 1) * stride;
47 		rowptr = buffer - startoff;
48 	}
49 
50 	i = 0;
51 	while (height--) {
52 		im->tpixels[i] = rowptr;
53 		rowptr += stride;
54 		i++;
55 	}
56 
57 	im->sx = sx;
58 	im->sy = sy;
59 	im->transparent = (-1);
60 	im->interlace = 0;
61 	im->trueColor = 1;
62 	im->saveAlphaFlag = 0;
63 	im->alphaBlendingFlag = 1;
64 	im->thick = 1;
65 	im->AA = 0;
66 	im->cx1 = 0;
67 	im->cy1 = 0;
68 	im->cx2 = im->sx - 1;
69 	im->cy2 = im->sy - 1;
70 	return im;
71 }
72 
gdImageDetachBuffer(gdImagePtr im)73 void gdImageDetachBuffer(gdImagePtr im)
74 {
75 	free(im->tpixels);
76 	free(im);
77 }
78 
79 
gdCreateBmp(int width,int height)80 BITMAPINFO gdCreateBmp(int width, int height)
81 {
82 	BITMAPINFO bmp_info;
83 
84 	// Configure bitmap properties
85 
86 	ZeroMemory(&bmp_info, sizeof(BITMAPINFO));
87 	bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
88 	bmp_info.bmiHeader.biWidth = width;
89 	bmp_info.bmiHeader.biHeight = height;
90 	bmp_info.bmiHeader.biPlanes = 1;
91 	bmp_info.bmiHeader.biBitCount = 32;
92 	bmp_info.bmiHeader.biCompression = BI_RGB;
93 	bmp_info.bmiHeader.biSizeImage = 0;
94 	bmp_info.bmiHeader.biXPelsPerMeter = 0;
95 	bmp_info.bmiHeader.biYPelsPerMeter = 0;
96 	bmp_info.bmiHeader.biClrUsed = 0;
97 	bmp_info.bmiHeader.biClrImportant = 0;
98 	return bmp_info;
99 }
100 
101 LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
102 
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow)103 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
104                     PSTR szCmdLine, int iCmdShow)
105 {
106 	static TCHAR szAppName[] = TEXT ("Bezier") ;
107 	HWND         hwnd ;
108 	MSG          msg ;
109 	WNDCLASS     wndclass ;
110 
111 	wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
112 	wndclass.lpfnWndProc   = WndProc ;
113 	wndclass.cbClsExtra    = 0 ;
114 	wndclass.cbWndExtra    = 0 ;
115 	wndclass.hInstance     = hInstance ;
116 	wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
117 	wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
118 	wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
119 	wndclass.lpszMenuName  = NULL ;
120 	wndclass.lpszClassName = szAppName ;
121 
122 	if (!RegisterClass (&wndclass)) {
123 		// UNICODE-Compilierung ist die einzige realistische Fehlermöglichkeit
124 		MessageBox (NULL, TEXT ("Programm arbeitet mit Unicode und setzt Windows NT voraus!"),
125 		            szAppName, MB_ICONERROR) ;
126 		return 0 ;
127 	}
128 
129 	hwnd = CreateWindow (szAppName, TEXT ("Bezierkurven"),
130 	                     WS_OVERLAPPEDWINDOW,
131 	                     CW_USEDEFAULT, CW_USEDEFAULT,
132 	                     CW_USEDEFAULT, CW_USEDEFAULT,
133 	                     NULL, NULL, hInstance, NULL) ;
134 
135 	ShowWindow (hwnd, iCmdShow) ;
136 	UpdateWindow (hwnd) ;
137 
138 	while (GetMessage (&msg, NULL, 0, 0)) {
139 		TranslateMessage (&msg) ;
140 		DispatchMessage (&msg) ;
141 	}
142 	return msg.wParam ;
143 }
144 
DrawBezier(HDC hdc,POINT apt[])145 void DrawBezier (HDC hdc, POINT apt[])
146 {
147 	PolyBezier (hdc, apt, 4) ;
148 
149 	MoveToEx (hdc, apt[0].x, apt[0].y, NULL) ;
150 	LineTo   (hdc, apt[1].x, apt[1].y) ;
151 
152 	MoveToEx (hdc, apt[2].x, apt[2].y, NULL) ;
153 	LineTo   (hdc, apt[3].x, apt[3].y) ;
154 }
155 
156 
gdDrawImage(HDC hdc,RECT * rc)157 void gdDrawImage(HDC hdc, RECT *rc)
158 {
159 	HDC  mem_dc;
160 	BITMAPINFO bmp_info;
161 	void* bits;
162 	HBITMAP bmp, temp;
163 	gdImagePtr im;
164 	int width, height, stride;
165 	int white, black, blue, red;
166 	char *s = "Hello world!";
167 	gdFontPtr lfont, gfont;
168 
169 	width = rc->right - rc->left;
170 	height = rc->bottom - rc->top;
171 
172 	bmp_info = gdCreateBmp(width, height);
173 
174 	// Create memory device context
175 	mem_dc = CreateCompatibleDC(hdc);
176 	if (!mem_dc) {
177 		MessageBox(NULL, "Can't create a compatible DC!", "Error!", MB_ICONEXCLAMATION | MB_OK);
178 		return;
179 	}
180 
181 	// bits points to a shared buffer of pixels
182 	bits = NULL;
183 	bmp = CreateDIBSection(mem_dc, &bmp_info, DIB_RGB_COLORS, (void**)&bits, 0, 0);
184 
185 	// Selecting the object before doing anything allows you to use libgd
186 	// together with native Windows GDI.
187 	temp = (HBITMAP)SelectObject(mem_dc, bmp);
188 
189 	/*stride = ((width * 1 + 3) >> 2) << 2;*/
190 	// always uses 32bit in BMPINFO
191 	stride = width;
192 	im = NULL;
193 
194 	// Attach shared buffer of pixels to GD image
195 	// Negative stride places 0,0 in upper-left corner
196 	im = gdImageTrueColorAttachBuffer((int*)bits, width, height, -stride);
197 	if (!im) {
198 		MessageBox(NULL, "GD image creation failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
199 		return;
200 	}
201 
202 	// Start of GD drawing
203 	white = gdImageColorAllocate(im, 255, 255, 255);
204 	black = gdImageColorAllocate(im, 0, 0, 0);
205 	blue = gdImageColorAllocate(im, 0, 0, 255);
206 
207 	// Allocate the color red, 50% transparent.
208 	red = gdImageColorAllocateAlpha(im, 255, 0, 0, 64);
209 
210 	// Erase background with white color
211 	gdImageFilledRectangle(im, 0, 0, width, height, 0xFF0000);
212 
213 	lfont = gdFontGetLarge();
214 	gfont = gdFontGetGiant();
215 
216 	// Draw a dashed line from the upper left corner to the lower right corner.
217 	gdImageFilledRectangle(im, 25, 25, 100, 100, blue);
218 
219 	gdImageChar(im, gfont, 35, 35, 'Q', white);
220 	gdImageFilledRectangle(im, 50, 50, 75, 175, red);
221 	gdImageLine(im, 0, 0, 150, 150, black);
222 
223 	gdImageString(im, gdFontGetLarge(),
224 	              im->sx / 2 - (strlen(s) * lfont->w / 2),
225 	              im->sy / 2 - lfont->h / 2,
226 	              (unsigned char*)s, black);
227 
228 	// Copy drawing from memory context (shared bitmap buffer) to screen DC.
229 	BitBlt(hdc, rc->left, rc->top, width, height, mem_dc, 0, 0, SRCCOPY);
230 
231 	// Free
232 	gdImageDetachBuffer(im);
233 	SelectObject(mem_dc, temp);
234 	DeleteObject(bmp);
235 	DeleteObject(mem_dc);
236 }
237 
WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)238 LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
239 {
240 	static POINT apt[4] ;
241 	HDC          hdc ;
242 	int          cxClient, cyClient ;
243 	PAINTSTRUCT  ps ;
244 	RECT rc;
245 
246 	GetClientRect(hwnd, &rc);
247 
248 	switch (message) {
249 	case WM_SIZE:
250 		cxClient = LOWORD (lParam) ;
251 		cyClient = HIWORD (lParam) ;
252 
253 		apt[0].x = cxClient / 4 ;
254 		apt[0].y = cyClient / 2 ;
255 
256 		apt[1].x = cxClient / 2 ;
257 		apt[1].y = cyClient / 4 ;
258 
259 		apt[2].x =     cxClient / 2 ;
260 		apt[2].y = 3 * cyClient / 4 ;
261 
262 		apt[3].x = 3 * cxClient / 4 ;
263 		apt[3].y =     cyClient / 2 ;
264 		return 0 ;
265 
266 	case WM_LBUTTONDOWN:
267 	case WM_RBUTTONDOWN:
268 	case WM_MOUSEMOVE:
269 		if (wParam & MK_LBUTTON || wParam & MK_RBUTTON) {
270 			hdc = GetDC (hwnd) ;
271 
272 			// alte Kurve löschen (mit Weiß übermalen)
273 			SelectObject (hdc, GetStockObject (WHITE_PEN)) ;
274 			DrawBezier (hdc, apt) ;
275 
276 			if (wParam & MK_LBUTTON) {
277 				apt[1].x = LOWORD (lParam) ;
278 				apt[1].y = HIWORD (lParam) ;
279 			}
280 
281 			if (wParam & MK_RBUTTON) {
282 				apt[2].x = LOWORD (lParam) ;
283 				apt[2].y = HIWORD (lParam) ;
284 			}
285 
286 			// neue Kurve (mit Schwarz) zeichnen
287 			SelectObject (hdc, GetStockObject (BLACK_PEN)) ;
288 			gdDrawImage(hdc, &rc);
289 			DrawBezier (hdc, apt) ;
290 			ReleaseDC (hwnd, hdc) ;
291 		}
292 		return 0 ;
293 
294 
295 	case WM_PAINT:
296 		hdc = BeginPaint (hwnd, &ps) ;
297 
298 		GetClientRect(hwnd, &rc);
299 		gdDrawImage(hdc, &rc);
300 		DrawBezier (hdc, apt) ;
301 
302 		EndPaint (hwnd, &ps) ;
303 		return 0 ;
304 
305 	case WM_DESTROY:
306 		PostQuitMessage (0) ;
307 		return 0 ;
308 	}
309 	return DefWindowProc (hwnd, message, wParam, lParam) ;
310 }
311