home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / netpbma.zip / pnm / pnmtosgi.c < prev    next >
C/C++ Source or Header  |  1994-01-28  |  10KB  |  371 lines

  1. /* pnmtosgi.c - convert portable anymap to SGI image
  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. */
  17. #include "pnm.h"
  18. #include "sgi.h"
  19.  
  20. /*#define DEBUG*/
  21.  
  22. typedef short       ScanElem;
  23. typedef struct {
  24.     ScanElem *  data;
  25.     long        length;
  26. } ScanLine;
  27.  
  28. /* prototypes */
  29. static void put_big_short ARGS((short s));
  30. static void put_big_long ARGS((long l));
  31. #define put_byte(b)     (void)(putc((unsigned char)(b), stdout))
  32. static void put_short_as_byte ARGS((short s));
  33. static void write_header ARGS((int cols, int rows, xelval maxval, int bpc, int dimensions, int channels, char *imagename));
  34. static void write_table  ARGS((long *table, int tabsize));
  35. static void write_channels ARGS((int cols, int rows, int channels, void (*put) ARGS((short)) ));
  36. static long * build_channels ARGS((FILE *ifp, int cols, int rows, xelval maxval, int format, int bpc, int channels));
  37. static ScanElem *compress ARGS((ScanElem *temp, int row, int rows, int cols, int chan_no, long *table, int bpc));
  38. static int rle_compress ARGS((ScanElem *inbuf, int cols));
  39. static void * xmalloc ARGS((int bytes));
  40. #define MALLOC(n, type)     (type *)xmalloc((n) * sizeof(type))
  41.  
  42. #define WORSTCOMPR(x)   (2*(x) + 2)
  43.  
  44.  
  45. #define MAXVAL_BYTE     255
  46. #define MAXVAL_WORD     65535
  47.  
  48. static char storage = STORAGE_RLE;
  49. static ScanLine * channel[3];
  50. static ScanElem * rletemp;
  51. static xel * pnmrow;
  52.  
  53.  
  54. int
  55. main(argc, argv)
  56.     int argc;
  57.     char *argv[];
  58. {
  59.     FILE *ifp;
  60.     int argn;
  61.     char *usage = "[-verbatim|-rle] [-imagename <name>] [pnmfile]";
  62.     int cols, rows, format;
  63.     xelval maxval;
  64.     char *imagename = "no name";
  65.     int bpc, dimensions, channels;
  66.     long *table = NULL;
  67.  
  68.     pnm_init(&argc, argv);
  69.  
  70.     argn = 1;
  71.     while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
  72.         if( pm_keymatch(argv[argn], "-verbatim", 2) )
  73.             storage = STORAGE_VERBATIM;
  74.         else
  75.         if( pm_keymatch(argv[argn], "-rle", 2) )
  76.             storage = STORAGE_RLE;
  77.         else
  78.         if( pm_keymatch(argv[argn], "-imagename", 2) ) {
  79.             if( ++argn >= argc )
  80.                 pm_usage(usage);
  81.             imagename = argv[argn];
  82.         }
  83.         else
  84.             pm_usage(usage);
  85.         ++argn;
  86.     }
  87.  
  88.     if( argn < argc ) {
  89.         ifp = pm_openr( argv[argn] );
  90.         argn++;
  91.     }
  92.     else
  93.         ifp = stdin;
  94.  
  95.     if( argn != argc )
  96.         pm_usage(usage);
  97.  
  98.     pnm_pbmmaxval = PNM_MAXMAXVAL;  /* use larger value for better results */
  99.     pnm_readpnminit(ifp, &cols, &rows, &maxval, &format);
  100.     pnmrow = pnm_allocrow(cols);
  101.  
  102.     switch( PNM_FORMAT_TYPE(format) ) {
  103.         case PBM_TYPE:
  104.             pm_message("promoting PBM to PGM");
  105.         case PGM_TYPE:
  106.             dimensions = 2; channels = 1;
  107.             break;
  108.         case PPM_TYPE:
  109.             dimensions = 3; channels = 3;
  110.             break;
  111.         default:
  112.             pm_error("can\'t happen");
  113.     }
  114.     if( maxval <= MAXVAL_BYTE )
  115.         bpc = 1;
  116.     else if( maxval <= MAXVAL_WORD )
  117.         bpc = 2;
  118.     else
  119.         pm_error("maxval too large - try using \"pnmdepth %d\"", MAXVAL_WORD);
  120.  
  121.     table = build_channels(ifp, cols, rows, maxval, format, bpc, channels);
  122.     pnm_freerow(pnmrow);
  123.     pm_close(ifp);
  124.  
  125.     write_header(cols, rows, maxval, bpc, dimensions, channels, imagename);
  126.     if( table )
  127.         write_table(table, rows * channels);
  128.     if( bpc == 1 )
  129.         write_channels(cols, rows, channels, put_short_as_byte);
  130.     else
  131.         write_channels(cols, rows, channels, put_big_short);
  132.  
  133.     exit(0);
  134. }
  135.  
  136.  
  137. static void
  138. write_header(cols, rows, maxval, bpc, dimensions, channels, imagename)
  139.     int cols, rows;
  140.     xelval maxval;
  141.     int bpc, dimensions, channels;
  142.     char *imagename;
  143. {
  144.     int i;
  145.  
  146. #ifdef DEBUG
  147.     pm_message("writing header");
  148. #endif
  149.  
  150.     put_big_short(SGI_MAGIC);
  151.     put_byte(storage);
  152.     put_byte((char)bpc);
  153.     put_big_short(dimensions);
  154.     put_big_short(cols);
  155.     put_big_short(rows);
  156.     put_big_short(channels);
  157.     put_big_long(0);                /* PIXMIN */
  158.     put_big_long(maxval);           /* PIXMAX */
  159.     for( i = 0; i < 4; i++ )
  160.         put_byte(0);
  161.     for( i = 0; i < 79 && imagename[i] != '\0'; i++ )
  162.         put_byte(imagename[i]);
  163.     for(; i < 80; i++ )
  164.         put_byte(0);
  165.     put_big_long(CMAP_NORMAL);
  166.     for( i = 0; i < 404; i++ )
  167.         put_byte(0);
  168. }
  169.  
  170.  
  171. static void
  172. write_table(table, tabsize)
  173.     long *table;
  174.     int tabsize;
  175. {
  176.     int i;
  177.     long offset;
  178.  
  179. #ifdef DEBUG
  180.     pm_message("writing table");
  181. #endif
  182.  
  183.     offset = HeaderSize + tabsize * 8;
  184.     for( i = 0; i < tabsize; i++ ) {
  185.         put_big_long(offset);
  186.         offset += table[i];
  187.     }
  188.     for( i = 0; i < tabsize; i++ )
  189.         put_big_long(table[i]);
  190. }
  191.  
  192.  
  193. static void
  194. write_channels(cols, rows, channels, put)
  195.     int cols, rows, channels;
  196.     void (*put) ARGS((short));
  197. {
  198.     int i, row, col;
  199.  
  200. #ifdef DEBUG
  201.     pm_message("writing image data");
  202. #endif
  203.  
  204.     for( i = 0; i < channels; i++ ) {
  205.         for( row = 0; row < rows; row++ ) {
  206.             for( col = 0; col < channel[i][row].length; col++ ) {
  207.                 (*put)(channel[i][row].data[col]);
  208.             }
  209.         }
  210.     }
  211. }
  212.  
  213. static void *
  214. xmalloc(bytes)
  215.     int bytes;
  216. {
  217.     void *mem;
  218.  
  219.     if( bytes == 0 )
  220.         return NULL;
  221.  
  222.     mem = malloc(bytes);
  223.     if( mem == NULL )
  224.         pm_error("out of memory allocating %d bytes", bytes);
  225.     return mem;
  226. }
  227.  
  228. static void
  229. put_big_short(s)
  230.     short s;
  231. {
  232.     if ( pm_writebigshort( stdout, s ) == -1 )
  233.         pm_error( "write error" );
  234. }
  235.  
  236.  
  237. static void
  238. put_big_long(l)
  239.     long l;
  240. {
  241.     if ( pm_writebiglong( stdout, l ) == -1 )
  242.         pm_error( "write error" );
  243. }
  244.  
  245.  
  246. static void
  247. put_short_as_byte(s)
  248.     short s;
  249. {
  250.     put_byte((unsigned char)s);
  251. }
  252.  
  253.  
  254. static long *
  255. build_channels(ifp, cols, rows, maxval, format, bpc, channels)
  256.     FILE *ifp;
  257.     int cols, rows;
  258.     xelval maxval;
  259.     int format, bpc, channels;
  260. {
  261.     int i, row, col, sgirow;
  262.     long *table = NULL;
  263.     ScanElem *temp;
  264.  
  265. #ifdef DEBUG
  266.     pm_message("building channels");
  267. #endif
  268.  
  269.     if( storage != STORAGE_VERBATIM ) {
  270.         table = MALLOC(channels * rows, long);
  271.         rletemp = MALLOC(WORSTCOMPR(cols), ScanElem);
  272.     }
  273.     temp = MALLOC(cols, ScanElem);
  274.  
  275.     for( i = 0; i < channels; i++ )
  276.         channel[i] = MALLOC(rows, ScanLine);
  277.  
  278.     for( row = 0, sgirow = rows-1; row < rows; row++, sgirow-- ) {
  279.         pnm_readpnmrow(ifp, pnmrow, cols, maxval, format);
  280.         if( channels == 1 ) {
  281.             for( col = 0; col < cols; col++ )
  282.                 temp[col] = (ScanElem)PNM_GET1(pnmrow[col]);
  283.             temp = compress(temp, sgirow, rows, cols, 0, table, bpc);
  284.         }
  285.         else {
  286.             for( col = 0; col < cols; col++ )
  287.                 temp[col] = (ScanElem)PPM_GETR(pnmrow[col]);
  288.             temp = compress(temp, sgirow, rows, cols, 0, table, bpc);
  289.             for( col = 0; col < cols; col++ )
  290.                 temp[col] = (ScanElem)PPM_GETG(pnmrow[col]);
  291.             temp = compress(temp, sgirow, rows, cols, 1, table, bpc);
  292.             for( col = 0; col < cols; col++ )
  293.                 temp[col] = (ScanElem)PPM_GETB(pnmrow[col]);
  294.             temp = compress(temp, sgirow, rows, cols, 2, table, bpc);
  295.         }
  296.     }
  297.  
  298.     free(temp);
  299.     if( table )
  300.         free(rletemp);
  301.     return table;
  302. }
  303.  
  304.  
  305. static ScanElem *
  306. compress(temp, row, rows, cols, chan_no, table, bpc)
  307.     ScanElem *temp;
  308.     int row, rows, cols, chan_no;
  309.     long *table;
  310.     int bpc;
  311. {
  312.     int len, i, tabrow;
  313.     ScanElem *p;
  314.  
  315.     switch( storage ) {
  316.         case STORAGE_VERBATIM:
  317.             channel[chan_no][row].length = cols;
  318.             channel[chan_no][row].data = temp;
  319.             temp = MALLOC(cols, ScanElem);
  320.             break;
  321.         case STORAGE_RLE:
  322.             tabrow = chan_no * rows + row;
  323.             len = rle_compress(temp, cols);     /* writes result into rletemp */
  324.             channel[chan_no][row].length = len;
  325.             channel[chan_no][row].data = p = MALLOC(len, ScanElem);
  326.             for( i = 0; i < len; i++, p++ )
  327.                 *p = rletemp[i];
  328.             table[tabrow] = len * bpc;
  329.             break;
  330.         default:
  331.             pm_error("unknown storage type - can\'t happen");
  332.     }
  333.     return temp;
  334. }
  335.  
  336.  
  337. /*
  338. slightly modified RLE algorithm from ppmtoilbm.c
  339. written by Robert A. Knop (rknop@mop.caltech.edu)
  340. */
  341. static int
  342. rle_compress(inbuf, size)
  343.     ScanElem *inbuf;
  344.     int size;
  345. {
  346.     int in, out, hold, count;
  347.     ScanElem *outbuf = rletemp;
  348.  
  349.     in=out=0;
  350.     while( in<size ) {
  351.         if( (in<size-1) && (inbuf[in]==inbuf[in+1]) ) {     /*Begin replicate run*/
  352.             for( count=0,hold=in; in<size && inbuf[in]==inbuf[hold] && count<127; in++,count++)
  353.                 ;
  354.             outbuf[out++]=(ScanElem)(count);
  355.             outbuf[out++]=inbuf[hold];
  356.         }
  357.         else {  /*Do a literal run*/
  358.             hold=out; out++; count=0;
  359.             while( ((in>=size-2)&&(in<size)) || ((in<size-2) && ((inbuf[in]!=inbuf[in+1])||(inbuf[in]!=inbuf[in+2]))) ) {
  360.                 outbuf[out++]=inbuf[in++];
  361.                 if( ++count>=127 )
  362.                     break;
  363.             }
  364.             outbuf[hold]=(ScanElem)(count | 0x80);
  365.         }
  366.     }
  367.     outbuf[out++] = (ScanElem)0;     /* terminator */
  368.     return(out);
  369. }
  370.  
  371.