"Fossies" - the Fresh Open Source Software Archive

Member "littleutils-1.2.5/imageutils/imagsize.c" (29 Oct 2021, 33053 Bytes) of package /linux/privat/littleutils-1.2.5.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 and the latest Fossies "Diffs" side-by-side code changes report: 1.2.4_vs_1.2.5.

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