Back to index

tetex-bin  3.0
ebb.c
Go to the documentation of this file.
00001 /*  $Header$
00002 
00003     This is ebb, a bounding box extraction program.
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 #include <stdio.h>
00025 #include <time.h>
00026 #include <string.h>
00027 #include "system.h"
00028 #include "mem.h"
00029 #include "mfileio.h"
00030 #include "numbers.h"
00031 #include "pdfobj.h"
00032 #include "jpeg.h"
00033 #include "pdfparse.h"
00034 
00035 #include "config.h"
00036 
00037 #ifdef HAVE_LIBPNG
00038 #include "pngimage.h"
00039 #include <png.h>
00040 #endif
00041 
00042 #define EBB_PROGRAM "ebb"
00043 #define EBB_VERSION "Version 0.5.2"
00044 
00045 static void usage (void)
00046 {
00047   fprintf (stderr, "%s, version %s, Copyright (C) 1998, 1999 by Mark A. Wicks\n",
00048           EBB_PROGRAM, EBB_VERSION);
00049   fprintf (stderr, "ebb comes with ABSOLUTELY NO WARRANTY.\n");
00050   fprintf (stderr, "This is free software, and you are welcome to redistribute it\n");
00051   fprintf (stderr, "under certain conditions.  Details are distributed with the software.\n");
00052   fprintf (stderr, "\nUsage: [-v] [-b] ebb [files]\n");
00053   fprintf (stderr, "\t-b\t\tWrite .bb file in binary mode\n");
00054   fprintf (stderr, "\t-v\t\tVerbose\n");
00055   exit(1);
00056 }
00057 
00058 static char verbose = 0;
00059 
00060 static void do_time(FILE *file)
00061 {
00062   time_t current_time;
00063   struct tm *bd_time;
00064   time(&current_time);
00065   bd_time = localtime(&current_time);
00066   fprintf (file, "%%%%CreationDate: %s\n", asctime (bd_time));
00067 }
00068 
00069 char *extensions[] = {
00070   ".jpeg", ".JPEG", ".jpg", ".JPG", ".pdf", ".PDF", ".png", ".PNG"
00071 };
00072 
00073 static char *make_bb_filename (const char *name)
00074 {
00075   int i;
00076   char *result;
00077 #ifdef HAVE_XBASENAME   
00078   name = xbasename (name);
00079 #else   
00080   name = basename (name);
00081 #endif
00082   for (i=0; i<sizeof(extensions)/sizeof(extensions[0]); i++) {
00083     if (strlen (extensions[i]) < strlen(name) &&
00084        !strncmp (name+strlen(name)-strlen(extensions[i]),
00085                 extensions[i], strlen(extensions[i])))
00086       break;
00087   }
00088   if (i == sizeof(extensions)/sizeof(extensions[0])) {
00089     fprintf (stderr,
00090             "ebb: Warning: %s: Filename does not end in a recognizeable extension.\n",
00091             name);
00092     result = NEW (strlen(name)+3, char);
00093     strcpy (result, name);
00094   }
00095   else { /* Remove extension */
00096     result = NEW (strlen(name)+3-strlen(extensions[i])+1, char);
00097     strncpy (result, name, strlen(name)-strlen(extensions[i]));
00098     result[strlen(name)-strlen(extensions[i])] = 0;
00099   }
00100     strcat (result, ".bb");
00101   return result;
00102 }
00103 
00104 static char *bb_file_mode = FOPEN_W_MODE;
00105 
00106 static void write_bb (char *filename, int bbllx, int bblly, int bburx,
00107                     int bbury) 
00108 {
00109   char *bbfilename;
00110   FILE *bbfile;
00111   if (verbose)
00112     fprintf (stderr, "okay\n");
00113   bbfilename = make_bb_filename (filename);
00114   if ((bbfile = MFOPEN (bbfilename, bb_file_mode)) == NULL) {
00115     fprintf (stderr, "Unable to open output file: %s\n", bbfilename);
00116     return;
00117   }
00118   if (verbose) {
00119     fprintf (stderr, "Writing to %s:  ", bbfilename);
00120     fprintf (stderr, "Bounding box:  %d %d %d %d\n", bbllx, bblly,
00121             bburx, bbury);
00122   }
00123   fprintf (bbfile, "%%%%Title: %s\n", filename);
00124   fprintf (bbfile, "%%%%Creator: %s %s\n", EBB_PROGRAM, EBB_VERSION);
00125   fprintf (bbfile, "%%%%BoundingBox: %d %d %d %d\n",
00126           bbllx, bblly, bburx, bbury);
00127   do_time(bbfile);
00128   RELEASE (bbfilename);
00129   MFCLOSE (bbfile);
00130   return;
00131 }
00132 
00133 
00134 #define PIX2PT (72.0/100.0)
00135 void do_jpeg (FILE *file, char *filename)
00136 {
00137   struct jpeg *jpeg;
00138   if (verbose) {
00139     fprintf (stderr, "%s looks like a JPEG file...", filename);
00140   }
00141   jpeg = NEW (1, struct jpeg);
00142   jpeg -> file = file;
00143   if (!jpeg_headers (jpeg)) {
00144         fprintf (stderr, "\n%s: Corrupt JPEG file?\n", filename);
00145     MFCLOSE (file);
00146     RELEASE (jpeg);
00147     return;
00148   }
00149   write_bb (filename, 0, 0,
00150            ROUND(jpeg -> width * PIX2PT,1.0),
00151            ROUND(jpeg -> height * PIX2PT,1.0));
00152   RELEASE (jpeg);
00153   return;
00154 }
00155 #ifdef HAVE_LIBPNG
00156 void do_png (FILE *file, char *filename)
00157 {
00158   png_structp png_ptr;
00159   png_infop info_ptr;
00160   unsigned long width, height;
00161   rewind (file);
00162   if (verbose) {
00163     fprintf (stderr, "%s looks like a PNG file...", filename);
00164   }
00165   if (!(png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,    
00166                                      NULL, NULL, NULL)) ||
00167       !(info_ptr = png_create_info_struct (png_ptr))) {
00168     fprintf (stderr, "\n\n%s: Corrupt PNG file?\n", filename);
00169     if (png_ptr)
00170       png_destroy_read_struct(&png_ptr, NULL, NULL);
00171     MFCLOSE (file);
00172     return;
00173   }
00174   png_init_io (png_ptr, file);
00175   /* Read PNG header */
00176   png_read_info (png_ptr, info_ptr);
00177   width = png_get_image_width(png_ptr, info_ptr);
00178   height = png_get_image_height(png_ptr, info_ptr);
00179   write_bb (filename, 0, 0,
00180            ROUND(width * PIX2PT,1.0),
00181            ROUND(height * PIX2PT,1.0));
00182   if (info_ptr)
00183     png_destroy_info_struct(png_ptr, &info_ptr);
00184   if (png_ptr)
00185     png_destroy_read_struct(&png_ptr, NULL, NULL);
00186   return;
00187 }
00188 #endif /* HAVE_LIBPNG */
00189 
00190 void do_pdf (FILE *file, char *filename)
00191 {
00192   pdf_obj *trailer, *catalog, *page_tree, *media_box, *crop_box;
00193   pdf_obj *kids_ref, *kids, *tmp1;
00194   if (verbose) {
00195     fprintf (stderr, "%s looks like a PDF file...", filename);
00196   }
00197   if ((trailer = pdf_open (file)) == NULL) {
00198     fprintf (stderr, "%s: Corrupt PDF file?\n", filename);
00199     return;
00200   };
00201   if ((catalog = pdf_deref_obj(pdf_lookup_dict (trailer,"Root"))) ==
00202       NULL) {
00203     fprintf (stderr, "\nCatalog isn't where I expect it.\n");
00204     return;
00205   }
00206   /* Got catalog, so done with trailer */
00207   pdf_release_obj (trailer);
00208   /* Lookup page tree in catalog */
00209   page_tree = pdf_deref_obj (pdf_lookup_dict (catalog, "Pages"));
00210   pdf_release_obj (catalog);
00211   /* Media box can be inherited so start looking for it now */
00212   media_box = pdf_deref_obj (pdf_lookup_dict (page_tree, "MediaBox"));
00213   crop_box = pdf_deref_obj (pdf_lookup_dict (page_tree, "CropBox"));
00214   while ((kids_ref = pdf_lookup_dict (page_tree, "Kids")) != NULL) {
00215     kids = pdf_deref_obj (kids_ref);
00216     pdf_release_obj (page_tree);
00217     page_tree = pdf_deref_obj (pdf_get_array(kids, 0));
00218     pdf_release_obj (kids);
00219     /* Replace MediaBox if it's here */
00220     tmp1 = pdf_deref_obj(pdf_lookup_dict (page_tree, "MediaBox"));
00221     if (tmp1 && media_box)
00222       pdf_release_obj (media_box);
00223     if (tmp1) 
00224       media_box = tmp1;
00225     /* Likewise for CropBox */
00226     tmp1 = pdf_deref_obj(pdf_lookup_dict (page_tree, "CropBox"));
00227     if (tmp1 && crop_box)
00228       pdf_release_obj (crop_box);
00229     if (tmp1) 
00230       crop_box = tmp1;
00231   }
00232   /* At this point, we should have the media box for the first page */ 
00233   {
00234     pdf_obj *bbllx, *bblly, *bburx, *bbury;
00235     if (crop_box) {
00236       pdf_release_obj (media_box);
00237       media_box = crop_box;
00238       crop_box = NULL;
00239     }
00240     if ((bbllx = pdf_get_array (media_box, 0)) == NULL ||
00241        (bblly = pdf_get_array (media_box, 1)) == NULL ||
00242        (bburx = pdf_get_array (media_box, 2)) == NULL ||
00243        (bbury = pdf_get_array (media_box, 3)) == NULL) {
00244       fprintf (stderr, "Invalid mediabox\n");
00245     } else
00246       write_bb (filename,
00247               (int) pdf_number_value (bbllx), (int) pdf_number_value (bblly),
00248               (int) pdf_number_value (bburx), (int) pdf_number_value (bbury));
00249   }
00250   pdf_release_obj (media_box);
00251   pdf_release_obj (page_tree);
00252   pdf_close();
00253 }
00254 
00255 FILE *inputfile;
00256 
00257 int main (int argc, char *argv[]) 
00258 {
00259   kpse_set_program_name (argv[0], NULL);
00260   argc -= 1;
00261   argv += 1;
00262   if (argc == 0)
00263     usage();
00264   while (argc > 0 && *argv[0] == '-') {
00265     switch (*(argv[0]+1)) {
00266     case 'b':
00267       bb_file_mode = FOPEN_WBIN_MODE;
00268     case 'v':
00269       verbose = 1;
00270       argc -= 1;
00271       argv += 1;
00272       break;
00273     case 'h':  
00274       usage();
00275       argc -= 1;
00276       argv += 1;
00277       break;
00278     default:
00279       usage();
00280     }
00281   }
00282   for (; argc > 0; argc--, argv++) {
00283     char *kpse_file_name;
00284     if (!(kpse_file_name = kpse_find_pict(argv[0])) ||
00285         (inputfile = MFOPEN (kpse_file_name, FOPEN_RBIN_MODE)) == NULL)  {
00286       fprintf (stderr, "Can't find file (%s)...skipping\n", argv[0]);
00287       continue;
00288     }
00289     if (check_for_jpeg (inputfile)) {
00290       do_jpeg(inputfile, kpse_file_name);
00291       MFCLOSE (inputfile);
00292       continue;
00293     }
00294     if (check_for_pdf (inputfile)) {
00295       do_pdf(inputfile, kpse_file_name);
00296       MFCLOSE (inputfile);
00297       continue;
00298     }
00299 #ifdef HAVE_LIBPNG
00300     if (check_for_png (inputfile)) {
00301       do_png(inputfile, kpse_file_name);
00302       MFCLOSE (inputfile);
00303       continue;
00304     }
00305 #endif /* HAVE_LIBPNG */
00306     fprintf (stderr, "Can't handle file type for file named %s\n",
00307             argv[0]);
00308   }
00309   return 0;
00310 }
00311 
00312 /* The following is here to prevent a link error.  Other routines
00313    that get linked with ebb call this, but it isn't actually needed
00314    for ebb  */
00315 
00316 pdf_obj *get_reference (char **start, char *end)
00317 {
00318   fprintf (stderr, "get_reference():  This should never have been called\n");
00319   return NULL;
00320 }
00321 
00322 void error_cleanup(void)
00323 {
00324   /* For now, this is a do nothing routine, but the stub is required
00325      by error.h */
00326   return;
00327 }