/* * sligraphics.cc * * This file is part of NEST. * * Copyright (C) 2004 The NEST Initiative * * NEST is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * NEST is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with NEST. If not, see <http://www.gnu.org/licenses/>. * */ #include <cctype> // for isspace #include <cstdio> #include <iostream> #include "arraydatum.h" #include "stringdatum.h" #include "integerdatum.h" #include "aggregatedatum.h" #include "numericdatum.h" #include "fdstream.h" #include "sligraphics.h" /* BeginDocumentation Name:readPGM - read in grey-level image in PGM Format. Synopsis:string readPGM -> int int int arraytype fname readPGM -> width height maxval [grayvals] Description:this function reads an image file in the PGM format and returns the width, height, maximum gray value and the image itself (as a linear array). On Unix systems, man pgm should give you a description of the PGM (Portable GrayMap) image format. Parameters:fname - name of file to be read [grayvals] - one-dim. array containing the pixel gray values, starting from the upper left corner of the image, continuing rowwise (normal englissh reading order). maxval - the maximum gray value width - width of image in pixels (no. of columns) height - height of image (no. of rows) Examples:(FancyImage.pgm) readPGM -> 16 24 255 [grayvals] This reads the image FancyImage.pgm, and tells you that it has 16 columns, 24 rows, and a maximum gray value of 255. The pixel gray values are stored in the array. Author:Schmuker, Gewaltig FirstVersion:9.1.2003 SeeAlso:writePGM */ void SLIgraphics::ReadPGMFunction::execute(SLIInterpreter *i) const { // call: filename readPGM -> width height maxval image(array) if(i->OStack.load()<1) { i->raiseerror(i->StackUnderflowError); return; } StringDatum *sd= dynamic_cast<StringDatum *>(i->OStack.top().datum()); if(sd ==NULL) { i->raiseerror(i->ArgumentTypeError); return; } std::istream *in=NULL; vector<long> image; int width=0, height=0, maxval=0; // for the image parameters: width, height, maxval try { in = openPGMFile(sd); char magic[2]; readMagicNumber(in, magic); initRead(in, width, height, maxval); readImage(in, magic, image, width, height, maxval); delete in; } catch(string const &s) { delete in; i->message(SLIInterpreter::M_ERROR, "readPGM","Error reading image."); i->message(SLIInterpreter::M_ERROR, "readPGM",s.c_str()); i->raiseerror(i->BadIOError); return; } i->EStack.pop(); i->OStack.pop(); i->OStack.push(ArrayDatum(image)); i->OStack.push(maxval); i->OStack.push(height); i->OStack.push(width); } std::istream * SLIgraphics::ReadPGMFunction::openPGMFile(StringDatum *filename) const { //opens pgm file for reading and returns pointer to the istream std::istream *in = new ifdstream(filename->c_str()); if(in->good()) { return in; } else { throw string("File open error."); } } void SLIgraphics::ReadPGMFunction::readMagicNumber(std::istream * in, char * magic) const { // reads in the magic number which determines the file format try { *in >> magic; } catch(std::exception& e) { throw string("Magic number read error: ")+ e.what(); } } void SLIgraphics::ReadPGMFunction::initRead(std::istream * in, int &width, int &height, int &maxval) const { //reads the width, height, and max. gray value in this order char temp[256]; try { //throw away whitespaces after magic number //otherwise, >> gets confused about the newline before the numbers char trash; while(std::isspace(trash=in->get())) continue; in->putback(trash); //skip comments do { in->getline(temp, 255); } while (temp[0]=='#'); //width and height are now in temp, so parse it sscanf(temp, "%d %d", &width, &height); *in >> maxval; } catch(std::exception& e) { throw string("Read init error: ")+ e.what(); } } void SLIgraphics::ReadPGMFunction::readImage(std::istream *in, char magic[2], vector<long> &image, int width, int height, int maxval) const { // this reads the gray value array image.clear(); image.reserve(width*height); try{ if(string(magic)==string("P2")) //ASCII PGM { int tmp; while((*in >> tmp) && !(in->eof())) { image.push_back((long) tmp); } } else if(string(magic)==string("P5") || string(magic)==string("P6")) //Raw PGM (resp. PPM) { if(maxval > 255) { throw string("read: maxval too large for format RawPGM(P5)."); } char tmp; long tmp2; in->read(&tmp, 1); //throw away LF after maxval //TODO: Protect this from reading too much data like trailing //newlines: use for instead of while while(in->read(&tmp, 1) && !(in->eof())){ tmp2=(unsigned char) tmp; image.push_back((long) tmp2); } } else { throw string("image read error:") + string(magic) + string(": Unsupported file type."); } } catch(std::exception& e){ throw string("image read error: ") + e.what(); } } /* BeginDocumentation Name:writePGM - write out a grey-level image in PGM format Synopsis:string arraytype int int int writePGM fname [grayvals] maxval height width writePGM Description:This writes an array of integers as grey-level image using the PGM (PortableGrayMap) format. On Unix systems, man 5 pgm should give you a description of the PGM image format. Parameters:fname - name of file to be written [grayvals] - one-dim. array containing the pixel gray values, starting at the upper left corner and continuing rowwise (normal english reading order). maxval - the maximum gray value width - width of image in pixels (no. of columns) height - height of image (no. of rows) Remarks:So far, only the plain ASCII variant of the PGM Format is used. In the PGM manual, this is referred to as "P2". Examples:(FancyImage.pgm) [grayvals] 255 24 16 writePGM This writes an image named FancyImage.pgm with the gray values from the array, having 16 columns and 24 rows. Author:Schmuker, Gewaltig FirstVersion:9.1.2003 SeeAlso:readPGM */ void SLIgraphics::WritePGMFunction::execute(SLIInterpreter *i) const { //TODO: fix argument order!!! Should be the same as when getting //the parameters read by readPGM.First make sure that your script is //properly working! // call: filename image(array) maxval height width writePGM if(i->OStack.load()<5) { i->raiseerror(i->StackUnderflowError); return; } IntegerDatum * w = dynamic_cast<IntegerDatum*>(i->OStack.pick(0).datum()); IntegerDatum * h = dynamic_cast<IntegerDatum*>(i->OStack.pick(1).datum()); IntegerDatum * m = dynamic_cast<IntegerDatum*>(i->OStack.pick(2).datum()); ArrayDatum * image = dynamic_cast<ArrayDatum*>(i->OStack.pick(3).datum()); StringDatum * filename= dynamic_cast<StringDatum*>(i->OStack.pick(4).datum()); long width = (long) w->get(); long height = (long) h->get(); long maxval = (long) m->get(); std::ostream * out=NULL; try { out = new ofdstream(filename->c_str()); if(!out->good()) throw string("Error when opening file for writing."); if ((long) image->size() != width * height) throw string("Array size does not match given dimensions."); //Plain ASCII PGM format *out << "P2" << std::endl; //Magic Number *out << "# CREATOR: SLI/Synod. The NEST cooperation 2003." << std::endl; *out << width << " " << height << std::endl; *out << maxval << std::endl; for (unsigned int i=0; i < image->size(); i++){ *out << image->get(i); // write newline after 20 written numbers or // one pixel row, which ever comes first if (width > 20) { if ((i+1) % 20 == 0) *out << std::endl; else *out << " "; } else { if ((i+1)% width == 0) *out << std::endl; else *out << " "; } } *out << std::endl; //make sure file ends in a newline delete out; } catch(std::exception& e) { throw string("exception: ") + e.what(); } catch(string const &s) { delete out; i->message(SLIInterpreter::M_ERROR, "writePGM","Error writing image."); i->message(SLIInterpreter::M_ERROR, "writePGM",s.c_str()); i->raiseerror(i->BadIOError); return; } // clean up i->EStack.pop(); i->OStack.pop(); i->OStack.pop(); i->OStack.pop(); i->OStack.pop(); i->OStack.pop(); } void SLIgraphics::init(SLIInterpreter *i) { i->createcommand("readPGM",&readpgmfunction); i->createcommand("writePGM",&writepgmfunction); } const string SLIgraphics::name() const { return string("SLIgraphics"); } const string SLIgraphics::commandstring() const { return "M_DEBUG (SLIgraphics) (Initialising Graphics IO) message"; }