Include config.h. If not HAVE_FREETYPE nor HAVE_GD, define a pseudo
[m17n/m17n-lib.git] / example / mdump.c
1 /* mdump.c -- Dump text image                           -*- coding: euc-jp; -*-
2    Copyright (C) 2003, 2004
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 /***en
24     @enpage mdump dump text image
25
26     @section mdump-synopsis SYNOPSIS
27
28     mdump [ OPTION ... ] [ FILE ]
29
30     @section mdump-description DESCRIPTION
31
32     Dump a text as PNG image file.
33
34     The PNG file is written to a file created in the current directory
35     with the name "BASE.png" where BASE is the basename of FILE.  If
36     FILE is omitted, text is read from standard input, and the image
37     is dumped into the file "output.png".
38
39     The following OPTIONs are available.
40
41     <ul>
42
43     <li> -s SIZE
44
45     SIZE is the font size in point.  The default font size is 12 point.
46
47     <li> -d DPI
48
49     DPI is the resolution in dots per inch.  The default resolution is
50     300 dpi.
51
52     <li> -p PAPER
53
54     PAPER is the paper size: a4, a4r, a5, a5r, b5, b5r, letter, or
55     WxH.  In the last case, W and H are the width and height in
56     millimeter.  If this option is specified, PAPER limits the image
57     size.  If FILE is too large for a single page, multiple files with
58     the names "BASE.01.png", "BASE.02.png", etc. are created.
59
60     <li> -m MARGIN
61
62     MARGIN is the horizontal and vertical margin in millimeter.  The
63     default margin is 20 mm.  It is ignored when PAPER is not
64     specified.
65
66     <li> -c POS
67
68     POS is the character position of cursor to draw.  By default,
69     cursor is not drawn.
70
71     <li> -x
72
73     FILE is assumed to be an XML file generated by the serialize
74     facility of the m17n library, and FILE is deserialized before an
75     image is created.
76
77     <li> -w
78
79     Each line is broken at word boundary.
80
81     <li> -f FILTER
82
83     FILTER is a string containing a shell command line.  If this
84     option is specified, the PNG image is not written info a
85     file but is given to FILTER as standard input.  If FILTER
86     contains "%s", that part is replaced by a basename of FILE.
87     So, the default behaviour is the same as specifying "cat >
88     %s.png" as FILTER.
89
90     <li> -q
91
92     Quiet mode.  Don't print any messages.
93
94     <li> --version
95
96     Print the version number.
97
98     <li> -h, --help
99
100     Print this message.
101
102     </ul>
103 */
104 /***ja
105     @japage mdump ¥Æ¥­¥¹¥È²èÁü¤Î¥À¥ó¥×
106
107     @section mdump-synopsis SYNOPSIS
108
109     mdump [ OPTION ... ] [ FILE ]
110
111     @section mdump-description DESCRIPTION
112
113     ¥Æ¥­¥¹¥È¤ò PNG ²èÁü¤È¤·¤Æ¥À¥ó¥×¤¹¤ë¡£ 
114
115     PNG ²èÁü¤Ï¸½ºß¤Î¥Ç¥£¥ì¥¯¥È¥ê¤Ëºî¤é¤ì¤¿ "BASE.png" ¤È¤¤¤¦Ì¾Á°¤Î 
116     ¥Õ¥¡¥¤¥ë¤Ë½ñ¤­¹þ¤Þ¤ì¤ë¡£¤³¤³¤Ç BASE ¤ÏFILE ¤Î basename ¤Ç¤¢¤ë¡£ 
117     FILE ¤¬¾Êά¤µ¤ì¤ì¤Ð¡¢¥Æ¥­¥¹¥È¤Ïɸ½àÆþÎϤ«¤éÆɤޤ졢²èÁü¤Ï 
118     "output.png" ¤Ë¥À¥ó¥×¤µ¤ì¤ë¡£
119
120     °Ê²¼¤Î¥ª¥×¥·¥ç¥ó¤¬ÍøÍѤǤ­¤ë¡£
121
122     <ul>
123
124     <li> -s SIZE
125
126     SIZE ¤Ï¥Õ¥©¥ó¥È¤ÎÂ礭¤µ¤ò¥Ý¥¤¥ó¥Èñ°Ì¤Ç¼¨¤·¤¿¤â¤Î¤Ç¤¢¤ë¡£¥Ç¥Õ¥©¥ë
127     ¥È¤ÎÂ礭¤µ¤Ï 12 ¥Ý¥¤¥ó¥È¡£
128
129     <li> -d DPI
130
131     DPI ¤Ï²òÁüÅÙ¤ò£±¥¤¥ó¥Á¤¢¤¿¤ê¤Î¥É¥Ã¥Èñ°Ì¤Ç¼¨¤·¤¿¤â¤Î¤Ç¤¢¤ë¡£¥Ç¥Õ¥© 
132     ¥ë¥È¤Î²òÁüÅ٤Ϡ300 dpi¡£
133
134     <li> -p PAPER
135
136     PAPER ¤Ï¤Ú¡¼¥Ñ¥µ¥¤¥º : a4, a4r, a5, a5r, b5, b5r, letter, ¤Þ¤¿¤Ï 
137     WxH. WxH ¤Î¾ì¹ç¡¢ W ¤È H ¤ÏÉý¤È¹â¤µ¤ò¥ß¥ê¥á¡¼¥¿Ã±°Ì¤Ç¼¨¤·¤¿¤â¤Î¡£ 
138     ¤³¤Î¥ª¥×¥·¥ç¥ó¤¬»ØÄꤵ¤ì¤Æ¤¤¤ë¾ì¹ç¤Ï¡¢ PAPER ¤¬²èÁü¥µ¥¤¥º¤òÀ©¸Â¤¹ 
139     ¤ë¡£FILE ¤¬ 1 ¥Ú¡¼¥¸¤ËǼ¤Þ¤é¤Ê¤¤¤Û¤ÉÂ礭¤¤¾ì¹ç¤Ï¡¢"BASE.01.png",
140     "BASE.02.png" Åù¤Î̾Á°¤Î¤Ä¤¤¤¿Ê£¿ô¤Î¥Õ¥¡¥¤¥ë¤¬ºî¤é¤ì¤ë¡£
141
142     <li> -m MARGIN
143
144     MARGIN ¤Ï¿åÊ¿¡¢¿âľ¥Þ¡¼¥¸¥ó¤ò¥ß¥ê¥á¡¼¥¿Ã±°Ì¤Ç¼¨¤·¤¿¤â¤Î¤Ç¤¢¤ë¡£¥Ç 
145     ¥Õ¥©¥ë¥È¤Î¥Þ¡¼¥¸¥ó¤Ï 20 mm¡£PAPER ¤¬»ØÄꤵ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð̵»ë¤µ¤ì¤ë¡£
146
147     <li> -c POS
148
149     POS ¤Ï¥«¡¼¥½¥ë¤Îʸ»ú°ÌÃÖ¡£¥Ç¥Õ¥©¥ë¥È¤Ç¤Ï¡¢¥«¡¼¥½¥ë¤ÏÉÁ¤«¤ì¤Ê¤¤¡£
150
151     <li> -x
152
153     FILE ¤Ï m17n ¥é¥¤¥Ö¥é¥ê¤Î¥·¥ê¥¢¥é¥¤¥ºµ¡Ç½¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿ XML ¥Õ¥¡ 
154     ¥¤¥ë¤Ç¤¢¤ê¡¢²èÁü¤òÀ¸À®¤¹¤ëÁ°¤Ë¥Ç¥·¥ê¥¢¥é¥¤¥º¤µ¤ì¤ë¡£
155
156     <li> -w
157
158     ¸ì¤Î¶­³¦¤Ç²þ¹Ô¤¹¤ë¡£ 
159
160     <li> -f FILTER
161
162     FILTER ¤Ï¥·¥§¥ë¥³¥Þ¥ó¥É¹Ô¤ò´Þ¤àʸ»úÎó¤Ç¤¢¤ë¡£¤³¤Î¥ª¥×¥·¥ç¥ó¤¬»ØÄê
163     ¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢PNG ²èÁü¤Ï¥Õ¥¡¥¤¥ë¤Ë½ñ¤«¤ì¤ë¤Î¤Ç¤Ï¤Ê¤¯¡¢FILTER ¤Ë 
164     É¸½àÆþÎϤȤ·¤ÆÅϤµ¤ì¤ë¡£ FILTER ¤¬ "s" ¤ò´Þ¤ó¤Ç¤¤¤ì¤Ð¡¢¤½¤ì¤Ï FILE 
165     ¤Î¥Ù¡¼¥¹¥Í¡¼¥à¤ËÃÖ¤­´¹¤¨¤é¤ì¤ë¡£¤³¤Î¥×¥í¥°¥é¥à¤Î¥Ç¥Õ¥©¥ë¥È¤Î¿¶Éñ¤¤
166     ¤È¡¢FILTER ¤Ë "cat > s.png" ¤ò»ØÄꤷ¤¿¾ì¹ç¤Î¿¶Éñ¤ÏƱ°ì¤Ç¤¢¤ë¡£
167
168     <li> -q
169
170     °ìÀڤΥá¥Ã¥»¡¼¥¸¤òɽ¼¨¤·¤Ê¤¤¡£ 
171
172     <li> --version
173
174     ¥Ð¡¼¥¸¥ç¥óÈÖ¹æ¤òɽ¼¨¤¹¤ë¡£
175
176     <li> -h, --help
177
178     ¤³¤Î¥á¥Ã¥»¡¼¥¸¤òɽ¼¨¤¹¤ë¡£ 
179
180     </ul>
181 */
182
183 #ifndef FOR_DOXYGEN
184
185 #include <stdio.h>
186 #include <stdlib.h>
187 #include <string.h>
188 #include <libgen.h>
189
190 #include "config.h"
191
192 #if defined (HAVE_FREETYPE) && defined (HAVE_GD)
193 #include <gd.h>
194
195 #include <m17n-gui.h>
196 #include <m17n-misc.h>
197
198 #define VERSION "1.0"
199
200 /* Enumuration of the supported paper types.  */
201 enum paper_type
202   {
203     PAPER_A4,
204     PAPER_A4R,
205     PAPER_A5,
206     PAPER_A5R,
207     PAPER_B5,
208     PAPER_B5R,
209     PAPER_LETTER,
210     PAPER_USER,
211     PAPER_NOLIMIT
212   };
213
214 /* Array of paper sizes for the supported paper types.  */
215 struct
216 {
217   int width, height;            /* in millimeter */
218 } paper_size[PAPER_NOLIMIT] = {
219   { 210, 297 },                 /* a4 */
220   { 297, 210 },                 /* a4r */
221   { 148, 210 },                 /* a5 */
222   { 210, 148 },                 /* a5r */
223   { 250, 176 },                 /* b5 */
224   { 176, 250 },                 /* b5r */
225   { 216, 279 },                 /* letter */
226 };
227
228
229 /* Print the usage of this program (the name is PROG), and exit with
230    EXIT_CODE.  */
231
232 void
233 help_exit (char *prog, int exit_code)
234 {
235   char *p = prog;
236
237   while (*p)
238     if (*p++ == '/')
239       prog = p;
240
241   printf ("Usage: %s [ OPTION ...] [ FILE ]\n", prog);
242   printf ("Dump a text as a PNG image into a file.\n");
243   printf ("  The PNG file is created in the current directory\n");
244   printf ("    with the name \"BASE.png\" where BASE is the basename of FILE.\n");
245   printf ("  If FILE is omitted, text is read from standard input, and\n");
246   printf ("    dumped into the file \"output.png\".\n");
247   printf ("The following OPTIONs are available.\n");
248   printf ("  %-13s %s", "-s SIZE",
249           "Font size in point (default 12).\n");
250   printf ("  %-13s %s", "-d DPI",
251           "Resolution in dots per inch (defualt 300).\n");
252   printf ("  %-13s %s", "-p PAPER",
253           "Paper size; a4, a4r, a5, a5r, b5, b5r, letter, or WxH.\n");
254   printf ("  %-13s %s", "-m MARGIN",
255           "Marginal space in millimeter (default 20).\n");
256   printf ("  %-13s %s", "-c POS",
257           "Character position of cursor to draw (default no cursor)\n");
258   printf ("  %-13s %s", "-x",
259           "FILE is assumed to be an XML file.\n");
260   printf ("  %-13s %s", "-f FILTER",
261           "String containing a shell command line to be used as a filter.\n");
262   printf ("  %-13s %s", "-w", "Each line is broken at word boundary.\n");
263   printf ("  %-13s %s", "-q", "Quiet mode.  Don't print any messages.\n");
264   printf ("  %-13s %s", "--version", "Print the version number.\n");
265   printf ("  %-13s %s", "-h, --help", "Print this message.\n");
266   exit (exit_code);
267 }
268
269
270 /* Format MSG by FMT and print the result to the stderr, and exit.  */
271
272 #define FATAL_ERROR(fmt, arg)   \
273   do {                          \
274     fprintf (stderr, fmt, arg); \
275     exit (1);                   \
276   } while (0)
277
278
279 /* Move POS to the next line head in M-text MT whose length is LEN.
280    If POS is already on the last line, set POS to LEN.  */
281
282 #define NEXTLINE(pos, len)                      \
283   do {                                          \
284     pos = mtext_character (mt, pos, len, '\n'); \
285     if (pos < 0)                                \
286       pos = len;                                \
287     else                                        \
288       pos++;                                    \
289   } while (0)
290
291
292 /* Find the range of M-text MT that fits in one page of height HEIGHT
293    when drawn from the character position POS.  Set RECT->y to the
294    Y-offset of the first baseline.  */
295
296 int
297 find_page_end (MFrame *frame, int height, MText *mt, int pos,
298                MDrawControl *control, MDrawMetric *rect)
299 {
300   int len = mtext_len (mt);
301   int to = pos;
302   int y = 0, yoff;
303
304   while (to < len)
305     {
306       int next = to;
307
308       NEXTLINE (next, len);
309       mdraw_text_extents (frame, mt, to, next, control, NULL, NULL, rect);
310       if (to == pos)
311         yoff = rect->y;
312       if (y + rect->height > height)
313         {
314           MDrawGlyphInfo info;
315
316           while (to < next)
317             {
318               mdraw_glyph_info (frame, mt, to, to, control, &info);
319               if (y + info.this.height > height)
320                 break;
321               y += info.this.height;
322               to = info.line_to;
323             }
324           break;
325         }
326       y += rect->height;
327       to = next;
328     }
329
330   rect->y = yoff;
331   return to;
332 }
333
334
335 /* Table to convert a byte of LSBFirst to MSBFirst. */
336 char reverse_bit_order[256];
337
338 /* Initialize the above table.  */
339
340 void
341 init_reverse_bit_order ()
342 {
343   int i;
344
345   for (i = 0; i < 256; i++)
346     reverse_bit_order[i]
347       = (((i & 1) << 7) | ((i & 2) << 5) | ((i & 4) << 3) | ((i & 8) << 1)
348          | ((i & 16) >> 1) | ((i & 32) >> 3)
349          | ((i & 64) >> 5) | ((i & 128) >> 7));
350 }
351
352
353 /* Dump the image in IMAGE into a file whose name is generated from
354    FILENAME and PAGE_INDEX (if it is not zero).  */
355
356 void
357 dump_image (gdImagePtr image, char *filename, char *filter,
358             int page_index, int quiet_mode)
359 {
360   FILE *fp;
361
362   if (page_index)
363     {
364       char *name = alloca (strlen (filename) + 8);
365
366       sprintf (name, "%s.%02d", filename, page_index);
367       filename = name;
368     }
369
370   if (filter)
371     {
372       char *command = alloca (strlen (filename) + strlen (filter) + 1);
373
374       sprintf (command, filter, filename);
375       fp = popen (command, "w");
376       if (! fp)
377         FATAL_ERROR ("Can't run the command \"%s\"\n", command);
378       if (! quiet_mode)
379         printf ("Running \"%s\" ... ", command);
380     }
381   else
382     {
383       char *fullname = alloca (strlen (filename) + 5);
384
385       sprintf (fullname, "%s.png", filename);
386       fp = fopen (fullname, "w");
387       if (! fp)
388         FATAL_ERROR ("Can't write to \"%s\"\n", fullname);
389       if (! quiet_mode)
390         printf ("Writing %s ... ", fullname);
391     }
392
393   /* Generate PNG.  */
394   gdImagePng (image, fp);
395   fclose (fp);
396   if (! quiet_mode)
397     printf (" done (%dx%d)\n", image->sx, image->sy);
398 }
399
400 extern int line_break (MText *mt, int pos, int from, int to, int line, int y);
401
402 int
403 main (int argc, char **argv)
404 {
405   int fontsize = 120;
406   int paper = PAPER_NOLIMIT;
407   int dpi = 300;
408   int margin = 20;
409   int xml = 0;
410   FILE *fp = stdin;
411   int cursor_pos = -1;
412   int quiet_mode = 0;
413   int break_by_word = 0;
414   char *filter = NULL;
415   int i;
416   int paper_width, paper_height;
417   int page_index;
418   gdImagePtr image;
419   int white;
420
421   MFrame *frame;
422   MText *mt;
423   MDrawControl control;
424   MDrawMetric rect;
425   char *filename = "output";
426   int len, from;
427
428   /* Parse the command line arguments.  */
429   for (i = 1; i < argc; i++)
430     {
431       if (! strcmp (argv[i], "--help")
432                || ! strcmp (argv[i], "-h")
433                || ! strcmp (argv[i], "-?"))
434         help_exit (argv[0], 0);
435       else if (! strcmp (argv[i], "--version"))
436         {
437           printf ("mdump (m17n library) %s\n", VERSION);
438           printf ("Copyright (C) 2003, 2004 AIST, JAPAN\n");
439           exit (0);
440         }
441       else if (! strcmp (argv[i], "-s") && i + 1< argc)
442         {
443           fontsize = atoi (argv[++i]);
444           if (! fontsize)
445             FATAL_ERROR ("Invalid font size: %s\n", argv[i]);
446         }
447       else if (! strcmp (argv[i], "-p") && i + 1< argc)
448         {
449           int w, h;
450
451           i++;
452           if (! strcmp (argv[i], "a4"))
453             paper = PAPER_A4;
454           else if (! strcmp (argv[i], "a4r"))
455             paper = PAPER_A4R;
456           else if (! strcmp (argv[i], "a5"))
457             paper = PAPER_A5;
458           else if (! strcmp (argv[i], "a5r"))
459             paper = PAPER_A5R;
460           else if (! strcmp (argv[i], "b5"))
461             paper = PAPER_B5;
462           else if (! strcmp (argv[i], "b5r"))
463             paper = PAPER_B5R;
464           else if (! strcmp (argv[i], "letter"))
465             paper = PAPER_LETTER;
466           else if (sscanf (argv[i], "%dx%d", &w, &h) == 2
467                    && w > 0 && h > 0)
468             {
469               paper = PAPER_USER;
470               paper_size[paper].width = w;
471               paper_size[paper].height = h;
472             }
473           else
474             FATAL_ERROR ("Invalid paper type: %s\n", argv[i]);
475         }
476       else if (! strcmp (argv[i], "-d") && i + 1< argc)
477         {
478           dpi = atoi (argv[++i]);
479           if (! dpi)
480             FATAL_ERROR ("Invalid resolution: %s\n", argv[i]);
481         }
482       else if (! strcmp (argv[i], "-m") && i + 1< argc)
483         {
484           margin = atoi (argv[++i]);
485           if (margin < 0)
486             FATAL_ERROR ("Invalid margin: %s\n", argv[i]);
487         }
488       else if (! strcmp (argv[i], "-c") && i + 1< argc)
489         {
490           cursor_pos = atoi (argv[++i]);
491           if (cursor_pos < 0)
492             FATAL_ERROR ("Invalid cursor position: %s\n", argv[i]);
493         }
494       else if (! strcmp (argv[i], "-f") && i + 1< argc)
495         {
496           filter = argv[++i];
497         }
498       else if (! strcmp (argv[i], "-x"))
499         {
500           xml = 1;
501         }
502       else if (! strcmp (argv[i], "-w"))
503         {
504           break_by_word = 1;
505         }
506       else if (! strcmp (argv[i], "-q"))
507         {
508           quiet_mode = 1;
509         }
510       else if (argv[i][0] != '-')
511         {
512           fp = fopen (argv[i], "r");
513           if (! fp)
514             FATAL_ERROR ("Fail to open the file %s!\n", argv[i]);
515           filename = basename (argv[i]);
516         }
517       else
518         {
519           fprintf (stderr, "Unknown or invalid option: %s\n", argv[i]);
520           help_exit (argv[0], 1);
521         }
522     }
523
524   /* Initialize the m17n library.  */
525   M17N_INIT ();
526   if (merror_code != MERROR_NONE)
527     FATAL_ERROR ("%s\n", "Fail to initialize the m17n library.");
528
529   mt = mconv_decode_stream (Mcoding_utf_8, fp);
530   fclose (fp);
531   if (xml)
532     mt = mtext_deserialize (mt);
533   if (! mt)
534     FATAL_ERROR ("%s\n", "Fail to decode the input file or stream!");
535
536   len = mtext_len (mt);
537
538   if (paper == PAPER_NOLIMIT)
539     paper_width = paper_height = margin = 0;
540   else
541     {
542       paper_width = paper_size[paper].width * dpi / 25.4;
543       paper_height = paper_size[paper].height * dpi / 25.4;
544       margin = margin * dpi / 25.4;
545     }
546
547   {
548     MPlist *plist = mplist (), *p;
549     MFontset *fontset = mfontset ("truetype");
550     MFace *face = mface ();
551
552     mface_put_prop (face, Mfontset, fontset);
553     mface_put_prop (face, Msize, (void *) (fontsize * dpi / 100));
554     p = mplist_add (plist, Mdevice, msymbol ("gd"));
555     p = mplist_add (p, Mface, face);
556     m17n_object_unref (face);
557     frame = mframe (plist);
558     m17n_object_unref (plist);
559     if (! frame)
560       FATAL_ERROR ("%s\n", "Can't open a frame (perhaps no font avairable)!");
561   }
562
563   memset (&control, 0, sizeof control);
564   control.as_image = 1;
565   control.two_dimensional = 1;
566   control.enable_bidi = 1;
567   control.anti_alias = 1;
568   if (cursor_pos >= 0)
569     {
570       control.with_cursor = 1;
571       if (cursor_pos > len)
572         cursor_pos = len;
573       control.cursor_pos = cursor_pos;
574       control.cursor_width = -1;
575     }
576   else
577     control.ignore_formatting_char = 1;
578   if (break_by_word)
579     control.line_break = line_break;
580
581   if (paper == PAPER_NOLIMIT)
582     {
583       control.max_line_width = 0;
584       mdraw_text_extents (frame, mt, 0, len, &control, NULL, NULL, &rect);
585       paper_width = rect.width;
586       paper_height = rect.height;
587     }
588   else
589     control.max_line_width = paper_width - margin * 2;
590
591   image = gdImageCreate (paper_width, paper_height);
592   from = 0;
593   page_index = 1;
594   white = gdImageColorAllocate (image, 255, 255, 255);
595   while (from < len)
596     {
597       int to;
598
599       if (paper == PAPER_NOLIMIT)
600         to = len;
601       else
602         to = find_page_end (frame, paper_height - margin * 2, mt, from,
603                             &control, &rect);
604
605       gdImageFilledRectangle (image, 0, 0, paper_width - 1, paper_height - 1,
606                               white);
607       mdraw_text_with_control (frame, image,
608                                margin, margin - rect.y, mt, from, to,
609                                &control);
610       dump_image (image, filename, filter,
611                   ((from > 0 || to < len) ? page_index : 0),
612                   quiet_mode);
613
614       from = to;
615       page_index++;
616     }
617
618   m17n_object_unref (frame);
619   m17n_object_unref (mt);
620   M17N_FINI ();
621   gdImageDestroy (image);
622   exit (0);
623 }
624
625 #else  /* not HAVE_FREETYPE nor HAVE_GD */
626
627 int
628 main (int argc, char **argv)
629 {
630   fprintf (stderr, "Can't run without Freetype and GD library!\n");
631   exit (1);
632 }
633
634 #endif  /* not HAVE_FREETYPE nor HAVE_GD */
635 #endif /* not FOR_DOXYGEN */