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 #include <sstream>
00027 #include <fstream>
00028 #include "iostream"
00029
00030
00031
00032
00033 #include "ioTGA.hpp"
00034 #include "ImageException.hpp"
00035 #include "Image.hpp"
00036
00037
00038
00039
00040 namespace kn {
00041 typedef struct str_TGA_Header_loader
00042 {
00043 unsigned char size_id_file;
00044 unsigned char as_color_map;
00045 unsigned char image_type;
00046 unsigned char color_map_spec[5];
00047 size_t width;
00048 size_t height;
00049 int xorigine;
00050 int yorigine;
00051 unsigned int depth_per_pixel;
00052 unsigned char size_alpha_per_pixel;
00053 bool vertical_flip;
00054 bool horizont_flip;
00055 } TGA_Header_loader;
00056
00057
00058
00059
00060 void readingError(std::ifstream& is,unsigned char* tab) {
00061 if (!is.good()) {
00062 if (tab != NULL) delete[](tab);
00063 is.close();
00064 throw ImageException("TGA Loader : Data corruption. Could not read file data","loadFile");
00065 }
00066 }
00067
00068 unsigned char* readColorTGANoCompress(std::ifstream& is,TGA_Header_loader* tgaheader,
00069 int& nb_component_per_pixel) {
00070 unsigned int cswap;
00071 unsigned char* tabRVB;
00072 nb_component_per_pixel = 3;
00073 int d = tgaheader->depth_per_pixel;
00074 size_t w = tgaheader->width;
00075 size_t h = tgaheader->height;
00076
00077 if( (d != 24) && (d !=32) ) {
00078 is.close();
00079 throw ImageException("TGA Data file corrupted : color image (no compress) should have depth 24 or 32","readColorTGANoCompress");
00080 }
00081
00082
00083
00084
00085 if(d == 32) {
00086 nb_component_per_pixel = 4;
00087 is.close();
00088 throw ImageException("Impossible to read TGA with transparency. Maybe in future release","readColorTGANoCompress");
00089 }
00090
00091 size_t size = nb_component_per_pixel * w * h;
00092
00093 tabRVB = new unsigned char[size];
00094 if(tabRVB == NULL) {
00095 is.close();
00096 throw ImageException("Unable to fetch memory in loading TGA","readColorTGANoCompress");
00097 }
00098
00099 is.read((char*)tabRVB,size);
00100 readingError(is,tabRVB);
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120 unsigned char tmp;
00121 for(cswap = 0; cswap < size; cswap += nb_component_per_pixel) {
00122 tmp = tabRVB[cswap];
00123 tabRVB[cswap] = tabRVB[cswap+2];
00124 tabRVB[cswap+2] = tmp;
00125
00126
00127
00128 }
00129
00130 return tabRVB;
00131 }
00132
00133 unsigned char* readColorTGACompress(std::ifstream& is,TGA_Header_loader* tgaheader,
00134 int& nb_component_per_pixel) {
00135
00136 size_t pixelcount = 0;
00137 size_t currentpixel = 0;
00138 unsigned char *tabRVB = NULL;
00139 unsigned int currentbyte = 0;
00140 unsigned char* colorbuffer = NULL;
00141 size_t size = 0;
00142 nb_component_per_pixel = 3;
00143
00144
00145 pixelcount = tgaheader->width * tgaheader->height;
00146 if((tgaheader->depth_per_pixel != 24) && (tgaheader->depth_per_pixel !=32)) {
00147 is.close();
00148 throw ImageException("TGA Data file corrupted : color image (compress) should have depth 24 or 32","readColorTGANoCompress");
00149 }
00150 if(tgaheader->depth_per_pixel == 32) {
00151 nb_component_per_pixel = 4;
00152 is.close();
00153 throw ImageException("Impossible to read TGA with transparency. Maybe in future release","readColorTGANoCompress");
00154 }
00155
00156
00157 size = (nb_component_per_pixel * pixelcount);
00158 tabRVB = new unsigned char[size];
00159 if(tabRVB == NULL) {
00160 is.close();
00161 throw ImageException("Unable to fetch memory in loading TGA","readColorTGANoCompress");
00162 }
00163 colorbuffer = new unsigned char[nb_component_per_pixel];
00164 if(colorbuffer == NULL) {
00165 is.close();
00166 throw ImageException("Unable to fetch memory in loading TGA","readColorTGANoCompress");
00167 }
00168 do {
00169 unsigned char chunkheader = 0;
00170 is.read((char*)(&chunkheader),1);
00171 readingError(is,tabRVB);
00172
00173 if(chunkheader < 128) {
00174
00175 short counter;
00176 chunkheader++;
00177 for(counter = 0; counter < chunkheader; counter++) {
00178 is.read((char*)colorbuffer,nb_component_per_pixel);
00179 readingError(is,tabRVB);
00180
00181
00182 tabRVB[currentbyte ] = colorbuffer[2];
00183 tabRVB[currentbyte + 1 ] = colorbuffer[1];
00184 tabRVB[currentbyte + 2 ] = colorbuffer[0];
00185
00186 if(nb_component_per_pixel == 4) {
00187 tabRVB[currentbyte + 3] = colorbuffer[3];
00188 }
00189
00190 currentbyte += nb_component_per_pixel;
00191 currentpixel++;
00192
00193 if(currentpixel > pixelcount) {
00194 if (tabRVB != NULL) delete[](tabRVB);
00195 tabRVB = NULL;
00196 is.close();
00197 throw ImageException("TGA Loader : Error too many pixels read","loadFile");
00198 }
00199 }
00200 }
00201 else {
00202
00203 short counter;
00204 chunkheader -= 127;
00205 is.read((char*)colorbuffer,nb_component_per_pixel);
00206 readingError(is,tabRVB);
00207
00208 for(counter = 0; counter < chunkheader; counter++) {
00209 tabRVB[currentbyte ] = colorbuffer[2];
00210 tabRVB[currentbyte + 1 ] = colorbuffer[1];
00211 tabRVB[currentbyte + 2 ] = colorbuffer[0];
00212 if(nb_component_per_pixel == 4) tabRVB[currentbyte + 3] = colorbuffer[3];
00213
00214 currentbyte += nb_component_per_pixel;
00215 currentpixel++;
00216 if(currentpixel > pixelcount){
00217 if (tabRVB != NULL) delete[](tabRVB);
00218 tabRVB = NULL;
00219 is.close();
00220 throw ImageException("TGA Loader : Error too many pixels read","loadFile");
00221 }
00222 }
00223 }
00224 }
00225 while(currentpixel < pixelcount);
00226
00227 return tabRVB;
00228 }
00229
00230 int loadTGA(Image<unsigned char>& res,const std::string& filename) {
00231 TGA_Header_loader tgaheader;
00232 unsigned char Header[18];
00233 unsigned char* thebuffer;
00234 std::ifstream is;
00235 std::stringstream serr;
00236
00237 bool no_data = false;
00238
00239 char descriptor;
00240
00241
00242 if (res.size()>0) {
00243 throw ImageException("Image already allocated. Cannot store TGA image in that image.","loadImage");
00244 }
00245
00246 is.open(filename.c_str(),std::ios::in);
00247 if (is == NULL) {
00248 throw ImageException("TGA Loader : Error could not read file "+filename,"loadImage");
00249 }
00250
00251 is.read((char*)Header,18);
00252 if (is.rdstate() == std::ios_base::failbit) {
00253 is.close();
00254 throw ImageException("TGA Loader : Error could not read file header","loadImage");
00255 }
00256 tgaheader.size_id_file = Header[0];
00257
00258 tgaheader.as_color_map = Header[1];
00259
00260 tgaheader.image_type = Header[2];
00261
00262
00263 if (tgaheader.as_color_map == 1) {
00264
00265 is.close();
00266 throw ImageException("TGA Loader : We do not handle TGA with color map","loadImage");
00267 }
00268
00269 tgaheader.xorigine = Header[9]*256 + Header[8];
00270 tgaheader.yorigine = Header[11]*256 + Header[10];
00271 tgaheader.width = *((unsigned short*) (Header+12));
00272 tgaheader.height = *((unsigned short*) (Header+14));
00273
00274 tgaheader.depth_per_pixel = Header[16];
00275 descriptor = Header[17];
00276 tgaheader.size_alpha_per_pixel = (descriptor & 0x0F);
00277
00278 tgaheader.vertical_flip = false;
00279 if (descriptor & 0x20) {tgaheader.vertical_flip = true;}
00280 tgaheader.horizont_flip = false;
00281 if (descriptor & 0x10) {tgaheader.horizont_flip = true;}
00282
00283
00284
00285 if (tgaheader.horizont_flip) {
00286 is.close();
00287 throw ImageException("TGA Loader : Not handling horizontaly mirrored image","loadImage");
00288 }
00289 if ((tgaheader.width <= 0) || (tgaheader.height <= 0)) {
00290 is.close();
00291 throw ImageException("TGA Loader : Not handling negative or null sized image","loadImage");
00292 }
00293 if ((tgaheader.xorigine != 0) || (tgaheader.yorigine != 0)) {
00294
00295 serr << "TGA Loader : Not handling translated image(";
00296 serr << tgaheader.xorigine<< "/"<<tgaheader.yorigine<<")";
00297
00298
00299 }
00300
00301
00302
00303 if (tgaheader.size_id_file > 0) {
00304 std::cerr<<"Reading id file"<<std::endl;
00305 char *tmp = new char[tgaheader.size_id_file];
00306 is.read(tmp,tgaheader.size_id_file);
00307 if (is.rdstate() == std::ios_base::failbit) {
00308 is.close();
00309 throw ImageException("TGA Loader : Error could not read id file","loadImage");
00310 }
00311 }
00312
00313
00314
00315
00316
00317 int componentperpixel = 0;
00318 switch(tgaheader.image_type) {
00319 case (NONE_TGA) :
00320 no_data = true;
00321 break;
00322 case (COLOR_TGA) :
00323 thebuffer = readColorTGANoCompress(is,&tgaheader,componentperpixel);
00324 break;
00325 case (COLOR_RLE_TGA) :
00326 thebuffer = readColorTGACompress(is,&tgaheader,componentperpixel);
00327 break;
00328 case (INDEXED_TGA) :
00329 case (INDEXED_RLE_TGA) :
00330 case (GS_TGA) :
00331 case (GS_RLE_TGA) :
00332 is.close();
00333 serr << "TGA Loader : Not handling this type of image (";
00334 serr << tgaheader.image_type<< ")";
00335 throw ImageException(serr.str(),"loadImage");
00336 break;
00337 default :
00338 is.close();
00339 throw ImageException("TGA Loader : data failure","loadImage");
00340 }
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351 if (!tgaheader.vertical_flip) {
00352 unsigned char* tmp = new unsigned char[tgaheader.width*tgaheader.height*tgaheader.depth_per_pixel/8];
00353 if (tmp == NULL) {
00354 is.close();
00355 throw ImageException("TGA Loader : unable to fetch memory","loadImage");
00356 }
00357 size_t sizeoneline = tgaheader.width*tgaheader.depth_per_pixel/8;
00358 for(size_t i=0;i<tgaheader.height;i++) {
00359
00360 memcpy(tmp+(i*sizeoneline),thebuffer+(tgaheader.height-1-i)*sizeoneline,sizeoneline);
00361 }
00362 memcpy(thebuffer,tmp,sizeoneline*tgaheader.height);
00363 delete[](tmp);
00364 }
00365
00366
00367 try {
00368 if (no_data) {
00369
00370 res.buildImageFromBuffer(tgaheader.width,tgaheader.height,componentperpixel,NULL);
00371 }
00372 else {
00373
00374
00375 res.buildImageFromBuffer(tgaheader.width,tgaheader.height,
00376 componentperpixel,thebuffer);
00377 if (thebuffer != NULL) delete[](thebuffer);
00378 }
00379 }
00380 catch (ImageException &e) {
00381
00382 if (thebuffer != NULL) delete[](thebuffer);
00383 throw ImageException("Exception rising from Image library : "+e.errorString(),"loadFile");
00384 }
00385
00386 return tgaheader.image_type;
00387 }
00388
00389
00390
00391
00392 }