pnmparser.cc

Go to the documentation of this file.
00001 
00003 
00004 //
00005 // Copyright (c) 1999-2004 California Institute of Technology
00006 // Copyright (c) 2004-2007 University of Southern California
00007 // Rob Peters <rjpeters at usc dot edu>
00008 //
00009 // created: Tue Jun 15 16:41:07 1999
00010 // commit: $Id: pnmparser.cc 10065 2007-04-12 05:54:56Z rjpeters $
00011 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/media/pnmparser.cc $
00012 //
00013 // --------------------------------------------------------------------
00014 //
00015 // This file is part of GroovX.
00016 //   [http://ilab.usc.edu/rjpeters/groovx/]
00017 //
00018 // GroovX is free software; you can redistribute it and/or modify it
00019 // under the terms of the GNU General Public License as published by
00020 // the Free Software Foundation; either version 2 of the License, or
00021 // (at your option) any later version.
00022 //
00023 // GroovX is distributed in the hope that it will be useful, but
00024 // WITHOUT ANY WARRANTY; without even the implied warranty of
00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00026 // General Public License for more details.
00027 //
00028 // You should have received a copy of the GNU General Public License
00029 // along with GroovX; if not, write to the Free Software Foundation,
00030 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00031 //
00033 
00034 #ifndef GROOVX_MEDIA_PNMPARSER_CC_UTC20050626084018_DEFINED
00035 #define GROOVX_MEDIA_PNMPARSER_CC_UTC20050626084018_DEFINED
00036 
00037 #include "pnmparser.h"
00038 
00039 #include "geom/vec2.h"
00040 
00041 #include "media/bmapdata.h"
00042 
00043 #include "rutz/error.h"
00044 #include "rutz/fstring.h"
00045 #include "rutz/gzstreambuf.h"
00046 #include "rutz/sfmt.h"
00047 #include "rutz/shared_ptr.h"
00048 
00049 #include <cctype>
00050 #include <iostream>
00051 
00052 #include "rutz/trace.h"
00053 #include "rutz/debug.h"
00054 GVX_DBG_REGISTER
00055 
00056 namespace
00057 {
00058   int mode_for_bit_depth(int depth)
00059   {
00060     switch (depth)
00061       {
00062       case 1: return 4; // black+white
00063       case 8: return 5; // grayscale
00064       case 24: return 6; // RGB
00065       }
00066 
00067     throw rutz::error(rutz::sfmt("invalid PNM bit depth value: %d",
00068                                  depth), SRC_POS);
00069 
00070     GVX_ASSERT(0); return 0; // can't get here
00071   }
00072 
00073   int bit_depth_for_mode(int mode)
00074   {
00075     switch (mode)
00076       {
00077       case 1: case 4: return 1; // b+w
00078       case 2: case 5: return 8; // grayscale
00079       case 3: case 6: return 24; // RGB
00080       }
00081 
00082     throw rutz::error(rutz::sfmt("invalid PNM mode value: %d", mode),
00083                       SRC_POS);
00084 
00085     GVX_ASSERT(0); return 0; // can't happen
00086   }
00087 
00088   void parse_pbm_mode_1(std::istream& is, media::bmap_data& data)
00089   {
00090     GVX_TRACE("parse_pbm_mode_1");
00091 
00092     int position = 0;
00093     int val = 0;
00094 
00095     const int byte_count = data.byte_count();
00096 
00097     while (is.peek() != EOF && position < byte_count)
00098       {
00099         dbg_eval(3, position);
00100 
00101         is >> val;
00102         data.bytes_ptr()[position] = (val == 0) ? 0 : 255;
00103 
00104         ++position;
00105       }
00106   }
00107 
00108   void parse_pbm_mode_23(std::istream& is, media::bmap_data& data,
00109                          int max_grey)
00110   {
00111   GVX_TRACE("parse_pbm_mode_23");
00112 
00113     const double scale = 255.0/double(max_grey);
00114 
00115     int position = 0;
00116     int val = 0;
00117 
00118     const int byte_count = data.byte_count();
00119 
00120     while (is.peek() != EOF && position < byte_count)
00121       {
00122         dbg_eval(3, position);
00123 
00124         is >> val;
00125         data.bytes_ptr()[position] = static_cast<unsigned char>(val * scale);
00126 
00127         ++position;
00128       }
00129   }
00130 
00131   void parse_pbm_mode_456(std::istream& is,
00132                           media::bmap_data& data,
00133                           int max_grey,
00134                           int mode)
00135   {
00136   GVX_TRACE("parse_pbm_mode_456");
00137 
00138     dbg_eval_nl(3, data.byte_count());
00139 
00140     if (max_grey == 255 // the most common case
00141         || mode == 4)
00142       {
00143         is.read(reinterpret_cast<char*>(data.bytes_ptr()), data.byte_count());
00144         unsigned int numread = is.gcount();
00145         if (numread < data.byte_count())
00146           throw rutz::error("stream underflow in parse_pbm_mode_456", SRC_POS);
00147       }
00148     else
00149       {
00150         int nbits = 0;
00151         for (int g = max_grey; g != 0; g >>= 1)
00152           {
00153             ++nbits;
00154           }
00155 
00156         dbg_eval_nl(3, nbits);
00157 
00158         GVX_ASSERT(nbits >= 1);
00159 
00160         const int nbytes = ((nbits - 1) / 8) + 1;
00161 
00162         dbg_eval_nl(3, nbytes);
00163 
00164         unsigned char* p = data.bytes_ptr();
00165         unsigned char* stop = data.bytes_ptr() + data.byte_count();
00166 
00167         while (p != stop)
00168           {
00169             int val = 0;
00170             for (int i = 0; i < nbytes; ++i)
00171               {
00172                 int c = is.get();
00173                 if (c == EOF)
00174                   throw rutz::error("premature EOF while reading pnm file", SRC_POS);
00175                 val += (c << (8*i));
00176               }
00177 
00178             *p = (unsigned char)(255*double(val)/double(max_grey));
00179             ++p;
00180           }
00181       }
00182 
00183     if (is.fail() && !is.eof())
00184       throw rutz::error("input stream failed in parse_pbm_mode_456", SRC_POS);
00185   }
00186 }
00187 
00189 //
00190 // PNM load/save definitions
00191 //
00193 
00194 void media::save_pnm(const char* filename, const media::bmap_data& data)
00195 {
00196   rutz::shared_ptr<std::ostream> os
00197     (rutz::ogzopen(filename, std::ios::binary));
00198 
00199   save_pnm(*os, data);
00200 }
00201 
00202 void media::save_pnm(std::ostream& os, const media::bmap_data& data)
00203 {
00204 GVX_TRACE("media::save_pnm");
00205 
00206   int mode = mode_for_bit_depth(data.bits_per_pixel());
00207 
00208   os << 'P' << mode
00209      << ' ' << data.size().x()
00210      << ' ' << data.size().y();
00211 
00212   if (mode != 1 && mode != 4)
00213     {
00214       const int max_grey = 255;
00215       os << ' ' << max_grey;
00216     }
00217 
00218   os << '\n';
00219 
00220   for (int row = 0; row < data.height(); ++row)
00221     os.write(reinterpret_cast<const char*>(data.row_ptr(row)),
00222              data.bytes_per_row());
00223 }
00224 
00225 void media::load_pnm(const char* filename, media::bmap_data& data)
00226 {
00227   rutz::shared_ptr<std::istream> is
00228     (rutz::igzopen(filename, std::ios::binary));
00229 
00230   load_pnm(*is, data);
00231 }
00232 
00233 void media::load_pnm(std::istream& is, media::bmap_data& data)
00234 {
00235 GVX_TRACE("media::load_pnm");
00236   if (is.fail())
00237     {
00238       throw rutz::error("input stream failed before reading pnm file",
00239                         SRC_POS);
00240     }
00241 
00242   if (is.peek() == EOF)
00243     {
00244       throw rutz::error("input stream empty while reading pnm file",
00245                         SRC_POS);
00246     }
00247 
00248   int c = is.get();
00249   if (c != 'P')
00250     {
00251       throw rutz::error(rutz::sfmt("bad magic number while "
00252                                    "reading pnm file: %d", c), SRC_POS);
00253     }
00254 
00255   int mode;
00256 
00257   is >> mode;
00258   dbg_eval_nl(3, mode);
00259 
00260   const int bit_depth = bit_depth_for_mode(mode);
00261 
00262   while ( isspace(is.peek()) )
00263     {
00264       is.get();
00265     }
00266   if ( is.peek() == '#' )
00267     {
00268       is.ignore(1000, '\n');
00269     }
00270 
00271   geom::vec2<int> extent;
00272 
00273   is >> extent.x();
00274   is >> extent.y();
00275 
00276   dbg_dump(3, extent);
00277 
00278   int max_grey = 1;
00279 
00280   if (mode != 1 && mode != 4)
00281     {
00282       is >> max_grey;
00283     }
00284 
00285   dbg_eval_nl(3, max_grey);
00286 
00287   if (max_grey < 1)
00288     {
00289       throw rutz::error(rutz::sfmt("while reading pnm file: "
00290                                    "invalid max grey value: %d",
00291                                    max_grey), SRC_POS);
00292     }
00293 
00294   // one more character of whitespace after max_grey
00295   c = is.get();
00296   if ( !isspace(c) )
00297     {
00298       throw rutz::error("missing whitespace while reading pnm file",
00299                         SRC_POS);
00300     }
00301 
00302   media::bmap_data new_data(extent, bit_depth, 1);
00303 
00304   switch (mode)
00305     {
00306     case 1:                 parse_pbm_mode_1(is, new_data); break;
00307     case 2: case 3:         parse_pbm_mode_23(is, new_data, max_grey); break;
00308     case 4: case 5: case 6: parse_pbm_mode_456(is, new_data, max_grey, mode); break;
00309     default: GVX_ASSERT(false); break;
00310     }
00311 
00312   data.swap(new_data);
00313 }
00314 
00315 static const char __attribute__((used)) vcid_groovx_media_pnmparser_cc_utc20050626084018[] = "$Id: pnmparser.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00316 #endif // !GROOVX_MEDIA_PNMPARSER_CC_UTC20050626084018_DEFINED

The software described here is Copyright (c) 1998-2005, Rob Peters.
This page was generated Wed Dec 3 06:49:39 2008 by Doxygen version 1.5.5.