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