Adjusted for the member name change
[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 <ctype.h>
217 #include <libgen.h>
218
219 #include "config.h"
220
221 #if defined (HAVE_FREETYPE) && defined (HAVE_GD)
222 #include <gd.h>
223
224 #include <m17n-gui.h>
225 #include <m17n-misc.h>
226
227 #define PROGRAM_VERSION "1.1"
228
229 /* Enumuration of the supported paper types.  */
230 enum paper_type
231   {
232     PAPER_A4,
233     PAPER_A4R,
234     PAPER_A5,
235     PAPER_A5R,
236     PAPER_B5,
237     PAPER_B5R,
238     PAPER_LETTER,
239     PAPER_USER,
240     PAPER_NOLIMIT
241   };
242
243 /* Array of paper sizes for the supported paper types.  */
244 struct
245 {
246   int width, height;            /* in millimeter */
247 } paper_size[PAPER_NOLIMIT] = {
248   { 210, 297 },                 /* a4 */
249   { 297, 210 },                 /* a4r */
250   { 148, 210 },                 /* a5 */
251   { 210, 148 },                 /* a5r */
252   { 250, 176 },                 /* b5 */
253   { 176, 250 },                 /* b5r */
254   { 216, 279 },                 /* letter */
255 };
256
257
258 /* Print the usage of this program (the name is PROG), and exit with
259    EXIT_CODE.  */
260
261 void
262 help_exit (char *prog, int exit_code)
263 {
264   char *p = prog;
265
266   while (*p)
267     if (*p++ == '/')
268       prog = p;
269
270   printf ("Usage: %s [ OPTION ...] [ FILE ]\n", prog);
271   printf ("Dump a text as a PNG image into a file.\n");
272   printf ("  The PNG file is created in the current directory\n");
273   printf ("    with the name \"BASE.png\" where BASE is the basename of FILE.\n");
274   printf ("  If FILE is omitted, text is read from standard input, and\n");
275   printf ("    dumped into the file \"output.png\".\n");
276   printf ("The following OPTIONs are available.\n");
277   printf ("  %-13s %s", "-s SIZE",
278           "Font size in 1/10 point (default 120).\n");
279   printf ("  %-13s %s", "-d DPI",
280           "Resolution in dots per inch (defualt 300).\n");
281   printf ("  %-13s %s", "-p PAPER",
282           "Paper size; a4, a4r, a5, a5r, b5, b5r, letter, W, or WxH.\n");
283   printf ("  %-13s %s", "-m MARGIN",
284           "Marginal space in millimeter (default 20).\n");
285   printf ("  %-13s %s", "-c POS",
286           "Character position of cursor to draw (default no cursor)\n");
287   printf ("  %-13s %s", "-x",
288           "FILE is assumed to be an XML file.\n");
289   printf ("  %-13s %s", "-f FILTER",
290           "String containing a shell command line to be used as a filter.\n");
291   printf ("  %-13s %s", "-w", "Each line is broken at word boundary.\n");
292   printf ("  %-13s %s", "-a", "Enable anti-alias drawing.\n");
293   printf ("  %-13s %s", "--family FAMILY", 
294           "Prefer a font whose family is FAMILY.\n");
295   printf ("  %-13s %s", "--language LANG", 
296           "Prefer a font specified for the langauge LANG.\n");
297   printf ("  %-13s %s", "-q", "Quiet mode.  Don't print any messages.\n");
298   printf ("  %-13s %s", "--version", "Print the version number.\n");
299   printf ("  %-13s %s", "-h, --help", "Print this message.\n");
300   exit (exit_code);
301 }
302
303
304 /* Format MSG by FMT and print the result to the stderr, and exit.  */
305
306 #define FATAL_ERROR(fmt, arg)   \
307   do {                          \
308     fprintf (stderr, fmt, arg); \
309     exit (1);                   \
310   } while (0)
311
312
313 /* Move POS to the next line head in M-text MT whose length is LEN.
314    If POS is already on the last line, set POS to LEN.  */
315
316 #define NEXTLINE(pos, len)                      \
317   do {                                          \
318     pos = mtext_character (mt, pos, len, '\n'); \
319     if (pos < 0)                                \
320       pos = len;                                \
321     else                                        \
322       pos++;                                    \
323   } while (0)
324
325
326 /* Find the range of M-text MT that fits in one page of height HEIGHT
327    when drawn from the character position POS.  Set RECT->y to the
328    Y-offset of the first baseline.  */
329
330 int
331 find_page_end (MFrame *frame, int height, MText *mt, int pos,
332                MDrawControl *control, MDrawMetric *rect)
333 {
334   int len = mtext_len (mt);
335   int to = pos;
336   int y = 0, yoff;
337
338   while (to < len)
339     {
340       int next = to;
341
342       NEXTLINE (next, len);
343       mdraw_text_extents (frame, mt, to, next, control, NULL, NULL, rect);
344       if (to == pos)
345         yoff = rect->y;
346       if (y + rect->height > height)
347         {
348           MDrawGlyphInfo info;
349
350           while (to < next)
351             {
352               mdraw_glyph_info (frame, mt, to, to, control, &info);
353               if (y + info.metrics.height > height)
354                 break;
355               y += info.metrics.height;
356               to = info.line_to;
357             }
358           break;
359         }
360       y += rect->height;
361       to = next;
362     }
363
364   rect->y = yoff;
365   return to;
366 }
367
368
369 /* Table to convert a byte of LSBFirst to MSBFirst. */
370 char reverse_bit_order[256];
371
372 /* Initialize the above table.  */
373
374 void
375 init_reverse_bit_order ()
376 {
377   int i;
378
379   for (i = 0; i < 256; i++)
380     reverse_bit_order[i]
381       = (((i & 1) << 7) | ((i & 2) << 5) | ((i & 4) << 3) | ((i & 8) << 1)
382          | ((i & 16) >> 1) | ((i & 32) >> 3)
383          | ((i & 64) >> 5) | ((i & 128) >> 7));
384 }
385
386
387 /* Dump the image in IMAGE into a file whose name is generated from
388    FILENAME and PAGE_INDEX (if it is not zero).  */
389
390 void
391 dump_image (gdImagePtr image, char *filename, char *filter,
392             int page_index, int quiet_mode)
393 {
394   FILE *fp;
395
396   if (page_index)
397     {
398       char *name = alloca (strlen (filename) + 8);
399
400       sprintf (name, "%s.%02d", filename, page_index);
401       filename = name;
402     }
403
404   if (filter)
405     {
406       char *command = alloca (strlen (filename) + strlen (filter) + 1);
407
408       sprintf (command, filter, filename);
409       fp = popen (command, "w");
410       if (! fp)
411         FATAL_ERROR ("Can't run the command \"%s\"\n", command);
412       if (! quiet_mode)
413         printf ("Running \"%s\" ... ", command);
414     }
415   else
416     {
417       char *fullname = alloca (strlen (filename) + 5);
418
419       sprintf (fullname, "%s.png", filename);
420       fp = fopen (fullname, "w");
421       if (! fp)
422         FATAL_ERROR ("Can't write to \"%s\"\n", fullname);
423       if (! quiet_mode)
424         printf ("Writing %s ... ", fullname);
425     }
426
427   /* Generate PNG.  */
428   gdImagePng (image, fp);
429   fclose (fp);
430   if (! quiet_mode)
431     printf (" done (%dx%d)\n", image->sx, image->sy);
432 }
433
434 extern int line_break (MText *mt, int pos, int from, int to, int line, int y);
435
436 int
437 main (int argc, char **argv)
438 {
439   int fontsize = 120;
440   int paper = PAPER_NOLIMIT;
441   int dpi = 300;
442   int margin = 20;
443   int xml = 0;
444   FILE *fp = stdin;
445   int cursor_pos = -1;
446   int quiet_mode = 0;
447   int break_by_word = 0;
448   char *filter = NULL;
449   int paper_width, paper_height;
450   int anti_alias = 0;
451   char *family_name = NULL;
452   char *lang_name = NULL;
453   int i;
454   int page_index;
455   gdImagePtr image;
456   int white;
457
458   MFrame *frame;
459   MText *mt;
460   MDrawControl control;
461   MDrawMetric rect;
462   char *filename = "output";
463   int len, from;
464
465   /* Parse the command line arguments.  */
466   for (i = 1; i < argc; i++)
467     {
468       if (! strcmp (argv[i], "--help")
469                || ! strcmp (argv[i], "-h")
470                || ! strcmp (argv[i], "-?"))
471         help_exit (argv[0], 0);
472       else if (! strcmp (argv[i], "--version"))
473         {
474           printf ("mdump (m17n library) %s\n", PROGRAM_VERSION);
475           printf ("Copyright (C) 2003, 2004 AIST, JAPAN\n");
476           exit (0);
477         }
478       else if (! strcmp (argv[i], "-s") && i + 1< argc)
479         {
480           fontsize = atoi (argv[++i]);
481           if (! fontsize)
482             FATAL_ERROR ("Invalid font size: %s\n", argv[i]);
483         }
484       else if (! strcmp (argv[i], "-p") && i + 1< argc)
485         {
486           int w, h;
487
488           i++;
489           if (! strcmp (argv[i], "a4"))
490             paper = PAPER_A4;
491           else if (! strcmp (argv[i], "a4r"))
492             paper = PAPER_A4R;
493           else if (! strcmp (argv[i], "a5"))
494             paper = PAPER_A5;
495           else if (! strcmp (argv[i], "a5r"))
496             paper = PAPER_A5R;
497           else if (! strcmp (argv[i], "b5"))
498             paper = PAPER_B5;
499           else if (! strcmp (argv[i], "b5r"))
500             paper = PAPER_B5R;
501           else if (! strcmp (argv[i], "letter"))
502             paper = PAPER_LETTER;
503           else if (sscanf (argv[i], "%dx%d", &w, &h) == 2
504                    && w > 0 && h > 0)
505             {
506               paper = PAPER_USER;
507               paper_size[paper].width = w;
508               paper_size[paper].height = h;
509             }
510           else if (sscanf (argv[i], "%d", &w) == 1
511                    && w > 0)
512             {
513               paper = PAPER_USER;
514               paper_size[paper].width = w;
515               paper_size[paper].height = 0;
516             }
517           else
518             FATAL_ERROR ("Invalid paper type: %s\n", argv[i]);
519         }
520       else if (! strcmp (argv[i], "-d") && i + 1< argc)
521         {
522           dpi = atoi (argv[++i]);
523           if (! dpi)
524             FATAL_ERROR ("Invalid resolution: %s\n", argv[i]);
525         }
526       else if (! strcmp (argv[i], "-m") && i + 1< argc)
527         {
528           margin = atoi (argv[++i]);
529           if (margin < 0)
530             FATAL_ERROR ("Invalid margin: %s\n", argv[i]);
531         }
532       else if (! strcmp (argv[i], "-c") && i + 1< argc)
533         {
534           cursor_pos = atoi (argv[++i]);
535           if (cursor_pos < 0)
536             FATAL_ERROR ("Invalid cursor position: %s\n", argv[i]);
537         }
538       else if (! strcmp (argv[i], "-f") && i + 1< argc)
539         {
540           filter = argv[++i];
541         }
542       else if (! strcmp (argv[i], "-x"))
543         {
544           xml = 1;
545         }
546       else if (! strcmp (argv[i], "-w"))
547         {
548           break_by_word = 1;
549         }
550       else if (! strcmp (argv[i], "-q"))
551         {
552           quiet_mode = 1;
553         }
554       else if (! strcmp (argv[i], "-a"))
555         {
556           anti_alias = 1;
557         }
558       else if (! strcmp (argv[i], "--family"))
559         {
560           family_name = argv[++i];
561         }
562       else if (! strcmp (argv[i], "--language"))
563         {
564           lang_name = argv[++i];
565         }
566       else if (argv[i][0] != '-')
567         {
568           fp = fopen (argv[i], "r");
569           if (! fp)
570             FATAL_ERROR ("Fail to open the file %s!\n", argv[i]);
571           filename = basename (argv[i]);
572         }
573       else
574         {
575           fprintf (stderr, "Unknown or invalid option: %s\n", argv[i]);
576           help_exit (argv[0], 1);
577         }
578     }
579
580   /* Initialize the m17n library.  */
581   M17N_INIT ();
582   if (merror_code != MERROR_NONE)
583     FATAL_ERROR ("%s\n", "Fail to initialize the m17n library.");
584
585   mt = mconv_decode_stream (Mcoding_utf_8, fp);
586   fclose (fp);
587   if (xml)
588     mt = mtext_deserialize (mt);
589   if (! mt)
590     FATAL_ERROR ("%s\n", "Fail to decode the input file or stream!");
591
592   len = mtext_len (mt);
593   if (lang_name)
594     mtext_put_prop (mt, 0, len, Mlanguage, msymbol (lang_name));
595
596   if (paper == PAPER_NOLIMIT)
597     paper_width = paper_height = margin = 0;
598   else
599     {
600       paper_width = paper_size[paper].width * dpi / 25.4;
601       paper_height = paper_size[paper].height * dpi / 25.4;
602       margin = margin * dpi / 25.4;
603     }
604
605   {
606     MPlist *plist = mplist (), *p;
607     MFontset *fontset = mfontset ("truetype");
608     MFace *face = mface ();
609
610     mface_put_prop (face, Mfontset, fontset);
611     mface_put_prop (face, Msize, (void *) (fontsize * dpi / 100));
612     if (family_name)
613       {
614         char *p;
615
616         for (p = family_name; *p; p++)
617           if (isupper (*p)) *p = tolower (*p);
618         mface_put_prop (face, Mfamily, msymbol (family_name));
619       }
620
621     p = mplist_add (plist, Mdevice, msymbol ("gd"));
622     p = mplist_add (p, Mface, face);
623     m17n_object_unref (face);
624     frame = mframe (plist);
625     m17n_object_unref (plist);
626     if (! frame)
627       FATAL_ERROR ("%s\n", "Can't open a frame (perhaps no font available)!");
628   }
629
630   memset (&control, 0, sizeof control);
631   control.two_dimensional = 1;
632   control.enable_bidi = 1;
633   control.anti_alias = anti_alias;
634   if (cursor_pos >= 0)
635     {
636       control.with_cursor = 1;
637       if (cursor_pos > len)
638         cursor_pos = len;
639       control.cursor_pos = cursor_pos;
640       control.cursor_width = -1;
641     }
642   else
643     control.ignore_formatting_char = 1;
644   if (break_by_word)
645     control.line_break = line_break;
646
647   if (paper == PAPER_NOLIMIT)
648     {
649       control.max_line_width = 0;
650       mdraw_text_extents (frame, mt, 0, len, &control, NULL, NULL, &rect);
651       paper_width = rect.width;
652       paper_height = rect.height;
653     }
654   else
655     {
656       control.max_line_width = paper_width - margin * 2;
657       if (paper_height == 0)
658         {
659           mdraw_text_extents (frame, mt, 0, len, &control, NULL, NULL, &rect);
660           paper_height = rect.height + margin * 2;
661         }
662     }
663
664   image = gdImageCreate (paper_width, paper_height);
665   from = 0;
666   page_index = 1;
667   white = gdImageColorAllocate (image, 255, 255, 255);
668   while (from < len)
669     {
670       int to;
671
672       if (paper == PAPER_NOLIMIT || paper_size[paper].height == 0)
673         to = len;
674       else
675         to = find_page_end (frame, paper_height - margin * 2, mt, from,
676                             &control, &rect);
677
678       gdImageFilledRectangle (image, 0, 0, paper_width - 1, paper_height - 1,
679                               white);
680       mdraw_text_with_control (frame, image,
681                                margin, margin - rect.y, mt, from, to,
682                                &control);
683       dump_image (image, filename, filter,
684                   ((from > 0 || to < len) ? page_index : 0),
685                   quiet_mode);
686
687       from = to;
688       page_index++;
689     }
690
691   m17n_object_unref (frame);
692   m17n_object_unref (mt);
693   M17N_FINI ();
694   gdImageDestroy (image);
695   exit (0);
696 }
697
698 #else  /* not HAVE_FREETYPE nor HAVE_GD */
699
700 int
701 main (int argc, char **argv)
702 {
703   fprintf (stderr, "Can't run without Freetype and GD library!\n");
704   exit (1);
705 }
706
707 #endif  /* not HAVE_FREETYPE nor HAVE_GD */
708 #endif /* not FOR_DOXYGEN */