tumble.c

Mon, 14 Dec 2009 16:18:21 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 14 Dec 2009 16:18:21 +0000
changeset 172
2fae6df568f6
parent 166
301f6f17c364
permissions
-rw-r--r--

remove erroneous 0.33-philpem1 tag

     1 /*
     2  * tumble: build a PDF file from image files
     3  *
     4  * Main program
     5  * $Id: tumble.c,v 1.43 2003/04/10 01:02:12 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"
    36 #ifdef CTL_LANG
    37 #include "parser.tab.h"
    38 #endif
    40 #include "tumble.h"
    41 #include "bitblt.h"
    42 #include "pdf.h"
    43 #include "tumble_input.h"
    46 #define MAX_INPUT_FILES 5000
    48 typedef struct output_file_t
    49 {
    50   struct output_file_t *next;
    51   char *name;
    52   pdf_file_handle pdf;
    53 } output_file_t;
    56 int verbose;
    59 output_file_t *output_files;
    60 output_file_t *out;
    63 char *progname;
    66 bool close_pdf_output_files (void);
    69 #define QMAKESTR(x) #x
    70 #define MAKESTR(x) QMAKESTR(x)
    73 void usage (void)
    74 {
    75   fprintf (stderr, "\n");
    76   fprintf (stderr, "tumble version " MAKESTR(TUMBLE_VERSION) " - Copyright 2001-2003 Eric Smith <eric@brouhaha.com>\n");
    77   fprintf (stderr, "http://tumble.brouhaha.com/\n");
    78   fprintf (stderr, "\n");
    79   fprintf (stderr, "usage:\n");
    80 #ifdef CTL_LANG
    81   fprintf (stderr, "    %s [options] -c <control.tum>\n", progname);
    82 #endif
    83   fprintf (stderr, "    %s [options] <input.tif>... -o <output.pdf>\n", progname);
    84   fprintf (stderr, "options:\n");
    85   fprintf (stderr, "    -v        verbose\n");
    86   fprintf (stderr, "    -b <fmt>  create bookmarks\n");
    87   fprintf (stderr, "bookmark format:\n");
    88   fprintf (stderr, "    %%F  file name (sans suffix)\n");
    89   fprintf (stderr, "    %%p  page number\n");
    90 }
    93 /* generate fatal error message to stderr, doesn't return */
    94 void fatal (int ret, char *format, ...) __attribute__ ((noreturn));
    96 void fatal (int ret, char *format, ...)
    97 {
    98   va_list ap;
   100   fprintf (stderr, "fatal error");
   101   if (format)
   102     {
   103       fprintf (stderr, ": ");
   104       va_start (ap, format);
   105       vfprintf (stderr, format, ap);
   106       va_end (ap);
   107     }
   108   else
   109     fprintf (stderr, "\n");
   110   if (ret == 1)
   111     usage ();
   112   close_input_file ();
   113   close_pdf_output_files ();
   114   exit (ret);
   115 }
   118 bool close_pdf_output_files (void)
   119 {
   120   output_file_t *o, *n;
   122   for (o = output_files; o; o = n)
   123     {
   124       n = o->next;
   125       pdf_close (o->pdf, PDF_PAGE_MODE_USE_OUTLINES);
   126       free (o->name);
   127       free (o);
   128     }
   129   out = NULL;
   130   output_files = NULL;
   131   return (1);
   132 }
   134 bool open_pdf_output_file (char *name,
   135 			   pdf_file_attributes_t *attributes)
   136 {
   137   output_file_t *o;
   139   if (out && (strcmp (name, out->name) == 0))
   140     return (1);
   141   for (o = output_files; o; o = o->next)
   142     if (strcmp (name, o->name) == 0)
   143       {
   144 	out = o;
   145 	return (1);
   146       }
   147   o = calloc (1, sizeof (output_file_t));
   148   if (! o)
   149     {
   150       fprintf (stderr, "can't calloc output file struct for '%s'\n", name);
   151       return (0);
   152    }
   154   o->name = strdup (name);
   155   if (! o->name)
   156     {
   157       fprintf (stderr, "can't strdup output filename '%s'\n", name);
   158       free (o);
   159       return (0);
   160     }
   162   o->pdf = pdf_create (name);
   163   if (! o->pdf)
   164     {
   165       fprintf (stderr, "can't open output file '%s'\n", name);
   166       free (o->name);
   167       free (o);
   168       return (0);
   169     }
   171   if (attributes->author)
   172     pdf_set_author (o->pdf, attributes->author);
   173   if (attributes->creator)
   174     pdf_set_creator (o->pdf, attributes->creator);
   175   if (attributes->title)
   176     pdf_set_title (o->pdf, attributes->title);
   177   if (attributes->subject)
   178     pdf_set_subject (o->pdf, attributes->subject);
   179   if (attributes->keywords)
   180     pdf_set_keywords (o->pdf, attributes->keywords);
   182   /* prepend new output file onto list */
   183   o->next = output_files;
   184   output_files = o;
   186   out = o;
   187   return (1);
   188 }
   191 #define MAX_BOOKMARK_LEVEL 20
   192 static pdf_bookmark_handle bookmark_vector [MAX_BOOKMARK_LEVEL + 1] = { NULL };
   195 bool process_page (int image,  /* range 1 .. n */
   196 		   input_attributes_t input_attributes,
   197 		   bookmark_t *bookmarks,
   198 		   page_label_t *page_label)
   199 {
   200   pdf_page_handle page;
   201   image_info_t image_info;
   203   if (! get_image_info (image, input_attributes, & image_info))
   204     return (0);
   206   page = pdf_new_page (out->pdf,
   207 		       image_info.width_points,
   208 		       image_info.height_points);
   210   if (! process_image (image, input_attributes, & image_info, page))
   211     return (0);
   213   while (bookmarks)
   214     {
   215       if (bookmarks->level <= MAX_BOOKMARK_LEVEL)
   216 	{
   217 	  pdf_bookmark_handle parent = bookmark_vector [bookmarks->level - 1];
   218 	  bookmark_vector [bookmarks->level] = pdf_new_bookmark (parent,
   219 								 bookmarks->name,
   220 								 0,
   221 								 page);
   222 	}
   223       else
   224 	{
   225 	  (void) pdf_new_bookmark (bookmark_vector [MAX_BOOKMARK_LEVEL],
   226 				   bookmarks->name,
   227 				   0,
   228 				   page);
   229 	}
   230       bookmarks = bookmarks->next;
   231     }
   233   if (page_label)
   234     pdf_new_page_label (out->pdf,
   235 			page_label->page_index,
   236 			page_label->base,
   237 			page_label->count,
   238 			page_label->style,
   239 			page_label->prefix);
   241   return (page != NULL);
   242 }
   245 #define MAX_BOOKMARK_NAME_LEN 500
   248 static int filename_length_without_suffix (char *in_fn)
   249 {
   250   char *p;
   251   int len = strlen (in_fn);
   253   p = strrchr (in_fn, '.');
   254   if (p && match_input_suffix (p))
   255     return (p - in_fn);
   256   return (len);
   257 }
   260 /* $$$ this function should ensure that it doesn't overflow the name string! */
   261 static void generate_bookmark_name (char *name,
   262 				    char *bookmark_fmt, 
   263 				    char *in_fn,
   264 				    int page)
   265 {
   266   bool meta = 0;
   267   int len;
   269   while (*bookmark_fmt)
   270     {
   271       if (meta)
   272 	{
   273 	  meta = 0;
   274 	  switch (*bookmark_fmt)
   275 	    {
   276 	    case '%':
   277 	      *(name++) = '%';
   278 	      break;
   279 	    case 'F':
   280 	      len = filename_length_without_suffix (in_fn);
   281 	      strncpy (name, in_fn, len);
   282 	      name += len;
   283 	      break;
   284 	    case 'p':
   285 	      sprintf (name, "%d", page);
   286 	      name += strlen (name);
   287 	      break;
   288 	    default:
   289 	      break;
   290 	    }
   291 	}
   292       else
   293 	switch (*bookmark_fmt)
   294 	  {
   295 	  case '%':
   296 	    meta = 1;
   297 	    break;
   298 	  default:
   299 	    *(name++) = *bookmark_fmt;
   300 	  }
   301       bookmark_fmt++;
   302     }
   303   *name = '\0';
   304 }
   307 void main_args (char *out_fn,
   308 		int inf_count,
   309 		char **in_fn,
   310 		char *bookmark_fmt)
   311 {
   312   int i, ip;
   313   input_attributes_t input_attributes;
   314   pdf_file_attributes_t output_attributes;
   315   bookmark_t bookmark;
   316   char bookmark_name [MAX_BOOKMARK_NAME_LEN];
   318   bookmark.next = NULL;
   319   bookmark.level = 1;
   320   bookmark.name = & bookmark_name [0];
   322   memset (& input_attributes, 0, sizeof (input_attributes));
   323   memset (& output_attributes, 0, sizeof (output_attributes));
   325   if (! open_pdf_output_file (out_fn, & output_attributes))
   326     fatal (3, "error opening output file \"%s\"\n", out_fn);
   327   for (i = 0; i < inf_count; i++)
   328     {
   329       if (! open_input_file (in_fn [i]))
   330 	fatal (3, "error opening input file \"%s\"\n", in_fn [i]);
   331       for (ip = 1;; ip++)
   332 	{
   333 	  fprintf (stderr, "processing page %d of file \"%s\"\r", ip, in_fn [i]);
   334 	  if (bookmark_fmt)
   335 	    generate_bookmark_name (& bookmark_name [0],
   336 				    bookmark_fmt, 
   337 				    in_fn [i],
   338 				    ip);
   339 	  if (! process_page (ip, input_attributes,
   340 			      bookmark_fmt ? & bookmark : NULL,
   341 			      NULL))
   342 	    fatal (3, "error processing page %d of input file \"%s\"\n", ip, in_fn [i]);
   343 	  if (last_input_page ())
   344 	    break;
   345 	}
   346       if (verbose)
   347 	fprintf (stderr, "processed %d pages of input file \"%s\"\n", ip, in_fn [i]);
   348       if (! close_input_file ())
   349 	fatal (3, "error closing input file \"%s\"\n", in_fn [i]);
   350     }
   351   if (! close_pdf_output_files ())
   352     fatal (3, "error closing output file \"%s\"\n", out_fn);
   353 }
   356 #ifdef CTL_LANG
   357 void main_control (char *control_fn)
   358 {
   359   if (! parse_control_file (control_fn))
   360     fatal (2, "error parsing control file\n");
   361   if (! process_controls ())
   362     fatal (3, "error processing control file\n");
   363 }
   364 #endif
   367 int main (int argc, char *argv[])
   368 {
   369 #ifdef CTL_LANG
   370   char *control_fn = NULL;
   371 #endif
   372   char *out_fn = NULL;
   373   char *bookmark_fmt = NULL;
   374   int inf_count = 0;
   375   char *in_fn [MAX_INPUT_FILES];
   377   progname = argv [0];
   379   pdf_init ();
   381   init_tiff_handler ();
   382   init_jpeg_handler ();
   383   init_pbm_handler ();
   384   init_png_handler ();
   385   init_jp2_handler ();
   387   while (--argc)
   388     {
   389       if (argv [1][0] == '-')
   390 	{
   391 	  if (strcmp (argv [1], "-v") == 0)
   392 	    verbose++;
   393 	  else if (strcmp (argv [1], "-o") == 0)
   394 	    {
   395 	      if (argc)
   396 		{
   397 		  argc--;
   398 		  argv++;
   399 		  out_fn = argv [1];
   400 		}
   401 	      else
   402 		fatal (1, "missing filename after \"-o\" option\n");
   403 	    }
   404 #ifdef CTL_LANG
   405 	  else if (strcmp (argv [1], "-c") == 0)
   406 	    {
   407 	      if (argc)
   408 		{
   409 		  argc--;
   410 		  argv++;
   411 		  control_fn = argv [1];
   412 		}
   413 	      else
   414 		fatal (1, "missing filename after \"-s\" option\n");
   415 	    }
   416 #endif
   417 	  else if (strcmp (argv [1], "-b") == 0)
   418 	    {
   419 	      if (argc)
   420 		{
   421 		  argc--;
   422 		  argv++;
   423 		  bookmark_fmt = argv [1];
   424 		}
   425 	      else
   426 		fatal (1, "missing format string after \"-b\" option\n");
   427 	    }
   428 	  else
   429 	    fatal (1, "unrecognized option \"%s\"\n", argv [1]);
   430 	}
   431       else if (inf_count < MAX_INPUT_FILES)
   432 	in_fn [inf_count++] = argv [1];
   433       else
   434 	fatal (1, "exceeded maximum of %d input files\n", MAX_INPUT_FILES);
   435       argv++;
   436     }
   438 #ifdef CTL_LANG
   439   if (! ((! out_fn) ^ (! control_fn)))
   440     fatal (1, "either a control file or an output file (but not both) must be specified\n");
   441   if (control_fn && inf_count)
   442     fatal (1, "if control file is provided, input files can't be specified as arguments\n");
   443 #else
   444   if (! out_fn)
   445     fatal (1, "an output file must be specified\n");
   446 #endif
   448   if (out_fn && ! inf_count)
   449     fatal (1, "no input files specified\n");
   451 #ifdef CTL_LANG
   452   if (control_fn)
   453     main_control (control_fn);
   454   else
   455     main_args (out_fn, inf_count, in_fn, bookmark_fmt);
   456 #else
   457   main_args (out_fn, inf_count, in_fn, bookmark_fmt);
   458 #endif
   460   close_input_file ();
   461   close_pdf_output_files ();
   462   exit (0);
   463 }