37 #define RGBE_DATA_RED 0
38 #define RGBE_DATA_GREEN 1
39 #define RGBE_DATA_BLUE 2
41 #define RGBE_DATA_SIZE 3
52 static int rgbe_error(
const int rgbe_error_code,
const char *msg )
54 switch ( rgbe_error_code )
57 perror(
"RGBE read error" );
59 case rgbe_write_error:
60 perror(
"RGBE write error" );
62 case rgbe_format_error:
63 fprintf( stderr,
"RGBE bad file format: %s\n", msg );
66 case rgbe_memory_error:
67 fprintf( stderr,
"RGBE error: %s\n", msg );
70 return RGBE_RETURN_FAILURE;
76 float2rgbe(
unsigned char rgbe[4],
float red,
float green,
float blue )
82 if ( green > v ) v = green;
83 if ( blue > v ) v = blue;
86 rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
90 v = std::frexp( v, &e ) * 256.0 / v;
91 rgbe[0] = (
unsigned char )( red * v );
92 rgbe[1] = (
unsigned char )( green * v );
93 rgbe[2] = (
unsigned char )( blue * v );
94 rgbe[3] = (
unsigned char )( e + 128 );
102 rgbe2float(
float *red,
float *green,
float *blue,
unsigned char rgbe[4] )
108 f = std::ldexp( 1.0, rgbe[3] - (
int )( 128 + 8 ) );
110 *green = rgbe[1] * f;
114 *red = *green = *blue = 0.0;
118 int RGBE_WriteHeader( FILE *fp,
const int width,
const int height,
const rgbe_header_info *info )
120 const char *programtype =
"RGBE";
122 if ( info && ( info->valid & RGBE_VALID_PROGRAMTYPE ) )
123 programtype = info->programtype;
124 if ( fprintf( fp,
"#?%s\n", programtype ) < 0 )
125 return rgbe_error( rgbe_write_error, NULL );
127 if ( info && ( info->valid & RGBE_VALID_GAMMA ) )
129 if ( fprintf( fp,
"GAMMA=%g\n", info->gamma ) < 0 )
130 return rgbe_error( rgbe_write_error, NULL );
132 if ( info && ( info->valid & RGBE_VALID_EXPOSURE ) )
134 if ( fprintf( fp,
"EXPOSURE=%g\n", info->exposure ) < 0 )
135 return rgbe_error( rgbe_write_error, NULL );
137 if ( fprintf( fp,
"FORMAT=32-bit_rle_rgbe\n\n" ) < 0 )
138 return rgbe_error( rgbe_write_error, NULL );
139 if ( fprintf( fp,
"-Y %d +X %d\n", height, width ) < 0 )
140 return rgbe_error( rgbe_write_error, NULL );
141 return RGBE_RETURN_SUCCESS;
145 int RGBE_ReadHeader( FILE *fp,
int *width,
int *height,
rgbe_header_info *info )
158 info->programtype[0] = 0;
159 info->gamma = info->exposure = 1.0;
161 if ( fgets( buf,
sizeof( buf ), fp ) == NULL )
162 return rgbe_error( rgbe_read_error, NULL );
164 if (( buf[0] !=
'#' ) || ( buf[1] !=
'?' ) )
171 info->valid |= RGBE_VALID_PROGRAMTYPE;
172 for ( i = 0; i < (int)
sizeof( info->programtype ) - 1; i++ )
174 if (( buf[i+2] == 0 ) || isspace( buf[i+2] ) )
176 info->programtype[i] = buf[i+2];
178 info->programtype[i] = 0;
180 if ( fgets( buf,
sizeof( buf ), fp ) == 0 )
181 return rgbe_error( rgbe_read_error, NULL );
186 if ( buf[0] == 0 || buf[0] ==
'\r' || buf[0] ==
'\n' )
190 else if ( strncmp( buf,
"FORMAT=32-bit_rle_rgbe", strlen(
"FORMAT=32-bit_rle_rgbe" ) ) == 0 )
194 else if ( info && ( sscanf( buf,
"GAMMA=%g", &tempf ) == 1 ) )
197 info->valid |= RGBE_VALID_GAMMA;
200 else if ( info && ( sscanf( buf,
"EXPOSURE=%g", &tempf ) == 1 ) )
202 info->exposure = tempf;
203 info->valid |= RGBE_VALID_EXPOSURE;
206 if ( fgets( buf,
sizeof( buf ), fp ) == 0 )
207 return rgbe_error( rgbe_read_error, NULL );
210 if ( found_format == 0 )
211 return rgbe_error( rgbe_format_error,
"no FORMAT specifier found" );
215 if ( fgets( buf,
sizeof( buf ) /
sizeof( buf[0] ), fp ) == 0 )
216 return rgbe_error( rgbe_read_error, NULL );
218 if ( strcmp( buf,
"\n" ) != 0 )
219 return rgbe_error( rgbe_format_error,
"missing blank line after FORMAT specifier" );
222 if ( fgets( buf,
sizeof( buf ), fp ) == 0 )
223 return rgbe_error( rgbe_read_error, NULL );
226 if ( sscanf( buf,
"%[-+]Y %d %[-+]X %d", sh, height, sw, width ) != 4
227 && sscanf( buf,
"%[-+]X %d %[-+]Y %d", sh, height, sw, width ) != 4 )
228 return rgbe_error( rgbe_format_error,
"missing image size specifier" );
232 *width = - ( *width );
234 *height = - ( *height );
239 return RGBE_RETURN_SUCCESS;
245 int RGBE_WritePixels( FILE *fp,
const float *data,
const int n )
247 unsigned char rgbe[4];
250 while ( numpixels-- > 0 )
252 float2rgbe( rgbe, data[RGBE_DATA_RED], data[RGBE_DATA_GREEN], data[RGBE_DATA_BLUE] );
253 data += RGBE_DATA_SIZE;
254 if ( fwrite( rgbe,
sizeof( rgbe ), 1, fp ) < 1 )
255 return rgbe_error( rgbe_write_error, NULL );
257 return RGBE_RETURN_SUCCESS;
261 int RGBE_ReadPixels( FILE *fp,
float *data,
const int n )
263 unsigned char rgbe[4];
266 while ( numpixels-- > 0 )
268 if ( fread( rgbe,
sizeof( rgbe ), 1, fp ) < 1 )
269 return rgbe_error( rgbe_read_error, NULL );
270 rgbe2float( &data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE], rgbe );
271 data += RGBE_DATA_SIZE;
273 return RGBE_RETURN_SUCCESS;
281 static int RGBE_WriteBytes_RLE( FILE *fp,
const unsigned char *data,
const int numbytes )
283 #define MINRUNLENGTH 4
284 int cur, beg_run, run_count, old_run_count, nonrun_count;
285 unsigned char buf[2];
288 while ( cur < numbytes )
292 run_count = old_run_count = 0;
293 while (( run_count < MINRUNLENGTH ) && ( beg_run < numbytes ) )
295 beg_run += run_count;
296 old_run_count = run_count;
298 while( (beg_run + run_count < numbytes) && (run_count < 127)
299 && (data[beg_run] == data[beg_run + run_count]) )
303 if (( old_run_count > 1 ) && ( old_run_count == beg_run - cur ) )
305 buf[0] = 128 + old_run_count;
307 if ( fwrite( buf,
sizeof( buf[0] )*2, 1, fp ) < 1 )
308 return rgbe_error( rgbe_write_error, NULL );
312 while ( cur < beg_run )
314 nonrun_count = beg_run - cur;
315 if ( nonrun_count > 128 )
317 buf[0] = nonrun_count;
318 if ( fwrite( buf,
sizeof( buf[0] ), 1, fp ) < 1 )
319 return rgbe_error( rgbe_write_error, NULL );
320 if ( fwrite( &data[cur],
sizeof( data[0] )*nonrun_count, 1, fp ) < 1 )
321 return rgbe_error( rgbe_write_error, NULL );
325 if ( run_count >= MINRUNLENGTH )
327 buf[0] = 128 + run_count;
328 buf[1] = data[beg_run];
329 if ( fwrite( buf,
sizeof( buf[0] )*2, 1, fp ) < 1 )
330 return rgbe_error( rgbe_write_error, NULL );
334 return RGBE_RETURN_SUCCESS;
338 int RGBE_WritePixels_RLE( FILE *fp,
const float *data,
const int width,
const int n )
340 unsigned char rgbe[4];
341 unsigned char *buffer;
344 int scanline_width= width;
345 int num_scanlines= n;
346 if (( scanline_width < 8 ) || ( scanline_width > 0x7fff ) )
348 return RGBE_WritePixels( fp, data, scanline_width*num_scanlines );
349 buffer = (
unsigned char * )malloc(
sizeof(
unsigned char ) * 4 * scanline_width );
350 if ( buffer == NULL )
352 return RGBE_WritePixels( fp, data, scanline_width*num_scanlines );
353 while ( num_scanlines-- > 0 )
357 rgbe[2] = scanline_width >> 8;
358 rgbe[3] = scanline_width & 0xFF;
359 if ( fwrite( rgbe,
sizeof( rgbe ), 1, fp ) < 1 )
362 return rgbe_error( rgbe_write_error, NULL );
364 for ( i = 0;i < scanline_width;i++ )
366 float2rgbe( rgbe, data[RGBE_DATA_RED], data[RGBE_DATA_GREEN], data[RGBE_DATA_BLUE] );
368 buffer[i+scanline_width] = rgbe[1];
369 buffer[i+2*scanline_width] = rgbe[2];
370 buffer[i+3*scanline_width] = rgbe[3];
371 data += RGBE_DATA_SIZE;
375 for ( i = 0;i < 4;i++ )
377 if (( err = RGBE_WriteBytes_RLE( fp, &buffer[i*scanline_width], scanline_width ) ) != RGBE_RETURN_SUCCESS )
385 return RGBE_RETURN_SUCCESS;
388 int RGBE_ReadPixels_RLE( FILE *fp,
float *data,
const int width,
const int n )
390 unsigned char rgbe[4], *scanline_buffer, *ptr, *ptr_end;
392 unsigned char buf[2];
394 int scanline_width= width;
395 int num_scanlines= n;
396 if (( scanline_width < 8 ) || ( scanline_width > 0x7fff ) )
398 return RGBE_ReadPixels( fp, data, scanline_width*num_scanlines );
399 scanline_buffer = NULL;
401 while ( num_scanlines > 0 )
403 if ( fread( rgbe,
sizeof( rgbe ), 1, fp ) < 1 )
405 free( scanline_buffer );
406 return rgbe_error( rgbe_read_error, NULL );
408 if (( rgbe[0] != 2 ) || ( rgbe[1] != 2 ) || ( rgbe[2] & 0x80 ) )
411 rgbe2float( &data[0], &data[1], &data[2], rgbe );
412 data += RGBE_DATA_SIZE;
413 free( scanline_buffer );
414 return RGBE_ReadPixels( fp, data, scanline_width*num_scanlines - 1 );
416 if ((((
int )rgbe[2] ) << 8 | rgbe[3] ) != scanline_width )
418 free( scanline_buffer );
419 return rgbe_error( rgbe_format_error,
"wrong scanline width" );
421 if ( scanline_buffer == NULL )
422 scanline_buffer = (
unsigned char * ) malloc(
sizeof(
unsigned char ) * 4 * scanline_width );
423 if ( scanline_buffer == NULL )
424 return rgbe_error( rgbe_memory_error,
"unable to allocate buffer space" );
426 ptr = &scanline_buffer[0];
428 for ( i = 0;i < 4;i++ )
430 ptr_end = &scanline_buffer[( i+1 )*scanline_width];
431 while ( ptr < ptr_end )
433 if ( fread( buf,
sizeof(buf), 1, fp ) < 1 )
435 free( scanline_buffer );
436 return rgbe_error( rgbe_read_error, NULL );
441 count = buf[0] - 128;
442 if (( count == 0 ) || ( count > ptr_end - ptr ) )
444 free( scanline_buffer );
445 return rgbe_error( rgbe_format_error,
"bad scanline data" );
447 while ( count-- > 0 )
454 if (( count == 0 ) || ( count > ptr_end - ptr ) )
456 free( scanline_buffer );
457 return rgbe_error( rgbe_format_error,
"bad scanline data" );
462 if ( fread( ptr,
sizeof(
unsigned char )*count, 1, fp ) < 1 )
464 free( scanline_buffer );
465 return rgbe_error( rgbe_read_error, NULL );
473 for ( i = 0;i < scanline_width;i++ )
475 rgbe[0] = scanline_buffer[i];
476 rgbe[1] = scanline_buffer[i+scanline_width];
477 rgbe[2] = scanline_buffer[i+2*scanline_width];
478 rgbe[3] = scanline_buffer[i+3*scanline_width];
479 rgbe2float( &data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE], rgbe );
480 data += RGBE_DATA_SIZE;
484 free( scanline_buffer );
485 return RGBE_RETURN_SUCCESS;