00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "sstream"
00028 #include "iostream"
00029 #include "fstream"
00030
00031
00032
00033
00034 #include "ioPPM.hpp"
00035 #include "ImageException.hpp"
00036
00037
00038
00039
00040 namespace kn{
00041
00042 char skipComment(std::istream& is) {
00043 char c = is.get();
00044
00045
00046 while ((c == ' ') ||(c == '\n') || (c == '#'))
00047 {
00048
00049 if (c == '#') do { c = is.get(); } while (c != '\n');
00050 c = is.get();
00051 }
00052 is.putback(c);
00053 return c;
00054 }
00055
00056
00057 char skipSpace(std::istream& is) {
00058 char c = is.get();
00059
00060
00061 while ((c == ' ') || (c == '\n') || (c == '\t')) {
00062 c = is.get();
00063 }
00064 is.putback(c);
00065 return c;
00066 }
00067
00068
00069
00070
00071 int loadPPM(Image<unsigned char>& res,const std::string& filename) {
00072 std::fstream is;
00073 unsigned int componentperpixel = 1;
00074 bool isascii = false;
00075 bool isonebitperpixel = false;
00076 size_t width,height,size=0;
00077
00078
00079
00080 if (res.size()>0) {
00081 throw ImageException("Image already allocated. Cannot store PPM in that image.","loadFile");
00082 }
00083
00084
00085 is.open(filename.c_str(),std::ios::in);
00086 if (!is.is_open()) {
00087 throw ImageException("File " + filename + " not found or unreadable","loadFile");
00088 }
00089 std::string content;
00090 is >> content;
00091 if ((content.size()<2) || (content[0] != 'P') ||
00092 ((int)(content[1]-'0')<1) || ((int)(content[1]-'0')>6) ) {
00093 throw ImageException("File format error : Wrong header ("+content+")","loadFile");
00094 }
00095 int code = (content[1]-'0');
00096
00097 switch (code) {
00098 case (1) :
00099 isascii = true;
00100 case (4) :
00101 isonebitperpixel = true;
00102 break;
00103 case (2) :
00104 isascii = true;
00105 case (5) :
00106 break;
00107 case (3) :
00108 isascii = true;
00109 case (6) :
00110 componentperpixel = 3;
00111 break;
00112 default:
00113 throw ImageException("File format error : Wrong header ("+content+")","loadFile");
00114 break;
00115 }
00116
00117
00118 char c = skipComment(is);
00119
00120 is >> width;
00121 c = skipComment(is);
00122
00123 is >> height;
00124 c = skipComment(is);
00125
00126 if (!isonebitperpixel) {
00127 is >> size;
00128 c = is.get();
00129
00130 }
00131 if ((width<=0) || (height<=0)) {
00132 std::stringstream serr;
00133 serr << "File format error : width or size negative or null (w=";
00134 serr << width << "/h=" << height <<")";
00135 throw ImageException(serr.str(),"loadFile");
00136 }
00137 if ((!isonebitperpixel) && (size != 255)) {
00138 throw ImageException("File format problem : We deal only with 255 level of color. This image is "+size,"loadFile");
00139 }
00140
00141
00142 unsigned char* thebuffer = NULL;
00143 char pixchar;
00144 int pixel;
00145 thebuffer = new unsigned char[componentperpixel*width*height];
00146
00147 if (isascii) {
00148 for(size_t i=0;i<(unsigned int)(width*height*componentperpixel);i++) {
00149
00150 if (isonebitperpixel) {
00151 pixchar = skipSpace(is);
00152 pixchar = is.get();
00153 }
00154 else{
00155 is >> pixel;
00156 }
00157 if (!isonebitperpixel && ((pixel<0) || (pixel>255)))
00158 throw ImageException("File format problem : We deal only with 255 level of color. One pixel is "+pixel,"loadFile");
00159 if (isonebitperpixel){
00160 thebuffer[i]=((int)(pixchar-'0')==0)?255:0;
00161
00162 }
00163 else {
00164 thebuffer[i]=(unsigned char)pixel;
00165
00166 }
00167 }
00168 }
00169
00170 else {
00171 if (isonebitperpixel) {
00172
00173
00174
00175 unsigned int sizebitwidth = (width%8 == 0)?(width/8):(width/8)+1;
00176 unsigned int sizebitbuffer = sizebitwidth*height;
00177 char* firstbuffer = new char[sizebitbuffer];
00178 unsigned int index = 0;
00179 unsigned int decal = 0;
00180 unsigned char masq = 0x00;
00181
00182 is.read(firstbuffer,sizebitbuffer);
00183 for(size_t i=0;i<height;i++) {
00184
00185 for(size_t j=0;j<width;j++) {
00186 masq = 0x01;
00187 index = j/8;
00188 decal = j%8;
00189 masq = masq << (7-decal);
00190 thebuffer[i*width+j] = ((int)(masq & firstbuffer[i*sizebitwidth+index])>0)?0:255;
00191 }
00192 }
00193 }
00194 else {
00195 is.read((char*)thebuffer,width*height*componentperpixel*sizeof(unsigned char));
00196
00197 }
00198 }
00199 is.close();
00200
00201
00202 if ((res.nbChannel()>0) && (componentperpixel != res.nbChannel())) {
00203 unsigned char* buffer_bis = new unsigned char[res.nbChannel()*width*height];
00204 if ((componentperpixel == 3) && (res.nbChannel()==1)) {
00205
00206 for(unsigned int i=0;i<width*height;i++) {
00207 buffer_bis[i] = (unsigned char)((int)(thebuffer[3*i]+thebuffer[3*i+1]+thebuffer[3*i+2])/3);
00208 }
00209 }
00210 else if ((componentperpixel == 1) && (res.nbChannel()==3)) {
00211
00212
00213 for(unsigned int i=0;i<width*height;i++) {
00214 buffer_bis[3*i ] = (unsigned char)(thebuffer[i]);
00215 buffer_bis[3*i+1] = (unsigned char)(thebuffer[i]);
00216 buffer_bis[3*i+2] = (unsigned char)(thebuffer[i]);
00217 }
00218 }
00219 else {
00220 std::stringstream serr;
00221 serr << "When loading a PPM file with nbChannel "<<componentperpixel<<", conversion impossible for image nbChannel "<<res.nbChannel();
00222 throw ImageException(serr.str(),"loadFile");
00223 }
00224 delete[](thebuffer);
00225 thebuffer = buffer_bis;
00226 }
00227
00228
00229 try {
00230 res.buildImageFromBuffer(width,height,componentperpixel,thebuffer);
00231 }
00232 catch (ImageException &e) {
00233
00234 throw ImageException("Exception rising when building image from buffer : "+e.errorString(),"loadFilePPM");
00235 }
00236 if (thebuffer != NULL) delete[](thebuffer);
00237 return componentperpixel;
00238 }
00239
00240
00241 bool savePPM(Image<unsigned char>& res,const std::string& filename) {
00242
00243 size_t componentperpixel = res.nbChannel();
00244 size_t width = res.width();
00245 size_t height = res.height();
00246 size_t size = res.size();
00247
00248 if ( (componentperpixel == 0) || (width == 0) || (height == 0) || (size == 0)) {
00249 throw ImageException("No data in Image or data mismatch. No export in PPM file possible","exportFile");
00250 }
00251 if (size != width*height*componentperpixel*sizeof(unsigned char)) {
00252 throw ImageException("Something weird on data or not a UNSIGNED CHAR image","exportFile");
00253 }
00254 if ((componentperpixel!=1) && (componentperpixel!=3)) {
00255 std::stringstream serr;
00256 serr << "Component per pixel is "<<componentperpixel;
00257 serr << ". Unable to make a PPM with this image nbChannel"<<std::endl;
00258 throw ImageException(serr.str(),"exportFile");
00259 }
00260
00261 std::ofstream os(filename.c_str(),std::ofstream::binary);
00262 if (!os.is_open()) {
00263 throw ImageException("Unable to open "+filename+" for writing","exportFile");
00264 }
00265 if (componentperpixel == 1) {
00266 os << "P5" <<std::endl;
00267 }
00268 else {
00269 os << "P6" <<std::endl;
00270 }
00271 os<<"# PPM Image generated by OpenKraken info(biri@univ-mlv.fr)"<<std::endl;
00272 os<<width<<" "<<height<<std::endl;
00273
00274 os<<"255"<<std::endl;
00275
00276 os.write((char*)res.begin(),size);
00277
00278 os.close();
00279
00280 return (1);
00281 }
00282
00283
00284
00285
00286
00287
00288 }