pgmppm.cpp

Go to the documentation of this file.
00001 /*
00002  * pgmppm.cpp
00003  *
00004  * Copyright (C) 2008  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Implementation of PGM/PPM routines.
00032  * See pgmppm.h
00033  *
00034  * Also see http://netpbm.sourceforge.net/doc/pgm.html
00035  */
00036 
00037 // includes --------------------------------------------------------------------
00038 #include "pgmppm.h"                     // always include our own header first!
00039 
00040 #include "common/wave_ex.h"
00041 
00042 #include "perf/perf.h"
00043 
00044 #include "util/token_stream.h"
00045 
00046 
00047 namespace pgmppm {
00048 
00049 
00050 // constants
00051 static const int s_maxGray              = 256;
00052 static const int s_maxColor             = 256;
00053 
00054 static const char * s_magicPGM          = "P5";
00055 static const char * s_magicPPM          = "P6";
00056 
00057 
00058 ////////////////////////////////////////////////////////////////////////////////
00059 //
00060 //      public API: file writing
00061 //
00062 ////////////////////////////////////////////////////////////////////////////////
00063 
00064 void
00065 writePgm
00066 (
00067 IO std::ostream& out,
00068 IN int width,
00069 IN int height,
00070 IN int max_gray,
00071 IN pgm_pixel_fn fn,
00072 IN void * context
00073 )
00074 {
00075         perf::Timer timer("pgmppm::writePgm");
00076         ASSERT(out.good(), "bad?");
00077         ASSERT(width > 0, "bad width: %d", width);
00078         ASSERT(height > 0, "bad height: %d", height);
00079         ASSERT(max_gray > 0 && max_gray < s_maxGray, "bad max_gray: %d",
00080             max_gray);
00081         ASSERT(fn, "null pgm callback");
00082         // ASSERT(context) -- we don't care
00083 
00084         int bpv = 0;            // bytes per value
00085         if (max_gray < 256) {
00086                 bpv = 1;
00087         } else if (max_gray < 65536) {
00088                 bpv = 2;
00089         } else {
00090                 ASSERT(false, "Bad max_gray?");
00091         }
00092         ASSERT(bpv > 0, "Bad bytes per value: %d", bpv);
00093 
00094         // PGM header
00095         out << s_magicPGM << "\n";
00096         out << width << " " << height << "\n";
00097         out << max_gray << "\n";
00098 
00099         // raw data
00100         for (int j = 0; j < height; ++j) {
00101                 for (int i = 0; i < width; ++i) {
00102                         int val = fn(context, i, j);
00103 
00104                         ASSERT(val >= 0 && val <= max_gray,
00105                            "Bad pixel value [%d, %d] = %d", i, j, val);
00106 
00107                         // for now, all other programs only work with 8-bit!
00108                         out.put((byte_t) val);
00109 
00110 /*
00111                         byte_t * p = (byte_t *) &val;
00112                         p += bpv - 1;
00113                         for (int k = 0; k < bpv; ++k) {
00114                                 out.write((const char *) p, 1);
00115                                 --p;
00116                         }
00117  */
00118                 }
00119         }
00120 }
00121 
00122 
00123 
00124 void
00125 writePpm
00126 (
00127 IO std::ostream& out,
00128 IN int width,
00129 IN int height,
00130 IN int max_color,
00131 IN ppm_pixel_fn fn,
00132 IN void * context
00133 )
00134 {
00135         perf::Timer timer("pgmppm::writePpm");
00136         ASSERT(out.good(), "bad?");
00137         ASSERT(width > 0, "Bad width: %d", width);
00138         ASSERT(height > 0, "bad height: %d", height);
00139         ASSERT(max_color > 0 && max_color < s_maxColor, "Bad max_color: %d",
00140             max_color);
00141         ASSERT(fn, "null ppm callback");
00142         // ASSERT(context) -- we don't care
00143 
00144         // PPM header
00145         out << s_magicPPM << "\n";
00146         out << width << " " << height << "\n";
00147         out << max_color << "\n";
00148 
00149         for (int j = 0; j < height; ++j) {
00150                 for (int i = 0; i < width; ++i) {
00151                         color_t c = fn(context, i, j);
00152                         ASSERT(c.red >= 0 && c.red <= max_color,
00153                             "bad red val: %d", c.red);
00154                         ASSERT(c.green >= 0 && c.green <= max_color,
00155                             "bad green val: %d", c.green );
00156                         ASSERT(c.blue >= 0 && c.blue <= max_color,
00157                             "bad blue val: %d", c.blue );
00158 
00159                         out.put((byte_t) c.red);
00160                         out.put((byte_t) c.green);
00161                         out.put((byte_t) c.blue);
00162                 }
00163         }
00164 }
00165 
00166 
00167 
00168 ////////////////////////////////////////////////////////////////////////////////
00169 //
00170 //      file reading
00171 //
00172 ////////////////////////////////////////////////////////////////////////////////
00173 
00174 bool
00175 readPgm
00176 (
00177 IO std::istream& in,
00178 IN notify_size_fn notify,
00179 IN pgm_write_pixel_fn write_pixel,
00180 IN void * context
00181 )
00182 {
00183         perf::Timer timer("pgmppm::readPgm");
00184         ASSERT(in.good(), "bad?");
00185         ASSERT(notify, "null");
00186         ASSERT(write_pixel, "null");
00187         // ASSERT(context) - we don't care
00188 
00189         std::string token;
00190         expectToken(in, s_magicPGM);
00191 
00192         int width = readInteger(in, token);
00193         int length = readInteger(in, token);
00194         if (width <= 0 || length <= 0) {
00195                 WAVE_EX(wex);
00196                 wex << "Bad width (" << width << ") ";
00197                 wex << "or length (" << length << ")";
00198         }
00199         
00200         int max_val = readInteger(in, token);
00201         if (max_val <= 0 || max_val >= s_maxGray) {
00202                 WAVE_EX(wex);
00203                 wex << "Unsupported max_gray: " << max_val;
00204         }
00205 
00206         DPRINTF("Reading PGM of dimensions %d x %d, max_gray = %d",
00207             width, length, max_val);
00208         if (!notify(context, width, length, max_val))
00209                 return false;
00210 
00211         for (int j = 0; j < length; ++j) {
00212                 for (int i = 0; i < width; ++i) {
00213                         char c;
00214                         if (!in.good()) {
00215                                 WAVE_EX(wex);
00216                                 wex << "Could not read entire pgm image";
00217                         }
00218                         in.get(c);
00219                         byte_t b = c;
00220                         write_pixel(context, i, j, b);
00221                 }
00222         }
00223 
00224         return true;
00225 }
00226 
00227 
00228 
00229 };      // pgmppm namespace
00230