src/rcrt/textures/Image.cpp

Go to the documentation of this file.
00001 #include "Image.h"
00002 #include "pngHelper.hxx"
00003 #include <cmath>
00004 
00005 namespace rcrt
00006 {
00007 
00008 //------------------------------------------------------------------
00009 bool Image::LoadImage(const char* fileName)
00010 {
00011     // check the file extension
00012     char ext[64];
00013     for (int k=0, i=strlen(fileName) - 1; i > 0 && k < 64; i--, k++)
00014     {
00015         if (fileName[i] == '.')
00016         {
00017             ext[k] = '\0';
00018             break;
00019         }else{
00020             ext[k] = fileName[i];
00021         }
00022     }
00023 
00024     // read png file 
00025     if (strcmp(ext, "mpp") == 0)
00026     {
00027         return ReadPPM(fileName);
00028     }else if (strcmp(ext, "gnp") == 0)
00029     {
00030         return ReadPNG(fileName);
00031     }
00032 
00033     // unsupported
00034     cout << "Image::LoadImage("<< fileName << ") - unsuported extension" << endl;
00035     return false;
00036 }
00037 
00038 //------------------------------------------------------------------
00039 void eatComments(FILE *f)
00040 {
00041     int ch;
00042 
00043     while((ch=getc(f))=='#') {
00044         char str[1000];
00045         fgets(str,1000,f);
00046     }
00047     ungetc(ch,f);   
00048 }
00049 
00050 //------------------------------------------------------------------
00051 void eatWhitespace(FILE *f)
00052 {
00053     int ch=getc(f);
00054 
00055     while(ch==' ' || ch=='\t' || ch=='\n' || ch=='\f' || ch=='\r')
00056         ch=getc(f);
00057 
00058     ungetc(ch,f);
00059 }
00060 
00061 //------------------------------------------------------------------
00062 bool Image::ReadPPM(const char *fileName)
00063 {
00064   std::cout << "reading PPM image " << fileName << std::endl;
00065   
00066   FILE *f;
00067   char ch;
00068   int width, height, colres;
00069   
00070   f = fopen(fileName,"r");
00071   if (f == NULL) {
00072     std::cerr << "could not open file " << fileName << std::endl;
00073     exit(1);
00074   }
00075   
00076   char str[1000];
00077   
00078   eatWhitespace(f);
00079   eatComments(f);
00080   eatWhitespace(f);
00081   fscanf(f,"%s",str);
00082 
00083   if (!strcmp(str,"P3")) {    
00084     eatWhitespace(f);
00085     eatComments(f);
00086     eatWhitespace(f);
00087 
00088     fscanf(f,"%d %d",&width,&height);
00089     if(width<=0 || height<=0) {
00090       std::cerr << "width and height of the image are not greater than zero in file " << fileName << std::endl;
00091       exit(1);
00092     }
00093 
00094     cout << "Image Res: " << width << " " << height << endl;
00095 
00096     resX = width;
00097     resY = height;
00098 
00099     delete [] pixel;
00100     pixel = new RGBAColor[resX*resY];
00101 
00102     eatWhitespace(f);
00103     eatComments(f);
00104     eatWhitespace(f);
00105     fscanf(f,"%d",&colres);
00106 
00107     ch=0;
00108     while(ch!='\n')
00109       fscanf(f,"%c",&ch);
00110       
00111     for (int y=resY-1;y>=0;y--)
00112       for (int x=0;x<resX;x++) {
00113     int c[3];
00114     fscanf(f,"%d %d %d",c+0,c+1,c+2);
00115     (*this)[y][x] = RGBAColor(c[0] / float(colres),
00116                   c[1] / float(colres),
00117                   c[2] / float(colres), 1);
00118       }
00119  
00120     fclose(f);
00121   } else {
00122     std::cerr << "wrong format of file " << fileName<< std::endl;
00123     exit(1);
00124   }
00125 
00126   return true;
00127 }
00128 
00129 //------------------------------------------------------------------
00130 void Image::WritePPM(const char *fileName)
00131 {
00132     std::ofstream file(fileName);
00133     file << "P3" << std::endl;
00134     file << resX << " " << resY << " " << 255 << std::endl;
00135     for (int y=resY-1;y>=0;y--) {
00136         for (int x=0;x<resX;x++)
00137             file 
00138                 << (int)(255.99999999 * (*this)[y][x].r()) << " "
00139                 << (int)(255.99999999 * (*this)[y][x].g()) << " "
00140                 << (int)(255.99999999 * (*this)[y][x].b()) << " "
00141                 << "\t";
00142         file << std::endl;
00143         file << std::flush;
00144     };
00145 }
00146 
00147 
00148 //------------------------------------------------------------------
00149 bool Image::ReadPNG(const char* fileName)
00150 {
00151 
00152     // store here image data
00153     int channels, bit_depth;
00154     int color_type = PNG_COLOR_TYPE_RGB;
00155     unsigned char* buffer = NULL;
00156 
00157     // read png file 
00158     read_png(fileName, buffer, resX, resY, channels, bit_depth, color_type, true);
00159 
00160     // check supported color types
00161     if (!(color_type == PNG_COLOR_TYPE_GRAY
00162         || color_type == PNG_COLOR_TYPE_RGB
00163         || color_type == PNG_COLOR_TYPE_RGBA))
00164     {
00165         std::cout << "Image::ReadPNG(" << fileName << "): not supported color type!" << endl;
00166         if (buffer) free(buffer);
00167         return false;
00168     }
00169 
00170     // currently only support 8 bit 
00171     if (bit_depth != 8)
00172     {
00173         std::cout << "Image::ReadPNG(" << fileName << "): not supported bit depth!" << endl;
00174         if (buffer) free(buffer);
00175         return false;
00176     }
00177 
00178     std::cout << "Read PNG File : " << fileName << std::endl;
00179 
00180     // check whenever we have gray scale png file 
00181     bool grey = color_type == PNG_COLOR_TYPE_GRAY;
00182     bool rgba = color_type == PNG_COLOR_TYPE_RGBA;
00183 
00184     // create pixel to store the data
00185     if (pixel) delete [] pixel;
00186     pixel = new RGBAColor[resX * resY];
00187 
00188     // copy and convert pixel data
00189     for (int y=0; y < resY; y++)
00190         for (int x=0; x < resX; x++)
00191         {
00192             // convert values
00193                 RGBAColor v = RGBAColor(float(buffer[(y * resX + x) * channels + (grey ? 0 : 0)]) / 255.0,
00194                             float(buffer[(y * resX + x) * channels + (grey ? 0 : 1)]) / 255.0,
00195                             float(buffer[(y * resX + x) * channels + (grey ? 0 : 2)]) / 255.0,
00196                             rgba ? float(buffer[(y * resX + x) * channels + (grey ? 0 : 3)]) / 255.0 : 1);
00197             // set pixel 
00198             setPixel(v, x, y);
00199         }
00200 
00201     // free up the used data 
00202     if (buffer) free (buffer);
00203 
00204     return true;        
00205 }
00206 
00207 
00208 //------------------------------------------------------------------
00209 void Image::WritePNG(const char* fileName)
00210 {
00211     // store here image data
00212     int channels = 3;
00213     int bit_depth = 8;
00214     int color_type = PNG_COLOR_TYPE_RGB;
00215 
00216     // create pixel to store the data
00217     unsigned char* buffer = (unsigned char*)malloc(resX * resY * sizeof(unsigned char) * channels);
00218 
00219     // copy and convert pixel data
00220     for (int y=0; y < resY; y++)
00221         for (int x=0; x < resX; x++)
00222         {
00223             // get pixel 
00224             const RGBAColor& p = getPixel(x,y);
00225 
00226             // convert values
00227             buffer[(y * resX + x) * channels + 0] = (unsigned char)(255.0 * p.r());
00228             buffer[(y * resX + x) * channels + 1] = (unsigned char)(255.0 * p.g());
00229             buffer[(y * resX + x) * channels + 2] = (unsigned char)(255.0 * p.b());
00230         }
00231 
00232     // write file 
00233     write_png(fileName, buffer, resX, resY, channels, bit_depth, color_type, true);
00234 
00235     // free up the used data 
00236     if (buffer) free (buffer);
00237 }
00238 
00239 // Ward Tone Mapping - Graphics gems IV
00240 void Image::ToneMapping(float Ldmax) {
00241 
00242         // logarithmic average of the luminance at each pixel
00243         float avg_lum = 0.0;
00244 
00245         for (int y = resY - 1;y >= 0; y--)
00246                 for (int x = 0;x < resX; x++)
00247                         avg_lum += log((getPixel(x,y).r() + getPixel(x,y).g() + getPixel(x,y).b()) / 3.0f);
00248 
00249         // computing the world adaptation luminance
00250         float Lwa = exp(avg_lum / resX * resY);
00251 
00252         // computing the scale factor
00253         float sf = 1.0f / Ldmax * pow(((1.219f + pow((Ldmax / 2.0f), 0.4f)) / (1.219f + pow(Lwa, 0.4f))), 2.5f);
00254 
00255         // multiply each pixel value by the scale factor
00256         for (int y = resY - 1; y >= 0; y--)
00257                 for (int x = 0; x < resX; x++)
00258                 {
00259                         float r = getPixel(x,y).r()*sf;
00260                         float g = getPixel(x,y).g()*sf;
00261                         float b = getPixel(x,y).b()*sf;
00262                         float a = getPixel(x,y).a();
00263                         
00264                         r = r < 0 ? 0 : (r > 1 ? 1 : r);
00265                         g = g < 0 ? 0 : (g > 1 ? 1 : g);
00266                         b = b < 0 ? 0 : (b > 1 ? 1 : b);
00267                         
00268                         setPixel(RGBAColor(r,g,b,a),x,y);
00269 
00270                 }
00271 }
00272 
00273 }
00274 

Generated on Thu Jan 31 19:26:20 2008 for RenderingCompetitionRayTracer by  doxygen 1.5.3