gKitGL
ImageIO.h
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
 All Classes Namespaces Functions Variables Typedefs Enumerator Friends