"Fossies" - the Fresh Open Source Software Archive

Member "littleutils-1.0.43/imageutils/imagsize.c" (11 Sep 2019, 32934 Bytes) of package /linux/privat/littleutils-1.0.43.tar.lz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "imagsize.c" see the Fossies "Dox" file reference documentation.

    1 /* imagsize:  figure out the image size of BMP, GIF, JPEG, PBM, PGM, PPM, PNG,
    2               TIFF, XBM, and XPM files
    3 
    4    Original "image_size" program Copyright (C)1997,1998,2014 by Jef Poskanzer
    5    <jef@acme.com>.  All rights reserved.
    6 
    7    Redistribution and use in source and binary forms, with or without
    8    modification, are permitted provided that the following conditions are met:
    9    1. Redistributions of source code must retain the above copyright
   10       notice, this list of conditions and the following disclaimer.
   11    2. Redistributions in binary form must reproduce the above copyright
   12       notice, this list of conditions and the following disclaimer in the
   13       documentation and/or other materials provided with the distribution.
   14 
   15    THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
   16    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   17    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   18    DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
   19    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   20    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   21    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   22    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25 
   26    The JPEG quality estimation algorithm used in this program comes from the
   27    "jpegdump" program, which is Copyright (C)1992 Handmade Software, Inc. by
   28    Allan N. Hessenflow.
   29 
   30    Permission to use, copy, modify, and distribute the JPEG quality estimation
   31    routine for any purpose and without fee is hereby granted, provided that the
   32    above copyright notice appear in all copies and that both that copyright
   33    notice and this permission notice appear in supporting documentation.  This
   34    software is provided "as is" without express or implied warranty.
   35 
   36    Derived "imagsize" program Copyright (C)2004-2005 by Brian Lindholm.  All
   37    rights reserved.  Redistribution is permitted as described as above.  */
   38 
   39 
   40 /* various includes */
   41 
   42 #include "../config.h"
   43 #include <limits.h>
   44 #include <stdlib.h>
   45 #include <stdio.h>
   46 #include <string.h>
   47 #include <sys/stat.h>
   48 
   49 #ifdef HAVE_UNISTD_H
   50 #include <unistd.h>
   51 #define OPTEND -1
   52 #else
   53 #define OPTEND EOF
   54 #endif
   55 
   56 #ifdef HAVE_GETOPT_H
   57 #include <getopt.h>
   58 #endif
   59 
   60 #if HAVE_INTTYPES_H
   61 #include <inttypes.h>
   62 #endif
   63 
   64 #ifdef __MINGW32__
   65 extern int getopt (int argc, char * const *argv, const char *optstring);
   66 extern char *optarg;
   67 extern int optind;
   68 #endif
   69 
   70 #ifdef DJGPP
   71 unsigned short _djstat_flags = 63;  /* Speed up stat command for DJGPP */
   72 #endif
   73 
   74 #ifndef PATH_MAX
   75 #define PATH_MAX 256
   76 #endif
   77 
   78 /* Define a few JPEG markers. */
   79 
   80 #define M_SOF 0xc0
   81 #define M_SOI 0xd8
   82 #define M_EOI 0xd9
   83 #define M_SOS 0xda
   84 #define M_DQT 0xdb
   85 
   86 /* Define return codes */
   87 
   88 #define NOT_OK 0
   89 #define OK 1
   90 
   91 char *fmt0 = (sizeof (off_t) <= sizeof (long) ?
   92   "%s\tsize=%lu\tgeom=%dx%d\tdepth=%d\tqual=%.0f,%.0f\tsamp=%s\ttype=%s\n" :
   93   "%s\tsize=%llu\tgeom=%dx%d\tdepth=%d\tqual=%.0f,%.0f\tsamp=%s\ttype=%s\n");
   94 char *fmt1 = (sizeof (off_t) <= sizeof (long) ?
   95   "-name %s -size %lu -geometry %dx%d -bitdepth %d -quality %.0f,%.0f -sampling %s -type %s\n" :
   96   "-name %s -size %llu -geometry %dx%d -bitdepth %d -quality %.0f,%.0f -sampling %s -type %s\n");
   97 char *fmt2 = "<img src=\"%s\" alt=\"%s\" width=\"%d\" height=\"%d\">\n";
   98 char *fmt0a = (sizeof (off_t) <= sizeof (long) ?
   99   "%s\tsize=%lu\tgeom=0x0\tdepth=0\tqual=0,0\tsamp=none\ttype=%s\n" :
  100   "%s\tsize=%llu\tgeom=0x0\tdepth=0\tqual=0,0\tsamp=none\ttype=%s\n");
  101 char *fmt1a = (sizeof (off_t) <= sizeof (long) ?
  102   "-name %s -size %lu -geometry 0x0 -bitdepth 0 -quality 0,0 -sampling=none -type %s\n" :
  103   "-name %s -size %llu -geometry 0x0 -bitdepth 0 -quality 0,0 -sampling=none -type %s\n");
  104 char *fmt2a = "<img src=\"%s\" alt=\"%s\" width=\"0\" height=\"0\">\n";
  105 
  106 
  107 /* Sample quantization tables from JPEG spec --- only needed for
  108  * guesstimate of quality factor.  Note these are in zigzag order. */
  109 
  110 static int std_luminance_quant_tbl[64] = {
  111   16, 11, 12, 14, 12, 10, 16, 14,
  112   13, 14, 18, 17, 16, 19, 24, 40,
  113   26, 24, 22, 22, 24, 49, 35, 37,
  114   29, 40, 58, 51, 61, 60, 57, 51,
  115   56, 55, 64, 72, 92, 78, 64, 68,
  116   87, 69, 55, 56, 80, 109, 81, 87,
  117   95, 98, 103, 104, 103, 62, 77, 113,
  118   121, 112, 100, 120, 92, 101, 103, 99
  119 };
  120 
  121 static int std_chrominance_quant_tbl[64] = {
  122   17, 18, 18, 24, 21, 24, 47, 26,
  123   26, 47, 99, 66, 56, 66, 99, 99,
  124   99, 99, 99, 99, 99, 99, 99, 99,
  125   99, 99, 99, 99, 99, 99, 99, 99,
  126   99, 99, 99, 99, 99, 99, 99, 99,
  127   99, 99, 99, 99, 99, 99, 99, 99,
  128   99, 99, 99, 99, 99, 99, 99, 99,
  129   99, 99, 99, 99, 99, 99, 99, 99
  130 };
  131 
  132 static int *deftabs[2] =
  133   { std_luminance_quant_tbl, std_chrominance_quant_tbl };
  134 
  135 /* Other global variables */
  136 
  137 static char errstr[200];
  138 
  139 /* Function pre-defines */
  140 
  141 static void help (FILE *where);
  142 static int failure (char *reason);
  143 static int get (FILE *f, unsigned char *chP);
  144 static int mustbe (FILE *f, unsigned char ch);
  145 static int gif (FILE *f, int *widthP, int *heightP, int *depth);
  146 static int bmp (FILE *f, int *widthP, int *heightP, int *depth);
  147 static int jpeg (FILE *f, int *widthP, int *heightP, double *qual,
  148   int *depth, int *typenum, char *sampling);
  149 static int xbm (FILE *f, int *widthP, int *heightP);
  150 static int xpm (FILE *f, int *widthP, int *heightP, int *depth);
  151 static int ppm (FILE *f, int *widthP, int *heightP);
  152 static int png (FILE *f, int *widthP, int *heightP, int *bpp,
  153   int *typenum);
  154 static int tiff_be (FILE *f, int *widthP, int *heightP, int *depth);
  155 static int tiff_le (FILE *f, int *widthP, int *heightP, int *depth);
  156 static int image_size (FILE *f, int *widthP, int *heightP, double *qual,
  157   int *depth, char *type, char *sample);
  158 
  159 
  160 static void
  161 help (FILE *where)
  162 {
  163   fprintf (where,
  164     "imagsize " PACKAGE_VERSION "\n"
  165     "usage: imagsize [-f file_list] [-h(elp)] [-n(ormal_format)] [-p(ipe)]\n"
  166     "         [-x(window_format)] [-v(erbose)] [-w(eb_format)] file...\n");
  167 }
  168 
  169 
  170 static int
  171 failure (char *reason)
  172 {
  173   (void) strcpy (errstr, reason);
  174   return (NOT_OK);
  175 }
  176 
  177 
  178 static int
  179 get (FILE *f, unsigned char *chP)
  180 {
  181   int ich = getc (f);
  182   if (ich == EOF)
  183     return (failure ("imagsize error: unknown-EOF"));
  184   *chP = (unsigned char) ich;
  185   return (OK);
  186 }
  187 
  188 
  189 static int
  190 mustbe (FILE *f, unsigned char ch)
  191 {
  192   char buffer[200];
  193   unsigned char ch2;
  194 
  195   if (!get (f, &ch2))
  196     return (NOT_OK);
  197   if (ch2 != ch)
  198     {
  199       sprintf (buffer, "imagsize error: corrupted image -- expecting %x at %ld",
  200         (unsigned int) ch, ftell (f));
  201       return (failure (buffer));
  202     }
  203   return (OK);
  204 }
  205 
  206 
  207 static int
  208 gif (FILE *f, int *widthP, int *heightP, int *depth)
  209 {
  210   unsigned char ch, w1, w2, h1, h2, b1;
  211 
  212   /* Read rest of signature. */
  213   if (!mustbe (f, (unsigned char) 'F')) return (NOT_OK);
  214   if (!mustbe (f, (unsigned char) '8')) return (NOT_OK);
  215   if (!get (f, &ch)) return (NOT_OK);
  216   if (ch != (unsigned char) '7' && ch != (unsigned char) '9')
  217     return (failure ("imagsize error: corrupted image file"));
  218   if (!mustbe (f, 'a')) return (NOT_OK);
  219 
  220   /* Width and height are the next things in the file. */
  221   if (!get (f, &w1)) return (NOT_OK);
  222   if (!get (f, &w2)) return (NOT_OK);
  223   *widthP = (int) w2 * 256 + (int) w1;
  224   if (!get (f, &h1)) return (NOT_OK);
  225   if (!get (f, &h2)) return (NOT_OK);
  226   *heightP = (int) h2 * 256 + (int) h1;
  227   if (!get (f, &b1)) return (NOT_OK);
  228   *depth = ((int) b1 & 0x07) + 1;
  229 
  230   /* Indicate successful finish */
  231   return (OK);
  232 }
  233 
  234 
  235 static int
  236 bmp (FILE *f, int *widthP, int *heightP, int *depth)
  237 {
  238   unsigned char s1, s2, s3, s4;
  239   long l;
  240   int bp, bpp;
  241 
  242   /* Skip rest of bitmap file header */
  243   if (fseek (f, 12, 1)) return (NOT_OK);
  244 
  245   /* Get size of bitmap header */
  246   if (!get (f, &s1)) return (NOT_OK);
  247   if (!get (f, &s2)) return (NOT_OK);
  248   if (!get (f, &s3)) return (NOT_OK);
  249   if (!get (f, &s4)) return (NOT_OK);
  250   l = (long) s4 * (long) 16777216 + (long) s3 *
  251       (long) 65536 + (long) s2 * (long) 256 + (long) s1;
  252 
  253   if (l <= 12)  /* old style BMP */
  254     {
  255       if (!get (f, &s1)) return (NOT_OK);
  256       if (!get (f, &s2)) return (NOT_OK);
  257       *widthP = (int) s2 * 256 + (int) s1;
  258       if (!get (f, &s1)) return (NOT_OK);
  259       if (!get (f, &s2)) return (NOT_OK);
  260       *heightP = (int) s2 * 256 + (int) s1;
  261     }
  262   else  /* new style BMP */
  263     {
  264       if (!get (f, &s1)) return (NOT_OK);
  265       if (!get (f, &s2)) return (NOT_OK);
  266       if (!get (f, &s3)) return (NOT_OK);
  267       if (!get (f, &s4)) return (NOT_OK);
  268       *widthP = (int) s4 * 16777216 + (int) s3 * 65536 + (int) s2 * 256 + (int) s1;
  269       if (!get (f, &s1)) return (NOT_OK);
  270       if (!get (f, &s2)) return (NOT_OK);
  271       if (!get (f, &s3)) return (NOT_OK);
  272       if (!get (f, &s4)) return (NOT_OK);
  273       *heightP = (int) s4 * 16777216 + (int) s3 * 65536 + (int) s2 * 256 + (int) s1;
  274     }
  275 
  276   /* Get bitmap depth */
  277   if (!get (f, &s1)) return (NOT_OK);
  278   if (!get (f, &s2)) return (NOT_OK);
  279   bp = (int) s2 * 256 + (int) s1;
  280   if (!get (f, &s1)) return (NOT_OK);
  281   if (!get (f, &s2)) return (NOT_OK);
  282   bpp = (int) s2 * 256 + (int) s1;
  283   *depth = bp * bpp;
  284 
  285   /* Indicate successful finish */
  286   return (OK);
  287 }
  288 
  289 
  290 static int
  291 jpeg (FILE *f, int *widthP, int *heightP, double *qual,
  292       int *depth, int *typenum, char *sampling)
  293 {
  294   int allones, coefindex, done, entrysize, l, length, *reftable,
  295     tableindex, val;
  296   double cumsf, x;
  297   unsigned char ch, l1, l2, w1, w2, h1, h2, ti, v1, v2, s1, s2, s3, dep, junk;
  298 
  299   /* JPEG blocks consist of a 0xff, a marker byte, a block size
  300      ** (two bytes, big-endian), and the rest of the block.  The
  301      ** block size includes itself - i.e. is the block size was 2 then
  302      ** there would be no additional bytes in the block.
  303      **
  304      ** So, what we do here is read blocks until we get an SOF0-SOF3 marker,
  305      ** and then extract the width and height from that.
  306    */
  307   done = 0x00;
  308   while (!feof (f))
  309     {
  310       if (!mustbe (f, (unsigned char) 0xff)) return (NOT_OK);
  311       if (!get (f, &ch)) return (NOT_OK);
  312       if (!get (f, &l1)) return (NOT_OK);
  313       if (!get (f, &l2)) return (NOT_OK);
  314       l = (int) l1 * 256 + (int) l2;
  315       /* Is it one of the blocks we're looking for? */
  316       switch (ch)
  317         {
  318         case M_SOF + 0:
  319         case M_SOF + 1:
  320         case M_SOF + 2:
  321         case M_SOF + 3:
  322           *typenum = (int) (ch - (unsigned char) M_SOF) + 1;
  323           /* Skip the sample precision. */
  324           if (!get (f, &junk)) return (NOT_OK);
  325           /* Read the height and width. */
  326           if (!get (f, &h1)) return (NOT_OK);
  327           if (!get (f, &h2)) return (NOT_OK);
  328           *heightP = (int) h1 * 256 + (int) h2;
  329           if (!get (f, &w1)) return (NOT_OK);
  330           if (!get (f, &w2)) return (NOT_OK);
  331           *widthP = (int) w1 * 256 + (int) w2;
  332           if (!get (f, &dep)) return (NOT_OK);
  333           /* Read the depth. */
  334           *depth = (int) dep * 8;
  335           /* Determine the sampling scheme */
  336           if ((int) dep == 1)
  337             {
  338               if (!get (f, &junk)) return (NOT_OK);  /* Skip the id. */
  339               if (!get (f, &s1)) return (NOT_OK);
  340               sampling[0] = (char) (s1 >> 4) + '0';
  341               sampling[1] = 'x';
  342               sampling[2] = (char) (s1 & 0x0f) + '0';
  343               sampling[3] = (char) 0;
  344               if (!get (f, &junk)) return (NOT_OK);  /* Skip the quantization table. */
  345               if (fseek (f, l - 11, 1)) return (NOT_OK);
  346             }
  347           else if ((int) dep == 3)
  348             {
  349               if (!get (f, &junk)) return (NOT_OK);  /* Skip the id. */
  350               if (!get (f, &s1)) return (NOT_OK);
  351               sampling[0] = (char) (s1 >> 4) + '0';
  352               sampling[1] = 'x';
  353               sampling[2] = (char) (s1 & 0x0f) + '0';
  354               sampling[3] = ',';
  355               if (!get (f, &junk)) return (NOT_OK);  /* Skip the quantization table. */
  356               if (!get (f, &junk)) return (NOT_OK);  /* Skip the id. */
  357               if (!get (f, &s2)) return (NOT_OK);
  358               sampling[4] = (char) (s2 >> 4) + '0';
  359               sampling[5] = 'x';
  360               sampling[6] = (char) (s2 & 0x0f) + '0';
  361               sampling[7] = ',';
  362               if (!get (f, &junk)) return (NOT_OK);  /* Skip the quantization table. */
  363               if (!get (f, &junk)) return (NOT_OK);  /* Skip the id. */
  364               if (!get (f, &s3)) return (NOT_OK);
  365               sampling[8] = (char) (s3 >> 4) + '0';
  366               sampling[9] = 'x';
  367               sampling[10] = (char) (s3 & 0x0f) + '0';
  368               sampling[11] = (char) 0;
  369               if (!get (f, &junk)) return (NOT_OK);  /* Skip the quantization table. */
  370               if (fseek (f, l - 17, 1)) return (NOT_OK);
  371             }
  372           else
  373             return (NOT_OK);
  374           done = done | 0x01;
  375           if (done == 3) return (OK);
  376           break;
  377         case M_DQT:
  378           length = l - 2;
  379           while (length > 0)
  380             {
  381               cumsf = 0.0;
  382               allones = 1;
  383               if (!get (f, &ti)) return (NOT_OK);
  384               length--;
  385               tableindex = (int) ti & 0x0f;
  386               entrysize = ((int) ti & 0xf0) >> 4;
  387               if (tableindex < 2)
  388                 {
  389                   reftable = deftabs[tableindex];
  390                   for (coefindex = 0; coefindex < 64; coefindex++)
  391                     {
  392                       if (entrysize == 1)
  393                         {
  394                           if (!get (f, &v1)) return (NOT_OK);
  395                           length--;
  396                           if (!get (f, &v2)) return (NOT_OK);
  397                           length--;
  398                           val = (int) v1 * 256 + (int) v2;
  399                         }
  400                       else if (entrysize == 0)
  401                         {
  402                           if (!get (f, &v1)) return (NOT_OK);
  403                           val = (int) v1;
  404                           length--;
  405                         }
  406                       else
  407                         return (NOT_OK);
  408                       /* scaling factor in percent */
  409                       x = 100.0 * (double) val / (double) reftable[coefindex];
  410                       cumsf += x;
  411                       /* separate check for all-ones table (Q = 100) */
  412                       if (val != 0x01)
  413                         allones = 0;
  414                     }
  415                   cumsf /= 64.0;                  /* mean scale factor */
  416                   if (allones)      /* special case for all-ones table */
  417                     qual[tableindex] = 100.0;
  418                   else if (cumsf <= 100.0)
  419                     qual[tableindex] = (200.0 - cumsf) / 2.0;
  420                   else
  421                     qual[tableindex] = 5000.0 / cumsf;
  422                 }
  423               else
  424                 if (fseek (f, length, 1)) return (NOT_OK);
  425             }
  426           done = done | 0x02;
  427           if (done == 3) return (OK);
  428           break;
  429         default:
  430           if (fseek (f, l - 2, 1)) return (NOT_OK);
  431           break;
  432         }
  433     }
  434   return (failure ("imagsize error: JPEG size not found"));
  435 }
  436 
  437 
  438 static int
  439 xbm (FILE *f, int *widthP, int *heightP)
  440 {
  441   char line[500], name_and_type[500];
  442 
  443   if (fgets (line, (int) sizeof (line), f) == NULL)
  444     return (failure ("imagsize error: XBM width not found"));
  445   if (sscanf (line, "efine %s %d", name_and_type, widthP) != 2)
  446     return (failure ("imagsize error: XBM bogus width"));
  447   if (fgets (line, (int) sizeof (line), f) == NULL)
  448     return (failure ("Ximagsize error: BM height not found"));
  449   if (sscanf (line, "#define %s %d", name_and_type, heightP) != 2)
  450     return (failure ("imagsize error: XBM bogus height"));
  451 
  452   /* indicate successful finish */
  453   return (OK);
  454 }
  455 
  456 
  457 static int
  458 xpm (FILE *f, int *widthP, int *heightP, int *depth)
  459 {
  460   char line[500];
  461   int colors, done, dummy, bits;
  462 
  463   /* Read rest of signature. */
  464   if (!mustbe (f, ' ')) return (NOT_OK);
  465   if (!mustbe (f, 'X')) return (NOT_OK);
  466   if (!mustbe (f, 'P')) return (NOT_OK);
  467   if (!mustbe (f, 'M')) return (NOT_OK);
  468   if (!mustbe (f, ' ')) return (NOT_OK);
  469   if (!mustbe (f, '*')) return (NOT_OK);
  470   if (!mustbe (f, '/')) return (NOT_OK);
  471 
  472   /* look for imagsize variable */
  473   done = 0;
  474   bits = 0;
  475   while ((done == 0) && (fgets (line, (int) sizeof (line), f) != NULL))
  476     if (sscanf (line, "\"%d %d %d %d\"", widthP, heightP, &colors, &dummy) == 4)
  477       {
  478         colors--;
  479         while (colors > 0)
  480           {
  481             bits++;
  482             colors /= 2;
  483           }
  484         *depth = bits;
  485         done = 1;
  486       }
  487 
  488   /* complain if not found */
  489   if (done == 0) {
  490     *widthP = *heightP = *depth = 0;
  491     return (failure ("imagsize error: XPM width and height not found"));
  492   }
  493 
  494   /* indicate successful finish */
  495   return (OK);
  496 }
  497 
  498 
  499 static int
  500 ppm (FILE *f, int *widthP, int *heightP)
  501 {
  502   char line[500];
  503   int done;
  504 
  505   /* look for imagsize variable */
  506   done = 0;
  507   while ((done == 0) && (fgets (line, (int) sizeof (line), f) != NULL))
  508     if (sscanf (line, "%d %d", widthP, heightP) == 2)
  509       done = 1;
  510 
  511   /* complain if not found */
  512   if (done == 0) {
  513     *widthP = *heightP = 0;
  514     return (failure ("imagsize error: PPM width and height not found"));
  515   }
  516 
  517   /* indicate successful finish */
  518   return (OK);
  519 }
  520 
  521 
  522 static int
  523 tiff_be (FILE *f, int *widthP, int *heightP, int *depth)
  524 {
  525   int bpp, count, done, i, num_dirent, offset, planes, tag, type, val;
  526   unsigned char w1, w2, w3, w4;
  527 
  528   /* Read rest of signature. */
  529   if (!mustbe (f, (unsigned char) 0x00)) return (NOT_OK);
  530   if (!mustbe (f, (unsigned char) 0x2a)) return (NOT_OK);
  531 
  532   /* Determine offset of IFD and go there */
  533   if (!get (f, &w1)) return (NOT_OK);
  534   if (!get (f, &w2)) return (NOT_OK);
  535   if (!get (f, &w3)) return (NOT_OK);
  536   if (!get (f, &w4)) return (NOT_OK);
  537   offset = (int) w1 * 16777216 + (int) w2 * 65536 + (int) w3 * 256 + (int) w4;
  538   if (fseek (f, offset, 0)) return (NOT_OK);
  539 
  540   /* Determine number of directory entries */
  541   if (!get (f, &w1)) return (NOT_OK);
  542   if (!get (f, &w2)) return (NOT_OK);
  543   num_dirent = (int) w1 * 256 + (int) w2;
  544 
  545   /* Parse through directory entries */
  546   done = 0;
  547   count = 0;
  548   bpp = 1;
  549   planes = 1;
  550   while ((done != 15) && (count < num_dirent))
  551     {
  552       if (!get (f, &w1)) return (NOT_OK);
  553       if (!get (f, &w2)) return (NOT_OK);
  554       tag = (int) w1 * 256 + (int) w2;
  555       if (!get (f, &w1)) return (NOT_OK);
  556       if (!get (f, &w2)) return (NOT_OK);
  557       type = (int) w1 * 256 + (int) w2;
  558       for (i = 0; i < 4; i++)
  559         if (!get (f, &w1)) return (NOT_OK);
  560       if ((type == 1) || (type == 6))
  561         {
  562           if (!get (f, &w1)) return (NOT_OK);
  563           if (!get (f, &w2)) return (NOT_OK);
  564           if (!get (f, &w3)) return (NOT_OK);
  565           if (!get (f, &w4)) return (NOT_OK);
  566           val = (int) w1;
  567         }
  568       else if ((type == 3) || (type == 8))
  569         {
  570           if (!get (f, &w1)) return (NOT_OK);
  571           if (!get (f, &w2)) return (NOT_OK);
  572           if (!get (f, &w3)) return (NOT_OK);
  573           if (!get (f, &w4)) return (NOT_OK);
  574           val = (int) w1 * 256 + (int) w2;
  575         }
  576       else if ((type == 4) || (type == 9))
  577         {
  578           if (!get (f, &w1)) return (NOT_OK);
  579           if (!get (f, &w2)) return (NOT_OK);
  580           if (!get (f, &w3)) return (NOT_OK);
  581           if (!get (f, &w4)) return (NOT_OK);
  582           val = (int) w1 * 16777216 + (int) w2 * 65536 + (int) w3 * 256 + (int) w4;
  583         }
  584       else
  585         val = 0;
  586       if (tag == 0x0100)
  587         {
  588           *widthP = val;
  589           done = done | 0x01;
  590         }
  591       else if (tag == 0x0101)
  592         {
  593           *heightP = val;
  594           done = done | 0x02;
  595         }
  596       else if (tag == 0x0102)
  597         {
  598           bpp = val;
  599           done = done | 0x04;
  600         }
  601       else if (tag == 0x0115)
  602         {
  603           planes = val;
  604           done = done | 0x08;
  605         }
  606       count++;
  607     }
  608   *depth = bpp * planes;
  609 
  610   /* indicate successful finish */
  611   return (OK);
  612 }
  613 
  614 
  615 static int
  616 tiff_le (FILE *f, int *widthP, int *heightP, int *depth)
  617 {
  618   int bpp, count, done, i, num_dirent, offset, planes, tag, type, val;
  619   unsigned char w1, w2, w3, w4;
  620 
  621   /* Read rest of signature. */
  622   if (!mustbe (f, (unsigned char) 0x2a)) return (NOT_OK);
  623   if (!mustbe (f, (unsigned char) 0x00)) return (NOT_OK);
  624 
  625   /* Determine offset of IFD and go there */
  626   if (!get (f, &w1)) return (NOT_OK);
  627   if (!get (f, &w2)) return (NOT_OK);
  628   if (!get (f, &w3)) return (NOT_OK);
  629   if (!get (f, &w4)) return (NOT_OK);
  630   offset = (int) w4 * 16777216 + (int) w3 * 65536 + (int) w2 * 256 + (int) w1;
  631   if (fseek (f, offset, 0)) return (NOT_OK);
  632 
  633   /* Determine number of directory entries */
  634   if (!get (f, &w1)) return (NOT_OK);
  635   if (!get (f, &w2)) return (NOT_OK);
  636   num_dirent = (int) w2 * 256 + (int) w1;
  637 
  638   /* Parse through directory entries */
  639   done = 0;
  640   count = 0;
  641   bpp = 1;
  642   planes = 1;
  643   while ((done != 15) && (count < num_dirent))
  644     {
  645       if (!get (f, &w1)) return (NOT_OK);
  646       if (!get (f, &w2)) return (NOT_OK);
  647       tag = (int) w2 * 256 + (int) w1;
  648       if (!get (f, &w1)) return (NOT_OK);
  649       if (!get (f, &w2)) return (NOT_OK);
  650       type = (int) w2 * 256 + (int) w1;
  651       for (i = 0; i < 4; i++)
  652         if (!get (f, &w1)) return (NOT_OK);
  653       if ((type == 1) || (type == 6))
  654         {
  655           if (!get (f, &w1)) return (NOT_OK);
  656           if (!get (f, &w2)) return (NOT_OK);
  657           if (!get (f, &w3)) return (NOT_OK);
  658           if (!get (f, &w4)) return (NOT_OK);
  659           val = (int) w1;
  660         }
  661       else if ((type == 3) || (type == 8))
  662         {
  663           if (!get (f, &w1)) return (NOT_OK);
  664           if (!get (f, &w2)) return (NOT_OK);
  665           if (!get (f, &w3)) return (NOT_OK);
  666           if (!get (f, &w4)) return (NOT_OK);
  667           val = (int) w2 * 256 + (int) w1;
  668         }
  669       else if ((type == 4) || (type == 9))
  670         {
  671           if (!get (f, &w1)) return (NOT_OK);
  672           if (!get (f, &w2)) return (NOT_OK);
  673           if (!get (f, &w3)) return (NOT_OK);
  674           if (!get (f, &w4)) return (NOT_OK);
  675           val = (int) w4 * 16777216 + (int) w3 * 65536 + (int) w2 * 256 + (int) w1;
  676         }
  677       else
  678         val = 0;
  679       if (tag == 0x0100)
  680         {
  681           *widthP = val;
  682           done = done | 0x01;
  683         }
  684       else if (tag == 0x0101)
  685         {
  686           *heightP = val;
  687           done = done | 0x02;
  688         }
  689       else if (tag == 0x0102)
  690         {
  691           bpp = val;
  692           done = done | 0x04;
  693         }
  694       else if (tag == 0x0115)
  695         {
  696           planes = val;
  697           done = done | 0x08;
  698         }
  699       count++;
  700     }
  701   *depth = bpp * planes;
  702 
  703   /* indicate successful finish */
  704   return (OK);
  705 }
  706 
  707 
  708 static int
  709 png (FILE *f, int *widthP, int *heightP, int *bpp, int *typenum)
  710 {
  711   unsigned char ch1, ch2, ch3, ch4, l1, l2, l3, l4,
  712        w1, w2, w3, w4, h1, h2, h3, h4, b1, t1;
  713   long l;
  714 
  715   /* Read rest of signature. */
  716   if (!mustbe (f, (unsigned char) 78)) return (NOT_OK);
  717   if (!mustbe (f, (unsigned char) 71)) return (NOT_OK);
  718   if (!mustbe (f, (unsigned char) 13)) return (NOT_OK);
  719   if (!mustbe (f, (unsigned char) 10)) return (NOT_OK);
  720   if (!mustbe (f, (unsigned char) 26)) return (NOT_OK);
  721   if (!mustbe (f, (unsigned char) 10)) return (NOT_OK);
  722 
  723   /* PNG chunks consist of a length, a chunk type, chunk data, and
  724      ** a CRC.  We read chunks until we get an IHDR chunk, and then
  725      ** extract the width and height from that.  Actually, the IHDR chunk
  726      ** is required to come first, but we might as well allow for
  727      ** broken encoders that don't obey that.
  728    */
  729   while (!feof (f))
  730     {
  731       if (!get (f, &l1)) return (NOT_OK);
  732       if (!get (f, &l2)) return (NOT_OK);
  733       if (!get (f, &l3)) return (NOT_OK);
  734       if (!get (f, &l4)) return (NOT_OK);
  735       l = (long) l1 * 16777216 + (long) l2 * 65536 + (long) l3 * 256 + (long) l4;
  736       if (!get (f, &ch1)) return (NOT_OK);
  737       if (!get (f, &ch2)) return (NOT_OK);
  738       if (!get (f, &ch3)) return (NOT_OK);
  739       if (!get (f, &ch4)) return (NOT_OK);
  740       /* Is it the chunk we're looking for? */
  741       if (ch1 == (unsigned char) 'I' && ch2 == (unsigned char) 'H' &&
  742           ch3 == (unsigned char) 'D' && ch4 == (unsigned char) 'R')
  743         {
  744           /* Read the height, width, bits per plane, and colortype. */
  745           if (!get (f, &w1)) return (NOT_OK);
  746           if (!get (f, &w2)) return (NOT_OK);
  747           if (!get (f, &w3)) return (NOT_OK);
  748           if (!get (f, &w4)) return (NOT_OK);
  749           *widthP = (int) w1 * 16777216 + (int) w2 * 65536 + (int) w3 * 256 + (int) w4;
  750           if (!get (f, &h1)) return (NOT_OK);
  751           if (!get (f, &h2)) return (NOT_OK);
  752           if (!get (f, &h3)) return (NOT_OK);
  753           if (!get (f, &h4)) return (NOT_OK);
  754           *heightP = (int) h1 * 16777216 + (int) h2 * 65536 + (int) h3 * 256 + (int) h4;
  755           if (!get (f, &b1)) return (NOT_OK);
  756           *bpp = (int) b1;
  757           if (!get (f, &t1)) return (NOT_OK);
  758           *typenum = (int) t1;
  759           return (OK);
  760         }
  761       /* Not the block we want.  Skip it. */
  762       if (fseek (f, l + 4, 1)) return (NOT_OK);
  763     }
  764   return (failure ("imagsize error: PNG size not found"));
  765 }
  766 
  767 
  768 static int
  769 image_size (FILE *f, int *widthP, int *heightP, double *qual,
  770             int *depth, char *type, char *sampling)
  771 {
  772   unsigned char ch1, ch2;
  773   int bpp, rc, typenum;
  774 
  775   *widthP = 0;
  776   *heightP = 0;
  777   qual[0] = 0.0;
  778   qual[1] = 0.0;
  779   *depth = 0;
  780   strcpy (type, "unknown");
  781   strcpy (sampling, "none");
  782 
  783   if (!get (f, &ch1)) return (NOT_OK);
  784   if (!get (f, &ch2)) return (NOT_OK);
  785   if (ch1 == (unsigned char) 'G' && ch2 == (unsigned char) 'I')
  786     {
  787       rc = gif (f, widthP, heightP, depth);
  788       strcpy (type, "gif");
  789       return (rc);
  790     }
  791   else if (ch1 == (unsigned char) 'B' && ch2 == (unsigned char) 'M')
  792     {
  793       rc = bmp (f, widthP, heightP, depth);
  794       if (*depth <= 16)
  795         strcpy (type, "bmp-pal");
  796       else
  797         strcpy (type, "bmp-rgb");
  798       return (rc);
  799     }
  800   else if (ch1 == (unsigned char) 0xff && ch2 == (unsigned char) M_SOI)
  801     {
  802       rc = jpeg (f, widthP, heightP, qual, depth, &typenum, sampling);
  803       if (typenum == 1)
  804         strcpy (type, "jpg-base");
  805       else if (typenum == 2)
  806         strcpy (type, "jpg-extended");
  807       else if (typenum == 3)
  808         strcpy (type, "jpg-prog");
  809       else if (typenum == 4)
  810         strcpy (type, "jpg-lossless");
  811       else
  812         strcpy (type, "jpg-unknown");
  813       return (rc);
  814     }
  815   else if (ch1 == (unsigned char) '#' && ch2 == (unsigned char) 'd')
  816     {
  817       rc = xbm (f, widthP, heightP);
  818       strcpy (type, "xbm");
  819       return (rc);
  820     }
  821   else if (ch1 == (unsigned char) '/' && ch2 == (unsigned char) '*')
  822     {
  823       rc = xpm (f, widthP, heightP, depth);
  824       strcpy (type, "xpm");
  825       return (rc);
  826     }
  827   else if (ch1 == (unsigned char) 137 && ch2 == (unsigned char) 80)
  828     {
  829       *depth = 0;
  830       rc = png (f, widthP, heightP, &bpp, &typenum);
  831       if (typenum == 0)
  832         {
  833           *depth = bpp;
  834           strcpy (type, "png-gray");
  835         }
  836       else if (typenum == 2)
  837         {
  838           *depth = 3 * bpp;
  839           strcpy (type, "png-rgb");
  840         }
  841       else if (typenum == 3)
  842         {
  843           *depth = bpp;
  844           strcpy (type, "png-pal");
  845         }
  846       else if (typenum == 4)
  847         {
  848           *depth = bpp;
  849           strcpy (type, "png-gray-alpha");
  850         }
  851       else if (typenum == 6)
  852         {
  853           *depth = 3 * bpp;
  854           strcpy (type, "png-rgb-alpha");
  855         }
  856       else
  857         strcpy (type, "png-unknown");
  858       return (rc);
  859     }
  860   else if ((ch1 == (unsigned char) 'P') &&
  861     (ch2 >= (unsigned char) '1') && (ch2 <= (unsigned char) '6'))
  862     {
  863       rc = ppm (f, widthP, heightP);
  864       if (ch2 == (unsigned char) '1')
  865         strcpy (type, "pbm-text");
  866       else if (ch2 == (unsigned char) '2')
  867         strcpy (type, "pgm-text");
  868       else if (ch2 == (unsigned char) '3')
  869         strcpy (type, "ppm-text");
  870       else if (ch2 == (unsigned char) '4')
  871         strcpy (type, "pbm-raw");
  872       else if (ch2 == (unsigned char) '5')
  873         strcpy (type, "pgm-raw");
  874       else if (ch2 == (unsigned char) '6')
  875         strcpy (type, "ppm-raw");
  876       return (rc);
  877     }
  878   else if (ch1 == (unsigned char) 'M' && ch2 == (unsigned char) 'M')
  879     {
  880       rc = tiff_be (f, widthP, heightP, depth);
  881       strcpy (type, "tiff-be");
  882       return (rc);
  883     }
  884   else if (ch1 == (unsigned char) 'I' && ch2 == (unsigned char) 'I')
  885     {
  886       rc = tiff_le (f, widthP, heightP, depth);
  887       strcpy (type, "tiff-le");
  888       return (rc);
  889     }
  890   else
  891     {
  892       strcpy (type, "unknown");
  893       return (failure ("imagsize warning: unknown image type"));
  894     }
  895 }
  896 
  897 
  898 static int
  899 print_size (char *filename, int format, int verbose)
  900 {
  901   FILE *f;
  902   char sampling[16], type[200];
  903   int ok, width, height, depth;
  904   double qual[2];
  905   off_t size;
  906   struct stat file_stats;
  907 
  908   if (stat (filename, &file_stats))
  909     {
  910       fprintf (stderr, "imagsize error: can't determine size of %s\n", filename);
  911       return (NOT_OK);
  912     }
  913   if (((file_stats.st_mode & S_IFDIR) == S_IFDIR) ||
  914       ((file_stats.st_mode & S_IFREG) != S_IFREG))
  915     {
  916       size = (off_t) 0;
  917       return (OK);
  918     }
  919   size = file_stats.st_size;
  920 
  921   f = fopen (filename, "rb");
  922   if (f == NULL)
  923     {
  924       perror (filename);
  925       return (NOT_OK);
  926     }
  927   ok = image_size (f, &width, &height, qual, &depth, type, sampling);
  928   (void) fclose (f);
  929 
  930   if (ok)
  931     {
  932       if (depth != 24)
  933         qual[1] = qual[0];
  934       if (verbose || (width > 0))
  935         {
  936           if (format == 0)
  937             fprintf (stdout, fmt0, filename, size, width, height, depth, qual[0],
  938               qual[1], sampling, type);
  939           else if (format == 1)
  940             fprintf (stdout, fmt1, filename, size, width, height, depth, qual[0],
  941               qual[1], sampling, type);
  942           else if (format == 2)
  943             fprintf (stdout, fmt2, filename, filename, width, height);
  944         }
  945     }
  946   else if (verbose)
  947     {
  948       if (format == 0)
  949         fprintf (stdout, fmt0a, filename, size, errstr);
  950       else if (format == 1)
  951         fprintf (stdout, fmt1a, filename, size, errstr);
  952       else if (format == 2)
  953         fprintf (stdout, fmt2a, filename, filename);
  954     }
  955 
  956   return (ok);
  957 }
  958 
  959 
  960 int
  961 main (int argc, char **argv)
  962 {
  963   FILE *infile;
  964   char filename[PATH_MAX], *listname, *newline, *rc;
  965   int allok, argn, format, ok, opt, use_file, use_pipe, verbose;
  966 
  967   /* parse options */
  968 
  969   format = 0;  /* 0 = full, 1 = X-window style, 2 = Web-page style */
  970   listname = "";
  971   verbose = 0;
  972   use_file = 0;
  973   use_pipe = 0;
  974   while ((opt = getopt (argc, argv, "f:hnpvwx")) != OPTEND)
  975     switch (opt)
  976       {
  977       case 'f':
  978         use_file = 1;
  979         listname = optarg;
  980         break;
  981       case 'h':
  982         help (stdout);
  983         return (0);
  984       case 'n':
  985         format = 0;
  986         break;
  987       case 'p':
  988         use_pipe = 1;
  989         break;
  990       case 'v':
  991         verbose = 1;
  992         break;
  993       case 'w':
  994         format = 2;
  995         break;
  996       case 'x':
  997         format = 1;
  998         break;
  999       case '?':
 1000         help (stderr);
 1001         return (1);
 1002       }
 1003   if ((optind == argc) && (use_file == 0) && (use_pipe == 0))
 1004     {
 1005       help (stdout);
 1006       return (0);
 1007     }
 1008   allok = 1;
 1009 
 1010   /* process files in listed in file specified by -f option */
 1011 
 1012   if (use_file)
 1013     {
 1014       infile = fopen (listname, "r");
 1015       if (infile == NULL)
 1016         fprintf (stderr, "imagsize error: can't open %s!\n", listname);
 1017       else
 1018         {
 1019           while (!feof (infile))
 1020             {
 1021               rc = fgets (filename, PATH_MAX - 1, infile);
 1022               if (rc != NULL)
 1023                 {
 1024                   newline = strchr (filename, '\n');
 1025                   if (newline != NULL)
 1026                     *newline = '\0';
 1027                   if (strlen (filename) != 0)
 1028                     {
 1029                       ok = print_size (filename, format, verbose);
 1030                       allok &= ok;
 1031                     }
 1032                 }
 1033             }
 1034           (void) fclose (infile);
 1035         }
 1036     }
 1037 
 1038   /* process files listed on stdin (i.e., the -p option) */
 1039 
 1040   if (use_pipe)
 1041     while (!feof (stdin))
 1042       {
 1043         rc = fgets (filename, PATH_MAX - 1, stdin);
 1044         if (rc != NULL)
 1045           {
 1046             newline = strchr (filename, '\n');
 1047             if (newline != NULL)
 1048               *newline = '\0';
 1049             if (strlen (filename) != 0)
 1050               {
 1051                 ok = print_size (filename, format, verbose);
 1052                 allok &= ok;
 1053               }
 1054           }
 1055       }
 1056 
 1057   /* process files given in the argument list */
 1058 
 1059   for (argn = optind; argn < argc; argn++)
 1060     {
 1061       ok = print_size (argv[argn], format, verbose);
 1062       allok &= ok;
 1063     }
 1064 
 1065   /* return final exit code */
 1066 
 1067   if (!allok)
 1068     return (1);
 1069   return (0);
 1070 }