A tool to construct HDR-images from a series of exposures.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. #include <stdio.h>
  2. // for error recovery
  3. #include <setjmp.h>
  4. #include <iostream>
  5. #include <fstream>
  6. #include <sstream>
  7. #include <vector>
  8. #include "jpeglib.h"
  9. #define STB_IMAGE_IMPLEMENTATION
  10. #include "stb_image.h"
  11. #include "image.h"
  12. using namespace std;
  13. using namespace haader;
  14. Image::Image():
  15. m_width(0),
  16. m_height(0),
  17. m_components(0)
  18. {
  19. }
  20. void Image::to_string(string &s) {
  21. stringstream ss;
  22. ss << "Image(";
  23. ss << m_width << 'x' << m_height << 'x' << m_components << ")";
  24. s = ss.str();
  25. }
  26. bool Image::read_from_file(const char *file_path) {
  27. int x = 0;
  28. int y = 0;
  29. int components = 0;
  30. unsigned char *data = stbi_load(file_path, &x, &y, &components, 0);
  31. if (data) {
  32. m_width = x;
  33. m_height = y;
  34. m_components = components;
  35. size_t size = (size_t)x * (size_t)y * (size_t)components;
  36. m_image_data.assign(data, data + size);
  37. return true;
  38. } else {
  39. cerr << "Can not read \"" << file_path << "\" as an image." << endl;
  40. return false;
  41. }
  42. stbi_image_free(data);
  43. }
  44. struct my_error_mgr {
  45. struct jpeg_error_mgr pub; /* "public" fields */
  46. jmp_buf setjmp_buffer; /* for return to caller */
  47. };
  48. typedef struct my_error_mgr * my_error_ptr;
  49. /*
  50. * Here's the routine that will replace the standard error_exit method:
  51. */
  52. METHODDEF(void)
  53. my_error_exit (j_common_ptr cinfo)
  54. {
  55. /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
  56. my_error_ptr myerr = (my_error_ptr) cinfo->err;
  57. /* Always display the message. */
  58. /* We could postpone this until after returning, if we chose. */
  59. (*cinfo->err->output_message) (cinfo);
  60. /* Return control to the setjmp point */
  61. longjmp(myerr->setjmp_buffer, 1);
  62. }
  63. bool Image::read_from_jpeg_file(const char *file_path) {
  64. /* This struct contains the JPEG decompression parameters and pointers to
  65. * working space (which is allocated as needed by the JPEG library).
  66. */
  67. struct jpeg_decompress_struct cinfo;
  68. /* We use our private extension JPEG error handler.
  69. * Note that this struct must live as long as the main JPEG parameter
  70. * struct, to avoid dangling-pointer problems.
  71. */
  72. struct my_error_mgr jerr;
  73. /* More stuff */
  74. FILE * infile; /* source file */
  75. JSAMPARRAY buffer; /* Output row buffer */
  76. int row_stride; /* physical row width in output buffer */
  77. /* In this example we want to open the input file before doing anything else,
  78. * so that the setjmp() error recovery below can assume the file is open.
  79. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
  80. * requires it in order to read binary files.
  81. */
  82. if ((infile = fopen(file_path, "rb")) == NULL) {
  83. cerr << "Can not open \"" << file_path << "\"" << endl;
  84. return false;
  85. }
  86. /* Step 1: allocate and initialize JPEG decompression object */
  87. /* We set up the normal JPEG error routines, then override error_exit. */
  88. cinfo.err = jpeg_std_error(&jerr.pub);
  89. jerr.pub.error_exit = my_error_exit;
  90. /* Establish the setjmp return context for my_error_exit to use. */
  91. if (setjmp(jerr.setjmp_buffer)) {
  92. /* If we get here, the JPEG code has signaled an error.
  93. * We need to clean up the JPEG object, close the input file, and return.
  94. */
  95. jpeg_destroy_decompress(&cinfo);
  96. fclose(infile);
  97. return false;
  98. }
  99. /* Now we can initialize the JPEG decompression object. */
  100. jpeg_create_decompress(&cinfo);
  101. /* Step 2: specify data source (eg, a file) */
  102. jpeg_stdio_src(&cinfo, infile);
  103. /* Step 3: read file parameters with jpeg_read_header() */
  104. (void) jpeg_read_header(&cinfo, TRUE);
  105. /* We can ignore the return value from jpeg_read_header since
  106. * (a) suspension is not possible with the stdio data source, and
  107. * (b) we passed TRUE to reject a tables-only JPEG file as an error.
  108. * See libjpeg.txt for more info.
  109. */
  110. /* Step 4: set parameters for decompression */
  111. /* In this example, we don't need to change any of the defaults set by
  112. * jpeg_read_header(), so we do nothing here.
  113. */
  114. /* Step 5: Start decompressor */
  115. (void) jpeg_start_decompress(&cinfo);
  116. /* We can ignore the return value since suspension is not possible
  117. * with the stdio data source.
  118. */
  119. m_image_data.reserve(cinfo.output_width * cinfo.output_height * cinfo.output_components);
  120. m_width = cinfo.output_width;
  121. m_height = cinfo.output_height;
  122. m_components = cinfo.output_components;
  123. /* We may need to do some setup of our own at this point before reading
  124. * the data. After jpeg_start_decompress() we have the correct scaled
  125. * output image dimensions available, as well as the output colormap
  126. * if we asked for color quantization.
  127. * In this example, we need to make an output work buffer of the right size.
  128. */
  129. /* JSAMPLEs per row in output buffer */
  130. row_stride = cinfo.output_width * cinfo.output_components;
  131. /* Make a one-row-high sample array that will go away when done with image */
  132. buffer = (*cinfo.mem->alloc_sarray)
  133. ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
  134. /* Step 6: while (scan lines remain to be read) */
  135. /* jpeg_read_scanlines(...); */
  136. /* Here we use the library's state variable cinfo.output_scanline as the
  137. * loop counter, so that we don't have to keep track ourselves.
  138. */
  139. while (cinfo.output_scanline < cinfo.output_height) {
  140. /* jpeg_read_scanlines expects an array of pointers to scanlines.
  141. * Here the array is only one element long, but you could ask for
  142. * more than one scanline at a time if that's more convenient.
  143. */
  144. (void) jpeg_read_scanlines(&cinfo, buffer, 1);
  145. /* Assume put_scanline_someplace wants a pointer and sample count. */
  146. //put_scanline_someplace(buffer[0], row_stride);
  147. for (int i = 0; i < row_stride; i++) {
  148. m_image_data.push_back(buffer[0][i]);
  149. }
  150. }
  151. /* Step 7: Finish decompression */
  152. (void) jpeg_finish_decompress(&cinfo);
  153. /* We can ignore the return value since suspension is not possible
  154. * with the stdio data source.
  155. */
  156. /* Step 8: Release JPEG decompression object */
  157. /* This is an important step since it will release a good deal of memory. */
  158. jpeg_destroy_decompress(&cinfo);
  159. /* After finish_decompress, we can close the input file.
  160. * Here we postpone it until after no more JPEG errors are possible,
  161. * so as to simplify the setjmp error logic above. (Actually, I don't
  162. * think that jpeg_destroy can do an error exit, but why assume anything...)
  163. */
  164. fclose(infile);
  165. if (jerr.pub.num_warnings != 0) {
  166. cout << jerr.pub.num_warnings << " errors occured." << endl;
  167. return false;
  168. } else {
  169. return true;
  170. }
  171. }
  172. bool Image::save_as_ppm_file(const char *file_path, bool ascii) {
  173. if (ascii) {
  174. // ASCII
  175. ofstream out(file_path);
  176. out << "P3\n";
  177. out << m_width << ' ' << m_height << '\n';
  178. out << "255\n";
  179. unsigned int pixels = m_width * m_height;
  180. unsigned int index = 0;
  181. for (unsigned int i = 0; i < pixels; i++) {
  182. out << (int)m_image_data[index] << ' ' << (int)m_image_data[index + 1] << ' ' << (int)m_image_data[index + 2] << '\n';
  183. index += 3;
  184. }
  185. out.close();
  186. return true;
  187. } else {
  188. // binary
  189. ofstream out(file_path);
  190. out << "P6\n";
  191. out << m_width << ' ' << m_height << '\n';
  192. out << "255\n";
  193. unsigned int pixels = m_width * m_height;
  194. unsigned int index = 0;
  195. for (unsigned int i = 0; i < pixels; i++) {
  196. out << m_image_data[index] << m_image_data[index + 1] << m_image_data[index + 2];
  197. index += 3;
  198. }
  199. out.close();
  200. return true;
  201. }
  202. }
  203. unsigned int Image::get_width() {
  204. return m_width;
  205. }
  206. unsigned int Image::get_height() {
  207. return m_height;
  208. }
  209. unsigned int Image::get_components() {
  210. return m_components;
  211. }
  212. bool Image::has_equal_dimensions(const Image &other) {
  213. return (m_width == other.m_width &&
  214. m_height == other.m_height &&
  215. m_components == other.m_components);
  216. }