00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026 #include <cctype>
00027 #include <fstream>
00028 #include <strstream>
00029 #include "ImageIO.h"
00030
00031 namespace halftoner
00032 {
00033
00034
00035
00036
00037
00038 Image* ImageIO::loadPGM(std::istream& is) throw(ImageFormatError, IOError)
00039 {
00040
00041 const char P = 'P';
00042 const char TWO = '2';
00043 const char FIVE = '5';
00044 const char COMMENT = '#';
00045
00046 const int ASCII = 2;
00047 const int RAW = 5;
00048 const int ERROR = -1;
00049
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
00056 char b;
00057
00058 is.get(b);
00059 if (P != b)
00060 {
00061 std::string s("loadPGM - first character not P");
00062 throw ImageFormatError(s);
00063 }
00064
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
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
00082 while (END != state)
00083 {
00084 is.get(b);
00085
00086 if (COMMENT == b)
00087 {
00088 while (b != '\n') is.get(b);
00089 }
00090
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
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
00130 else if (isspace(b) && (assembling == false))
00131 {
00132 }
00133 }
00134
00135 int len = width * height;
00136 int* data = new int[len];
00137 int dataIndex = 0;
00138 b = 0;
00139
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
00156 else if (mode == ASCII)
00157 {
00158 assembling = false;
00159 int gray = 0;
00160 while (dataIndex < len)
00161 {
00162 is.get(b);
00163
00164 if (isdigit(b))
00165 {
00166 conv[0] = b;
00167 gray = gray * 10 + atoi(conv);
00168 assembling = true;
00169 }
00170
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
00178 else if (isspace(b) && assembling == false)
00179 {
00180 }
00181
00182 else
00183 {
00184 string s("loadPGM - corrupt data");
00185 throw ImageFormatError(s);
00186 }
00187 }
00188 }
00189
00190 else if (ERROR == mode)
00191 {
00192 string s("loadPGM - ERROR");
00193 throw ImageFormatError(s);
00194 }
00195
00196 else
00197 {
00198 string s("loadPGM - pikachu clause");
00199 throw ImageFormatError(s);
00200 }
00201
00202 Image* image = new Image(width, height);
00203
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
00214 delete [] data;
00215 return image;
00216 }
00217
00218 void ImageIO::savePBMraw(const Image& image, std::ostream& os) throw(IOError)
00219 {
00220
00221 const unsigned char* data = image.getCopy();
00222 const int w = image.getWidth();
00223 const int h = image.getHeight();
00224
00225 os << "P4" << '\n';
00226 os << w << " " << h << '\n';
00227
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
00268 const unsigned char* data = image.getCopy();
00269 const int w = image.getWidth();
00270 const int h = image.getHeight();
00271
00272 os << "P1" << std::endl;
00273 os << w << " " << h << std::endl;
00274
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 }