/src/FreeImage/Source/FreeImage/PluginPFM.cpp

https://bitbucket.org/cabalistic/ogredeps/ · C++ · 402 lines · 258 code · 81 blank · 63 comment · 79 complexity · 38dc9573ee3732b4f4a0acd8dd777887 MD5 · raw file

  1. // ==========================================================
  2. // PFM 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. // Internal functions
  25. // ==========================================================
  26. /** maximum size of a line in the header */
  27. #define PFM_MAXLINE 256
  28. /** Big endian / Little endian float conversion */
  29. #define REVERSEBYTES(source, dest) \
  30. { \
  31. char *j = (char *) source; \
  32. char *dj = (char *) dest; \
  33. dj[0] = j[3]; \
  34. dj[1] = j[2]; \
  35. dj[2] = j[1]; \
  36. dj[3] = j[0]; \
  37. }
  38. /**
  39. Get a line from a ASCII io stream
  40. */
  41. static BOOL
  42. pfm_get_line(FreeImageIO *io, fi_handle handle, char *buffer, int length) {
  43. int i;
  44. memset(buffer, 0, length);
  45. for(i = 0; i < length; i++) {
  46. if(!io->read_proc(&buffer[i], 1, 1, handle))
  47. return FALSE;
  48. if(buffer[i] == 0x0A)
  49. break;
  50. }
  51. return (i < length) ? TRUE : FALSE;
  52. }
  53. /**
  54. Get an integer value from the actual position pointed by handle
  55. */
  56. static int
  57. pfm_get_int(FreeImageIO *io, fi_handle handle) {
  58. char c = 0;
  59. BOOL firstchar;
  60. // skip forward to start of next number
  61. if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
  62. while (1) {
  63. // eat comments
  64. if (c == '#') {
  65. // if we're at a comment, read to end of line
  66. firstchar = TRUE;
  67. while (1) {
  68. if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
  69. if (firstchar && c == ' ') {
  70. // loop off 1 sp after #
  71. firstchar = FALSE;
  72. } else if (c == '\n') {
  73. break;
  74. }
  75. }
  76. }
  77. if (c >= '0' && c <='9') {
  78. // we've found what we were looking for
  79. break;
  80. }
  81. if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
  82. }
  83. // we're at the start of a number, continue until we hit a non-number
  84. int i = 0;
  85. while (1) {
  86. i = (i * 10) + (c - '0');
  87. if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
  88. if (c < '0' || c > '9')
  89. break;
  90. }
  91. return i;
  92. }
  93. // ==========================================================
  94. // Plugin Interface
  95. // ==========================================================
  96. static int s_format_id;
  97. // ==========================================================
  98. // Plugin Implementation
  99. // ==========================================================
  100. static const char * DLL_CALLCONV
  101. Format() {
  102. return "PFM";
  103. }
  104. static const char * DLL_CALLCONV
  105. Description() {
  106. return "Portable floatmap";
  107. }
  108. static const char * DLL_CALLCONV
  109. Extension() {
  110. return "pfm";
  111. }
  112. static const char * DLL_CALLCONV
  113. RegExpr() {
  114. return NULL;
  115. }
  116. static const char * DLL_CALLCONV
  117. MimeType() {
  118. return "image/x-portable-floatmap";
  119. }
  120. static BOOL DLL_CALLCONV
  121. Validate(FreeImageIO *io, fi_handle handle) {
  122. BYTE pfm_id1[] = { 0x50, 0x46 };
  123. BYTE pfm_id2[] = { 0x50, 0x66 };
  124. BYTE signature[2] = { 0, 0 };
  125. io->read_proc(signature, 1, sizeof(pfm_id1), handle);
  126. if (memcmp(pfm_id1, signature, sizeof(pfm_id1)) == 0)
  127. return TRUE;
  128. if (memcmp(pfm_id2, signature, sizeof(pfm_id2)) == 0)
  129. return TRUE;
  130. return FALSE;
  131. }
  132. static BOOL DLL_CALLCONV
  133. SupportsExportDepth(int depth) {
  134. return FALSE;
  135. }
  136. static BOOL DLL_CALLCONV
  137. SupportsExportType(FREE_IMAGE_TYPE type) {
  138. return (
  139. (type == FIT_FLOAT) ||
  140. (type == FIT_RGBF)
  141. );
  142. }
  143. static BOOL DLL_CALLCONV
  144. SupportsNoPixels() {
  145. return TRUE;
  146. }
  147. // ----------------------------------------------------------
  148. static FIBITMAP * DLL_CALLCONV
  149. Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
  150. char line_buffer[PFM_MAXLINE];
  151. char id_one = 0, id_two = 0;
  152. FIBITMAP *dib = NULL;
  153. float *lineBuffer = NULL;
  154. if (!handle) {
  155. return NULL;
  156. }
  157. BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
  158. try {
  159. FREE_IMAGE_TYPE image_type = FIT_UNKNOWN;
  160. // Read the first two bytes of the file to determine the file format
  161. // "PF" = color image
  162. // "Pf" = greyscale image
  163. io->read_proc(&id_one, 1, 1, handle);
  164. io->read_proc(&id_two, 1, 1, handle);
  165. if(id_one == 'P') {
  166. if(id_two == 'F') {
  167. image_type = FIT_RGBF;
  168. } else if(id_two == 'f') {
  169. image_type = FIT_FLOAT;
  170. }
  171. }
  172. if(image_type == FIT_UNKNOWN) {
  173. // signature error
  174. throw FI_MSG_ERROR_MAGIC_NUMBER;
  175. }
  176. // Read the header information: width, height and the scale value
  177. unsigned width = (unsigned) pfm_get_int(io, handle);
  178. unsigned height = (unsigned) pfm_get_int(io, handle);
  179. float scalefactor = 1;
  180. BOOL bResult = pfm_get_line(io, handle, line_buffer, PFM_MAXLINE);
  181. if(bResult) {
  182. bResult = (sscanf(line_buffer, "%f", &scalefactor) == 1) ? TRUE : FALSE;
  183. }
  184. if(!bResult) {
  185. throw "Read error: invalid PFM header";
  186. }
  187. // Create a new DIB
  188. dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height);
  189. if (dib == NULL) {
  190. throw FI_MSG_ERROR_DIB_MEMORY;
  191. }
  192. if(header_only) {
  193. // header only mode
  194. return dib;
  195. }
  196. // Read the image...
  197. if(image_type == FIT_RGBF) {
  198. const unsigned lineWidth = 3 * width;
  199. lineBuffer = (float*)malloc(lineWidth * sizeof(float));
  200. if(!lineBuffer) {
  201. throw FI_MSG_ERROR_MEMORY;
  202. }
  203. for (unsigned y = 0; y < height; y++) {
  204. FIRGBF *bits = (FIRGBF*)FreeImage_GetScanLine(dib, height - 1 - y);
  205. if(io->read_proc(lineBuffer, sizeof(float), lineWidth, handle) != lineWidth) {
  206. throw "Read error";
  207. }
  208. float *channel = lineBuffer;
  209. if(scalefactor > 0) {
  210. // MSB
  211. for (unsigned x = 0; x < width; x++) {
  212. REVERSEBYTES(channel++, &bits[x].red);
  213. REVERSEBYTES(channel++, &bits[x].green);
  214. REVERSEBYTES(channel++, &bits[x].blue);
  215. }
  216. } else {
  217. // LSB
  218. for (unsigned x = 0; x < width; x++) {
  219. bits[x].red = *channel++;
  220. bits[x].green = *channel++;
  221. bits[x].blue = *channel++;
  222. }
  223. }
  224. }
  225. free(lineBuffer);
  226. lineBuffer = NULL;
  227. } else if(image_type == FIT_FLOAT) {
  228. const unsigned lineWidth = width;
  229. lineBuffer = (float*)malloc(lineWidth * sizeof(float));
  230. if(!lineBuffer) {
  231. throw FI_MSG_ERROR_MEMORY;
  232. }
  233. for (unsigned y = 0; y < height; y++) {
  234. float *bits = (float*)FreeImage_GetScanLine(dib, height - 1 - y);
  235. if(io->read_proc(lineBuffer, sizeof(float), lineWidth, handle) != lineWidth) {
  236. throw "Read error";
  237. }
  238. float *channel = lineBuffer;
  239. if(scalefactor > 0) {
  240. // MSB - File is Big endian
  241. for (unsigned x = 0; x < width; x++) {
  242. REVERSEBYTES(channel++, &bits[x]);
  243. }
  244. } else {
  245. // LSB - File is Little Endian
  246. for (unsigned x = 0; x < width; x++) {
  247. bits[x] = *channel++;
  248. }
  249. }
  250. }
  251. free(lineBuffer);
  252. lineBuffer = NULL;
  253. }
  254. return dib;
  255. } catch (const char *text) {
  256. if(lineBuffer) free(lineBuffer);
  257. if(dib) FreeImage_Unload(dib);
  258. if(NULL != text) {
  259. FreeImage_OutputMessageProc(s_format_id, text);
  260. }
  261. return NULL;
  262. }
  263. }
  264. static BOOL DLL_CALLCONV
  265. Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
  266. if(!dib || !handle) return FALSE;
  267. FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
  268. if((image_type != FIT_RGBF) && (image_type != FIT_FLOAT)) {
  269. return FALSE;
  270. }
  271. unsigned width = FreeImage_GetWidth(dib);
  272. unsigned height = FreeImage_GetHeight(dib);
  273. unsigned lineWidth = FreeImage_GetLine(dib);
  274. // save image as Little Endian
  275. const float scalefactor = -1.0F;
  276. char buffer[PFM_MAXLINE]; // temporary buffer whose size should be enough for what we need
  277. // Find the appropriate magic number for this file type
  278. char magic = 0;
  279. switch(image_type) {
  280. case FIT_RGBF:
  281. magic = 'F'; // RGBF
  282. break;
  283. case FIT_FLOAT:
  284. magic = 'f'; // float greyscale
  285. break;
  286. default:
  287. return FALSE;
  288. }
  289. // Write the header info
  290. sprintf(buffer, "P%c\n%d %d\n%f\n", magic, width, height, scalefactor);
  291. io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle);
  292. // Write the image data
  293. for (unsigned y = 0; y < height; y++) {
  294. BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y);
  295. io->write_proc(bits, 1, lineWidth, handle);
  296. }
  297. return TRUE;
  298. }
  299. // ==========================================================
  300. // Init
  301. // ==========================================================
  302. void DLL_CALLCONV
  303. InitPFM(Plugin *plugin, int format_id) {
  304. s_format_id = format_id;
  305. plugin->format_proc = Format;
  306. plugin->description_proc = Description;
  307. plugin->extension_proc = Extension;
  308. plugin->regexpr_proc = RegExpr;
  309. plugin->open_proc = NULL;
  310. plugin->close_proc = NULL;
  311. plugin->pagecount_proc = NULL;
  312. plugin->pagecapability_proc = NULL;
  313. plugin->load_proc = Load;
  314. plugin->save_proc = Save;
  315. plugin->validate_proc = Validate;
  316. plugin->mime_proc = MimeType;
  317. plugin->supports_export_bpp_proc = SupportsExportDepth;
  318. plugin->supports_export_type_proc = SupportsExportType;
  319. plugin->supports_icc_profiles_proc = NULL;
  320. plugin->supports_no_pixels_proc = SupportsNoPixels;
  321. }