/src/FreeImage/Source/FreeImage/PluginHDR.cpp

https://bitbucket.org/cabalistic/ogredeps/ · C++ · 719 lines · 510 code · 98 blank · 111 comment · 132 complexity · 4c308290944fb12d8d53a5a0569e275f MD5 · raw file

  1. // ==========================================================
  2. // HDR Loader and writer
  3. //
  4. // Design and implementation by
  5. // - Hervé Drolon (drolon@infonie.fr)
  6. //
  7. // This file is part of FreeImage 3
  8. //
  9. // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
  10. // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
  11. // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
  12. // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
  13. // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
  14. // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
  15. // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
  16. // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
  17. // THIS DISCLAIMER.
  18. //
  19. // Use at your own risk!
  20. // ==========================================================
  21. #include "FreeImage.h"
  22. #include "Utilities.h"
  23. // ==========================================================
  24. // Plugin Interface
  25. // ==========================================================
  26. static int s_format_id;
  27. // ==========================================================
  28. // RGBE library
  29. // ==========================================================
  30. // ----------------------------------------------------------
  31. // maximum size of a line in the header
  32. #define HDR_MAXLINE 256
  33. // flags indicating which fields in an rgbeHeaderInfo are valid
  34. #define RGBE_VALID_PROGRAMTYPE 0x01
  35. #define RGBE_VALID_COMMENT 0x02
  36. #define RGBE_VALID_GAMMA 0x04
  37. #define RGBE_VALID_EXPOSURE 0x08
  38. // offsets to red, green, and blue components in a data (float) pixel
  39. #define RGBE_DATA_RED 0
  40. #define RGBE_DATA_GREEN 1
  41. #define RGBE_DATA_BLUE 2
  42. // ----------------------------------------------------------
  43. #ifdef _WIN32
  44. #pragma pack(push, 1)
  45. #else
  46. #pragma pack(1)
  47. #endif
  48. typedef struct tagHeaderInfo {
  49. int valid; // indicate which fields are valid
  50. char programtype[16]; // listed at beginning of file to identify it after "#?". defaults to "RGBE"
  51. char comment[HDR_MAXLINE]; // comment beginning with "# "
  52. float gamma; // image has already been gamma corrected with given gamma. defaults to 1.0 (no correction)
  53. float exposure; // a value of 1.0 in an image corresponds to <exposure> watts/steradian/m^2. defaults to 1.0
  54. } rgbeHeaderInfo;
  55. #ifdef _WIN32
  56. #pragma pack(pop)
  57. #else
  58. #pragma pack()
  59. #endif
  60. typedef enum {
  61. rgbe_read_error,
  62. rgbe_write_error,
  63. rgbe_format_error,
  64. rgbe_memory_error,
  65. } rgbe_error_code;
  66. // ----------------------------------------------------------
  67. // Prototypes
  68. // ----------------------------------------------------------
  69. static BOOL rgbe_Error(rgbe_error_code error_code, const char *msg);
  70. static BOOL rgbe_GetLine(FreeImageIO *io, fi_handle handle, char *buffer, int length);
  71. static inline void rgbe_FloatToRGBE(BYTE rgbe[4], FIRGBF *rgbf);
  72. static inline void rgbe_RGBEToFloat(FIRGBF *rgbf, BYTE rgbe[4]);
  73. static BOOL rgbe_ReadHeader(FreeImageIO *io, fi_handle handle, unsigned *width, unsigned *height, rgbeHeaderInfo *header_info);
  74. static BOOL rgbe_WriteHeader(FreeImageIO *io, fi_handle handle, unsigned width, unsigned height, rgbeHeaderInfo *info);
  75. static BOOL rgbe_ReadPixels(FreeImageIO *io, fi_handle handle, FIRGBF *data, unsigned numpixels);
  76. static BOOL rgbe_WritePixels(FreeImageIO *io, fi_handle handle, FIRGBF *data, unsigned numpixels);
  77. static BOOL rgbe_ReadPixels_RLE(FreeImageIO *io, fi_handle handle, FIRGBF *data, int scanline_width, unsigned num_scanlines);
  78. static BOOL rgbe_WriteBytes_RLE(FreeImageIO *io, fi_handle handle, BYTE *data, int numbytes);
  79. static BOOL rgbe_WritePixels_RLE(FreeImageIO *io, fi_handle handle, FIRGBF *data, unsigned scanline_width, unsigned num_scanlines);
  80. static BOOL rgbe_ReadMetadata(FIBITMAP *dib, rgbeHeaderInfo *header_info);
  81. static BOOL rgbe_WriteMetadata(FIBITMAP *dib, rgbeHeaderInfo *header_info);
  82. // ----------------------------------------------------------
  83. /**
  84. Default error routine. change this to change error handling
  85. */
  86. static BOOL
  87. rgbe_Error(rgbe_error_code error_code, const char *msg) {
  88. switch (error_code) {
  89. case rgbe_read_error:
  90. FreeImage_OutputMessageProc(s_format_id, "RGBE read error");
  91. break;
  92. case rgbe_write_error:
  93. FreeImage_OutputMessageProc(s_format_id, "RGBE write error");
  94. break;
  95. case rgbe_format_error:
  96. FreeImage_OutputMessageProc(s_format_id, "RGBE bad file format: %s\n", msg);
  97. break;
  98. default:
  99. case rgbe_memory_error:
  100. FreeImage_OutputMessageProc(s_format_id, "RGBE error: %s\n",msg);
  101. }
  102. return FALSE;
  103. }
  104. /**
  105. Get a line from a ASCII io stream
  106. */
  107. static BOOL
  108. rgbe_GetLine(FreeImageIO *io, fi_handle handle, char *buffer, int length) {
  109. int i;
  110. memset(buffer, 0, length);
  111. for(i = 0; i < length; i++) {
  112. if(!io->read_proc(&buffer[i], 1, 1, handle))
  113. return FALSE;
  114. if(buffer[i] == 0x0A)
  115. break;
  116. }
  117. return (i < length) ? TRUE : FALSE;
  118. }
  119. /**
  120. Standard conversion from float pixels to rgbe pixels.
  121. Note: you can remove the "inline"s if your compiler complains about it
  122. */
  123. static inline void
  124. rgbe_FloatToRGBE(BYTE rgbe[4], FIRGBF *rgbf) {
  125. float v;
  126. int e;
  127. v = rgbf->red;
  128. if (rgbf->green > v) v = rgbf->green;
  129. if (rgbf->blue > v) v = rgbf->blue;
  130. if (v < 1e-32) {
  131. rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
  132. }
  133. else {
  134. v = (float)(frexp(v, &e) * 256.0 / v);
  135. rgbe[0] = (BYTE) (rgbf->red * v);
  136. rgbe[1] = (BYTE) (rgbf->green * v);
  137. rgbe[2] = (BYTE) (rgbf->blue * v);
  138. rgbe[3] = (BYTE) (e + 128);
  139. }
  140. }
  141. /**
  142. Standard conversion from rgbe to float pixels.
  143. Note: Ward uses ldexp(col+0.5,exp-(128+8)).
  144. However we wanted pixels in the range [0,1] to map back into the range [0,1].
  145. */
  146. static inline void
  147. rgbe_RGBEToFloat(FIRGBF *rgbf, BYTE rgbe[4]) {
  148. if (rgbe[3]) { // nonzero pixel
  149. float f = (float)(ldexp(1.0, rgbe[3] - (int)(128+8)));
  150. rgbf->red = rgbe[0] * f;
  151. rgbf->green = rgbe[1] * f;
  152. rgbf->blue = rgbe[2] * f;
  153. }
  154. else {
  155. rgbf->red = rgbf->green = rgbf->blue = 0;
  156. }
  157. }
  158. /**
  159. Minimal header reading. Modify if you want to parse more information
  160. */
  161. static BOOL
  162. rgbe_ReadHeader(FreeImageIO *io, fi_handle handle, unsigned *width, unsigned *height, rgbeHeaderInfo *header_info) {
  163. char buf[HDR_MAXLINE];
  164. float tempf;
  165. int i;
  166. BOOL bFormatFound = FALSE;
  167. BOOL bHeaderFound = FALSE;
  168. header_info->valid = 0;
  169. header_info->programtype[0] = 0;
  170. header_info->gamma = 1.0;
  171. header_info->exposure = 1.0;
  172. // get the first line
  173. if(!rgbe_GetLine(io, handle, buf, HDR_MAXLINE))
  174. return rgbe_Error(rgbe_read_error, NULL);
  175. // check the signature
  176. if ((buf[0] != '#')||(buf[1] != '?')) {
  177. // if you don't want to require the magic token then comment the next line
  178. return rgbe_Error(rgbe_format_error,"bad initial token");
  179. }
  180. else {
  181. header_info->valid |= RGBE_VALID_PROGRAMTYPE;
  182. for(i = 0; i < sizeof(header_info->programtype) - 1; i++) {
  183. if((buf[i+2] == 0) || isspace(buf[i+2]))
  184. break;
  185. header_info->programtype[i] = buf[i+2];
  186. }
  187. header_info->programtype[i] = 0;
  188. }
  189. for(;;) {
  190. // get next line
  191. if(!rgbe_GetLine(io, handle, buf, HDR_MAXLINE))
  192. return rgbe_Error(rgbe_read_error, NULL);
  193. if((buf[0] == 0) || (buf[0] == '\n')) {
  194. // end of header so break out of loop
  195. bHeaderFound = TRUE;
  196. break;
  197. }
  198. else if(strcmp(buf,"FORMAT=32-bit_rle_rgbe\n") == 0) {
  199. bFormatFound = TRUE;
  200. }
  201. else if(sscanf(buf, "GAMMA=%g", &tempf) == 1) {
  202. header_info->gamma = tempf;
  203. header_info->valid |= RGBE_VALID_GAMMA;
  204. }
  205. else if(sscanf(buf,"EXPOSURE=%g",&tempf) == 1) {
  206. header_info->exposure = tempf;
  207. header_info->valid |= RGBE_VALID_EXPOSURE;
  208. }
  209. else if((buf[0] == '#') && (buf[1] == 0x20)) {
  210. header_info->valid |= RGBE_VALID_COMMENT;
  211. strcpy(header_info->comment, buf);
  212. }
  213. }
  214. if(!bHeaderFound || !bFormatFound) {
  215. return rgbe_Error(rgbe_format_error, "invalid header");
  216. }
  217. // get next line
  218. if(!rgbe_GetLine(io, handle, buf, HDR_MAXLINE))
  219. return rgbe_Error(rgbe_read_error, NULL);
  220. // get the image width & height
  221. if(sscanf(buf,"-Y %d +X %d", height, width) < 2) {
  222. if(sscanf(buf,"+X %d +Y %d", height, width) < 2) {
  223. return rgbe_Error(rgbe_format_error, "missing image size specifier");
  224. }
  225. }
  226. return TRUE;
  227. }
  228. /**
  229. default minimal header. modify if you want more information in header
  230. */
  231. static BOOL
  232. rgbe_WriteHeader(FreeImageIO *io, fi_handle handle, unsigned width, unsigned height, rgbeHeaderInfo *info) {
  233. char buffer[HDR_MAXLINE];
  234. const char *programtype = "RADIANCE";
  235. if(info && (info->valid & RGBE_VALID_PROGRAMTYPE)) {
  236. programtype = info->programtype;
  237. }
  238. // The #? is to identify file type, the programtype is optional
  239. sprintf(buffer, "#?%s\n", programtype);
  240. if(io->write_proc(buffer, 1, (unsigned int)strlen(buffer), handle) < 1)
  241. return rgbe_Error(rgbe_write_error, NULL);
  242. sprintf(buffer, "%s\n", info->comment);
  243. if(io->write_proc(buffer, 1, (unsigned int)strlen(buffer), handle) < 1)
  244. return rgbe_Error(rgbe_write_error, NULL);
  245. sprintf(buffer, "FORMAT=32-bit_rle_rgbe\n");
  246. if(io->write_proc(buffer, 1, (unsigned int)strlen(buffer), handle) < 1)
  247. return rgbe_Error(rgbe_write_error, NULL);
  248. if(info && (info->valid & RGBE_VALID_GAMMA)) {
  249. sprintf(buffer, "GAMMA=%g\n", info->gamma);
  250. if(io->write_proc(buffer, 1, (unsigned int)strlen(buffer), handle) < 1)
  251. return rgbe_Error(rgbe_write_error, NULL);
  252. }
  253. if(info && (info->valid & RGBE_VALID_EXPOSURE)) {
  254. sprintf(buffer,"EXPOSURE=%g\n", info->exposure);
  255. if(io->write_proc(buffer, 1, (unsigned int)strlen(buffer), handle) < 1)
  256. return rgbe_Error(rgbe_write_error, NULL);
  257. }
  258. sprintf(buffer, "\n-Y %d +X %d\n", height, width);
  259. if(io->write_proc(buffer, 1, (unsigned int)strlen(buffer), handle) < 1)
  260. return rgbe_Error(rgbe_write_error, NULL);
  261. return TRUE;
  262. }
  263. static BOOL
  264. rgbe_ReadMetadata(FIBITMAP *dib, rgbeHeaderInfo *header_info) {
  265. return TRUE;
  266. }
  267. static BOOL
  268. rgbe_WriteMetadata(FIBITMAP *dib, rgbeHeaderInfo *header_info) {
  269. header_info->gamma = 1;
  270. header_info->valid |= RGBE_VALID_GAMMA;
  271. header_info->exposure = 0;
  272. header_info->valid |= RGBE_VALID_EXPOSURE;
  273. return TRUE;
  274. }
  275. /**
  276. Simple read routine. Will not correctly handle run length encoding
  277. */
  278. static BOOL
  279. rgbe_ReadPixels(FreeImageIO *io, fi_handle handle, FIRGBF *data, unsigned numpixels) {
  280. BYTE rgbe[4];
  281. for(unsigned x = 0; x < numpixels; x++) {
  282. if(io->read_proc(rgbe, 1, sizeof(rgbe), handle) < 1) {
  283. return rgbe_Error(rgbe_read_error, NULL);
  284. }
  285. rgbe_RGBEToFloat(&data[x], rgbe);
  286. }
  287. return TRUE;
  288. }
  289. /**
  290. Simple write routine that does not use run length encoding.
  291. These routines can be made faster by allocating a larger buffer and
  292. fread-ing and fwrite-ing the data in larger chunks.
  293. */
  294. static BOOL
  295. rgbe_WritePixels(FreeImageIO *io, fi_handle handle, FIRGBF *data, unsigned numpixels) {
  296. BYTE rgbe[4];
  297. for(unsigned x = 0; x < numpixels; x++) {
  298. rgbe_FloatToRGBE(rgbe, &data[x]);
  299. if(io->write_proc(rgbe, sizeof(rgbe), 1, handle) < 1)
  300. return rgbe_Error(rgbe_write_error, NULL);
  301. }
  302. return TRUE;
  303. }
  304. static BOOL
  305. rgbe_ReadPixels_RLE(FreeImageIO *io, fi_handle handle, FIRGBF *data, int scanline_width, unsigned num_scanlines) {
  306. BYTE rgbe[4], *scanline_buffer, *ptr, *ptr_end;
  307. int i, count;
  308. BYTE buf[2];
  309. if ((scanline_width < 8)||(scanline_width > 0x7fff)) {
  310. // run length encoding is not allowed so read flat
  311. return rgbe_ReadPixels(io, handle, data, scanline_width * num_scanlines);
  312. }
  313. scanline_buffer = NULL;
  314. // read in each successive scanline
  315. while(num_scanlines > 0) {
  316. if(io->read_proc(rgbe, 1, sizeof(rgbe), handle) < 1) {
  317. free(scanline_buffer);
  318. return rgbe_Error(rgbe_read_error,NULL);
  319. }
  320. if((rgbe[0] != 2) || (rgbe[1] != 2) || (rgbe[2] & 0x80)) {
  321. // this file is not run length encoded
  322. rgbe_RGBEToFloat(data, rgbe);
  323. data ++;
  324. free(scanline_buffer);
  325. return rgbe_ReadPixels(io, handle, data, scanline_width * num_scanlines - 1);
  326. }
  327. if((((int)rgbe[2]) << 8 | rgbe[3]) != scanline_width) {
  328. free(scanline_buffer);
  329. return rgbe_Error(rgbe_format_error,"wrong scanline width");
  330. }
  331. if(scanline_buffer == NULL) {
  332. scanline_buffer = (BYTE*)malloc(sizeof(BYTE) * 4 * scanline_width);
  333. if(scanline_buffer == NULL) {
  334. return rgbe_Error(rgbe_memory_error, "unable to allocate buffer space");
  335. }
  336. }
  337. ptr = &scanline_buffer[0];
  338. // read each of the four channels for the scanline into the buffer
  339. for(i = 0; i < 4; i++) {
  340. ptr_end = &scanline_buffer[(i+1)*scanline_width];
  341. while(ptr < ptr_end) {
  342. if(io->read_proc(buf, 1, 2 * sizeof(BYTE), handle) < 1) {
  343. free(scanline_buffer);
  344. return rgbe_Error(rgbe_read_error, NULL);
  345. }
  346. if(buf[0] > 128) {
  347. // a run of the same value
  348. count = buf[0] - 128;
  349. if((count == 0) || (count > ptr_end - ptr)) {
  350. free(scanline_buffer);
  351. return rgbe_Error(rgbe_format_error, "bad scanline data");
  352. }
  353. while(count-- > 0)
  354. *ptr++ = buf[1];
  355. }
  356. else {
  357. // a non-run
  358. count = buf[0];
  359. if((count == 0) || (count > ptr_end - ptr)) {
  360. free(scanline_buffer);
  361. return rgbe_Error(rgbe_format_error, "bad scanline data");
  362. }
  363. *ptr++ = buf[1];
  364. if(--count > 0) {
  365. if(io->read_proc(ptr, 1, sizeof(BYTE) * count, handle) < 1) {
  366. free(scanline_buffer);
  367. return rgbe_Error(rgbe_read_error, NULL);
  368. }
  369. ptr += count;
  370. }
  371. }
  372. }
  373. }
  374. // now convert data from buffer into floats
  375. for(i = 0; i < scanline_width; i++) {
  376. rgbe[0] = scanline_buffer[i];
  377. rgbe[1] = scanline_buffer[i+scanline_width];
  378. rgbe[2] = scanline_buffer[i+2*scanline_width];
  379. rgbe[3] = scanline_buffer[i+3*scanline_width];
  380. rgbe_RGBEToFloat(data, rgbe);
  381. data ++;
  382. }
  383. num_scanlines--;
  384. }
  385. free(scanline_buffer);
  386. return TRUE;
  387. }
  388. /**
  389. The code below is only needed for the run-length encoded files.
  390. Run length encoding adds considerable complexity but does
  391. save some space. For each scanline, each channel (r,g,b,e) is
  392. encoded separately for better compression.
  393. @return Returns TRUE if successful, returns FALSE otherwise
  394. */
  395. static BOOL
  396. rgbe_WriteBytes_RLE(FreeImageIO *io, fi_handle handle, BYTE *data, int numbytes) {
  397. static const int MINRUNLENGTH = 4;
  398. int cur, beg_run, run_count, old_run_count, nonrun_count;
  399. BYTE buf[2];
  400. cur = 0;
  401. while(cur < numbytes) {
  402. beg_run = cur;
  403. // find next run of length at least 4 if one exists
  404. run_count = old_run_count = 0;
  405. while((run_count < MINRUNLENGTH) && (beg_run < numbytes)) {
  406. beg_run += run_count;
  407. old_run_count = run_count;
  408. run_count = 1;
  409. while((data[beg_run] == data[beg_run + run_count]) && (beg_run + run_count < numbytes) && (run_count < 127))
  410. run_count++;
  411. }
  412. // if data before next big run is a short run then write it as such
  413. if ((old_run_count > 1)&&(old_run_count == beg_run - cur)) {
  414. buf[0] = (BYTE)(128 + old_run_count); // write short run
  415. buf[1] = data[cur];
  416. if(io->write_proc(buf, 2 * sizeof(BYTE), 1, handle) < 1)
  417. return rgbe_Error(rgbe_write_error, NULL);
  418. cur = beg_run;
  419. }
  420. // write out bytes until we reach the start of the next run
  421. while(cur < beg_run) {
  422. nonrun_count = beg_run - cur;
  423. if (nonrun_count > 128)
  424. nonrun_count = 128;
  425. buf[0] = (BYTE)nonrun_count;
  426. if(io->write_proc(buf, sizeof(buf[0]), 1, handle) < 1)
  427. return rgbe_Error(rgbe_write_error,NULL);
  428. if(io->write_proc(&data[cur], sizeof(data[0]) * nonrun_count, 1, handle) < 1)
  429. return rgbe_Error(rgbe_write_error,NULL);
  430. cur += nonrun_count;
  431. }
  432. // write out next run if one was found
  433. if (run_count >= MINRUNLENGTH) {
  434. buf[0] = (BYTE)(128 + run_count);
  435. buf[1] = data[beg_run];
  436. if(io->write_proc(buf, sizeof(buf[0]) * 2, 1, handle) < 1)
  437. return rgbe_Error(rgbe_write_error,NULL);
  438. cur += run_count;
  439. }
  440. }
  441. return TRUE;
  442. }
  443. static BOOL
  444. rgbe_WritePixels_RLE(FreeImageIO *io, fi_handle handle, FIRGBF *data, unsigned scanline_width, unsigned num_scanlines) {
  445. BYTE rgbe[4];
  446. BYTE *buffer;
  447. if ((scanline_width < 8)||(scanline_width > 0x7fff)) {
  448. // run length encoding is not allowed so write flat
  449. return rgbe_WritePixels(io, handle, data, scanline_width * num_scanlines);
  450. }
  451. buffer = (BYTE*)malloc(sizeof(BYTE) * 4 * scanline_width);
  452. if (buffer == NULL) {
  453. // no buffer space so write flat
  454. return rgbe_WritePixels(io, handle, data, scanline_width * num_scanlines);
  455. }
  456. while(num_scanlines-- > 0) {
  457. rgbe[0] = (BYTE)2;
  458. rgbe[1] = (BYTE)2;
  459. rgbe[2] = (BYTE)(scanline_width >> 8);
  460. rgbe[3] = (BYTE)(scanline_width & 0xFF);
  461. if(io->write_proc(rgbe, sizeof(rgbe), 1, handle) < 1) {
  462. free(buffer);
  463. return rgbe_Error(rgbe_write_error, NULL);
  464. }
  465. for(unsigned x = 0; x < scanline_width; x++) {
  466. rgbe_FloatToRGBE(rgbe, data);
  467. buffer[x] = rgbe[0];
  468. buffer[x+scanline_width] = rgbe[1];
  469. buffer[x+2*scanline_width] = rgbe[2];
  470. buffer[x+3*scanline_width] = rgbe[3];
  471. data ++;
  472. }
  473. // write out each of the four channels separately run length encoded
  474. // first red, then green, then blue, then exponent
  475. for(int i = 0; i < 4; i++) {
  476. BOOL bOK = rgbe_WriteBytes_RLE(io, handle, &buffer[i*scanline_width], scanline_width);
  477. if(!bOK) {
  478. free(buffer);
  479. return bOK;
  480. }
  481. }
  482. }
  483. free(buffer);
  484. return TRUE;
  485. }
  486. // ----------------------------------------------------------
  487. // ==========================================================
  488. // Plugin Implementation
  489. // ==========================================================
  490. static const char * DLL_CALLCONV
  491. Format() {
  492. return "HDR";
  493. }
  494. static const char * DLL_CALLCONV
  495. Description() {
  496. return "High Dynamic Range Image";
  497. }
  498. static const char * DLL_CALLCONV
  499. Extension() {
  500. return "hdr";
  501. }
  502. static const char * DLL_CALLCONV
  503. RegExpr() {
  504. return NULL;
  505. }
  506. static const char * DLL_CALLCONV
  507. MimeType() {
  508. return "image/vnd.radiance";
  509. }
  510. static BOOL DLL_CALLCONV
  511. Validate(FreeImageIO *io, fi_handle handle) {
  512. BYTE hdr_signature[] = { '#', '?' };
  513. BYTE signature[] = { 0, 0 };
  514. io->read_proc(signature, 1, 2, handle);
  515. return (memcmp(hdr_signature, signature, 2) == 0);
  516. }
  517. static BOOL DLL_CALLCONV
  518. SupportsExportDepth(int depth) {
  519. return FALSE;
  520. }
  521. static BOOL DLL_CALLCONV
  522. SupportsExportType(FREE_IMAGE_TYPE type) {
  523. return (type == FIT_RGBF) ? TRUE : FALSE;
  524. }
  525. static BOOL DLL_CALLCONV
  526. SupportsNoPixels() {
  527. return TRUE;
  528. }
  529. // --------------------------------------------------------------------------
  530. static FIBITMAP * DLL_CALLCONV
  531. Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
  532. FIBITMAP *dib = NULL;
  533. if(!handle) {
  534. return NULL;
  535. }
  536. BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
  537. try {
  538. rgbeHeaderInfo header_info;
  539. unsigned width, height;
  540. // Read the header
  541. if(rgbe_ReadHeader(io, handle, &width, &height, &header_info) == FALSE) {
  542. return NULL;
  543. }
  544. // allocate a RGBF image
  545. dib = FreeImage_AllocateHeaderT(header_only, FIT_RGBF, width, height);
  546. if(!dib) {
  547. throw FI_MSG_ERROR_MEMORY;
  548. }
  549. // set the metadata as comments
  550. rgbe_ReadMetadata(dib, &header_info);
  551. if(header_only) {
  552. // header only mode
  553. return dib;
  554. }
  555. // read the image pixels and fill the dib
  556. for(unsigned y = 0; y < height; y++) {
  557. FIRGBF *scanline = (FIRGBF*)FreeImage_GetScanLine(dib, height - 1 - y);
  558. if(!rgbe_ReadPixels_RLE(io, handle, scanline, width, 1)) {
  559. FreeImage_Unload(dib);
  560. return NULL;
  561. }
  562. }
  563. }
  564. catch(const char *text) {
  565. if(dib != NULL) {
  566. FreeImage_Unload(dib);
  567. }
  568. FreeImage_OutputMessageProc(s_format_id, text);
  569. }
  570. return dib;
  571. }
  572. static BOOL DLL_CALLCONV
  573. Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
  574. if(!dib) return FALSE;
  575. if(FreeImage_GetImageType(dib) != FIT_RGBF) {
  576. return FALSE;
  577. }
  578. unsigned width = FreeImage_GetWidth(dib);
  579. unsigned height = FreeImage_GetHeight(dib);
  580. // write the header
  581. rgbeHeaderInfo header_info;
  582. memset(&header_info, 0, sizeof(rgbeHeaderInfo));
  583. // fill the header with correct gamma and exposure
  584. rgbe_WriteMetadata(dib, &header_info);
  585. // fill a comment
  586. sprintf(header_info.comment, "# Made with FreeImage %s", FreeImage_GetVersion());
  587. if(!rgbe_WriteHeader(io, handle, width, height, &header_info)) {
  588. return FALSE;
  589. }
  590. // write each scanline
  591. for(unsigned y = 0; y < height; y++) {
  592. FIRGBF *scanline = (FIRGBF*)FreeImage_GetScanLine(dib, height - 1 - y);
  593. if(!rgbe_WritePixels_RLE(io, handle, scanline, width, 1)) {
  594. return FALSE;
  595. }
  596. }
  597. return TRUE;
  598. }
  599. // ==========================================================
  600. // Init
  601. // ==========================================================
  602. void DLL_CALLCONV
  603. InitHDR(Plugin *plugin, int format_id) {
  604. s_format_id = format_id;
  605. plugin->format_proc = Format;
  606. plugin->description_proc = Description;
  607. plugin->extension_proc = Extension;
  608. plugin->regexpr_proc = RegExpr;
  609. plugin->open_proc = NULL;
  610. plugin->close_proc = NULL;
  611. plugin->pagecount_proc = NULL;
  612. plugin->pagecapability_proc = NULL;
  613. plugin->load_proc = Load;
  614. plugin->save_proc = Save;
  615. plugin->validate_proc = Validate;
  616. plugin->mime_proc = MimeType;
  617. plugin->supports_export_bpp_proc = SupportsExportDepth;
  618. plugin->supports_export_type_proc = SupportsExportType;
  619. plugin->supports_icc_profiles_proc = NULL;
  620. plugin->supports_no_pixels_proc = SupportsNoPixels;
  621. }