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

  1. /* pnmtorle.c - convert portable anymap to Utah Raster Toolkit image
  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. /* prototypes */
  18. static void write_rle_header ARGS((FILE *ofp, int cols, int rows, int channels, int pixelbits));
  19. static void pnm_to_1_channel ARGS((FILE *ofp, xel **image, int cols, int rows));
  20. static void pnm_to_3_channels ARGS((FILE *ofp, xel **image, int cols, int rows));
  21. static void write_channel ARGS((FILE *ofp, int channel, unsigned char *rawrow, int cols));
  22. static void write_bytedata ARGS((FILE *ofp, unsigned char *rawrow, int nbytes));
  23. static void write_rundata  ARGS((FILE *ofp, unsigned char *rawrow, int nbytes));
  24. static void put_byte ARGS((FILE *fp, int byte));
  25. static void put_short ARGS((FILE *fp, int word));
  26. #define plural(x)   ((x) == 1 ? "" : "s")
  27.  
  28.  
  29. int
  30. main(argc, argv)
  31.     int argc;
  32.     char *argv[];
  33. {
  34.     int argn, cols, rows, format, channels, pixelbits;
  35.     xel **image;
  36.     xelval maxval;
  37.     FILE *ifp;
  38.     char *usage = "[-8bit] [pnmfile]";
  39.     short scale, force8;
  40.  
  41.     pnm_init(&argc, argv);
  42.     force8 = 0;
  43.  
  44.     argn = 1;
  45.     /* empty loop for easy option adding */
  46.     while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
  47.         if( pm_keymatch(argv[argn], "-8bit", 2) )
  48.             force8 = 1;
  49.         else
  50.             pm_usage(usage);
  51.         ++argn;
  52.     }
  53.     if( argn < argc ) {
  54.         ifp = pm_openr( argv[argn] );
  55.         argn++;
  56.     }
  57.     else
  58.         ifp = stdin;
  59.     if( argn != argc )
  60.         pm_usage(usage);
  61.  
  62.     pnm_pbmmaxval = 1;      /* PBM -> 1 bit per pixel */
  63.     image = pnm_readpnm(ifp, &cols, &rows, &maxval, &format);
  64.  
  65.     if( maxval > 255 ) {
  66.         pm_message("maxval too large - scaling pixel values");
  67.         scale = 1;
  68.     }
  69.     else
  70.     if( force8 && maxval < 255 ) {
  71.         pm_message("scaling pixels to 8 bit");
  72.         scale = 1;
  73.     }
  74.     else
  75.         scale = 0;
  76.  
  77.     if( scale ) {
  78.         int newformat = format;
  79.         if( PNM_FORMAT_TYPE(format) == PBM_TYPE ) {
  80.             pm_message("promoting PBM to PGM");
  81.             newformat = PGM_TYPE;
  82.         }
  83.         pnm_promoteformat(image, cols, rows, maxval, format, 255, newformat);
  84.         maxval = 255;
  85.         format = newformat;
  86.     }
  87.  
  88.     pixelbits = pm_maxvaltobits(maxval);
  89.     if( PNM_FORMAT_TYPE(format) == PPM_TYPE )
  90.         channels = 3;
  91.     else
  92.         channels = 1;
  93.  
  94.     pm_message("writing RLE image: %d channel%s, %d bit%s/pixel (per channel)",
  95.                 channels, plural(channels), pixelbits, plural(pixelbits));
  96.  
  97.     write_rle_header(stdout, cols, rows, channels, pixelbits);
  98.     if( channels == 1 )
  99.         pnm_to_1_channel(stdout, image, cols, rows);
  100.     else
  101.         pnm_to_3_channels(stdout, image, cols, rows);
  102.     put_byte(stdout, OP_EOF);
  103.     put_byte(stdout, 0);    /* dummy datum, in case someone reads opcode+datum as a word */
  104.     exit(0);
  105. }
  106.  
  107.  
  108. static void
  109. write_rle_header(ofp, cols, rows, channels, pixelbits)
  110.     FILE *ofp;
  111.     int cols, rows, channels, pixelbits;
  112. {
  113.     put_short(ofp, RLE_MAGIC);
  114.     put_short(ofp, 0);                  /* xpos */
  115.     put_short(ofp, 0);                  /* ypos */
  116.     put_short(ofp, cols);               /* xsize */
  117.     put_short(ofp, rows);               /* ysize */
  118.     put_byte(ofp, H_NO_BACKGROUND);     /* flags */
  119.     put_byte(ofp, channels);            /* ncolors */
  120.     put_byte(ofp, pixelbits);           /* pixelbits */
  121.     put_byte(ofp, 0);                   /* ncmap */
  122.     put_byte(ofp, 0);                   /* cmaplen */
  123.  
  124.     put_byte(ofp, 0);                   /* fill byte for H_NO_BACKGROUND */
  125. }
  126.  
  127.  
  128. static void
  129. pnm_to_1_channel(ofp, image, cols, rows)
  130.     FILE *ofp;
  131.     xel **image;
  132.     int cols, rows;
  133. {
  134.     int row, col;
  135.     unsigned char *rawrow = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
  136.  
  137.     for( row = rows-1; row >= 0; row-- ) {
  138.         for( col = 0; col < cols; col++ )
  139.             rawrow[col] = PNM_GET1(image[row][col]);
  140.         write_channel(ofp, 0, rawrow, cols);
  141.         put_byte(ofp, OP_SKIPLINES); put_byte(ofp, 1);
  142.     }
  143. }
  144.  
  145.  
  146. static void
  147. pnm_to_3_channels(ofp, image, cols, rows)
  148.     FILE *ofp;
  149.     xel **image;
  150.     int cols, rows;
  151. {
  152.     int row, col;
  153.     unsigned char *redrow, *greenrow, *bluerow;
  154.  
  155.     redrow   = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
  156.     greenrow = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
  157.     bluerow  = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
  158.  
  159.     for( row = rows-1; row >= 0; row-- ) {
  160.         for( col = 0; col < cols; col++ ) {
  161.             redrow[col]   = PPM_GETR(image[row][col]);
  162.             greenrow[col] = PPM_GETG(image[row][col]);
  163.             bluerow[col]  = PPM_GETB(image[row][col]);
  164.         }
  165.         write_channel(ofp, CHANNEL_RED,   redrow, cols);
  166.         write_channel(ofp, CHANNEL_GREEN, greenrow, cols);
  167.         write_channel(ofp, CHANNEL_BLUE,  bluerow, cols);
  168.         put_byte(ofp, OP_SKIPLINES); put_byte(ofp, 1);
  169.     }
  170. }
  171.  
  172.  
  173. static void
  174. write_channel(ofp, channel, src, cols)
  175.     FILE *ofp;
  176.     int channel;
  177.     unsigned char *src;
  178.     int cols;
  179. {
  180.     unsigned char *end, *lit, *rep;
  181. #define MINLEN  5
  182.  
  183.     put_byte(ofp, OP_SETCOLOR); put_byte(ofp, channel);
  184. #if 0
  185.     write_bytedata(ofp, src, cols);
  186. #else
  187.  
  188.     end = src + cols;
  189.     lit = src;
  190.     while( src < end ) {
  191.         /* find longest literal run */
  192.         do
  193.             if( ++src == end )
  194.                 goto Done;
  195.         while( *src != *(src-1) );
  196.  
  197.         /* find longest replicate run */
  198.         rep = src-1;
  199.         do
  200.             if( ++src == end )
  201.                 break;
  202.         while( *src == *(src-1) );
  203.  
  204.         /* if the replicate run is at least MINLEN bytes, save the literal
  205.            run and the replicate run, else merge the replicate run into the
  206.            literal run */
  207.         if( src-rep >= MINLEN ) {
  208.             if( rep > lit )
  209.                 write_bytedata(ofp, lit, rep-lit);
  210.             write_rundata(ofp, rep, src-rep);
  211.             lit = src;
  212.         }
  213.     }
  214.  
  215. Done:
  216.     if( src > lit )
  217.         write_bytedata(ofp, lit, src-lit);
  218. #endif
  219. }
  220.  
  221.  
  222. static void
  223. write_bytedata(ofp, rawrow, nbytes)
  224.     FILE *ofp;
  225.     unsigned char *rawrow;
  226.     int nbytes;
  227. {
  228.     if( nbytes <= 256 ) {
  229.         put_byte(ofp, OP_BYTEDATA);  put_byte(ofp, nbytes-1);
  230.     }
  231.     else {
  232.         put_byte(ofp, OP_BYTEDATA|OP_LONG_DATUM); put_byte(ofp, 0);
  233.         put_short(ofp, nbytes-1);
  234.     }
  235.     if( fwrite(rawrow, 1, nbytes, ofp) != nbytes )
  236.         pm_error("write error");
  237.     if( odd(nbytes) )
  238.         put_byte(ofp, 0);
  239. }
  240.  
  241.  
  242. static void
  243. write_rundata(ofp, rawrow, nbytes)
  244.     FILE *ofp;
  245.     unsigned char *rawrow;
  246.     int nbytes;
  247. {
  248.     if( nbytes <= 256 ) {
  249.         put_byte(ofp, OP_RUNDATA); put_byte(ofp, nbytes-1);
  250.     }
  251.     else {
  252.         put_byte(ofp, OP_RUNDATA|OP_LONG_DATUM); put_byte(ofp, 0);
  253.         put_short(ofp, nbytes-1);
  254.     }
  255.     put_short(ofp, *rawrow);
  256. }
  257.  
  258.  
  259. static void
  260. put_byte(fp, byte)
  261.     FILE *fp;
  262.     int byte;
  263. {
  264.     if( fputc((unsigned char)byte, fp) == EOF )
  265.         pm_error("write error");
  266. }
  267.  
  268.  
  269. static void
  270. put_short(fp, word)
  271.     FILE *fp;
  272.     int word;
  273. {
  274.     if( pm_writelittleshort(fp, (unsigned short)word) == -1 )
  275.         pm_error("write error");
  276. }
  277.  
  278.