Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

ImageIO.cxx

Go to the documentation of this file.
00001 /*
00002  * @(#)src/ImageIO.cxx  1.0  2002-08-27 13:35
00003  *
00004  * Copyright (C)  2002  Daniel Léonard
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00019  */
00020 
00026 #include <cctype>
00027 #include <fstream>
00028 #include <strstream>
00029 #include "ImageIO.h"
00030 
00031 namespace halftoner
00032 {
00033 
00034 //---------------------------
00035 // Class methods
00036 //---------------------------
00037 
00038    Image* ImageIO::loadPGM(std::istream& is) throw(ImageFormatError, IOError)
00039    {
00040    // litterals
00041       const char P = 'P';
00042       const char TWO = '2';
00043       const char FIVE = '5';
00044       const char COMMENT = '#';
00045    // greater states
00046       const int ASCII = 2;
00047       const int RAW = 5;
00048       const int ERROR = -1;
00049    // specific states
00050       const int BEGIN = -1;
00051       const int GRAY = 0;
00052       const int WIDTH = 1;
00053       const int HEIGHT = 2;
00054       const int END = 3;
00055    // tmp
00056       char b;
00057    // get the 'P'
00058       is.get(b);
00059       if (P != b)
00060       {
00061          std::string s("loadPGM - first character not P");
00062          throw ImageFormatError(s);
00063       }
00064    // get the '2' or '5'
00065       is.get(b);
00066       if ((TWO != b) && (FIVE != b))
00067       {
00068          std::string s("loadPGM - second character not 2 or 5");
00069          throw ImageFormatError(s);
00070       }
00071    // initialize finite state machine
00072       int mode = ERROR;
00073       if (TWO == b) mode = ASCII;
00074       if (FIVE == b) mode = RAW;
00075       int width = 0;
00076       int height = 0;
00077       int maxgray = 0;
00078       bool assembling = false;
00079       char conv[2]; conv[1] = '\0';
00080       int state = BEGIN;
00081    // here we go
00082       while (END != state)
00083       {
00084          is.get(b);
00085       // comment ?
00086          if (COMMENT == b)
00087          {
00088             while (b != '\n') is.get(b);
00089          }
00090       // a number
00091          if (isdigit(b))
00092          {
00093             conv[0] = static_cast<char>(b);
00094             assembling = true;
00095             switch (state)
00096             {
00097                case BEGIN:
00098                   width = width * 10 + atoi(conv);
00099                   state = WIDTH;
00100                   break;
00101                case WIDTH:
00102                   width = width * 10 + atoi(conv);
00103                   break;
00104                case HEIGHT:
00105                   height = height * 10 + atoi(conv);
00106                   break;
00107                case GRAY:
00108                   maxgray = maxgray * 10 + atoi(conv);
00109                   break;
00110             }
00111          }
00112       // separator, change state
00113          else if (isspace(b) && assembling)
00114          {
00115             switch (state)
00116             {
00117                case GRAY:
00118                   state = END;
00119                   break;
00120                case WIDTH:
00121                   state = HEIGHT;
00122                   break;
00123                case HEIGHT:
00124                   state = GRAY;
00125                   break;
00126             }
00127             assembling = false;
00128          }
00129       // white space - do nothing
00130          else if (isspace(b) && (assembling == false))
00131          {
00132          }
00133       }
00134    // reading data
00135       int len = width * height;
00136       int* data = new int[len];
00137       int dataIndex = 0;
00138       b = 0;
00139    // raw mode
00140       if (mode == RAW)
00141       {
00142          unsigned char uc;
00143          while (dataIndex < len)
00144          {
00145             is.get(uc);
00146             if (uc > maxgray)
00147             {
00148                ostrstream os;
00149                os << "loadPGM - " << uc << " greater than maxgray " << maxgray;
00150                throw ImageFormatError(os.str());
00151             }
00152             data[dataIndex++] = static_cast<int>((static_cast<double>(uc) / static_cast<double>(maxgray)) * 255);
00153          }
00154       }
00155    // ascii mode
00156       else if (mode == ASCII)
00157       {
00158          assembling = false;
00159          int gray = 0;
00160          while (dataIndex < len)
00161          {
00162             is.get(b);
00163          // a number
00164             if (isdigit(b))
00165             {
00166                conv[0] = b;
00167                gray = gray * 10 + atoi(conv);
00168                assembling = true;
00169             }
00170          // separator
00171             else if (isspace(b) && assembling)
00172             {
00173                data[dataIndex++] = static_cast<int>((static_cast<double>(gray) / static_cast<double>(maxgray)) * 255);
00174                gray = 0;
00175                assembling = false;
00176             }
00177          // white space - do nothing
00178             else if (isspace(b) && assembling == false)
00179             {
00180             }
00181          // pikachu
00182             else
00183             {
00184                string s("loadPGM - corrupt data");
00185                throw ImageFormatError(s);
00186             }
00187          }
00188       }
00189    // error checking - should not happen
00190       else if (ERROR == mode)
00191       {
00192          string s("loadPGM - ERROR");
00193          throw ImageFormatError(s);
00194       }
00195    // pedantic error checking
00196       else
00197       {
00198          string s("loadPGM - pikachu clause");
00199          throw ImageFormatError(s);
00200       }
00201    // image creation
00202       Image* image = new Image(width, height);
00203    // copy pixels
00204       dataIndex = 0;
00205       int h, w;
00206       for (h = 0; h < height; h++)
00207       {
00208          for (w = 0; w < width; w++)
00209          {
00210             image->setColorAt(w, h, data[dataIndex++]);
00211          }
00212       }
00213    // been a pleasure dealing with you
00214       delete [] data;
00215       return image;
00216    }
00217 
00218    void ImageIO::savePBMraw(const Image& image, std::ostream& os) throw(IOError)
00219    {
00220    // getting pixels and dimensions
00221       const unsigned char* data = image.getCopy();
00222       const int w = image.getWidth();
00223       const int h = image.getHeight();
00224    // printing header
00225       os << "P4" << '\n';
00226       os << w << " " << h << '\n';
00227    // printing pixels
00228       unsigned char bw = 0x00;
00229       int len = w * h;
00230       for (int i = 0; i < len; i++)
00231       {
00232          int color = data[i] & 0x01;
00233          switch (i % 8)
00234          {
00235             case 0:
00236                bw = (color << 7 | bw);
00237                break;
00238             case 1:
00239                bw = (color << 6 | bw);
00240                break;
00241             case 2:
00242                bw = (color << 5 | bw);
00243                break;
00244             case 3:
00245                bw = (color << 4 | bw);
00246                break;
00247             case 4:
00248                bw = (color << 3 | bw);
00249                break;
00250             case 5:
00251                bw = (color << 2 | bw);
00252                break;
00253             case 6:
00254                bw = (color << 1 | bw);
00255                break;
00256             case 7:
00257                bw = (color | bw);
00258                os.put(~bw & 0xff);
00259                bw = 0x00;
00260                break;
00261          }
00262       }
00263    }
00264 
00265    void ImageIO::savePBMascii(const Image& image, std::ostream& os) throw(IOError)
00266    {
00267    // getting pixels and dimensions
00268       const unsigned char* data = image.getCopy();
00269       const int w = image.getWidth();
00270       const int h = image.getHeight();
00271    // printing header
00272       os << "P1" << std::endl;
00273       os << w << " " << h << std::endl;
00274    // printing pixels
00275       int len = w * h;
00276       for (int i = 0; i < len; i++)
00277       {
00278          os << (1 - (data[i] & 0x01));
00279          if ((i % 15) == 14) os << std::endl;
00280          else os << " ";
00281       }
00282    }
00283 
00284 }

Generated on Sat Sep 7 16:31:38 2002 for Halftoning Library by doxygen1.2.17