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