tumble.c

Tue, 25 Mar 2003 09:38:08 +0000

author
eric
date
Tue, 25 Mar 2003 09:38:08 +0000
changeset 156
745483d15215
parent 154
5cfcac03d43f
child 157
160d624271cc
permissions
-rw-r--r--

support both big- and little-endian TIFF files. don't crash in close_input_file() if current_input_handler is NULL.

     1 /*
     2  * tumble: build a PDF file from image files
     3  *
     4  * Main program
     5  * $Id: tumble.c,v 1.41 2003/03/20 08:23:37 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 #define MAX_BOOKMARK_LEVEL 20
   182 static pdf_bookmark_handle bookmark_vector [MAX_BOOKMARK_LEVEL + 1] = { NULL };
   185 bool process_page (int image,  /* range 1 .. n */
   186 		   input_attributes_t input_attributes,
   187 		   bookmark_t *bookmarks,
   188 		   page_label_t *page_label)
   189 {
   190   pdf_page_handle page;
   191   image_info_t image_info;
   193   if (! get_image_info (image, input_attributes, & image_info))
   194     return (0);
   196   page = pdf_new_page (out->pdf,
   197 		       image_info.width_points,
   198 		       image_info.height_points);
   200   if (! process_image (image, input_attributes, & image_info, page))
   201     return (0);
   203   while (bookmarks)
   204     {
   205       if (bookmarks->level <= MAX_BOOKMARK_LEVEL)
   206 	{
   207 	  pdf_bookmark_handle parent = bookmark_vector [bookmarks->level - 1];
   208 	  bookmark_vector [bookmarks->level] = pdf_new_bookmark (parent,
   209 								 bookmarks->name,
   210 								 0,
   211 								 page);
   212 	}
   213       else
   214 	{
   215 	  (void) pdf_new_bookmark (bookmark_vector [MAX_BOOKMARK_LEVEL],
   216 				   bookmarks->name,
   217 				   0,
   218 				   page);
   219 	}
   220       bookmarks = bookmarks->next;
   221     }
   223   if (page_label)
   224     pdf_new_page_label (out->pdf,
   225 			page_label->page_index,
   226 			page_label->base,
   227 			page_label->count,
   228 			page_label->style,
   229 			page_label->prefix);
   231   return (page != NULL);
   232 }
   235 #define MAX_BOOKMARK_NAME_LEN 500
   238 static int filename_length_without_suffix (char *in_fn)
   239 {
   240   char *p;
   241   int len = strlen (in_fn);
   243   p = strrchr (in_fn, '.');
   244   if (p && match_input_suffix (p))
   245     return (p - in_fn);
   246   return (len);
   247 }
   250 /* $$$ this function should ensure that it doesn't overflow the name string! */
   251 static void generate_bookmark_name (char *name,
   252 				    char *bookmark_fmt, 
   253 				    char *in_fn,
   254 				    int page)
   255 {
   256   bool meta = 0;
   257   int len;
   259   while (*bookmark_fmt)
   260     {
   261       if (meta)
   262 	{
   263 	  meta = 0;
   264 	  switch (*bookmark_fmt)
   265 	    {
   266 	    case '%':
   267 	      *(name++) = '%';
   268 	      break;
   269 	    case 'F':
   270 	      len = filename_length_without_suffix (in_fn);
   271 	      strncpy (name, in_fn, len);
   272 	      name += len;
   273 	      break;
   274 	    case 'p':
   275 	      sprintf (name, "%d", page);
   276 	      name += strlen (name);
   277 	      break;
   278 	    default:
   279 	      break;
   280 	    }
   281 	}
   282       else
   283 	switch (*bookmark_fmt)
   284 	  {
   285 	  case '%':
   286 	    meta = 1;
   287 	    break;
   288 	  default:
   289 	    *(name++) = *bookmark_fmt;
   290 	  }
   291       bookmark_fmt++;
   292     }
   293   *name = '\0';
   294 }
   297 void main_args (char *out_fn,
   298 		int inf_count,
   299 		char **in_fn,
   300 		char *bookmark_fmt)
   301 {
   302   int i, ip;
   303   input_attributes_t input_attributes;
   304   pdf_file_attributes_t output_attributes;
   305   bookmark_t bookmark;
   306   char bookmark_name [MAX_BOOKMARK_NAME_LEN];
   308   bookmark.next = NULL;
   309   bookmark.level = 1;
   310   bookmark.name = & bookmark_name [0];
   312   memset (& input_attributes, 0, sizeof (input_attributes));
   313   memset (& output_attributes, 0, sizeof (output_attributes));
   315   if (! open_pdf_output_file (out_fn, & output_attributes))
   316     fatal (3, "error opening output file \"%s\"\n", out_fn);
   317   for (i = 0; i < inf_count; i++)
   318     {
   319       if (! open_input_file (in_fn [i]))
   320 	fatal (3, "error opening input file \"%s\"\n", in_fn [i]);
   321       for (ip = 1;; ip++)
   322 	{
   323 	  fprintf (stderr, "processing page %d of file \"%s\"\r", ip, in_fn [i]);
   324 	  if (bookmark_fmt)
   325 	    generate_bookmark_name (& bookmark_name [0],
   326 				    bookmark_fmt, 
   327 				    in_fn [i],
   328 				    ip);
   329 	  if (! process_page (ip, input_attributes,
   330 			      bookmark_fmt ? & bookmark : NULL,
   331 			      NULL))
   332 	    fatal (3, "error processing page %d of input file \"%s\"\n", ip, in_fn [i]);
   333 	  if (last_input_page ())
   334 	    break;
   335 	}
   336       if (verbose)
   337 	fprintf (stderr, "processed %d pages of input file \"%s\"\n", ip, in_fn [i]);
   338       if (! close_input_file ())
   339 	fatal (3, "error closing input file \"%s\"\n", in_fn [i]);
   340     }
   341   if (! close_pdf_output_files ())
   342     fatal (3, "error closing output file \"%s\"\n", out_fn);
   343 }
   346 void main_control (char *control_fn)
   347 {
   348   if (! parse_control_file (control_fn))
   349     fatal (2, "error parsing control file\n");
   350   if (! process_controls ())
   351     fatal (3, "error processing control file\n");
   352 }
   355 int main (int argc, char *argv[])
   356 {
   357   char *control_fn = NULL;
   358   char *out_fn = NULL;
   359   char *bookmark_fmt = NULL;
   360   int inf_count = 0;
   361   char *in_fn [MAX_INPUT_FILES];
   363   progname = argv [0];
   365   pdf_init ();
   367   init_tiff_handler ();
   368   init_jpeg_handler ();
   370   while (--argc)
   371     {
   372       if (argv [1][0] == '-')
   373 	{
   374 	  if (strcmp (argv [1], "-v") == 0)
   375 	    verbose++;
   376 	  else if (strcmp (argv [1], "-o") == 0)
   377 	    {
   378 	      if (argc)
   379 		{
   380 		  argc--;
   381 		  argv++;
   382 		  out_fn = argv [1];
   383 		}
   384 	      else
   385 		fatal (1, "missing filename after \"-o\" option\n");
   386 	    }
   387 	  else if (strcmp (argv [1], "-c") == 0)
   388 	    {
   389 	      if (argc)
   390 		{
   391 		  argc--;
   392 		  argv++;
   393 		  control_fn = argv [1];
   394 		}
   395 	      else
   396 		fatal (1, "missing filename after \"-s\" option\n");
   397 	    }
   398 	  else if (strcmp (argv [1], "-b") == 0)
   399 	    {
   400 	      if (argc)
   401 		{
   402 		  argc--;
   403 		  argv++;
   404 		  bookmark_fmt = argv [1];
   405 		}
   406 	      else
   407 		fatal (1, "missing format string after \"-b\" option\n");
   408 	    }
   409 	  else
   410 	    fatal (1, "unrecognized option \"%s\"\n", argv [1]);
   411 	}
   412       else if (inf_count < MAX_INPUT_FILES)
   413 	in_fn [inf_count++] = argv [1];
   414       else
   415 	fatal (1, "exceeded maximum of %d input files\n", MAX_INPUT_FILES);
   416       argv++;
   417     }
   419   if (! ((! out_fn) ^ (! control_fn)))
   420     fatal (1, "either a control file or an output file (but not both) must be specified\n");
   422   if (out_fn && ! inf_count)
   423     fatal (1, "no input files specified\n");
   425   if (control_fn && inf_count)
   426     fatal (1, "if control file is provided, input files can't be specified as arguments\n");
   428   if (control_fn)
   429     main_control (control_fn);
   430   else
   431     main_args (out_fn, inf_count, in_fn, bookmark_fmt);
   433   close_input_file ();
   434   close_pdf_output_files ();
   435   exit (0);
   436 }