tumble.c

Thu, 20 Mar 2003 15:26:16 +0000

author
eric
date
Thu, 20 Mar 2003 15:26:16 +0000
changeset 153
4a4a5b5fd6e5
parent 151
83a99cc69861
child 154
5cfcac03d43f
permissions
-rw-r--r--

*** empty log message ***

     1 /*
     2  * tumble: build a PDF file from image files
     3  *
     4  * Main program
     5  * $Id: tumble.c,v 1.40 2003/03/20 06:55:27 eric Exp $
     6  * Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License version 2 as
    10  * published by the Free Software Foundation.  Note that permission is
    11  * not granted to redistribute this program under the terms of any
    12  * other version of the General Public License.
    13  *
    14  * This program is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17  * GNU General Public License for more details.
    18  *
    19  * You should have received a copy of the GNU General Public License
    20  * along with this program; if not, write to the Free Software
    21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
    22  */
    25 #include <stdarg.h>
    26 #include <stdbool.h>
    27 #include <stdint.h>
    28 #include <stdio.h>
    29 #include <stdlib.h>
    30 #include <string.h>
    31 #include <unistd.h>
    34 #include "semantics.h"
    35 #include "parser.tab.h"
    36 #include "tumble.h"
    37 #include "bitblt.h"
    38 #include "pdf.h"
    39 #include "tumble_input.h"
    42 #define MAX_INPUT_FILES 5000
    44 typedef struct output_file_t
    45 {
    46   struct output_file_t *next;
    47   char *name;
    48   pdf_file_handle pdf;
    49 } output_file_t;
    52 int verbose;
    55 output_file_t *output_files;
    56 output_file_t *out;
    59 char *progname;
    62 bool close_pdf_output_files (void);
    65 void usage (void)
    66 {
    67   fprintf (stderr, "\n");
    68   fprintf (stderr, "tumble - Copyright 2001-2003 Eric Smith <eric@brouhaha.com>\n");
    69   fprintf (stderr, "http://tumble.brouhaha.com/\n");
    70   fprintf (stderr, "\n");
    71   fprintf (stderr, "usage:\n");
    72   fprintf (stderr, "    %s [options] -c <control.tum>\n", progname);
    73   fprintf (stderr, "    %s [options] <input.tif>... -o <output.pdf>\n", progname);
    74   fprintf (stderr, "options:\n");
    75   fprintf (stderr, "    -v        verbose\n");
    76   fprintf (stderr, "    -b <fmt>  create bookmarks\n");
    77   fprintf (stderr, "bookmark format:\n");
    78   fprintf (stderr, "    %%F  file name (sans suffix)\n");
    79   fprintf (stderr, "    %%p  page number\n");
    80 }
    83 /* generate fatal error message to stderr, doesn't return */
    84 void fatal (int ret, char *format, ...) __attribute__ ((noreturn));
    86 void fatal (int ret, char *format, ...)
    87 {
    88   va_list ap;
    90   fprintf (stderr, "fatal error");
    91   if (format)
    92     {
    93       fprintf (stderr, ": ");
    94       va_start (ap, format);
    95       vfprintf (stderr, format, ap);
    96       va_end (ap);
    97     }
    98   else
    99     fprintf (stderr, "\n");
   100   if (ret == 1)
   101     usage ();
   102   close_input_file ();
   103   close_pdf_output_files ();
   104   exit (ret);
   105 }
   108 bool close_pdf_output_files (void)
   109 {
   110   output_file_t *o, *n;
   112   for (o = output_files; o; o = n)
   113     {
   114       n = o->next;
   115       pdf_close (o->pdf, PDF_PAGE_MODE_USE_OUTLINES);
   116       free (o->name);
   117       free (o);
   118     }
   119   out = NULL;
   120   output_files = NULL;
   121   return (1);
   122 }
   124 bool open_pdf_output_file (char *name,
   125 			   pdf_file_attributes_t *attributes)
   126 {
   127   output_file_t *o;
   129   if (out && (strcmp (name, out->name) == 0))
   130     return (1);
   131   for (o = output_files; o; o = o->next)
   132     if (strcmp (name, o->name) == 0)
   133       {
   134 	out = o;
   135 	return (1);
   136       }
   137   o = calloc (1, sizeof (output_file_t));
   138   if (! o)
   139     {
   140       fprintf (stderr, "can't calloc output file struct for '%s'\n", name);
   141       return (0);
   142    }
   144   o->name = strdup (name);
   145   if (! o->name)
   146     {
   147       fprintf (stderr, "can't strdup output filename '%s'\n", name);
   148       free (o);
   149       return (0);
   150     }
   152   o->pdf = pdf_create (name);
   153   if (! o->pdf)
   154     {
   155       fprintf (stderr, "can't open output file '%s'\n", name);
   156       free (o->name);
   157       free (o);
   158       return (0);
   159     }
   161   if (attributes->author)
   162     pdf_set_author (o->pdf, attributes->author);
   163   if (attributes->creator)
   164     pdf_set_creator (o->pdf, attributes->creator);
   165   if (attributes->title)
   166     pdf_set_title (o->pdf, attributes->title);
   167   if (attributes->subject)
   168     pdf_set_subject (o->pdf, attributes->subject);
   169   if (attributes->keywords)
   170     pdf_set_keywords (o->pdf, attributes->keywords);
   172   /* prepend new output file onto list */
   173   o->next = output_files;
   174   output_files = o;
   176   out = o;
   177   return (1);
   178 }
   181 bool process_page (int image,  /* range 1 .. n */
   182 		   input_attributes_t input_attributes,
   183 		   bookmark_t *bookmarks,
   184 		   page_label_t *page_label)
   185 {
   186   pdf_page_handle page;
   187   image_info_t image_info;
   189   if (! get_image_info (image, input_attributes, & image_info))
   190     return (0);
   192   page = pdf_new_page (out->pdf,
   193 		       image_info.width_points,
   194 		       image_info.height_points);
   196   if (! process_image (image, input_attributes, & image_info, page))
   197     return (0);
   199   while (bookmarks)
   200     {
   201       /* $$$ need to handle level here */
   202       pdf_new_bookmark (NULL, bookmarks->name, 0, page);
   203       bookmarks = bookmarks->next;
   204     }
   206   if (page_label)
   207     pdf_new_page_label (out->pdf,
   208 			page_label->page_index,
   209 			page_label->base,
   210 			page_label->count,
   211 			page_label->style,
   212 			page_label->prefix);
   214   return (page != NULL);
   215 }
   218 #define MAX_BOOKMARK_NAME_LEN 500
   221 static int filename_length_without_suffix (char *in_fn)
   222 {
   223   char *p;
   224   int len = strlen (in_fn);
   226   p = strrchr (in_fn, '.');
   227   if (p && match_input_suffix (p))
   228     return (p - in_fn);
   229   return (len);
   230 }
   233 /* $$$ this function should ensure that it doesn't overflow the name string! */
   234 static void generate_bookmark_name (char *name,
   235 				    char *bookmark_fmt, 
   236 				    char *in_fn,
   237 				    int page)
   238 {
   239   bool meta = 0;
   240   int len;
   242   while (*bookmark_fmt)
   243     {
   244       if (meta)
   245 	{
   246 	  meta = 0;
   247 	  switch (*bookmark_fmt)
   248 	    {
   249 	    case '%':
   250 	      *(name++) = '%';
   251 	      break;
   252 	    case 'F':
   253 	      len = filename_length_without_suffix (in_fn);
   254 	      strncpy (name, in_fn, len);
   255 	      name += len;
   256 	      break;
   257 	    case 'p':
   258 	      sprintf (name, "%d", page);
   259 	      name += strlen (name);
   260 	      break;
   261 	    default:
   262 	      break;
   263 	    }
   264 	}
   265       else
   266 	switch (*bookmark_fmt)
   267 	  {
   268 	  case '%':
   269 	    meta = 1;
   270 	    break;
   271 	  default:
   272 	    *(name++) = *bookmark_fmt;
   273 	  }
   274       bookmark_fmt++;
   275     }
   276   *name = '\0';
   277 }
   280 void main_args (char *out_fn,
   281 		int inf_count,
   282 		char **in_fn,
   283 		char *bookmark_fmt)
   284 {
   285   int i, ip;
   286   input_attributes_t input_attributes;
   287   pdf_file_attributes_t output_attributes;
   288   bookmark_t bookmark;
   289   char bookmark_name [MAX_BOOKMARK_NAME_LEN];
   291   bookmark.next = NULL;
   292   bookmark.level = 1;
   293   bookmark.name = & bookmark_name [0];
   295   memset (& input_attributes, 0, sizeof (input_attributes));
   296   memset (& output_attributes, 0, sizeof (output_attributes));
   298   if (! open_pdf_output_file (out_fn, & output_attributes))
   299     fatal (3, "error opening output file \"%s\"\n", out_fn);
   300   for (i = 0; i < inf_count; i++)
   301     {
   302       if (! open_input_file (in_fn [i]))
   303 	fatal (3, "error opening input file \"%s\"\n", in_fn [i]);
   304       for (ip = 1;; ip++)
   305 	{
   306 	  fprintf (stderr, "processing page %d of file \"%s\"\r", ip, in_fn [i]);
   307 	  if (bookmark_fmt)
   308 	    generate_bookmark_name (& bookmark_name [0],
   309 				    bookmark_fmt, 
   310 				    in_fn [i],
   311 				    ip);
   312 	  if (! process_page (ip, input_attributes,
   313 			      bookmark_fmt ? & bookmark : NULL,
   314 			      NULL))
   315 	    fatal (3, "error processing page %d of input file \"%s\"\n", ip, in_fn [i]);
   316 	  if (last_input_page ())
   317 	    break;
   318 	}
   319       if (verbose)
   320 	fprintf (stderr, "processed %d pages of input file \"%s\"\n", ip, in_fn [i]);
   321       if (! close_input_file ())
   322 	fatal (3, "error closing input file \"%s\"\n", in_fn [i]);
   323     }
   324   if (! close_pdf_output_files ())
   325     fatal (3, "error closing output file \"%s\"\n", out_fn);
   326 }
   329 void main_control (char *control_fn)
   330 {
   331   if (! parse_control_file (control_fn))
   332     fatal (2, "error parsing control file\n");
   333   if (! process_controls ())
   334     fatal (3, "error processing control file\n");
   335 }
   338 int main (int argc, char *argv[])
   339 {
   340   char *control_fn = NULL;
   341   char *out_fn = NULL;
   342   char *bookmark_fmt = NULL;
   343   int inf_count = 0;
   344   char *in_fn [MAX_INPUT_FILES];
   346   progname = argv [0];
   348   pdf_init ();
   350   init_tiff_handler ();
   351   init_jpeg_handler ();
   353   while (--argc)
   354     {
   355       if (argv [1][0] == '-')
   356 	{
   357 	  if (strcmp (argv [1], "-v") == 0)
   358 	    verbose++;
   359 	  else if (strcmp (argv [1], "-o") == 0)
   360 	    {
   361 	      if (argc)
   362 		{
   363 		  argc--;
   364 		  argv++;
   365 		  out_fn = argv [1];
   366 		}
   367 	      else
   368 		fatal (1, "missing filename after \"-o\" option\n");
   369 	    }
   370 	  else if (strcmp (argv [1], "-c") == 0)
   371 	    {
   372 	      if (argc)
   373 		{
   374 		  argc--;
   375 		  argv++;
   376 		  control_fn = argv [1];
   377 		}
   378 	      else
   379 		fatal (1, "missing filename after \"-s\" option\n");
   380 	    }
   381 	  else if (strcmp (argv [1], "-b") == 0)
   382 	    {
   383 	      if (argc)
   384 		{
   385 		  argc--;
   386 		  argv++;
   387 		  bookmark_fmt = argv [1];
   388 		}
   389 	      else
   390 		fatal (1, "missing format string after \"-b\" option\n");
   391 	    }
   392 	  else
   393 	    fatal (1, "unrecognized option \"%s\"\n", argv [1]);
   394 	}
   395       else if (inf_count < MAX_INPUT_FILES)
   396 	in_fn [inf_count++] = argv [1];
   397       else
   398 	fatal (1, "exceeded maximum of %d input files\n", MAX_INPUT_FILES);
   399       argv++;
   400     }
   402   if (! ((! out_fn) ^ (! control_fn)))
   403     fatal (1, "either a control file or an output file (but not both) must be specified\n");
   405   if (out_fn && ! inf_count)
   406     fatal (1, "no input files specified\n");
   408   if (control_fn && inf_count)
   409     fatal (1, "if control file is provided, input files can't be specified as arguments\n");
   411   if (control_fn)
   412     main_control (control_fn);
   413   else
   414     main_args (out_fn, inf_count, in_fn, bookmark_fmt);
   416   close_input_file ();
   417   close_pdf_output_files ();
   418   exit (0);
   419 }