home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / grafix / netpbm / rletopnm.lha / src / rletopnm.c < prev   
Encoding:
C/C++ Source or Header  |  1994-12-11  |  13.1 KB  |  482 lines

  1. /* rletopnm.c - convert Utah Raster Toolkit image to portable anymap
  2. **
  3. ** Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
  4. **
  5. ** Permission to use, copy, modify, and distribute this software and its
  6. ** documentation for any purpose and without fee is hereby granted, provided
  7. ** that the above copyright notice appear in all copies and that both that
  8. ** copyright notice and this permission notice appear in supporting
  9. ** documentation.  This software is provided "as is" without express or
  10. ** implied warranty.
  11. **
  12. ** 09/Dec/94: first version
  13. */
  14. #include "pnm.h"
  15. #include "rle.h"
  16.  
  17. /*#define DEBUG*/
  18.  
  19. /* prototypes */
  20. static Header * read_header ARGS((FILE *ifp));
  21. static xel **   read_rle_image ARGS((FILE *ifp, Header *hdr));
  22. static int  do_bytedata ARGS((FILE *ifp, Header *hdr, xel *imagerow, int col, long nbytes, int channel));
  23. static int  do_rundata  ARGS((FILE *ifp, Header *hdr, xel *imagerow, int col, long nbytes, int channel));
  24. static void readerr ARGS((FILE *fp));
  25. static unsigned short   get_short ARGS((FILE *ifp));
  26. static unsigned char    get_byte  ARGS((FILE *ifp));
  27. static void skip_bytes ARGS((FILE *ifp, long nbytes));
  28. static void *   xmalloc ARGS((int bytes));
  29. #define MALLOC(n, type)     ((type *)xmalloc((n) * sizeof(type)))
  30. #define plural(x)   ((x) == 1 ? "" : "s")
  31.  
  32. static int mode;
  33. #define MODE_COLORMAP       0       /* colormap file (0 channels) */
  34. #define MODE_GRAYSCALE      1       /* 1 channel, no colormap */
  35. #define MODE_PSEUDOCOLOR    2       /* 1 channel with colormap */
  36. #define MODE_TRUECOLOR      3       /* 3 channels with colormap */
  37. #define MODE_DIRECTCOLOR    4       /* 3 channels, no colormap */
  38.  
  39. static xel bg_xel;
  40.  
  41. static short verbose = 0;
  42. static pixel *colormap = (pixel *)NULL;
  43. static long colors = 0;
  44.  
  45. int
  46. main(argc, argv)
  47.     int argc;
  48.     char *argv[];
  49. {
  50.     Header *hdr;
  51.     FILE *ifp;
  52.     xel **image;
  53.     xelval maxval;
  54.     int argn, format;
  55.     char *usage = "[-verbose] [rlefile]";
  56.  
  57.     pnm_init(&argc, argv);
  58.  
  59.     argn = 1;
  60.     while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
  61.         if( pm_keymatch(argv[argn], "-verbose", 2) )
  62.             verbose++;
  63.         else
  64.         if( pm_keymatch(argv[argn], "-noverbose", 4) )
  65.             verbose = 0;
  66.         else
  67.             pm_usage(usage);
  68.         ++argn;
  69.     }
  70.     if( argn < argc ) {
  71.         ifp = pm_openr( argv[argn] );
  72.         argn++;
  73.     }
  74.     else
  75.         ifp = stdin;
  76.     if( argn != argc )
  77.         pm_usage(usage);
  78.  
  79.     hdr = read_header(ifp);
  80.     maxval = pm_bitstomaxval(hdr->pixelbits);
  81.     if( mode != MODE_COLORMAP ) {
  82.         image = read_rle_image(ifp, hdr);
  83.  
  84.         if( mode == MODE_GRAYSCALE ) {
  85.             if( hdr->pixelbits == 1 ) {
  86.                 pm_message("writing PBM image");
  87.                 format = PBM_TYPE;
  88.             }
  89.             else {
  90.                 pm_message("writing PGM image");
  91.                 format = PGM_TYPE;
  92.             }
  93.         }
  94.         else {
  95.             pm_message("writing PPM image");
  96.             format = PPM_TYPE;
  97.         }
  98.         pnm_writepnm(stdout, image, hdr->xsize, hdr->ysize, maxval, format, 0);
  99.     }
  100.     else {
  101.         pm_message("writing colormap file (PPM P3 ASCII)");
  102.         ppm_writeppminit(stdout, colors, 1, maxval, 1);
  103.         ppm_writeppmrow(stdout, colormap, colors, maxval, 1);
  104.     }
  105.     pm_close(ifp);
  106.     exit(0);
  107. }
  108.  
  109.  
  110. static Header *
  111. read_header(ifp)
  112.     FILE *ifp;
  113. {
  114.     Header *hdr = MALLOC(1, Header);
  115.  
  116.     hdr->magic = get_short(ifp);
  117.     if( hdr->magic != RLE_MAGIC )
  118.         pm_error("bad magic number - not an Utah Raster file");
  119.  
  120.     hdr->xpos       = get_short(ifp);
  121.     hdr->ypos       = get_short(ifp);
  122.     hdr->xsize      = get_short(ifp);
  123.     hdr->ysize      = get_short(ifp);
  124.     hdr->flags      = get_byte(ifp);
  125.     hdr->ncolors    = get_byte(ifp);
  126.     hdr->pixelbits  = get_byte(ifp);
  127.     hdr->ncmap      = get_byte(ifp);
  128.     hdr->cmaplen    = get_byte(ifp);
  129.  
  130.     /* some sanity checks */
  131.     if( hdr->pixelbits > 8 )
  132.         pm_error("too many bits per pixel: %d (max 8)", hdr->pixelbits);
  133.  
  134.     if( verbose ) {
  135.         pm_message("dimensions: %d x %d, %d channel%s, %d bit%s/pixel (per channel)",
  136.                     hdr->xsize, hdr->ysize,
  137.                     hdr->ncolors, plural(hdr->ncolors),
  138.                     hdr->pixelbits, plural(hdr->pixelbits));
  139.     }
  140.  
  141.     switch( hdr->ncolors ) {
  142.         case 0:
  143.             if( hdr->ncmap == 3 )
  144.                 mode = MODE_COLORMAP;
  145.             else
  146.                 goto fail1;
  147.             break;
  148.         case 1:
  149.             if( hdr->ncmap == 0 )
  150.                 mode = MODE_GRAYSCALE;
  151.             else
  152.             if( hdr->ncmap == 3 )
  153.                 mode = MODE_PSEUDOCOLOR;
  154.             else
  155.                 goto fail1;
  156.             break;
  157.         case 3:
  158.             if( hdr->ncmap == 0 )
  159.                 mode = MODE_DIRECTCOLOR;
  160.             else
  161.             if( hdr->ncmap == 3 )
  162.                 mode = MODE_TRUECOLOR;
  163.             else
  164.                 goto fail1;
  165.             break;
  166.         default:
  167.         fail1:
  168.             pm_error("don't know how to handle %d channels with %d color map channels", hdr->ncolors, hdr->ncmap);
  169.             break;
  170.     }
  171.  
  172. #ifdef DEBUG
  173.     pm_message("mode = %d", mode);
  174. #endif
  175.  
  176.     if( hdr->flags & H_NO_BACKGROUND ) {
  177.         /* set bg_xel to black */
  178.         bg_xel = pnm_blackxel(pm_bitstomaxval(hdr->pixelbits), mode == MODE_GRAYSCALE ? PGM_TYPE : PPM_TYPE);
  179.         get_byte(ifp);      /* skip pad byte */
  180.     }
  181.     else {
  182.         unsigned char r, g, b;
  183.         if( hdr->ncolors == 1 ) {
  184.             r = get_byte(ifp);
  185.             PNM_ASSIGN1(bg_xel, r);
  186.         }
  187.         else
  188.         if( hdr->ncolors == 3 ) {
  189.             r = get_byte(ifp);
  190.             g = get_byte(ifp);
  191.             b = get_byte(ifp);
  192.             PPM_ASSIGN(bg_xel, r, g, b);
  193.         }
  194.  
  195.         if( !odd(hdr->ncolors) )
  196.             (void)get_byte(ifp);    /* skip pad byte */
  197.     }
  198.  
  199.     if( hdr->ncmap ) {
  200.         long i;
  201.  
  202.         colors = 1 << hdr->cmaplen;
  203.         colormap = ppm_allocrow(colors);
  204.  
  205.         /* 3 colormap channels (because of the previous switch) */
  206.         for( i = 0; i < colors; i++ )
  207.             PPM_PUTR(colormap[i], get_short(ifp) & 0xff);
  208.         for( i = 0; i < colors; i++ )
  209.             PPM_PUTG(colormap[i], get_short(ifp) & 0xff);
  210.         for( i = 0; i < colors; i++ )
  211.             PPM_PUTB(colormap[i], get_short(ifp) & 0xff);
  212.     }
  213.  
  214.     if( hdr->flags & H_COMMENT ) {
  215.         unsigned short length = (unsigned short)get_short(ifp);
  216.         skip_bytes(ifp, (long)length);
  217.         if( odd(length) )
  218.             (void)get_byte(ifp);    /* skip pad byte */
  219.     }
  220.  
  221. #ifdef DEBUG
  222.     pm_message("file position after reading header: %ld", ftell(ifp));
  223. #endif
  224.  
  225.     return hdr;
  226. }
  227.  
  228.  
  229. static xel **
  230. read_rle_image(ifp, hdr)
  231.     FILE *ifp;
  232.     Header *hdr;
  233. {
  234.     int col, row, cols, rows, rlerow;
  235.     xel **image;
  236.     int opcode;
  237.     unsigned short channel = CHANNEL_RED;
  238.     unsigned short datum;
  239.     long nbytes;
  240.  
  241.     cols = hdr->xsize;
  242.     rows = hdr->ysize;
  243.  
  244.     image = pnm_allocarray(cols, rows);
  245.  
  246.     /* clear image to background color */
  247.     for( row = 0; row < rows; row++ )
  248.         for( col = 0; col < cols; col++ )
  249.             image[row][col] = bg_xel;
  250.  
  251.     row = rows-1;  col = 0;         /* RLE files have origin in lower left corner */
  252.     rlerow = 0;
  253.     for(;;) {
  254.         opcode = fgetc(ifp);
  255.         if( opcode == EOF || opcode == OP_EOF || opcode == (OP_EOF|OP_LONG_DATUM) )
  256.             return image;
  257.         datum = (unsigned short)get_byte(ifp);
  258.         if( opcode & OP_LONG_DATUM ) {
  259.             datum = get_short(ifp);
  260.             opcode &= ~OP_LONG_DATUM;
  261.         }
  262.  
  263.         switch( opcode ) {
  264.             case OP_SKIPLINES:
  265.                 row -= datum;
  266.                 rlerow += datum;
  267.                 break;
  268.             case OP_SETCOLOR:
  269.                 channel = datum;
  270.                 col = 0;
  271.                 break;
  272.             case OP_SKIPPIXELS:
  273.                 col += datum;
  274.                 break;
  275.             case OP_BYTEDATA:
  276.                 nbytes = (long)datum + 1;
  277.                 if( nbytes > cols-col )
  278.                     pm_error("row %d: %ld bytes ByteData, space left %d", rlerow, nbytes, cols-col);
  279.                 if( (hdr->flags & H_ALPHA) && channel == CHANNEL_ALPHA ) {
  280.                     skip_bytes(ifp, nbytes);
  281.                 }
  282.                 else
  283.                 if( channel >= hdr->ncolors )
  284.                     pm_error("** TODO **");
  285.                 else
  286.                     col = do_bytedata(ifp, hdr, image[row], col, nbytes, (int)channel);
  287.                 if( odd(nbytes) )
  288.                     (void)get_byte(ifp);
  289.                 break;
  290.             case OP_RUNDATA:
  291.                 nbytes = (long)datum + 1;
  292.                 if( nbytes > cols-col )
  293.                     pm_error("row %d: %ld bytes RunData, space left %d", rlerow, nbytes, cols-col);
  294.                 if( (hdr->flags & H_ALPHA) && channel == CHANNEL_ALPHA ) {
  295.                     (void)get_short(ifp);
  296.                 }
  297.                 else
  298.                 if( channel >= hdr->ncolors )
  299.                     pm_error("** TODO **");
  300.                 else
  301.                     col = do_rundata(ifp, hdr, image[row], col, nbytes, (int)channel);
  302.                 break;
  303.             default:
  304.                 pm_error("unkown opcode %d @ file pos %ld", opcode, ftell(ifp));
  305.         }
  306.     }
  307. }
  308.  
  309.  
  310. static int
  311. do_bytedata(ifp, hdr, imagerow, col, nbytes, channel)
  312.     FILE *ifp;
  313.     Header *hdr;
  314.     xel *imagerow;
  315.     int col;
  316.     long nbytes;
  317.     int channel;
  318. {
  319.     long i;
  320.     int byte;
  321.  
  322.     for( i = 0; i < nbytes; i++ ) {
  323.         byte = get_byte(ifp);
  324.         switch( mode ) {
  325.             case MODE_GRAYSCALE:
  326.                 PNM_ASSIGN1(imagerow[col], byte);
  327.                 break;
  328.             case MODE_PSEUDOCOLOR:
  329.                 byte = get_byte(ifp);
  330.                 imagerow[col] = colormap[byte];
  331.                 break;
  332.             case MODE_TRUECOLOR:
  333.                 switch( channel ) {
  334.                     case CHANNEL_RED:
  335.                         PPM_PUTR(imagerow[col], PPM_GETR(colormap[byte]));
  336.                         break;
  337.                     case CHANNEL_GREEN:
  338.                         PPM_PUTG(imagerow[col], PPM_GETG(colormap[byte]));
  339.                         break;
  340.                     case CHANNEL_BLUE:
  341.                         PPM_PUTB(imagerow[col], PPM_GETB(colormap[byte]));
  342.                         break;
  343.                 }
  344.                 break;
  345.             case MODE_DIRECTCOLOR:
  346.                 switch( channel ) {
  347.                     case CHANNEL_RED:
  348.                         PPM_PUTR(imagerow[col], byte);
  349.                         break;
  350.                     case CHANNEL_GREEN:
  351.                         PPM_PUTG(imagerow[col], byte);
  352.                         break;
  353.                     case CHANNEL_BLUE:
  354.                         PPM_PUTB(imagerow[col], byte);
  355.                         break;
  356.                 }
  357.                 break;
  358.         }
  359.         ++col;
  360.     }
  361.     return col;
  362. }
  363.  
  364.  
  365. static int
  366. do_rundata(ifp, hdr, imagerow, col, nbytes, channel)
  367.     FILE *ifp;
  368.     Header *hdr;
  369.     xel *imagerow;
  370.     int col;
  371.     long nbytes;
  372.     int channel;
  373. {
  374.     long i;
  375.     int byte;
  376.  
  377.     byte = get_short(ifp) & 0xff;
  378.  
  379.     for( i = 0; i < nbytes; i++ ) {
  380.         switch( mode ) {
  381.             case MODE_GRAYSCALE:
  382.                 PNM_ASSIGN1(imagerow[col], byte);
  383.                 break;
  384.             case MODE_PSEUDOCOLOR:
  385.                 byte = get_byte(ifp);
  386.                 imagerow[col] = colormap[byte];
  387.                 break;
  388.             case MODE_TRUECOLOR:
  389.                 switch( channel ) {
  390.                     case CHANNEL_RED:
  391.                         PPM_PUTR(imagerow[col], PPM_GETR(colormap[byte]));
  392.                         break;
  393.                     case CHANNEL_GREEN:
  394.                         PPM_PUTG(imagerow[col], PPM_GETG(colormap[byte]));
  395.                         break;
  396.                     case CHANNEL_BLUE:
  397.                         PPM_PUTB(imagerow[col], PPM_GETB(colormap[byte]));
  398.                         break;
  399.                 }
  400.                 break;
  401.             case MODE_DIRECTCOLOR:
  402.                 switch( channel ) {
  403.                     case CHANNEL_RED:
  404.                         PPM_PUTR(imagerow[col], byte);
  405.                         break;
  406.                     case CHANNEL_GREEN:
  407.                         PPM_PUTG(imagerow[col], byte);
  408.                         break;
  409.                     case CHANNEL_BLUE:
  410.                         PPM_PUTB(imagerow[col], byte);
  411.                         break;
  412.                 }
  413.                 break;
  414.         }
  415.         ++col;
  416.     }
  417.     return col;
  418. }
  419.  
  420.  
  421. static void
  422. readerr(fp)
  423.     FILE *fp;
  424. {
  425.     if( ferror(fp) )
  426.         pm_error("read error");
  427.     else
  428.         pm_error("premature EOF");
  429. }
  430.  
  431.  
  432. static unsigned short
  433. get_short(ifp)
  434.     FILE *ifp;
  435. {
  436.     short s;
  437.  
  438.     if( pm_readlittleshort(ifp, &s) == -1 )
  439.         readerr(ifp);
  440.     return s;
  441. }
  442.  
  443.  
  444. static unsigned char
  445. get_byte(ifp)
  446.     FILE *ifp;
  447. {
  448.     int i;
  449.  
  450.     i = fgetc(ifp);
  451.     if( i == EOF )
  452.         readerr(ifp);
  453.     return (unsigned char)i;
  454. }
  455.  
  456.  
  457. static void
  458. skip_bytes(ifp, nbytes)
  459.     FILE *ifp;
  460.     long nbytes;
  461. {
  462.     while( nbytes-- )
  463.         (void)get_byte(ifp);
  464. }
  465.  
  466.  
  467. static void *
  468. xmalloc(bytes)
  469.     int bytes;
  470. {
  471.     void *mem;
  472.  
  473.     if( bytes == 0 )
  474.         return NULL;
  475.  
  476.     mem = malloc(bytes);
  477.     if( mem == NULL )
  478.         pm_error("out of memory allocating %d bytes", bytes);
  479.     return mem;
  480. }
  481.  
  482.