Back to index

tetex-bin  3.0
dvipdfm.c
Go to the documentation of this file.
00001 /*  $Header$
00002 
00003     This is dvipdfm, a DVI to PDF translator.
00004     Copyright (C) 1998, 1999 by Mark A. Wicks
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019     
00020     The author may be contacted via the e-mail address
00021 
00022        mwicks@kettering.edu
00023 */
00024 
00025        
00026 #include <stdio.h>
00027 #include <string.h>
00028 #include <limits.h>
00029 #include <ctype.h>
00030 #include "config.h"
00031 #include "system.h"
00032 #include "mem.h"
00033 #include "mfileio.h"
00034 #include "dvi.h"
00035 #include "pdfdoc.h"
00036 #include "pdfdev.h"
00037 #include "encodings.h"
00038 #include "type1.h"
00039 #include "ttf.h"
00040 #include "colorsp.h"
00041 #include "pdfspecial.h"
00042 #include "pdfparse.h"
00043 #include "vf.h"
00044 #include "pkfont.h"
00045 #include "thumbnail.h"
00046 #include "psimage.h"
00047 #include "tfm.h"
00048 
00049 struct rect 
00050 {
00051   double width;
00052   double height;
00053 };
00054 typedef struct rect rect;
00055 
00056 struct 
00057 {
00058   char *s;
00059   struct rect data;
00060 } paper_sizes[] = {
00061   {"letter" , { 612.0, 792.0}},
00062   {"legal" , { 612.0, 1008.0}},
00063   {"ledger" , { 1224.0, 792.0}},
00064   {"tabloid" , { 792.0, 1224.0}},
00065   {"a5" , { 420.91, 595.27}},
00066   {"a4" , { 595.27, 841.82}},
00067   {"a3" , { 841.82, 1190.16}}};
00068 
00069 static rect get_paper_size (char *string)
00070 {
00071   int i;
00072   for (i=0; i<sizeof(paper_sizes)/sizeof(paper_sizes[0]); i++) {
00073     if (!strcmp (string, paper_sizes[i].s))
00074       break;
00075   }
00076   if (i == sizeof(paper_sizes)/sizeof(paper_sizes[0]))
00077     ERROR ("Paper size is invalid");
00078   return paper_sizes[i].data;
00079 }
00080 
00081 
00082 char *dvi_filename = NULL, *pdf_filename = NULL;
00083 static void set_default_pdf_filename(void)
00084 {
00085   const char *dvi_base;
00086 #ifdef HAVE_XBASENAME
00087   dvi_base = xbasename (dvi_filename);
00088 #else   
00089   dvi_base = basename (dvi_filename);
00090 #endif   
00091   if (strlen (dvi_base) < 5 || strncmp (".dvi", dvi_base+strlen(dvi_base)-4, 4)) 
00092   {
00093     pdf_filename = NEW (strlen(dvi_base)+5, char);
00094     strcpy (pdf_filename, dvi_base);
00095     strcat (pdf_filename, ".pdf");
00096   } else
00097   {
00098     pdf_filename = NEW (strlen(dvi_base)+1, char);
00099     strncpy (pdf_filename, dvi_base, strlen(dvi_base)-4);
00100     strcpy (pdf_filename+strlen(dvi_base)-4, ".pdf");
00101   }
00102 }
00103 static void usage (void)
00104 {
00105    fprintf (stdout, "\n%s, version %s, Copyright (C) 1998, 1999 by Mark A. Wicks\n", PACKAGE, VERSION);
00106    fprintf (stdout, "dvipdfm comes with ABSOLUTELY NO WARRANTY.\n");
00107    fprintf (stdout, "This is free software, and you are welcome to redistribute it\n");
00108    fprintf (stdout, "under certain conditions.  Details are distributed with the software.\n");
00109    fprintf (stdout, "\nUsage: dvipdfm [options] dvifile\n");
00110    fprintf (stdout, "-c      \tIgnore color specials (for B&W printing)\n");
00111    fprintf (stdout, "-f filename\tSet font map file name [t1fonts.map]\n");
00112    fprintf (stdout, "-o filename\tSet output file name [dvifile.pdf]\n");
00113    fprintf (stdout, "-l \t\tLandscape mode\n");
00114    fprintf (stdout, "-m number\tSet additional magnification\n");
00115    fprintf (stdout, "-p papersize\tSet papersize (letter, legal,\n");
00116    fprintf (stdout, "            \tledger, tabloid, a4, or a3) [letter]\n");
00117    fprintf (stdout, "-r resolution\tSet resolution (in DPI) for raster fonts [600]\n");
00118    fprintf (stdout, "-s pages\tSelect page ranges (-)\n");
00119    fprintf (stdout, "-t      \tEmbed thumbnail images\n");
00120    fprintf (stdout, "-d      \tRemove thumbnail images when finished\n");
00121    fprintf (stdout, "-x dimension\tSet horizontal offset [1.0in]\n");
00122    fprintf (stdout, "-y dimension\tSet vertical offset [1.0in]\n");
00123    fprintf (stdout, "-e          \tDisable partial font embedding [default is enabled])\n");
00124    fprintf (stdout, "-z number\tSet compression level (0-9) [default is 9])\n");
00125    fprintf (stdout, "-v          \tBe verbose\n");
00126    fprintf (stdout, "-vv         \tBe more verbose\n");
00127    fprintf (stdout, "\nAll dimensions entered on the command line are \"true\" TeX dimensions.\n");
00128    fprintf (stdout, "Argument of \"-s\" lists physical page ranges separated by commas, e.g., \"-s 1-3,5-6\"\n\n");
00129    exit(1);
00130 }
00131 
00132 static double paper_width = 612.0, paper_height = 792.0;
00133 static char landscape_mode = 0;
00134 static char ignore_colors = 0;
00135 static double mag = 1.0, x_offset=72.0, y_offset=72.0;
00136 static int font_dpi = 600;
00137 static int really_quiet = 0;
00138 
00139 struct page_range 
00140 {
00141   unsigned int first, last;
00142 } *page_ranges = NULL;
00143 int max_page_ranges = 0, num_page_ranges = 0;
00144 
00145 void set_landscape_mode (void)
00146 {
00147   dev_set_page_size (paper_height, paper_width);
00148 }
00149 
00150 #define pop_arg() {argv += 1; argc -= 1;}
00151 static void do_args (int argc, char *argv[])
00152 {
00153   char *flag;
00154   while (argc > 0 && *argv[0] == '-') {
00155     for (flag=argv[0]+1; *flag != 0; flag++) {
00156       switch (*flag) {
00157       case 'D':
00158        if (argc < 2) {
00159          fprintf (stderr, "PS->PDF conversion command line template missing\n\n");
00160          usage();
00161        }
00162        set_distiller_template(argv[1]);
00163        pop_arg();
00164        break;
00165       case 'r':
00166        if (argc < 2) {
00167          fprintf (stderr, "\nResolution specification missing a number\n\n");
00168          usage();
00169        }
00170        {
00171          char *result, *end, *start = argv[1];
00172          end = start + strlen(argv[1]);
00173          result = parse_number (&start, end);
00174          if (result != NULL && start == end) {
00175            font_dpi = (int) atof (result);
00176          }
00177          else {
00178            fprintf (stderr, "\nError in number following resolution specification\n\n");
00179            usage();
00180          }
00181          if (result != NULL) {
00182            RELEASE (result);
00183          }
00184        }
00185        pop_arg();
00186        break;
00187       case 'm':
00188        if (argc < 2) {
00189          fprintf (stderr, "\nMagnification specification missing a number\n\n");
00190          usage();
00191        }
00192        {
00193          char *result, *end, *start = argv[1];
00194          end = start + strlen(argv[1]);
00195          result = parse_number (&start, end);
00196          if (result != NULL && start == end) {
00197            mag = atof (result);
00198          }
00199          else {
00200            fprintf (stderr, "\nError in number following magnification specification\n\n");
00201            usage();
00202          }
00203          if (result != NULL) {
00204            RELEASE (result);
00205          }
00206        }
00207        pop_arg();
00208        break;
00209       case 'g':
00210        if (argc < 2) {
00211          fprintf (stderr, "\nAnnotation \"grow\" specification missing a number\n\n");
00212          usage();
00213        }
00214        {
00215          char *result, *end, *start = argv[1];
00216          end = start + strlen(argv[1]);
00217          result = parse_number (&start, end);
00218          if (result != NULL && start == end) {
00219            pdf_special_set_grow (atof (result));
00220          }
00221          else {
00222            fprintf (stderr, "\nError in number following magnification specification\n\n");
00223            usage();
00224          }
00225          if (result != NULL) {
00226            RELEASE (result);
00227          }
00228        }
00229        pop_arg();
00230        break;
00231       case 'x':
00232        if (argc < 2) {
00233          fprintf (stderr, "\nX Offset specification missing a number\n\n");
00234          usage();
00235        }
00236        {
00237          char *result, *end, *start = argv[1];
00238          double unit;
00239          end = start + strlen(argv[1]);
00240          result = parse_number (&start, end);
00241          if (result != NULL) {
00242            x_offset = atof (result);
00243          }
00244          else {
00245            fprintf (stderr, "\nError in number following xoffset specification\n\n");
00246            usage();
00247          }
00248          if (result != NULL) {
00249            RELEASE (result);
00250          }
00251          unit = parse_one_unit(&start, end);
00252          if (unit > 0.0) {
00253            x_offset *= unit;
00254          }
00255          else {
00256            fprintf (stderr, "\nError in dimension specification following xoffset\n\n");
00257            usage();
00258          }
00259        }
00260        pop_arg();
00261        break;
00262       case 'y':
00263        if (argc < 2) {
00264          fprintf (stderr, "\nY offset specification missing a number\n\n");
00265          usage();
00266        }
00267        {
00268          char *result, *end, *start = argv[1];
00269          double unit;
00270          end = start + strlen(argv[1]);
00271          result = parse_number (&start, end);
00272          if (result != NULL) {
00273            y_offset = atof (result);
00274          }
00275          else {
00276            fprintf (stderr, "\nError in number following yoffset specification\n\n");
00277            usage();
00278          }
00279          if (result != NULL) {
00280            RELEASE (result);
00281          }
00282          unit = parse_one_unit(&start, end);
00283          if (unit > 0.0) {
00284            y_offset *= unit;
00285          }
00286          else {
00287            fprintf (stderr, "\nError in dimension specification following yoffset\n\n");
00288            usage();
00289          }
00290        }
00291        pop_arg();
00292        break;
00293       case 'o':  
00294        if (argc < 2)
00295          ERROR ("Missing output file name");
00296        pdf_filename = NEW (strlen(argv[1])+1,char);
00297        strcpy (pdf_filename, argv[1]);
00298        pop_arg();
00299        break;
00300       case 's':
00301        {
00302          char *result, *end, *start = argv[1];
00303          if (argc < 2)
00304            ERROR ("Missing page selection specification");
00305          end = start + strlen (argv[1]);
00306          while (start < end) {
00307            /* Enlarge page range table if necessary */
00308            if (num_page_ranges >= max_page_ranges) {
00309              max_page_ranges += 4;
00310              page_ranges = RENEW (page_ranges, max_page_ranges,
00311                                struct page_range);
00312            }
00313            skip_white (&start, end);
00314            page_ranges[num_page_ranges].first = 0;
00315            if ((result = parse_unsigned (&start, end))) {
00316              page_ranges[num_page_ranges].first = atoi(result)-1;
00317              page_ranges[num_page_ranges].last =
00318               page_ranges[num_page_ranges].first;
00319              RELEASE(result);
00320            }
00321            skip_white (&start, end);
00322            if (*start == '-') {
00323              start += 1;
00324              page_ranges[num_page_ranges].last = UINT_MAX;
00325              skip_white (&start, end);
00326              if (start < end &&
00327                 ((result = parse_unsigned (&start, end)))) {
00328               page_ranges[num_page_ranges].last = atoi(result)-1;
00329               RELEASE (result);
00330              }
00331            }
00332            num_page_ranges += 1;
00333            skip_white (&start, end);
00334            if (start < end && *start == ',') {
00335              start += 1;
00336              continue;
00337            }
00338            skip_white (&start, end);
00339            if (start < end) {
00340              fprintf (stderr, "Page selection? %s", start);
00341              ERROR ("Bad page range specification");
00342            }
00343          }
00344          pop_arg();
00345        }
00346        break;
00347       case 't':
00348        {
00349 #ifdef HAVE_LIBPNG
00350          pdf_doc_enable_thumbnails ();
00351 #else
00352          ERROR ("The thumbnail option requires libpng, which you apparently don't have.");
00353 #endif /* HAVE_LIBPNG */
00354        }
00355        break;
00356       case 'd':
00357        {
00358 #ifdef HAVE_LIBPNG
00359          thumb_remove ();
00360 #else
00361          ERROR ("The thumbnail option requires libpng, which you apparently don't have.");
00362 #endif /* HAVE_LIBPNG */
00363        }
00364        break;
00365       case 'p':
00366        {
00367          struct rect paper_size;
00368          if (argc < 2)
00369            ERROR ("Missing paper size");
00370          paper_size = get_paper_size (argv[1]);
00371          paper_width = paper_size.width;
00372          paper_height = paper_size.height;
00373          pop_arg();
00374        }
00375        break;
00376       case 'c':
00377        ignore_colors = 1;
00378        break;
00379       case 'l':
00380        landscape_mode = 1;
00381        break;
00382       case 'f':
00383        dev_read_mapfile (argv[1]);
00384        pop_arg();
00385        break;
00386       case 'e':
00387        type1_disable_partial();
00388        break;
00389       case 'q':
00390        really_quiet = 1;
00391        break;
00392       case 'v':
00393        encoding_set_verbose();
00394        dev_set_verbose();
00395        dvi_set_verbose();
00396        type1_set_verbose();
00397        vf_set_verbose();
00398        pk_set_verbose();
00399        pdf_obj_set_verbose();
00400        pdf_doc_set_verbose();
00401        tfm_set_verbose();
00402 #ifdef HAVE_TTF_FORMATS      
00403        ttf_set_verbose();
00404 #endif  
00405        break;
00406       case 'V':
00407        {
00408          unsigned level = 2;
00409          if (isdigit (*(flag+1))) {
00410            level = *(++flag) - '0';
00411          } else {
00412            char *result, *end, *start = argv[1];
00413            if (argc < 2) {
00414              fprintf (stderr, "\nVersion specification missing number (2 or 3)\n\n");
00415              usage();
00416            }
00417            end = start + strlen(argv[1]);
00418            result = parse_number (&start, end);
00419            if (result != NULL && start == end) {
00420              level = (int) atof (result);
00421            }
00422            else {
00423              fprintf (stderr, "\nError in number following version specification\n\n");
00424              usage();
00425            }
00426            if (result != NULL) {
00427              RELEASE (result);
00428            }
00429            pop_arg();
00430          }
00431          if (level >= 2 && level <= 3) {
00432            pdf_set_version(level);
00433          } else {
00434            fprintf (stderr, "\nNumber following version specification is out of range\n\n");
00435          }
00436        }
00437        break;
00438       case 'z': 
00439        {
00440          int level = 9;
00441 #ifndef HAVE_ZLIB
00442          fprintf (stderr, "\nYou don't have compression compiled in.  Possibly libz wasn't found by configure.\nCompression specification will be ignored.\n\n");
00443 #endif  /* HAVE_ZLIB */
00444          if (isdigit (*(flag+1))) {
00445            level = *(++flag) - '0';
00446          } else {
00447            char *result, *end, *start = argv[1];
00448            if (argc < 2) {
00449              fprintf (stderr, "\nCompression specification missing number for level\n\n");
00450              usage();
00451            }
00452            end = start + strlen(argv[1]);
00453            result = parse_number (&start, end);
00454            if (result != NULL && start == end) {
00455              level = (int) atof (result);
00456            }
00457            else {
00458              fprintf (stderr, "\nError in number following compression specification\n\n");
00459              usage();
00460            }
00461            if (result != NULL) {
00462              RELEASE (result);
00463            }
00464            pop_arg();
00465          }
00466          if (level >= 0 && level <= 9) {
00467            pdf_obj_set_compression(level);
00468          } else {
00469            fprintf (stderr, "\nNumber following compression specification is out of range\n\n");
00470          }
00471        }
00472        break;
00473       default:
00474        usage();
00475       }
00476     }
00477     argc -= 1 ;
00478     argv += 1;
00479   }
00480   if (argc > 1) {
00481     fprintf (stderr, "\nMultiple dvi filenames?\n\n");
00482     usage();
00483   }
00484   /* The only legitimate way to have argc == 0 here is
00485      is do_args was called from config file.  In that case, there is
00486      no dvi file name.  Check for that case  */
00487   if (argc > 0) {
00488     if (strncmp (".dvi", argv[0]+strlen(argv[0])-4, 4)) {
00489       dvi_filename = NEW (strlen (argv[0])+1+4, char);
00490       strcpy (dvi_filename, argv[0]);
00491       strcat (dvi_filename, ".dvi");
00492     }
00493     else {
00494       dvi_filename = NEW (strlen (argv[0])+1, char);
00495       strcpy (dvi_filename, argv[0]);
00496     }
00497   }
00498 }
00499 
00500 
00501 static void cleanup(void)
00502 {
00503   RELEASE (dvi_filename);
00504   RELEASE (pdf_filename);
00505   if (page_ranges)
00506     RELEASE (page_ranges);
00507   psimage_close();
00508 }
00509 
00510 static char *config_file_name = "config";
00511 static void read_config_file (void)
00512 {
00513   char *full_config_name, *start, *end;
00514   char *argv[2], *option;
00515   FILE *config_file;
00516   
00517   if ((full_config_name = kpse_find_file (config_file_name,
00518                                kpse_program_text_format,
00519                                true)) == NULL) {
00520     return;
00521   }
00522   if (!(config_file = MFOPEN (full_config_name, FOPEN_R_MODE))) {
00523     fprintf (stderr, "\nError opening configuration file.  Continuing with defaults.\n");
00524     return;
00525   }
00526   while ((start = mfgets (work_buffer, WORK_BUFFER_SIZE,
00527                        config_file))) {
00528     int argc = 0;
00529     end = work_buffer+strlen(work_buffer);
00530     skip_white (&start, end);
00531     if (start >= end)
00532       continue;
00533     /* Build up an argument list as if it were passed on the command
00534        line */
00535     if ((option = parse_ident (&start, end))) {
00536       argc = 1;
00537       argv[0] = NEW (strlen(option)+2, char);
00538       strcpy (argv[0]+1, option);
00539       RELEASE (option);
00540       *argv[0] = '-';
00541       skip_white (&start, end);
00542       if (start < end) {
00543        argc += 1;
00544        if (*start == '"') {
00545          argv[1] = parse_c_string (&start, end);
00546        }
00547        else
00548          argv[1] = parse_ident (&start, end);
00549       }
00550     }
00551     do_args (argc, argv);
00552     while (argc > 0) {
00553       RELEASE (argv[--argc]);
00554     }
00555   }
00556 }
00557 
00558 void error_cleanup (void)
00559 {
00560   pdf_error_cleanup();
00561   remove (pdf_filename);
00562   fprintf (stderr, "\nOutput file removed.\n");
00563 }
00564 
00565 int CDECL main (int argc, char *argv[]) 
00566 {
00567   int i;
00568   int at_least_one_page = 0;
00569   if (argc < 2) {
00570     fprintf (stderr, "\nNo dvi filename specified.\n\n");
00571     usage();
00572     return 1;
00573   }
00574 #ifdef KPATHSEA
00575   kpse_set_program_name (argv[0], NULL);
00576 #endif
00577 
00578   argv+=1;
00579   argc-=1;
00580 
00581   /* Process config file, if any */
00582   read_config_file();
00583 
00584   do_args (argc, argv);
00585 
00586 #ifdef KPATHSEA
00587   kpse_init_prog ("", font_dpi, NULL, NULL);
00588   pk_set_dpi (font_dpi);
00589   kpse_set_program_enabled (kpse_pk_format, true, kpse_src_texmf_cnf);
00590 #endif
00591 
00592   if (!dvi_filename) {
00593     fprintf (stderr, "\nNo dvi filename specified.\n\n");
00594     usage();
00595   }
00596 
00597   /* Check for ".dvi" at end of argument name */
00598   if (pdf_filename == NULL)
00599     set_default_pdf_filename();
00600   
00601   if (!really_quiet)
00602     fprintf (stdout, "\n%s -> %s\n", dvi_filename, pdf_filename);
00603 
00604   dvi_init (dvi_filename, pdf_filename, mag, x_offset, y_offset);
00605 
00606   if (ignore_colors) {
00607     color_special_ignore_colors();
00608     pdf_special_ignore_colors();
00609   }
00610   
00611   if (landscape_mode)
00612     dev_set_page_size (paper_height, paper_width);
00613   else
00614     dev_set_page_size (paper_width, paper_height);
00615 
00616   if ((num_page_ranges))
00617     for (i=0; i<num_page_ranges; i++) {
00618       unsigned j;
00619       if (page_ranges[i].first <= page_ranges[i].last)
00620        for (j=page_ranges[i].first; j<=page_ranges[i].last && j<dvi_npages(); j++) {
00621          fprintf (stderr, "[%d", j+1);
00622          dvi_do_page (j);
00623          at_least_one_page = 1;
00624          fprintf (stderr, "]");
00625        }
00626       else
00627        for (j=page_ranges[i].first;
00628             j>=page_ranges[i].last && j<dvi_npages(); j--) {
00629          fprintf (stderr, "[%d", j+1);
00630          dvi_do_page (j);
00631          at_least_one_page = 1;
00632          fprintf (stderr, "]");
00633        }
00634     }
00635   if (!at_least_one_page && num_page_ranges) {
00636     fprintf (stderr, "No pages fall in range!\nFalling back to entire document.\n");
00637   }
00638   if (!at_least_one_page) /* Fall back to entire document */
00639     for (i=0; i<dvi_npages(); i++) {
00640       fprintf (stderr, "[%d", i+1);
00641       dvi_do_page (i);
00642       fprintf (stderr, "]");
00643     }
00644   dvi_close();
00645   fprintf (stderr, "\n");
00646   cleanup();
00647   return 0;
00648 }
00649