gKitGL
|
00001 00002 #ifndef _IOIMAGE_H 00003 #define _IOIMAGE_H 00004 00005 #include <cstdio> 00006 #include <cstdlib> 00007 #include <cassert> 00008 00009 #include "SDLImagePlatform.h" 00010 00011 #ifdef __cplusplus 00012 extern "C" { 00013 #include "rgbe.h" 00014 } 00015 #endif 00016 00017 #include "Geometry.h" 00018 #include "IOResource.h" 00019 00020 #include "IOManager.h" 00021 #include "Image.h" 00022 00023 // Modifs JPF : includes pour exr 00024 #include <ImfRgbaFile.h> 00025 #include <ImfStringAttribute.h> 00026 #include <ImfMatrixAttribute.h> 00027 #include <ImfArray.h> 00028 00029 using namespace Imf; 00030 using namespace Imath; 00031 00032 namespace gk { 00033 00034 //! operations d'entree/sortie sur les formats standards, jpg, bmp, png, tiff, etc. 00035 class ImageIO : public IOManager<Image> 00036 { 00037 // non copyable 00038 ImageIO( const ImageIO& ); 00039 ImageIO& operator=( const ImageIO& ); 00040 00041 // private default constructor, singleton 00042 ImageIO( ) 00043 : 00044 IOManager<Image>() 00045 {} 00046 00047 public: 00048 static 00049 bool isColorFile( const std::string& filename ) 00050 { 00051 return ((filename.rfind(".bmp") != std::string::npos) 00052 || (filename.rfind(".png") != std::string::npos) 00053 || (filename.rfind(".jpg") != std::string::npos) 00054 || (filename.rfind(".jpeg") != std::string::npos) 00055 || (filename.rfind(".tga") != std::string::npos)); 00056 } 00057 00058 //! charge le fichier 'filename' et renvoie l'image correspondante. 00059 static 00060 Image *read( const std::string& filename, const std::string& name= "" ) 00061 { 00062 // importer le fichier, si necessaire 00063 Image *image= manager().find(filename, name); 00064 if(image != NULL) 00065 return image; 00066 00067 #ifdef VERBOSE 00068 printf("loading color image '%s'...\n", filename.c_str()); 00069 #endif 00070 00071 // importer le fichier 00072 SDL_Surface *surface= IMG_Load(filename.c_str()); 00073 if(surface == NULL) 00074 return NULL; 00075 00076 // verifier le format, rgb ou rgba 00077 const SDL_PixelFormat format= *surface->format; 00078 00079 #ifdef VERBOSE_DEBUG 00080 printf(" image pixel format : " 00081 "bytes %d, bpp %d, " 00082 "red %x, shift %d, loss %d, " 00083 "green %x, shift %d, loss %d, " 00084 "blue %x, shift %d, loss %d, " 00085 "alpha %x, shift %d, loss %d\n", 00086 format.BytesPerPixel, format.BitsPerPixel, 00087 format.Rmask, format.Rshift, format.Rloss, 00088 format.Gmask, format.Gshift, format.Gloss, 00089 format.Bmask, format.Bshift, format.Bloss, 00090 format.Amask, format.Ashift, format.Aloss); 00091 #endif 00092 00093 if(format.BitsPerPixel != 24 && format.BitsPerPixel != 32) 00094 { 00095 SDL_FreeSurface(surface); 00096 return NULL; 00097 } 00098 00099 // creer l'image 00100 const int height= surface->h; 00101 const int width= surface->w; 00102 image= new Image(width, height); 00103 if(image == NULL) 00104 return NULL; 00105 00106 // converti les donnees en pixel rgba, retourne l'image, openGL utilise une origine en bas a gauche. 00107 Uint8 *p= (Uint8 *) surface->pixels; 00108 int py= 0; 00109 if(format.BitsPerPixel == 32) 00110 { 00111 for(int y= height -1; y >= 0; y--, py++) 00112 { 00113 p= (Uint8 *) surface->pixels + py * surface->pitch; 00114 for(int x= 0; x < width; x++, p+= format.BytesPerPixel) 00115 { 00116 const Uint8 r= p[format.Rshift / 8]; 00117 const Uint8 g= p[format.Gshift / 8]; 00118 const Uint8 b= p[format.Bshift / 8]; 00119 const Uint8 a= p[format.Ashift / 8]; 00120 00121 image->setPixel(x, y, Pixel(r, g, b, a)); 00122 } 00123 } 00124 } 00125 else if(format.BitsPerPixel == 24) 00126 { 00127 for(int y= height -1; y >= 0; y--, py++) 00128 { 00129 p= (Uint8 *) surface->pixels + py * surface->pitch; 00130 for(int x= 0; x < width; x++, p+= format.BytesPerPixel) 00131 { 00132 const Uint8 r= p[format.Rshift / 8]; 00133 const Uint8 g= p[format.Gshift / 8]; 00134 const Uint8 b= p[format.Bshift / 8]; 00135 00136 image->setPixel(x, y, Pixel(r, g, b)); 00137 } 00138 } 00139 } 00140 00141 SDL_FreeSurface(surface); 00142 00143 // reference l'image avec le manager 00144 return manager().insert(image, filename, name); 00145 } 00146 00147 //! ecrit une image dans un fichier .bmp nomme 'filename'. 00148 static 00149 int write( const Image *image, const std::string& filename ) 00150 { 00151 if(image == NULL) 00152 return -1; 00153 00154 #ifdef VERBOSE 00155 printf("writing color image '%s'...\n", filename.c_str()); 00156 #endif 00157 00158 // flip de l'image : Y inverse entre GL et BMP 00159 Pixel *flip= new Pixel[image->width() * image->height()]; 00160 Pixel *data= flip; 00161 for(int y= image->height() -1; y >= 0; y--) 00162 { 00163 memcpy(data, (Pixel *) image->data() + y * image->width(), image->width() * sizeof(Pixel)); 00164 data+= image->width(); 00165 } 00166 00167 SDL_Surface *bmp= SDL_CreateRGBSurfaceFrom((void *) flip, 00168 image->width(), image->height(), 00169 32, image->width() * 4, 00170 #if 0 00171 0xFF000000, 00172 0x00FF0000, 00173 0x0000FF00, 00174 0x000000FF 00175 #else 00176 0x000000FF, 00177 0x0000FF00, 00178 0x00FF0000, 00179 0xFF000000 00180 #endif 00181 ); 00182 00183 int code= SDL_SaveBMP(bmp, filename.c_str()); 00184 SDL_FreeSurface(bmp); 00185 delete [] flip; 00186 return code; 00187 } 00188 00189 static 00190 ImageIO& manager( ) // singleton 00191 { 00192 static ImageIO manager; 00193 return manager; 00194 } 00195 }; 00196 00197 00198 //! operations d'entree/sortie sur une image .hdr. 00199 class HDRImageIO : public IOManager<HDRImage> 00200 { 00201 HDRImageIO( const HDRImageIO& ); 00202 HDRImageIO& operator=( const HDRImageIO& ); 00203 00204 // private default constructor, singleton 00205 HDRImageIO( ) 00206 : 00207 IOManager<HDRImage>() 00208 {} 00209 00210 public: 00211 //! charge une image rgbe, .hdr 00212 static 00213 HDRImage *RGBEread( const std::string& filename, const std::string& name= "" ) 00214 { 00215 FILE *in= fopen( filename.c_str(), "rb" ); 00216 if(in == NULL) 00217 { 00218 printf("\n -- read error '%s'\n", filename.c_str()); 00219 return NULL; 00220 } 00221 00222 rgbe_header_info info; 00223 int width, height; 00224 int code = RGBE_ReadHeader(in, &width, &height, &info); 00225 if(code != RGBE_RETURN_SUCCESS) 00226 { 00227 fclose(in); 00228 printf("\n -- read error '%s'\n", filename.c_str()); 00229 return NULL; 00230 } 00231 00232 float *data= new float[width*height*3]; 00233 code= RGBE_ReadPixels_RLE(in, data, width, height); 00234 if(code != RGBE_RETURN_SUCCESS) 00235 { 00236 fclose(in); 00237 delete [] data; 00238 printf("\n -- read error '%s'\n", filename.c_str()); 00239 return NULL; 00240 } 00241 00242 fclose(in); 00243 00244 // converti les donnees en pixels hdr, retourne l'image, openGL utilise une origine en bas a gauche. 00245 HDRImage *image= new HDRImage(width, height); 00246 if(image == NULL) 00247 return NULL; 00248 00249 float *p= data; 00250 for(int y= height -1; y >= 0; y--) 00251 for(int x= 0; x < width; x++, p+= 3) 00252 image->setPixel(x, y, HDRPixel(p[0], p[1], p[2])); 00253 00254 delete [] data; 00255 00256 // reference l'image avec le manager 00257 return manager().insert(image, filename, name); 00258 } 00259 00260 static 00261 bool is_rgbe_file( const std::string& filename ) 00262 { 00263 return (filename.rfind(".hdr") != std::string::npos); 00264 } 00265 00266 //! charge une image openexr, .exr 00267 // Fait par JPF 00268 static 00269 HDRImage *EXRread( const std::string& filename, const std::string& name= "" ) 00270 { 00271 RgbaInputFile file (filename.c_str()); 00272 Box2i dw = file.dataWindow(); 00273 int width = dw.max.x - dw.min.x + 1; 00274 int height = dw.max.y - dw.min.y + 1; 00275 00276 Array2D<Rgba> pixels; 00277 00278 pixels.resizeErase (height, width); 00279 file.setFrameBuffer (&pixels[0][0] - dw.min.x - dw.min.y * width, 1, width); 00280 file.readPixels (dw.min.y, dw.max.y); 00281 00282 // Recompie du framebuffer en HDRImage gKit 00283 Rgba* p = pixels[0]; 00284 HDRImage *image= new HDRImage(width, height); 00285 00286 for(int y= height -1; y >= 0; y--) 00287 for(int x= 0; x < width; x++, p++) 00288 image->setPixel(x, y, HDRPixel((float)(p[0].r), (float)(p[0].g), (float)(p[0].b))); 00289 00290 return manager().insert(image, filename, name); 00291 } 00292 00293 static 00294 bool is_exr_file( const std::string& filename ) 00295 { 00296 return (filename.rfind(".exr") != std::string::npos); 00297 } 00298 00299 static 00300 bool isHDRFile( const std::string& filename ) 00301 { 00302 return is_rgbe_file(filename); // || is_exr_file(filename) 00303 } 00304 00305 //! charge le fichier 'filename' et renvoie l'image correspondante. 00306 static 00307 HDRImage *read( const std::string& filename, const std::string& name= "" ) 00308 { 00309 // importer le fichier, si necessaire 00310 HDRImage *image= manager().find(filename, name); 00311 if(image != NULL) 00312 return image; 00313 00314 #ifdef VERBOSE 00315 printf("loading hdr image '%s'...\n", filename.c_str()); 00316 #endif 00317 00318 if(is_rgbe_file(filename)) 00319 return RGBEread(filename, name); 00320 00321 // Modifs JPF 00322 if(is_exr_file(filename)) 00323 return EXRread(filename, name); 00324 00325 if(ImageIO::isColorFile(filename)) 00326 { 00327 // charger... 00328 Image *color= ImageIO::read(filename, name); 00329 if(color == NULL) 00330 return NULL; 00331 00332 //... et convertir l'image 00333 HDRImage *hdr= new HDRImage(color->width(), color->height()); 00334 00335 for(unsigned int y= 0; y < color->height(); y++) 00336 for(unsigned int x= 0; x < color->width(); x++) 00337 hdr->setPixel(x, y, color->getPixel(x, y)); 00338 00339 // reference l'image avec le manager 00340 return manager().insert(hdr, filename, name); 00341 } 00342 00343 // format non supporte. 00344 return NULL; 00345 } 00346 00347 //! enregistre l'image avec le nom 'filename'. 00348 static 00349 int write( const HDRImage *image, const std::string& filename ) 00350 { 00351 if(image == NULL) 00352 return -1; 00353 00354 #ifdef VERBOSE 00355 printf("writing hdr image '%s'...\n", filename.c_str()); 00356 #endif 00357 00358 FILE *out= fopen(filename.c_str(), "wb"); 00359 if(out == NULL) 00360 { 00361 printf("\n -- write error '%s'\n", filename.c_str()); 00362 return -1; 00363 } 00364 00365 int code= RGBE_WriteHeader(out, image->width(), image->height(), NULL); 00366 if(code != RGBE_RETURN_SUCCESS) 00367 { 00368 printf("\n -- write error '%s'\n", filename.c_str()); 00369 fclose(out); 00370 return -1; 00371 } 00372 00373 float *data= new float[image->width() * image->height() * 3]; 00374 float *p= data; 00375 for(int y= (int) image->height() -1; y > 0; y--) 00376 { 00377 for(unsigned int x= 0; x < image->width(); x++, p+= 3) 00378 { 00379 const HDRPixel& pixel= image->getPixel(x, y); 00380 p[0]= pixel.r; 00381 p[1]= pixel.g; 00382 p[2]= pixel.b; 00383 } 00384 } 00385 00386 code= RGBE_WritePixels_RLE(out, (const float *) data, image->width(), image->height()); 00387 fclose(out); 00388 delete [] data; 00389 00390 if(code != RGBE_RETURN_SUCCESS) 00391 { 00392 printf("\n -- write error '%s'\n", filename.c_str()); 00393 return -1; 00394 } 00395 00396 return 0; 00397 } 00398 00399 static 00400 HDRImageIO& manager( ) // singleton 00401 { 00402 static HDRImageIO manager; 00403 return manager; 00404 } 00405 }; 00406 00407 } // namespace 00408 00409 #endif