tumble.c

Thu, 20 Mar 2003 06:54:08 +0000

author
eric
date
Thu, 20 Mar 2003 06:54:08 +0000
changeset 141
752599b50ff3
parent 139
ec2a06d8a2a6
child 149
460c336ec8d7
permissions
-rw-r--r--

more JPEG support. added input file handler API.

     1 /*
     2  * tumble: build a PDF file from image files
     3  *
     4  * Main program
     5  * $Id: tumble.c,v 1.38 2003/03/19 22:54:07 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 && ((strcasecmp (p, ".tif") == 0) ||
   228 	    (strcasecmp (p, ".tiff") == 0)))
   229     return (p - in_fn);
   230   return (len);
   231 }
   234 /* $$$ this function should ensure that it doesn't overflow the name string! */
   235 static void generate_bookmark_name (char *name,
   236 				    char *bookmark_fmt, 
   237 				    char *in_fn,
   238 				    int page)
   239 {
   240   bool meta = 0;
   241   int len;
   243   while (*bookmark_fmt)
   244     {
   245       if (meta)
   246 	{
   247 	  meta = 0;
   248 	  switch (*bookmark_fmt)
   249 	    {
   250 	    case '%':
   251 	      *(name++) = '%';
   252 	      break;
   253 	    case 'F':
   254 	      len = filename_length_without_suffix (in_fn);
   255 	      strncpy (name, in_fn, len);
   256 	      name += len;
   257 	      break;
   258 	    case 'p':
   259 	      sprintf (name, "%d", page);
   260 	      name += strlen (name);
   261 	      break;
   262 	    default:
   263 	      break;
   264 	    }
   265 	}
   266       else
   267 	switch (*bookmark_fmt)
   268 	  {
   269 	  case '%':
   270 	    meta = 1;
   271 	    break;
   272 	  default:
   273 	    *(name++) = *bookmark_fmt;
   274 	  }
   275       bookmark_fmt++;
   276     }
   277   *name = '\0';
   278 }
   281 void main_args (char *out_fn,
   282 		int inf_count,
   283 		char **in_fn,
   284 		char *bookmark_fmt)
   285 {
   286   int i, ip;
   287   input_attributes_t input_attributes;
   288   pdf_file_attributes_t output_attributes;
   289   bookmark_t bookmark;
   290   char bookmark_name [MAX_BOOKMARK_NAME_LEN];
   292   bookmark.next = NULL;
   293   bookmark.level = 1;
   294   bookmark.name = & bookmark_name [0];
   296   memset (& input_attributes, 0, sizeof (input_attributes));
   297   memset (& output_attributes, 0, sizeof (output_attributes));
   299   if (! open_pdf_output_file (out_fn, & output_attributes))
   300     fatal (3, "error opening output file \"%s\"\n", out_fn);
   301   for (i = 0; i < inf_count; i++)
   302     {
   303       if (! open_input_file (in_fn [i]))
   304 	fatal (3, "error opening input file \"%s\"\n", in_fn [i]);
   305       for (ip = 1;; ip++)
   306 	{
   307 	  fprintf (stderr, "processing page %d of file \"%s\"\r", ip, in_fn [i]);
   308 	  if (bookmark_fmt)
   309 	    generate_bookmark_name (& bookmark_name [0],
   310 				    bookmark_fmt, 
   311 				    in_fn [i],
   312 				    ip);
   313 	  if (! process_page (ip, input_attributes,
   314 			      bookmark_fmt ? & bookmark : NULL,
   315 			      NULL))
   316 	    fatal (3, "error processing page %d of input file \"%s\"\n", ip, in_fn [i]);
   317 	  if (last_input_page ())
   318 	    break;
   319 	}
   320       if (verbose)
   321 	fprintf (stderr, "processed %d pages of input file \"%s\"\n", ip, in_fn [i]);
   322       if (! close_input_file ())
   323 	fatal (3, "error closing input file \"%s\"\n", in_fn [i]);
   324     }
   325   if (! close_pdf_output_files ())
   326     fatal (3, "error closing output file \"%s\"\n", out_fn);
   327 }
   330 void main_control (char *control_fn)
   331 {
   332   if (! parse_control_file (control_fn))
   333     fatal (2, "error parsing control file\n");
   334   if (! process_controls ())
   335     fatal (3, "error processing control file\n");
   336 }
   339 int main (int argc, char *argv[])
   340 {
   341   char *control_fn = NULL;
   342   char *out_fn = NULL;
   343   char *bookmark_fmt = NULL;
   344   int inf_count = 0;
   345   char *in_fn [MAX_INPUT_FILES];
   347   progname = argv [0];
   349   pdf_init ();
   351   init_tiff_handler ();
   352   init_jpeg_handler ();
   354   while (--argc)
   355     {
   356       if (argv [1][0] == '-')
   357 	{
   358 	  if (strcmp (argv [1], "-v") == 0)
   359 	    verbose++;
   360 	  else if (strcmp (argv [1], "-o") == 0)
   361 	    {
   362 	      if (argc)
   363 		{
   364 		  argc--;
   365 		  argv++;
   366 		  out_fn = argv [1];
   367 		}
   368 	      else
   369 		fatal (1, "missing filename after \"-o\" option\n");
   370 	    }
   371 	  else if (strcmp (argv [1], "-c") == 0)
   372 	    {
   373 	      if (argc)
   374 		{
   375 		  argc--;
   376 		  argv++;
   377 		  control_fn = argv [1];
   378 		}
   379 	      else
   380 		fatal (1, "missing filename after \"-s\" option\n");
   381 	    }
   382 	  else if (strcmp (argv [1], "-b") == 0)
   383 	    {
   384 	      if (argc)
   385 		{
   386 		  argc--;
   387 		  argv++;
   388 		  bookmark_fmt = argv [1];
   389 		}
   390 	      else
   391 		fatal (1, "missing format string after \"-b\" option\n");
   392 	    }
   393 	  else
   394 	    fatal (1, "unrecognized option \"%s\"\n", argv [1]);
   395 	}
   396       else if (inf_count < MAX_INPUT_FILES)
   397 	in_fn [inf_count++] = argv [1];
   398       else
   399 	fatal (1, "exceeded maximum of %d input files\n", MAX_INPUT_FILES);
   400       argv++;
   401     }
   403   if (! ((! out_fn) ^ (! control_fn)))
   404     fatal (1, "either a control file or an output file (but not both) must be specified\n");
   406   if (out_fn && ! inf_count)
   407     fatal (1, "no input files specified\n");
   409   if (control_fn && inf_count)
   410     fatal (1, "if control file is provided, input files can't be specified as arguments\n");
   412   if (control_fn)
   413     main_control (control_fn);
   414   else
   415     main_args (out_fn, inf_count, in_fn, bookmark_fmt);
   417   close_input_file ();
   418   close_pdf_output_files ();
   419   exit (0);
   420 }