writePpm/main.cpp

Go to the documentation of this file.
00001 /*
00002  * main.cpp
00003  *
00004  * Copyright (C) 2009  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  * Program that writes a PPM file, given the raw data in text form on stdin.
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include <fstream>
00036 
00037 #include "common/wave_ex.h"
00038 #include "perf/perf.h"
00039 #include "pgmppm/pgmppm.h"
00040 #include "util/parsing.h"
00041 
00042 
00043 
00044 ////////////////////////////////////////////////////////////////////////////////
00045 ///
00046 /// \ingroup wave_tool
00047 /// \defgroup tool_write_ppm writePpm
00048 ///
00049 /// Simple command-line tool to write PPM files.
00050 ////////////////////////////////////////////////////////////////////////////////
00051 
00052 
00053 // statics and typedefs --------------------------------------------------------
00054 struct context_t {
00055         context_t(void) throw() { this->clear(); }
00056         void clear(void) throw() {
00057                         width = 0;
00058                         height = 0;
00059                         array = NULL;
00060                 }
00061 
00062         // data fields
00063         int                     width;
00064         int                     height;
00065         pgmppm::color_t *       array;
00066 };
00067 
00068 
00069 
00070 ////////////////////////////////////////////////////////////////////////////////
00071 //
00072 //      static helper methods
00073 //
00074 ////////////////////////////////////////////////////////////////////////////////
00075 
00076 static pgmppm::color_t
00077 getPixel
00078 (
00079 IN void * context,
00080 IN int x,
00081 IN int y
00082 )
00083 {
00084         context_t * ctx = (context_t *) context;
00085         ASSERT(ctx, "null");
00086         ASSERT(ctx->array, "null");
00087         ASSERT(x >= 0 && x < ctx->width, "bad x: %d", x);
00088         ASSERT(y >= 0 && y < ctx->height, "bad y: %d", y);
00089 
00090         int idx = (y * ctx->width) + x;
00091         return ctx->array[idx];
00092 }
00093 
00094 
00095 
00096 static void
00097 writePpm
00098 (
00099 IO std::istream& stream,
00100 IN const char * filename
00101 )
00102 {
00103         ASSERT(stream.good(), "bad?");
00104         ASSERT(filename, "null");
00105 
00106         // in general, strip out comments and bogus characters (see parsing.h)
00107         eParseBehavior parseFlags = eParse_Strip;
00108 
00109         // parse PPM data from input stream
00110         std::string line = getNextLineFromStream(stream, parseFlags);
00111         std::string token;
00112 
00113         // first line: width and height
00114         dictionary_t dict;
00115         getDictionaryFromString(line.c_str(), "first line of PPM input", dict);
00116         int width = atoi(getRequiredValue(dict, "width"));
00117         int height = atoi(getRequiredValue(dict, "height"));
00118         if (width < 2 || height < 2) {
00119                 WAVE_EX(wex);
00120                 wex << "Bad width or height: " << width << " x " << height;
00121         }
00122 
00123         // allocate memory for gray values
00124         context_t ctx;
00125         ctx.width = width;
00126         ctx.height = height;
00127         ctx.array = new pgmppm::color_t[width * height];
00128         ASSERT(ctx.array, "out of memory");
00129 
00130         // now parse xy values
00131         int max_color = 255;            // hard-coded
00132         pgmppm::color_t * p = ctx.array;
00133         int expectX = 0;
00134         int expectY = 0;
00135         while (!stream.eof()) {
00136                 line = getNextLineFromStream(stream, parseFlags);
00137                 //DPRINTF("line: %s", line.c_str());
00138                 getDictionaryFromString(line.c_str(), "PPM data line", dict);
00139                 int x = atoi(getRequiredValue(dict, "x"));
00140                 int y = atoi(getRequiredValue(dict, "y"));
00141                 int r = atoi(getRequiredValue(dict, "r"));
00142                 int g = atoi(getRequiredValue(dict, "g"));
00143                 int b = atoi(getRequiredValue(dict, "b"));
00144 
00145                 if (x != expectX || y != expectY) {
00146                         WAVE_EX(wex);
00147                         wex << "unexpected or out of order x,y values?\n";
00148                         wex << "  expected: (" << expectX << ", " << expectY << ")\n";
00149                         wex << "  read: (" << x << ", " << y << ")";
00150                 }
00151                 if (r < 0 || r > max_color ||
00152                     g < 0 || g > max_color ||
00153                     b < 0 || b > max_color) {
00154                         WAVE_EX(wex);
00155                         wex << "invalid color value:\n";
00156                         wex << "  red  : " << r << "\n";
00157                         wex << "  green: " << g << "\n";
00158                         wex << "  blue : " << b << "\n";
00159                 }
00160 
00161                 pgmppm::color_t c;
00162                 c.red = r;
00163                 c.blue = b;
00164                 c.green = g;
00165                 *p = c;
00166                 ++p;
00167 
00168                 ++expectX;
00169                 if (expectX >= width) {
00170                         expectX = 0;
00171                         ++expectY;
00172                 }
00173 
00174                 if (expectY >= height) {
00175                         break;
00176                 }
00177         }
00178 
00179         // write PPM file
00180         std::ofstream outfile(filename);
00181         if (!outfile.good()) {
00182                 WAVE_EX(wex);
00183                 wex << "Failed to open file for writing: " << filename;
00184         }
00185         pgmppm::writePpm(outfile, width, height, max_color, getPixel,
00186             (void *) &ctx);
00187 }
00188 
00189 
00190 
00191 ////////////////////////////////////////////////////////////////////////////////
00192 //
00193 //      entry point
00194 //
00195 ////////////////////////////////////////////////////////////////////////////////
00196 
00197 int
00198 main
00199 (
00200 IN int argc,
00201 IN const char * argv[]
00202 )
00203 {
00204         ASSERT(2 == argc, "usage: writePpm <ppm-filename>");
00205         const char * filename = argv[1];
00206 
00207         int retval = 0;
00208 
00209         try {
00210                 perf::Timer timer("overall timer");
00211                 writePpm(std::cin, filename);
00212 
00213         } catch (std::exception& e) {
00214                 DPRINTF("Exception: %s", e.what());
00215                 retval = 1;
00216         }
00217 
00218         // dump timers and leave
00219         perf::dumpTimingSummary(std::cerr);
00220         return retval;
00221 }
00222