Git init
[external/pango1.0.git] / examples / pangowin32tobmp.c
1 /* Pango
2  * Copyright (C) 1999 Red Hat Software
3  *
4  * testfonts.c:
5  * Copyright (C) 2001 Hans Breuer
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "config.h"
24
25 #include <glib.h>
26 #include <stdlib.h>
27 #include <gmodule.h>
28 #include "pango.h"
29 #include "pango-impl-utils.h"
30 #include "pangowin32.h"
31
32
33 #include <errno.h>
34 #include <string.h>
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 #include <stdio.h>
39 #include <locale.h>
40
41 #include <windows.h>
42
43 static HDC pre_render (int width, int height);
44 static void post_render (HDC hdc, const char* sFile);
45
46 static float
47 calc_duration (GTimeVal *tv1, GTimeVal *tv0)
48 {
49   return (  ((float)tv1->tv_sec - tv0->tv_sec)
50           + (tv1->tv_usec - tv0->tv_usec) / 1000000.0);
51 }
52
53 static int
54 compare_font_family (PangoFontFamily** a,
55                      PangoFontFamily** b)
56 {
57   return strcmp (pango_font_family_get_name (*a), pango_font_family_get_name (*b));
58 }
59
60 int main (int argc, char **argv)
61 {
62   PangoFontMap *fontmap = pango_win32_font_map_for_display();
63   PangoContext *context;
64   PangoCoverage * coverage = NULL;
65   PangoFont* font = NULL;
66   PangoFontFamily** families = NULL;
67   PangoFontFace** faces = NULL;
68   int nb, i;
69   gchar* family_name = NULL;
70   PangoLanguage *lang = pango_language_from_string (g_win32_getlocale ());
71   HDC hdc = NULL;
72   int line = 0;
73   GTimeVal tv0, tv1;
74   int my_font_size = 12;
75
76   printf ("# Pango Font Test\n"
77           "# Language: %s\n"
78           "#\n", pango_language_to_string (lang));
79
80   /* this wasn't necessary with previous version
81    *
82    * force initialization of built-in engines, otherwise
83    * the rendering get's really fast - too fast to work :-(
84    */
85   context = pango_win32_get_context ();
86
87   if (argc == 1)                /* No arguments given */
88     {
89       char *std_fonts[] = {"Sans 12", "Serif 12", "Monospace 12"};
90
91       /* try to load some fonts often hardcoded */
92       for (i = 0; i < G_N_ELEMENTS (std_fonts); i++)
93         {
94           PangoFontDescription *desc = pango_font_description_from_string(std_fonts[i]);
95
96           /* spits warnings if font cannot be loaded */
97           font = pango_font_map_load_font (fontmap, context, desc);
98
99           g_object_unref (font);
100         }
101     }
102   else
103     {
104       PangoFontDescription *desc = NULL;
105       GString *s;
106
107       s = g_string_new (argv[1]);
108       for (i = 2; i < argc; i++)
109         {
110           s = g_string_append_c (s, ' ');
111           s = g_string_append (s, argv[i]);
112
113           if (0 != atoi (argv[i]))
114             my_font_size = atoi (argv[i]);
115         }
116
117       desc = pango_font_description_from_string(s->str);
118       family_name = g_strdup (pango_font_description_get_family (desc));
119
120       font = pango_font_map_load_font (fontmap, context, desc);
121
122       coverage = pango_font_get_coverage (font, lang);
123
124       /* ... */
125
126       pango_coverage_unref (coverage);
127       pango_font_description_free (desc);
128       g_object_unref (font);
129     }
130
131   pango_font_map_list_families (fontmap, &families, &nb);
132
133   if (!family_name)
134     {
135       qsort (families, nb, sizeof (PangoFontFamily*), compare_font_family);
136     }
137   else
138     {
139       /* Get on the family faces. No simple way ? */
140       for (i = 0; i < nb; i++)
141         {
142           if (0 == g_ascii_strcasecmp (pango_font_family_get_name (families[i]), family_name))
143             {
144               pango_font_family_list_faces (families[i], &faces, &nb);
145               /* now nb is the number of faces */
146               break;
147             }
148         }
149       g_free (families);
150       families = NULL;
151       g_free (family_name);
152       family_name = NULL;
153     }
154
155   hdc = pre_render(my_font_size * 64, 3 * my_font_size * nb / 2);
156
157   for (i = 0; i < nb; i++)
158     {
159       PangoFontDescription *desc;
160       const char *f_name;
161       PangoWeight weight;
162       PangoStyle  style;
163
164       if (families)
165         {
166           desc = pango_font_description_new ();
167
168           f_name =  pango_font_family_get_name (families[i]);
169           pango_font_description_set_family (desc, f_name);
170         }
171       else
172         {
173           desc = pango_font_face_describe (faces[i]);
174           /* this is _not_ the family name from above */
175           f_name = pango_font_description_get_family (desc);
176         }
177       weight = pango_font_description_get_weight (desc);
178       style  = pango_font_description_get_style  (desc);
179
180       g_print ("%s; Style: %d; Weight: %d\n",
181                f_name, style, weight);
182
183       /* give it an arbitray size to load it */
184       pango_font_description_set_size (desc, my_font_size * PANGO_SCALE);
185
186       g_get_current_time (&tv0);
187       font = pango_font_map_load_font (fontmap, context, desc);
188       g_get_current_time (&tv1);
189       g_print ("\tpango_font_map_load_font took %.3f sec\n", calc_duration (&tv1, &tv0));
190
191       if (font)
192         {
193           PangoItem     *item;
194           PangoGlyphString * glyphs;
195           char s[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
196                      "abcdefghijklmnopqrstuvwxyz"
197                      "1234567890 -+*/!\xc2\xa7$%&()[]{}<>|#=?@";
198
199           g_get_current_time (&tv0);
200           coverage = pango_font_get_coverage (font, lang);
201           g_get_current_time (&tv1);
202           g_print ("\tpango_font_get_coverage took %.3f sec\n", calc_duration (&tv1, &tv0));
203
204           /* ... */
205           pango_context_set_language (context, lang);
206           pango_context_set_base_dir (context, PANGO_DIRECTION_LTR);
207           pango_context_set_font_description (context, desc);
208
209           glyphs = pango_glyph_string_new ();
210           item = pango_item_new ();
211
212           item->analysis.shape_engine = pango_font_find_shaper (font, lang, s[0]);
213           item->analysis.font = g_object_ref (font);
214           pango_shape ( s, sizeof(s), &(item->analysis), glyphs);
215
216           if (hdc)
217             {
218               /* the positioning isn't correct */
219               char* name = g_strdup_printf ("%s (%s%s)",
220                                             f_name,
221                                             weight == PANGO_WEIGHT_NORMAL ? "n" :
222                                               (weight == PANGO_WEIGHT_HEAVY ? "h" :
223                                               (weight > PANGO_WEIGHT_NORMAL ? "b" : "l")),
224                                             style == PANGO_STYLE_OBLIQUE ? "o" :
225                                               (style == PANGO_STYLE_ITALIC ? "i" : "n"));
226
227               TextOut (hdc, 0, line, name, strlen(name));
228               g_get_current_time (&tv0);
229               pango_win32_render (hdc, font, glyphs, 200, line);
230               g_get_current_time (&tv1);
231               g_print ("\tpango_win32_render took %.3f sec\n",
232                        calc_duration (&tv1, &tv0));
233               line += (3 * my_font_size / 2);
234               g_free(name);
235             }
236
237           /* free glyphs, ... */
238           pango_glyph_string_free (glyphs);
239           pango_item_free (item);
240
241           pango_coverage_unref (coverage);
242           g_object_unref (font);
243         }
244       pango_font_description_free (desc);
245     }
246
247   if (hdc)
248     post_render (hdc, "pango-fonts.bmp");
249
250   g_free (families);
251   g_free (faces);
252
253   return 0;
254 }
255
256 /*
257  * Real Win32 specific render support
258  */
259 static HBITMAP hbmpold = NULL;
260 static HWND hwndRender = NULL;
261
262 static BOOL
263 SaveBitmap (HBITMAP hBmp, const char* pszFile);
264
265 static HDC
266 pre_render (int width, int height)
267 {
268   HDC hmemdc;
269   HDC hdc;
270   HBITMAP hbmp;
271   RECT r;
272   r.top = 0; r.left = 0;
273   r.right  = width;
274   r.bottom = height;
275
276   hwndRender = CreateWindow ("EDIT",
277                              "pango-render-window",
278                              WS_DISABLED,
279                              0, 0, width, height,
280                              GetDesktopWindow(),
281                              NULL,
282                              GetModuleHandle(NULL),
283                              NULL);
284
285   if (hwndRender == NULL)
286     fprintf (stderr, "Couldn't create window\n"), exit (1);
287
288   hdc = GetDC(hwndRender);
289   hmemdc = CreateCompatibleDC (hdc);
290   if (hdc == NULL)
291     fprintf (stderr, "CreateCompatibleDC failed\n"), exit (1);
292
293   hbmp = CreateCompatibleBitmap (hdc, width, height);
294   if (hbmp == NULL)
295     fprintf (stderr, "CreateCompatibleBitmap failed\n"), exit (1);
296
297   hbmpold = SelectObject(hmemdc, hbmp);
298
299   FillRect (hmemdc, &r, GetStockObject(WHITE_BRUSH));
300   SetTextColor (hmemdc, RGB (0,0,0));
301   SetBkMode (hmemdc, TRANSPARENT);
302   return hmemdc;
303 }
304
305 static void
306 post_render (HDC hdc, const char* sFile)
307 {
308   HBITMAP hbmp = SelectObject(hdc, hbmpold);
309   if (sFile)
310     SaveBitmap (hbmp, sFile);
311   DeleteObject (hbmp);
312   DeleteDC (hdc);
313   ReleaseDC(hwndRender, GetDC(hwndRender));
314   DestroyWindow (hwndRender);
315 }
316
317 static BOOL
318 SaveBitmap (HBITMAP hBmp, const char* pszFile)
319 {
320   BITMAP bmp;
321   PBITMAPINFO pbmi;
322   WORD    cClrBits;
323   /* Retrieve the bitmap's color format, width, and height. */
324   if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))
325     return FALSE;
326   /* Convert the color format to a count of bits. */
327   cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
328   if (cClrBits == 1)
329     cClrBits = 1;
330   else if (cClrBits <= 4)
331     cClrBits = 4;
332   else if (cClrBits <= 8)
333     cClrBits = 8;
334   else if (cClrBits <= 16)
335     cClrBits = 16;
336   else if (cClrBits <= 24)
337     cClrBits = 24;
338   else
339     cClrBits = 32;
340
341   /*
342    * Allocate memory for the BITMAPINFO structure. (This structure
343    * contains a BITMAPINFOHEADER structure and an array of RGBQUAD data
344    * structures.)      */
345   if (cClrBits < 24)
346     pbmi = (PBITMAPINFO) GlobalAlloc(LPTR,
347                                     sizeof(BITMAPINFOHEADER) +
348                                     sizeof(RGBQUAD) * (1 << cClrBits));
349   /*
350    * There is no RGBQUAD array for the 24-bit-per-pixel format.      */
351   else
352     pbmi = (PBITMAPINFO) GlobalAlloc(LPTR,
353                                     sizeof(BITMAPINFOHEADER));
354   /* Initialize the fields in the BITMAPINFO structure. */
355   pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
356   pbmi->bmiHeader.biWidth = bmp.bmWidth;
357   pbmi->bmiHeader.biHeight = bmp.bmHeight;
358   pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
359   pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
360   if (cClrBits < 24)
361     pbmi->bmiHeader.biClrUsed = (1 << cClrBits);
362   else
363     pbmi->bmiHeader.biClrUsed = 0;
364   /* If the bitmap is not compressed, set the BI_RGB flag. */
365   pbmi->bmiHeader.biCompression = BI_RGB;
366   /*
367    * Compute the number of bytes in the array of color
368    * indices and store the result in biSizeImage.
369    */
370   pbmi->bmiHeader.biSizeImage = (pbmi->bmiHeader.biWidth + 7) /8
371                                   * pbmi->bmiHeader.biHeight
372                                   * cClrBits;
373   /*
374    * Set biClrImportant to 0, indicating that all of the
375    * device colors are important.
376    */
377   pbmi->bmiHeader.biClrImportant = 0;
378
379   { /* C sucks */
380   HANDLE hf;                  /* file handle */
381   BITMAPFILEHEADER hdr;       /* bitmap file-header */
382   PBITMAPINFOHEADER pbih;     /* bitmap info-header */
383   LPBYTE lpBits;              /* memory pointer */
384   DWORD dwTotal;              /* total count of bytes */
385   DWORD cb;                   /* incremental count of bytes */
386   DWORD dwTmp;
387   HDC hDC;
388
389   pbih = (PBITMAPINFOHEADER) pbmi;
390   lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);
391   if (!lpBits)
392     return FALSE;
393   /*
394    * Retrieve the color table (RGBQUAD array) and the bits
395    * (array of palette indices) from the DIB.
396    */
397   hDC = CreateCompatibleDC(NULL);
398   if (!GetDIBits(hDC, hBmp, 0, (WORD) pbih->biHeight,
399                  lpBits, pbmi, DIB_RGB_COLORS))
400     return FALSE;
401   /* Create the .BMP file. */
402   hf = CreateFile (pszFile,
403                    GENERIC_READ | GENERIC_WRITE,
404                    (DWORD) 0,
405                    (LPSECURITY_ATTRIBUTES) NULL,
406                    CREATE_ALWAYS,
407                    FILE_ATTRIBUTE_NORMAL,
408                    (HANDLE) NULL);
409
410   if (hf == INVALID_HANDLE_VALUE)
411     return FALSE;
412   hdr.bfType = 0x4d42;        /* 0x42 = "B" 0x4d = "M" */
413   /* Compute the size of the entire file. */
414   hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER)
415                         + pbih->biSize + pbih->biClrUsed
416                         * sizeof(RGBQUAD) + pbih->biSizeImage);
417   hdr.bfReserved1 = 0;
418   hdr.bfReserved2 = 0;
419   /* Compute the offset to the array of color indices. */
420   hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER)
421                           + pbih->biSize + pbih->biClrUsed
422                           * sizeof (RGBQUAD);
423   /* Copy the BITMAPFILEHEADER into the .BMP file. */
424   if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),
425                  (LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))
426     return FALSE;
427   /* Copy the BITMAPINFOHEADER and RGBQUAD array into the file. */
428   if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER)
429                      + pbih->biClrUsed * sizeof (RGBQUAD),
430                      (LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))
431     return FALSE;
432   /* Copy the array of color indices into the .BMP file. */
433   dwTotal = cb = pbih->biSizeImage;
434
435   if (!WriteFile(hf, (LPSTR) lpBits, (int) cb,
436                  (LPDWORD) &dwTotal, (LPOVERLAPPED) NULL))
437       return FALSE;
438
439   /* Close the .BMP file. */
440   if (!CloseHandle(hf))
441     return FALSE;
442
443   /* Free memory. */
444   GlobalFree((HGLOBAL)lpBits);
445   GlobalFree((HGLOBAL)pbmi);
446
447   DeleteDC(hDC);
448   } /* C sucks */
449   return TRUE;
450 }