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 "ioHDR.hpp"
00028 #include "ImageException.hpp"
00029
00030
00031
00032
00033 #include <sstream>
00034 #include <fstream>
00035 #include <math.h>
00036 #include <malloc.h>
00037 #include <string.h>
00038 #include <ctype.h>
00039
00040
00041 #define RGBE_VALID_PROGRAMTYPE 0x01
00042 #define RGBE_VALID_GAMMA 0x02
00043 #define RGBE_VALID_EXPOSURE 0x04
00044
00045
00046 #define RGBE_RETURN_SUCCESS 0
00047 #define RGBE_RETURN_FAILURE -1
00048
00049 #define RGBE_DATA_RED 0
00050 #define RGBE_DATA_GREEN 1
00051 #define RGBE_DATA_BLUE 2
00052
00053 #define RGBE_DATA_SIZE 3
00054
00055
00056
00057
00058
00059 namespace kn{
00060
00061 typedef struct {
00062 int valid;
00063 char programtype[16];
00064
00065 float gamma;
00066
00067 float exposure;
00068
00069
00070 } rgbe_header_info;
00071
00072
00073
00074 enum rgbe_error_codes {
00075 rgbe_read_error,
00076 rgbe_write_error,
00077 rgbe_format_error,
00078 rgbe_memory_error
00079 };
00080
00081
00082
00083
00084 inline void float2rgbe(unsigned char rgbe[4], float red, float green, float blue)
00085 {
00086 float v;
00087 int e;
00088
00089 v = red;
00090 if (green > v) v = green;
00091 if (blue > v) v = blue;
00092 if (v < 1e-32) {
00093 rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
00094 }
00095 else {
00096 v = (float)frexp(v,&e) * 256.0f/v;
00097 rgbe[0] = (unsigned char) (red * v);
00098 rgbe[1] = (unsigned char) (green * v);
00099 rgbe[2] = (unsigned char) (blue * v);
00100 rgbe[3] = (unsigned char) (e + 128);
00101 }
00102 }
00103
00104
00105
00106
00107 inline void rgbe2float(float *red, float *green, float *blue, unsigned char rgbe[4])
00108 {
00109 double f;
00110
00111 if (rgbe[3]) {
00112 f = ldexp(1.0f,(int)rgbe[3]-(int)(128+8));
00113 *red = (float)((rgbe[0]+0.5) * f);
00114 *green = (float)((rgbe[1]+0.5) * f);
00115 *blue = (float)((rgbe[2]+0.5) * f);
00116 }
00117 else
00118 *red = *green = *blue = 0.0;
00119 }
00120
00121
00122
00123 static ImageException rgbe_error(int rgbe_error_code, char *msg) {
00124 std::stringstream serr;
00125 switch (rgbe_error_code) {
00126 case rgbe_read_error:
00127 return ImageException("RGBE read error","loadImageHDR");
00128 case rgbe_write_error:
00129 return ImageException("RGBE write error","loadImageHDR");
00130 case rgbe_format_error:
00131 serr<<"RGBE bad file format: "<<msg;
00132 return ImageException(serr.str(),"loadImageHDR");
00133
00134 break;
00135 default:
00136 case rgbe_memory_error:
00137 serr<<"RGBE error: "<<msg;
00138 return ImageException(serr.str(),"loadImageHDR");
00139 }
00140 return ImageException();
00141 }
00142
00143
00144 int RGBE_ReadHeader(FILE *fp, int *width, int *height, rgbe_header_info *info)
00145 {
00146 char buf[128];
00147 int found_format;
00148 float tempf;
00149 unsigned int i;
00150
00151 found_format = 0;
00152 if (info) {
00153 info->valid = 0;
00154 info->programtype[0] = 0;
00155 info->gamma = info->exposure = 1.0;
00156 }
00157 if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == NULL)
00158 throw rgbe_error(rgbe_read_error,NULL);
00159
00160 if ((buf[0] != '#')||(buf[1] != '?')) {
00161
00162 throw rgbe_error(rgbe_format_error,(char*)"bad initial token");
00163 }
00164 else if (info) {
00165 info->valid |= RGBE_VALID_PROGRAMTYPE;
00166 for(i=0;i<sizeof(info->programtype)-1;i++) {
00167 if ((buf[i+2] == 0) || isspace(buf[i+2]))
00168 break;
00169 info->programtype[i] = buf[i+2];
00170 }
00171 info->programtype[i] = 0;
00172 if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == 0)
00173 throw rgbe_error(rgbe_read_error,NULL);
00174 }
00175
00176 for(;;) {
00177 if ((buf[0] == 0)||(buf[0] == '\n'))
00178 throw rgbe_error(rgbe_format_error,(char*)"no FORMAT specifier found");
00179 else if (strcmp(buf,"FORMAT=32-bit_rle_rgbe\n") == 0)
00180 break;
00181 else if (info && (sscanf(buf,"GAMMA=%g",&tempf) == 1)) {
00182 info->gamma = tempf;
00183 info->valid |= RGBE_VALID_GAMMA;
00184 }
00185 else if (info && (sscanf(buf,"EXPOSURE=%g",&tempf) == 1)) {
00186 info->exposure = tempf;
00187 info->valid |= RGBE_VALID_EXPOSURE;
00188 }
00189 if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == 0)
00190 throw rgbe_error(rgbe_read_error,NULL);
00191 }
00192
00193 #if 0
00194 if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == 0)
00195 throw rgbe_error(rgbe_read_error,NULL);
00196 if (strcmp(buf,"\n") != 0)
00197 throw rgbe_error(rgbe_format_error,"missing blank line after FORMAT specifier");
00198 #endif
00199
00200 for(;;) {
00201 if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == 0)
00202 throw rgbe_error(rgbe_read_error,NULL);
00203
00204 if (sscanf(buf,"-Y %d +X %d",height,width) == 2)
00205 break;
00206 }
00207
00208 return RGBE_RETURN_SUCCESS;
00209 }
00210
00211
00212 int RGBE_ReadPixels(FILE *fp, float *data, int numpixels)
00213 {
00214 unsigned char rgbe[4];
00215
00216 while(numpixels-- > 0) {
00217 if (fread(rgbe, sizeof(rgbe), 1, fp) < 1)
00218 throw rgbe_error(rgbe_read_error,NULL);
00219
00220 rgbe2float(&data[RGBE_DATA_RED],&data[RGBE_DATA_GREEN],&data[RGBE_DATA_BLUE],rgbe);
00221
00222 data += RGBE_DATA_SIZE;
00223 }
00224 return RGBE_RETURN_SUCCESS;
00225 }
00226
00227
00228 int RGBE_ReadPixels_Raw(FILE *fp, unsigned char *data, int numpixels)
00229 {
00230 if ((int)fread(data, 4, numpixels, fp) < numpixels)
00231 throw rgbe_error(rgbe_read_error,NULL);
00232
00233 return RGBE_RETURN_SUCCESS;
00234 }
00235
00236 int RGBE_ReadPixels_RLE(FILE *fp, float *data, int scanline_width,int num_scanlines)
00237 {
00238 unsigned char rgbe[4], *scanline_buffer, *ptr, *ptr_end;
00239 int i, count;
00240 unsigned char buf[2];
00241
00242 if ((scanline_width < 8)||(scanline_width > 0x7fff))
00243
00244 return RGBE_ReadPixels(fp,data,scanline_width*num_scanlines);
00245
00246 scanline_buffer = NULL;
00247
00248 while(num_scanlines > 0) {
00249 if (fread(rgbe,sizeof(rgbe),1,fp) < 1) {
00250 free(scanline_buffer);
00251 throw rgbe_error(rgbe_read_error,NULL);
00252 }
00253 if ((rgbe[0] != 2)||(rgbe[1] != 2)||(rgbe[2] & 0x80)) {
00254
00255 rgbe2float(&data[0],&data[1],&data[2],rgbe);
00256
00257 data += RGBE_DATA_SIZE;
00258 free(scanline_buffer);
00259 return RGBE_ReadPixels(fp,data,scanline_width*num_scanlines-1);
00260 }
00261 if ((((int)rgbe[2])<<8 | rgbe[3]) != scanline_width) {
00262 free(scanline_buffer);
00263 throw rgbe_error(rgbe_format_error,(char*)("wrong scanline width"));
00264 }
00265 if (scanline_buffer == NULL)
00266 scanline_buffer = (unsigned char *) malloc(sizeof(unsigned char)*4*scanline_width);
00267 if (scanline_buffer == NULL)
00268 throw rgbe_error(rgbe_memory_error,(char*)("unable to allocate buffer space"));
00269
00270 ptr = &scanline_buffer[0];
00271
00272 for(i=0;i<4;i++) {
00273 ptr_end = &scanline_buffer[(i+1)*scanline_width];
00274 while(ptr < ptr_end) {
00275 if (fread(buf,sizeof(buf[0])*2,1,fp) < 1) {
00276 free(scanline_buffer);
00277 throw rgbe_error(rgbe_read_error,NULL);
00278 }
00279 if (buf[0] > 128) {
00280
00281 count = buf[0]-128;
00282 if ((count == 0)||(count > ptr_end - ptr)) {
00283 free(scanline_buffer);
00284 throw rgbe_error(rgbe_format_error,(char*)("bad scanline data"));
00285 }
00286 while(count-- > 0)
00287 *ptr++ = buf[1];
00288 }
00289 else {
00290
00291 count = buf[0];
00292 if ((count == 0)||(count > ptr_end - ptr)) {
00293 free(scanline_buffer);
00294 throw rgbe_error(rgbe_format_error,(char*)("bad scanline data"));
00295 }
00296 *ptr++ = buf[1];
00297 if (--count > 0) {
00298 if (fread(ptr,sizeof(*ptr)*count,1,fp) < 1) {
00299 free(scanline_buffer);
00300 throw rgbe_error(rgbe_read_error,NULL);
00301 }
00302 ptr += count;
00303 }
00304 }
00305 }
00306 }
00307
00308 for(i=0;i<scanline_width;i++) {
00309 rgbe[0] = scanline_buffer[i];
00310 rgbe[1] = scanline_buffer[i+scanline_width];
00311 rgbe[2] = scanline_buffer[i+2*scanline_width];
00312 rgbe[3] = scanline_buffer[i+3*scanline_width];
00313 rgbe2float(&data[RGBE_DATA_RED],&data[RGBE_DATA_GREEN],&data[RGBE_DATA_BLUE],rgbe);
00314
00315 data += RGBE_DATA_SIZE;
00316 }
00317 num_scanlines--;
00318 }
00319 free(scanline_buffer);
00320 return RGBE_RETURN_SUCCESS;
00321 }
00322
00323
00324
00325
00326 int loadHDR(Image<float>& res,const std::string& filename) {
00327 float* thebuffer;
00328 size_t w_size,h_size;
00329
00330 std::ifstream is;
00331 std::stringstream serr;
00332 rgbe_header_info header_stock;
00333
00334 FILE * infile;
00335
00336
00337 if (res.size()>0) {
00338 throw ImageException("Image already allocated. Cannot store HDR image in that image.","loadImage");
00339 }
00340
00341 infile = fopen(filename.c_str(),"rb");
00342 if (infile == NULL) {
00343 throw ImageException("Error could not read file "+filename,"loadImageHDR");
00344 }
00345
00346
00347 int succes;
00348 int i_width=-1,i_height=-1;
00349 succes = RGBE_ReadHeader(infile,&i_width,&i_height,&header_stock);
00350 if (i_width == -1 || i_height == -1) {
00351 serr << "Image size was impossible to fetch from header ("<<i_width<<"/"<<i_height<<")";
00352 throw ImageException(serr.str(),"loadImageHDR");
00353 }
00354 if (succes!= RGBE_RETURN_SUCCESS) {
00355 throw ImageException("Something was wrong and no throw by reader function","loadImageHDR");
00356 }
00357 w_size = i_width;
00358 h_size = i_height;
00359
00360
00361
00362
00363
00364 thebuffer = new float[3*w_size*h_size];
00365 if (thebuffer == NULL) {
00366 throw ImageException("Unable to get memory when loading HDR","loadImageHDR");
00367 }
00368
00369
00370 try {
00371 succes = RGBE_ReadPixels_RLE(infile,thebuffer,i_width,i_height);
00372 res.buildImageFromBuffer(w_size,h_size,3,thebuffer);
00373 }
00374 catch (ImageException &e) {
00375
00376 if (thebuffer != NULL) delete[](thebuffer);
00377 throw e;
00378 }
00379 if (thebuffer != NULL) delete[](thebuffer);
00380 fclose(infile);
00381
00382 return 1;
00383 }
00384
00385
00386
00387
00388 }