home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / NETWORK / netpbm_src.lzh / NETPBM / PNM / sgitopnm.c < prev    next >
C/C++ Source or Header  |  1996-11-27  |  11KB  |  450 lines

  1. /* sgitopnm.c - read an SGI image and and produce a portable anymap
  2. **
  3. ** Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
  4. **
  5. ** Based on the SGI image description v0.9 by Paul Haeberli (paul@sgi.comp)
  6. ** Available via ftp from sgi.com:graphics/SGIIMAGESPEC
  7. **
  8. ** Permission to use, copy, modify, and distribute this software and its
  9. ** documentation for any purpose and without fee is hereby granted, provided
  10. ** that the above copyright notice appear in all copies and that both that
  11. ** copyright notice and this permission notice appear in supporting
  12. ** documentation.  This software is provided "as is" without express or
  13. ** implied warranty.
  14. **
  15. ** 29Jan94: first version
  16. ** 08Feb94: minor bugfix
  17. */
  18. #include "pnm.h"
  19. #include "sgi.h"
  20. #ifndef _OSK
  21. #ifndef VMS
  22. #include <unistd.h>
  23. #endif
  24. #endif
  25.  
  26. /*#define DEBUG*/
  27.  
  28. #ifndef SEEK_SET
  29. #define SEEK_SET    0
  30. #endif
  31.  
  32.  
  33. /* entry in RLE offset table */
  34. typedef struct {
  35.     long start;     /* offset in file */
  36.     long length;    /* length of compressed scanline */
  37. } TabEntry;
  38.  
  39. typedef short       ScanElem;
  40. typedef ScanElem *  ScanLine;
  41.  
  42. /* prototypes */
  43. static unsigned char get_byte ARGS(( FILE* f ));
  44. static long get_big_long ARGS((FILE *f));
  45. static short get_big_short ARGS((FILE *f));
  46. static short get_byte_as_short ARGS((FILE *f));
  47. static void readerr ARGS((FILE *f));
  48. static void * xmalloc ARGS((int bytes));
  49. #define MALLOC(n, type)     (type *)xmalloc((n) * sizeof(type))
  50. static char * compression_name ARGS((char compr));
  51. static void       read_bytes ARGS((FILE *ifp, int n, char *buf));
  52. static Header *   read_header ARGS((FILE *ifp));
  53. static TabEntry * read_table ARGS((FILE *ifp, int tablen));
  54. static ScanLine * read_channels ARGS((FILE *ifp, Header *head, TabEntry *table, short (*func) ARGS((FILE *)) ));
  55. static void       image_to_pnm ARGS((Header *head, ScanLine *image, xelval maxval));
  56. static void       rle_decompress ARGS((ScanElem *src, int srclen, ScanElem *dest, int destlen));
  57.  
  58. #define WORSTCOMPR(x)   (2*(x) + 2)
  59.  
  60.  
  61. static short verbose = 0;
  62.  
  63.  
  64. int
  65. main(argc, argv)
  66.     int argc;
  67.     char *argv[];
  68. {
  69.     FILE *ifp;
  70.     int argn;
  71.     char *usage = "[-verbose] [sgifile]";
  72.     TabEntry *table = NULL;
  73.     ScanLine *image;
  74.     Header *head;
  75.     long maxval;
  76.  
  77.     pnm_init(&argc, argv);
  78.  
  79.     argn = 1;
  80.     while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
  81.         if( pm_keymatch(argv[argn], "-verbose", 2) )
  82.             verbose++;
  83.         else
  84.         if( pm_keymatch(argv[argn], "-noverbose", 4) )
  85.             verbose = 0;
  86.         else
  87.             pm_usage(usage);
  88.         ++argn;
  89.     }
  90.  
  91.     if( argn < argc ) {
  92.         ifp = pm_openr( argv[argn] );
  93.         argn++;
  94.     }
  95.     else
  96.         ifp = stdin;
  97.  
  98.     if( argn != argc )
  99.         pm_usage(usage);
  100.  
  101.     head = read_header(ifp);
  102.     maxval = head->pixmax - head->pixmin;
  103.     if( maxval > PNM_MAXMAXVAL )
  104.         pm_error("pixel values too large - try reconfiguring with PGM_BIGGRAYS\n    or without PPM_PACKCOLORS");
  105.  
  106.     if( head->storage != STORAGE_VERBATIM )
  107.         table = read_table(ifp, head->ysize * head->zsize);
  108.     if( head->bpc == 1 )
  109.         image = read_channels(ifp, head, table, get_byte_as_short);
  110.     else
  111.         image = read_channels(ifp, head, table, get_big_short);
  112.  
  113.     image_to_pnm(head, image, (xelval)maxval);
  114.     pm_close(ifp);
  115.  
  116.     exit(0);
  117. }
  118.  
  119.  
  120. static Header *
  121. read_header(ifp)
  122.     FILE *ifp;
  123. {
  124.     Header *head;
  125.  
  126.     head = MALLOC(1, Header);
  127.  
  128.     head->magic     = get_big_short(ifp);
  129.     head->storage   = get_byte(ifp);
  130.     head->bpc       = get_byte(ifp);
  131.     head->dimension = get_big_short(ifp);
  132.     head->xsize     = get_big_short(ifp);
  133.     head->ysize     = get_big_short(ifp);
  134.     head->zsize     = get_big_short(ifp);
  135.     head->pixmin    = get_big_long(ifp);
  136.     head->pixmax    = get_big_long(ifp);
  137.     read_bytes(ifp, 4, head->dummy1);
  138.     read_bytes(ifp, 80, head->name);
  139.     head->colormap  = get_big_long(ifp);
  140.     read_bytes(ifp, 404, head->dummy2);
  141.  
  142.     if( head->magic != SGI_MAGIC )
  143.         pm_error("bad magic number - not an SGI image");
  144.     if( head->storage < 0 || head->storage > 1 )
  145.         pm_error("unknown compression type");
  146.     if( head->bpc < 1 || head->bpc > 2 )
  147.         pm_error("illegal precision value %d (only 1-2 allowed)", head->bpc );
  148.     if( head->colormap != CMAP_NORMAL )
  149.         pm_error("unsupported non-normal pixel data");
  150.  
  151.     /* adjust ysize/zsize to dimension, just to be sure */
  152.     switch( head->dimension ) {
  153.         case 1:
  154.             head->ysize = 1;
  155.             break;
  156.         case 2:
  157.             head->zsize = 1;
  158.             break;
  159.         case 3:
  160.             switch( head->zsize ) {
  161.                 case 1:
  162.                     head->dimension = 2;
  163.                     break;
  164.                 case 2:
  165.                     pm_error("don\'t know how to interpret 2-channel image");
  166.                     break;
  167.                 case 3:
  168.                     break;
  169.                 default:
  170.                     pm_message("%d-channel image, using only first 3 channels", head->zsize);
  171.                     head->zsize = 3;
  172.                     break;
  173.             }
  174.             break;
  175.         default:
  176.             pm_error("illegal dimension value %d (only 1-3 allowed)", head->dimension);
  177.     }
  178.  
  179.     if( verbose ) {
  180.         pm_message("raster size %dx%d, %d channels", head->xsize, head->ysize, head->zsize);
  181.         pm_message("compression: %d = %s", head->storage, compression_name(head->storage));
  182.         head->name[79] = '\0';  /* just to be safe */
  183.         pm_message("Image name: \"%s\"", head->name);
  184. #ifdef DEBUG
  185.         pm_message("bpc: %d    dimension: %d    zsize: %d", head->bpc, head->dimension, head->zsize);
  186.         pm_message("pixmin: %ld    pixmax: %ld    colormap: %ld", head->pixmin, head->pixmax, head->colormap);
  187. #endif
  188.     }
  189.  
  190.     return head;
  191. }
  192.  
  193.  
  194. static TabEntry *
  195. read_table(ifp, tablen)
  196.     FILE *ifp;
  197.     int tablen;
  198. {
  199.     TabEntry *table;
  200.     int i;
  201.  
  202.     table = MALLOC(tablen, TabEntry);
  203.  
  204. #ifdef DEBUG
  205.     pm_message("reading offset table");
  206. #endif
  207.  
  208.     for( i = 0; i < tablen; i++ )
  209.         table[i].start = get_big_long(ifp);
  210.     for( i = 0; i < tablen; i++ )
  211.         table[i].length = get_big_long(ifp);
  212.  
  213.     return table;
  214. }
  215.  
  216.  
  217.  
  218. static ScanLine *
  219. read_channels(ifp, head, table, func)
  220.     FILE *ifp;
  221.     Header *head;
  222.     TabEntry *table;
  223.     short (*func) ARGS((FILE *));
  224. {
  225.     ScanLine *image;
  226.     ScanElem *temp;
  227.     int channel, maxchannel, row, sgi_index, i;
  228.     long offset, length;
  229.  
  230. #ifdef DEBUG
  231.     pm_message("reading channels");
  232. #endif
  233.  
  234.     maxchannel = head->zsize;
  235.     image = MALLOC(head->ysize * maxchannel, ScanLine);
  236.     if( table ) temp = MALLOC(WORSTCOMPR(head->xsize), ScanElem);
  237.  
  238.     for( channel = 0; channel < maxchannel;  channel++ ) {
  239. #ifdef DEBUG
  240.         pm_message("    channel %d", channel);
  241. #endif
  242.         for( row = 0; row < head->ysize; row++ ) {
  243.             sgi_index = channel * head->ysize + row;
  244.             image[sgi_index] = MALLOC(head->xsize, ScanElem);
  245.             if( table ) {
  246.                 offset = table[sgi_index].start;
  247.                 length = table[sgi_index].length;
  248.                 if( head->bpc == 2 )
  249.                     length /= 2;   /* doc says length is in bytes, we are reading words */
  250.                 if( fseek(ifp, offset, SEEK_SET) != 0 )
  251.                     pm_error("seek error for offset %ld", offset);
  252.  
  253.                 for( i = 0; i < length; i++ )
  254.                     temp[i] = (*func)(ifp);
  255.                 rle_decompress(temp, length, image[sgi_index], head->xsize);
  256.             }
  257.             else {
  258.                 for( i = 0; i < head->xsize; i++ )
  259.                     image[sgi_index][i] = (*func)(ifp);
  260.             }
  261.         }
  262.     }
  263.  
  264.     if( table ) free(temp);
  265.     return image;
  266. }
  267.  
  268.  
  269. static void
  270. image_to_pnm(head, image, maxval)
  271.     Header *head;
  272.     ScanLine *image;
  273.     xelval maxval;
  274. {
  275.     int col, row, format;
  276.     xel *pnmrow = pnm_allocrow(head->xsize);
  277.     int sub = head->pixmin;
  278.  
  279.     if( head->zsize == 1 ) {
  280.         pm_message("writing PGM image");
  281.         format = PGM_TYPE;
  282.     }
  283.     else {
  284.         pm_message("writing PPM image");
  285.         format = PPM_TYPE;
  286.     }
  287.  
  288.     pnm_writepnminit(stdout, head->xsize, head->ysize, (xelval)maxval, format, 0);
  289.     for( row = head->ysize-1; row >= 0; row-- ) {
  290.         for( col = 0; col < head->xsize; col++ ) {
  291.             if( format == PGM_TYPE )
  292.                 PNM_ASSIGN1(pnmrow[col], image[row][col] - sub);
  293.             else {
  294.                 pixval r, g, b;
  295.                 r = image[row][col] - sub;
  296.                 g = image[head->ysize + row][col] - sub;
  297.                 b = image[2* head->ysize + row][col] - sub;
  298.                 PPM_ASSIGN(pnmrow[col], r, g, b);
  299.             }
  300.         }
  301.         pnm_writepnmrow(stdout, pnmrow, head->xsize, (xelval)maxval, format, 0);
  302.     }
  303.     pnm_freerow(pnmrow);
  304. }
  305.  
  306.  
  307. static void
  308. rle_decompress(src, srcleft, dest, destleft)
  309.     ScanElem *src;
  310.     int srcleft;
  311.     ScanElem *dest;
  312.     int destleft;
  313. {
  314.     int count;
  315.     unsigned char el;
  316.  
  317.     while( srcleft ) {
  318.         el = (unsigned char)(*src++ & 0xff);
  319.         --srcleft;
  320.         count = (int)(el & 0x7f);
  321.  
  322.         if( count == 0 )
  323.             return;
  324.         if( destleft < count )
  325.             pm_error("RLE error: too much input data (space left %d, need %d)", destleft, count);
  326.         destleft -= count;
  327.         if( el & 0x80 ) {
  328.             if( srcleft < count )
  329.                 pm_error("RLE error: not enough data for literal run (data left %d, need %d)", srcleft, count);
  330.             srcleft -= count;
  331.             while( count-- )
  332.                 *dest++ = *src++;
  333.         }
  334.         else {
  335.             if( srcleft == 0 )
  336.                 pm_error("RLE error: not enough data for replicate run");
  337.             while( count-- )
  338.                 *dest++ = *src;
  339.             ++src;
  340.             --srcleft;
  341.         }
  342.     }
  343.     pm_error("RLE error: no terminating 0-byte");
  344. }
  345.  
  346.  
  347. /* basic I/O functions, taken from ilbmtoppm.c */
  348.  
  349. static short
  350. get_big_short(ifp)
  351.     FILE *ifp;
  352. {
  353.     short s;
  354.  
  355.     if( pm_readbigshort(ifp, &s) == -1 )
  356.         readerr(ifp);
  357.  
  358.     return s;
  359. }
  360.  
  361. static long
  362. get_big_long(ifp)
  363.     FILE *ifp;
  364. {
  365.     long l;
  366.  
  367.     if( pm_readbiglong(ifp, &l) == -1 )
  368.         readerr(ifp);
  369.  
  370.     return l;
  371. }
  372.  
  373. static unsigned char
  374. get_byte(ifp)
  375.     FILE* ifp;
  376. {
  377.     int i;
  378.  
  379.     i = getc(ifp);
  380.     if( i == EOF )
  381.         readerr(ifp);
  382.  
  383.     return (unsigned char) i;
  384. }
  385.  
  386.  
  387. static void
  388. readerr(f)
  389.     FILE *f;
  390. {
  391.     if( ferror(f) )
  392.         pm_error("read error");
  393.     else
  394.         pm_error("premature EOF");
  395. }
  396.  
  397.  
  398. static void
  399. read_bytes(ifp, n, buf)
  400.     FILE *ifp;
  401.     int n;
  402.     char *buf;
  403. {
  404.     int r;
  405.  
  406.     r = fread((void *)buf, 1, n, ifp);
  407.     if( r != n )
  408.         readerr(ifp);
  409. }
  410.  
  411.  
  412. static short
  413. get_byte_as_short(ifp)
  414.     FILE *ifp;
  415. {
  416.     return (short)get_byte(ifp);
  417. }
  418.  
  419.  
  420. static void *
  421. xmalloc(bytes)
  422.     int bytes;
  423. {
  424.     void *mem;
  425.  
  426.     if( bytes == 0 )
  427.         return NULL;
  428.  
  429.     mem = malloc(bytes);
  430.     if( mem == NULL )
  431.         pm_error("out of memory allocating %d bytes", bytes);
  432.     return mem;
  433. }
  434.  
  435.  
  436. static char *
  437. compression_name(compr)
  438.     char compr;
  439. {
  440.     switch( compr ) {
  441.         case STORAGE_VERBATIM:
  442.             return "none";
  443.         case STORAGE_RLE:
  444.             return "RLE";
  445.         default:
  446.             return "unknown";
  447.     }
  448. }
  449.  
  450.