home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Libraries / grayimage / read_pgm.cc < prev    next >
Encoding:
Text File  |  1994-06-30  |  6.2 KB  |  218 lines  |  [TEXT/R*ch]

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3.  ************************************************************************
  4.  *
  5.  *               Grayscale Image
  6.  *
  7.  *         Read an image from a Portable GrayMap (pgm) file
  8.  * 
  9.  * The program reads a "binary" (RAWBITS) pgm file of the following format
  10.  *   - A "magic number" for identifying the file type.  A pgm
  11.  *     file's RAWBITS magic number is the two characters "P5".
  12.  *   - Whitespace (blanks, TABs, CRs, LFs).
  13.  *   - A width, formatted as ASCII characters in decimal.
  14.  *   - Whitespace.
  15.  *   - A height, again in ASCII decimal.
  16.  *   - Whitespace.
  17.  *   - The maximum gray value, again in ASCII decimal. For RAWBITS pgm file
  18.  *       the maximum grayscale value cannot exceed 255.
  19.  *   - A _single_ character of whitespace (typically a newline).
  20.  *   - Width * height gray values, each as plain bytes, between
  21.  *     0 and the specified maximum value, stored consecutivly, 
  22.  *     starting at the top-left corner of the graymap, proceding in normal
  23.  *     English reading order. 
  24.  *     A value of 0 means black, and the maximum value means white.
  25.  *
  26.  * For more detail, see documentation on PBMPLUS package (specifically,
  27.  * pgm(5)).
  28.  *
  29.  * $Id: read_pgm.cc,v 1.1 1994/01/12 21:07:24 oleg Exp oleg $
  30.  *
  31.  ************************************************************************
  32.  */
  33.  
  34. #include "image.h"
  35. #include "endian_io.h"
  36.  
  37. #include <iostream.h>
  38. #include <ctype.h>
  39.  
  40. /*
  41.  *------------------------------------------------------------------------
  42.  *               Class PGMFile
  43.  *     designed to contain the control info about the image
  44.  *        as defined in the Portable GrayMap file 
  45.  */
  46.  
  47. class PGMFile : public EndianIO
  48. {
  49. friend class IMAGE;
  50.  
  51.   int pixmap_width;            // Dimensions of the graymap
  52.   int pixmap_height;
  53.   int max_gray_value;            // Maximum value of a graymap pixel
  54.   int pixmap_depth;            // ceil(log2(max_gray_value))
  55.  
  56.   void set_pixmap_type(void);
  57.  
  58.   EndianIO& get(int& item);        // Read an item skipping whitespaces
  59.     
  60. public:
  61.   char * win_name;                  // Name of the image in the file
  62.   enum { PT_8bitGray, PT_BlackWhite, PT_General } pixmap_type;
  63.  
  64.   PGMFile(EndianIO& file_name);        // Constructor
  65.   ~PGMFile() {}                // Destructor
  66.   void info(void) const;        // Dump the header information
  67.                     // Reading the pixmap into image
  68.   void read_8bit_pixmap(GRAY& pixel_matrix, const int no_pixels);
  69.   void read_any_pixmap(IMAGE &image);    // Handle the general case
  70. };
  71.  
  72. /*
  73.  *------------------------------------------------------------------------
  74.  *            Construct the PGMFile
  75.  *       by reading the header of the X Window dump file
  76.  */
  77.  
  78. PGMFile::PGMFile(EndianIO& file) : EndianIO(file)
  79. {
  80.   const char * magic_str = "P5";
  81.   char read_magic_str[3] = {0,0,0};
  82.   read_magic_str[0] = read_byte("Reading magic string");
  83.   read_magic_str[1] = read_byte("Reading magic string");
  84.   if( strcmp(read_magic_str,magic_str) != 0 )
  85.     _error("Read magic string '%s' is not what's expected '%s':"
  86.            "it's not a Portable GrayMap (PGM) file",read_magic_str,magic_str);
  87.            
  88.   if( !get(pixmap_width) )
  89.     _error("Failed to read the number of columns (graymap width)");
  90.    
  91.   if( !get(pixmap_height) )
  92.     _error("Failed to read the number of rows (graymap height)");
  93.     
  94.   
  95.   if( !get(max_gray_value) )
  96.     _error("Failed to read the maximum gray value in the map");
  97.  
  98.   assert( pixmap_width > 0 && pixmap_height > 0 && max_gray_value > 0);
  99.  
  100.   if( max_gray_value > 255 )
  101.     _error("Can't handle the graymap with the maximum gray value, %d, "
  102.        "greater than 255",max_gray_value);
  103.    
  104.   {
  105.     int t;
  106.     for(pixmap_depth=0,t=1; t < max_gray_value+1; pixmap_depth++, t *= 2)
  107.       ;
  108.   }
  109.  
  110.   win_name = "";
  111.  
  112.   set_pixmap_type();
  113. }
  114.  
  115.                 // Analyse the header and figure out if
  116.                 // we can handle the PGMFile we've read.
  117.                 // Set the pixmap type.
  118. void PGMFile::set_pixmap_type(void)
  119. {
  120.   if( pixmap_depth > 8 || pixmap_depth < 1 )
  121.     _error("Can't handle the pixmap depth of %d: "
  122.        "we can process only 1..8-bit maps",
  123.            pixmap_depth);
  124.   pixmap_type = PT_8bitGray;
  125. }
  126.  
  127.                 // Read an item skipping whitespaces
  128. EndianIO& PGMFile::get(int& item)
  129. {
  130.   char c;
  131.   char buffer[10];
  132.   char * p = buffer;
  133.     
  134.   while( c=read_byte("Reading int item in ASCII"), isspace(c) )
  135.     ;
  136.   
  137.   *p++ = c;
  138.   while( c=read_byte("Reading int item in ASCII"), !isspace(c) )
  139.     *p++ = c;
  140.   *p++ = 0;
  141.     
  142.   item = strtol(buffer,&p,10);
  143.   assert( *p == '\0' );
  144.   
  145.   return *this;
  146. }
  147.  
  148. /*
  149.  *------------------------------------------------------------------------
  150.  *    Print out all the control information pertaining to the
  151.  *             X Window Image read
  152.  */
  153.  
  154. void PGMFile::info(void) const
  155. {
  156.   cout << "\n\n=====>The following Portable GrayMap has been read";
  157.   cout << "\nPixmap depth:   " << pixmap_depth;
  158.   cout << "\nPixmap width:   " << pixmap_width;
  159.   cout << "\nPixmap height:  " << pixmap_height;
  160.   cout << "\nMax gray value: " << max_gray_value;
  161.   cout << "\nWindow name:    " << win_name;
  162.  
  163.   cout << "\n-----End of PGM information\n";
  164. }
  165.  
  166. /*
  167.  *------------------------------------------------------------------------
  168.  *        Read the image pixmap and write it into the image
  169.  */
  170.  
  171.                 // Special case of the Gray scale pixelmap of
  172.                 // depth 8
  173. void PGMFile::read_8bit_pixmap(GRAY& pixel_matrix, const int no_pixels)
  174. {
  175.   register GRAY * pixelp;
  176.   for(pixelp = &pixel_matrix; pixelp < &pixel_matrix+no_pixels;)
  177.     *pixelp++ = read_byte("Reading the pixel map");
  178. }
  179.  
  180.                     // Handle the general case
  181. void PGMFile::read_any_pixmap(IMAGE &image)
  182. {
  183.   _error("PGMFile::read_any_pixmap is not implemented yet");
  184. }
  185.  
  186. /*
  187.  *========================================================================
  188.  *             Root module - actual IMAGE constructor
  189.  */
  190.  
  191. void IMAGE::read_pgm(EndianIO& file, const char print_header_info)
  192. {
  193.   message("Reading the Portable GrayMap (PGM)\n");
  194.   
  195.   PGMFile pgmfile(file);
  196.  
  197.   if( print_header_info )
  198.     pgmfile.info();
  199.  
  200.   allocate(pgmfile.pixmap_height,pgmfile.pixmap_width,pgmfile.pixmap_depth);
  201.  
  202.   name = pgmfile.win_name;
  203.  
  204.   switch( pgmfile.pixmap_type )
  205.   {                // Select the most efficient procedure
  206.     case PGMFile::PT_8bitGray:
  207.          pgmfile.read_8bit_pixmap(*pixels,npixels);
  208.      break;
  209.  
  210.     case PGMFile::PT_BlackWhite:        // Not implemented yet
  211.     default:
  212.      pgmfile.read_any_pixmap(*this);
  213.   }
  214.  
  215.   cout << "\n" << ncols << "x" << nrows << "x" << bits_per_pixel << " image '"
  216.          << name << "' has been read\n";
  217. }
  218.