1 /* mdump.c -- Dump text image
2 Copyright (C) 2003, 2004
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H15PRO112
6 This file is part of the m17n library.
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.
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.
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
24 @page mdump dump text image
26 @section mdump-synopsis SYNOPSIS
28 mdump [ OPTION ... ] [ FILE ]
30 @section mdump-description DESCRIPTION
32 Dump a text as a Netpbm image.
34 The Netpbm image is written to a file created in the current
35 directory with the name "BASE.pbm" where BASE is the basename of
36 FILE. If FILE is omitted, text is read from standard input, and
37 the image is dumped into the file "output.pbm".
39 The following OPTIONs are available.
45 SIZE is the font size in point. The default font size is 12 point.
49 DPI is the resolution in dots per inch. The default resolution is
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.pbm", "BASE.02.pbm", etc. are created.
62 MARGIN is the horizontal and vertical margin in millimeter. The
63 default margin is 20 mm. It is ignored when PAPER is not
68 POS is the character position of cursor to draw. By default,
73 FILE is assumed to be an XML file generated by the serialize
74 facility of the m17n library, and FILE is deserialized before the
79 Each line is broken at word boundary.
83 FILTER is a string containing a shell command line. If this
84 option is specified, the Netpbm 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 >
92 Quiet mode. Don't print any messages.
96 Print the version number.
112 #include <X11/Xlib.h>
114 #include <m17n-gui.h>
115 #include <m17n-misc.h>
117 #define VERSION "1.0"
119 /* Enumuration of the supported paper types. */
133 /* Array of paper sizes for the supported paper types. */
136 int width, height; /* in millimeter */
137 } paper_size[PAPER_NOLIMIT] = {
138 { 210, 297 }, /* a4 */
139 { 297, 210 }, /* a4r */
140 { 148, 210 }, /* a5 */
141 { 210, 148 }, /* a5r */
142 { 250, 176 }, /* b5 */
143 { 176, 250 }, /* b5r */
144 { 216, 279 }, /* letter */
148 /* Print the usage of this program (the name is PROG), and exit with
152 help_exit (char *prog, int exit_code)
160 printf ("Usage: %s [ OPTION ...] [ FILE ]\n", prog);
161 printf ("Dump a text as a Netpbm image into a PBM file.\n");
162 printf (" The PBM file is created in the current directory\n");
163 printf (" with the name \"BASE.pbm\" where BASE is the basename of FILE.\n");
164 printf (" If FILE is omitted, text is read from standard input, and\n");
165 printf (" dumped into the file \"output.pbm\".\n");
166 printf ("The following OPTIONs are available.\n");
167 printf (" %-13s %s", "-s SIZE",
168 "Font size in point (default 12).\n");
169 printf (" %-13s %s", "-d DPI",
170 "Resolution in dots per inch (defualt 300).\n");
171 printf (" %-13s %s", "-p PAPER",
172 "Paper size; a4, a4r, a5, a5r, b5, b5r, letter, or WxH.\n");
173 printf (" %-13s %s", "-m MARGIN",
174 "Marginal space in millimeter (default 20).\n");
175 printf (" %-13s %s", "-c POS",
176 "Character position of cursor to draw (default no cursor)\n");
177 printf (" %-13s %s", "-x",
178 "FILE is assumed to be an XML file.\n");
179 printf (" %-13s %s", "-f FILTER",
180 "String containing a shell command line to be used as a filter.\n");
181 printf (" %-13s %s", "-w", "Each line is broken at word boundary.\n");
182 printf (" %-13s %s", "-q", "Quiet mode. Don't print any messages.\n");
183 printf (" %-13s %s", "--version", "Print the version number.\n");
184 printf (" %-13s %s", "-h, --help", "Print this message.\n");
189 /* Format MSG by FMT and print the result to the stderr, and exit. */
191 #define FATAL_ERROR(fmt, arg) \
193 fprintf (stderr, fmt, arg); \
198 /* Move POS to the next line head in M-text MT whose length is LEN.
199 If POS is already on the last line, set POS to LEN. */
201 #define NEXTLINE(pos, len) \
203 pos = mtext_character (mt, pos, len, '\n'); \
211 /* Find the range of M-text MT that fits in one page of height HEIGHT
212 when drawn from the character position POS. Set RECT->y to the
213 Y-offset of the first baseline. */
216 find_page_end (MFrame *frame, int height, MText *mt, int pos,
217 MDrawControl *control, MDrawMetric *rect)
219 int len = mtext_len (mt);
227 NEXTLINE (next, len);
228 mdraw_text_extents (frame, mt, to, next, control, NULL, NULL, rect);
231 if (y + rect->height > height)
237 mdraw_glyph_info (frame, mt, to, to, control, &info);
238 if (y + info.this.height > height)
240 y += info.this.height;
254 /* Table to convert a byte of LSBFirst to MSBFirst. */
255 char reverse_bit_order[256];
257 /* Initialize the above table. */
260 init_reverse_bit_order ()
264 for (i = 0; i < 256; i++)
266 = (((i & 1) << 7) | ((i & 2) << 5) | ((i & 4) << 3) | ((i & 8) << 1)
267 | ((i & 16) >> 1) | ((i & 32) >> 3)
268 | ((i & 64) >> 5) | ((i & 128) >> 7));
272 /* Dump the image in IMAGE into a file whose name is generated from
273 FILENAME and PAGE_INDEX (if it is not zero). */
276 dump_image (XImage *image, char *filename, char *filter,
277 int white_is_zero, int page_index, int quiet_mode)
280 int pbm_bytes_per_line;
281 char *data = image->data;
286 char *name = alloca (strlen (filename) + 8);
288 sprintf (name, "%s.%02d", filename, page_index);
294 char *command = alloca (strlen (filename) + strlen (filter) + 1);
296 sprintf (command, filter, filename);
297 fp = popen (command, "w");
299 FATAL_ERROR ("Can't run the command \"%s\"\n", command);
301 printf ("Running \"%s\" ... ", command);
305 char *fullname = alloca (strlen (filename) + 5);
307 sprintf (fullname, "%s.pbm", filename);
308 fp = fopen (fullname, "w");
310 FATAL_ERROR ("Can't write to \"%s\"\n", fullname);
312 printf ("Writing %s ... ", fullname);
315 if (image->bitmap_bit_order != MSBFirst
316 || (image->byte_order != MSBFirst
317 && image->bitmap_unit != 8))
319 /* We must adjust image->data for PBM. */
320 int bytes_per_unit = image->bitmap_unit / 8;
322 for (y = 0; y < image->height; y++, data += image->bytes_per_line)
326 if (image->byte_order != MSBFirst)
328 if (reverse_bit_order[0] == 0)
329 init_reverse_bit_order ();
330 if (bytes_per_unit == 2)
331 for (x = 0; x < image->bytes_per_line; x += 2)
332 b = data[x], data[x] = data[x + 1], data[x + 1] = b;
333 else if (bytes_per_unit == 6)
334 for (x = 0; x < image->bytes_per_line; x += 3)
336 b = data[x], data[x] = data[x + 3], data[x + 3] = b;
338 b = data[x], data[x] = data[x + 1], data[x + 1] = b;
342 if (image->bitmap_bit_order != MSBFirst)
343 for (x = 0; x < image->bytes_per_line; x++)
344 data[x] = reverse_bit_order[(unsigned char) data[x]];
346 for (x = 0; x < image->bytes_per_line; x++)
353 /* Generate PBM (Portable Bitmap File Format) of P4 format. */
354 fprintf (fp, "P4\n%d %d\n", image->width, image->height);
355 pbm_bytes_per_line = (image->width + 7) / 8;
356 for (y = 0; y < image->height; y++, data += image->bytes_per_line)
357 fwrite (data, 1, pbm_bytes_per_line, fp);
361 printf (" done (%dx%d)\n", image->width, image->height);
364 extern int line_break (MText *mt, int pos, int from, int to, int line, int y);
367 main (int argc, char **argv)
375 int paper = PAPER_NOLIMIT;
382 int break_by_word = 0;
385 int paper_width, paper_height;
390 MDrawControl control;
392 char *filename = "output";
395 /* Parse the command line arguments. */
396 for (i = 1; i < argc; i++)
398 if (! strcmp (argv[i], "--help")
399 || ! strcmp (argv[i], "-h")
400 || ! strcmp (argv[i], "-?"))
401 help_exit (argv[0], 0);
402 else if (! strcmp (argv[i], "--version"))
404 printf ("mdump (m17n library) %s\n", VERSION);
405 printf ("Copyright (C) 2003, 2004 AIST, JAPAN\n");
408 else if (! strcmp (argv[i], "-s") && i + 1< argc)
410 fontsize = atoi (argv[++i]);
412 FATAL_ERROR ("Invalid font size: %s\n", argv[i]);
414 else if (! strcmp (argv[i], "-p") && i + 1< argc)
419 if (! strcmp (argv[i], "a4"))
421 else if (! strcmp (argv[i], "a4r"))
423 else if (! strcmp (argv[i], "a5"))
425 else if (! strcmp (argv[i], "a5r"))
427 else if (! strcmp (argv[i], "b5"))
429 else if (! strcmp (argv[i], "b5r"))
431 else if (! strcmp (argv[i], "letter"))
432 paper = PAPER_LETTER;
433 else if (sscanf (argv[i], "%dx%d", &w, &h) == 2
437 paper_size[paper].width = w;
438 paper_size[paper].height = h;
441 FATAL_ERROR ("Invalid paper type: %s\n", argv[i]);
443 else if (! strcmp (argv[i], "-d") && i + 1< argc)
445 dpi = atoi (argv[++i]);
447 FATAL_ERROR ("Invalid resolution: %s\n", argv[i]);
449 else if (! strcmp (argv[i], "-m") && i + 1< argc)
451 margin = atoi (argv[++i]);
453 FATAL_ERROR ("Invalid margin: %s\n", argv[i]);
455 else if (! strcmp (argv[i], "-c") && i + 1< argc)
457 cursor_pos = atoi (argv[++i]);
459 FATAL_ERROR ("Invalid cursor position: %s\n", argv[i]);
461 else if (! strcmp (argv[i], "-f") && i + 1< argc)
465 else if (! strcmp (argv[i], "-x"))
469 else if (! strcmp (argv[i], "-w"))
473 else if (! strcmp (argv[i], "-q"))
477 else if (argv[i][0] != '-')
479 fp = fopen (argv[i], "r");
481 FATAL_ERROR ("Fail to open the file %s!\n", argv[i]);
482 filename = basename (argv[i]);
486 fprintf (stderr, "Unknown or invalid option: %s\n", argv[i]);
487 help_exit (argv[0], 1);
491 /* Initialize the m17n library. */
493 if (merror_code != MERROR_NONE)
494 FATAL_ERROR ("%s\n", "Fail to initialize the m17n library.");
496 mt = mconv_decode_stream (Mcoding_utf_8, fp);
499 mt = mtext_deserialize (mt);
501 FATAL_ERROR ("%s\n", "Fail to decode the input file or stream!");
503 len = mtext_len (mt);
505 if (paper == PAPER_NOLIMIT)
506 paper_width = paper_height = margin = 0;
509 paper_width = paper_size[paper].width * dpi / 25.4;
510 paper_height = paper_size[paper].height * dpi / 25.4;
511 margin = margin * dpi / 25.4;
514 display = XOpenDisplay (NULL);
515 screen = DefaultScreen (display);
518 MPlist *plist = mplist (), *p;
519 MFontset *fontset = mfontset ("truetype");
520 MFace *face = mface ();
522 mface_put_prop (face, Mfontset, fontset);
523 mface_put_prop (face, Msize, (void *) (fontsize * dpi / 100));
524 p = mplist_add (plist, msymbol ("display"), display);
525 p = mplist_add (p, msymbol ("depth"), (void *) 1);
526 p = mplist_add (p, Mface, face);
527 m17n_object_unref (face);
528 frame = mframe (plist);
529 m17n_object_unref (plist);
531 FATAL_ERROR ("%s\n", "Can't open a frame (perhaps no font avairable)!");
534 memset (&control, 0, sizeof control);
535 control.as_image = 1;
536 control.two_dimensional = 1;
537 control.enable_bidi = 1;
540 control.with_cursor = 1;
541 if (cursor_pos > len)
543 control.cursor_pos = cursor_pos;
544 control.cursor_width = -1;
547 control.ignore_formatting_char = 1;
549 control.line_break = line_break;
551 if (paper == PAPER_NOLIMIT)
553 control.max_line_width = 0;
554 mdraw_text_extents (frame, mt, 0, len, &control, NULL, NULL, &rect);
555 paper_width = rect.width;
556 paper_height = rect.height;
559 control.max_line_width = paper_width - margin * 2;
561 pixmap = XCreatePixmap (display, RootWindow (display, screen),
562 paper_width, paper_height, 1);
563 gc = XCreateGC (display, pixmap, 0L, NULL);
571 if (paper == PAPER_NOLIMIT)
574 to = find_page_end (frame, paper_height - margin * 2, mt, from,
577 XSetForeground (display, gc, WhitePixel (display, screen));
578 XFillRectangle (display, pixmap, gc, 0, 0, paper_width, paper_height);
579 mdraw_text_with_control (frame, (MDrawWindow) pixmap,
580 margin, margin - rect.y, mt, from, to,
582 XSetForeground (display, gc, BlackPixel (display, screen));
584 XDrawRectangle (display, pixmap, gc, margin, margin,
585 paper_width - margin * 2 - 1,
586 paper_height - margin * 2 - 1);
588 image = XGetImage (display, pixmap, 0, 0, paper_width, paper_height,
589 AllPlanes, XYPixmap);
591 dump_image (image, filename, filter, !WhitePixel (display, screen),
592 ((from > 0 || to < len) ? page_index : 0),
599 m17n_object_unref (frame);
600 m17n_object_unref (mt);
602 XCloseDisplay (display);
605 #endif /* not FOR_DOXYGEN */