00001
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
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;
00063 case 8: return 5;
00064 case 24: return 6;
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;
00071 }
00072
00073 int bit_depth_for_mode(int mode)
00074 {
00075 switch (mode)
00076 {
00077 case 1: case 4: return 1;
00078 case 2: case 5: return 8;
00079 case 3: case 6: return 24;
00080 }
00081
00082 throw rutz::error(rutz::sfmt("invalid PNM mode value: %d", mode),
00083 SRC_POS);
00084
00085 GVX_ASSERT(0); return 0;
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
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
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
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