PICCANTE  0.4
The hottest HDR imaging library!
hdr.hpp
Go to the documentation of this file.
1 /*
2 
3 PICCANTE
4 The hottest HDR imaging library!
5 http://vcg.isti.cnr.it/piccante
6 
7 Copyright (C) 2014
8 Visual Computing Laboratory - ISTI CNR
9 http://vcg.isti.cnr.it
10 First author: Francesco Banterle
11 
12 This Source Code Form is subject to the terms of the Mozilla Public
13 License, v. 2.0. If a copy of the MPL was not distributed with this
14 file, You can obtain one at http://mozilla.org/MPL/2.0/.
15 
16 */
17 
18 #ifndef PIC_IO_HDR_HPP
19 #define PIC_IO_HDR_HPP
20 
21 #include <stdio.h>
22 #include <string.h>
23 
24 #include "../colors/rgbe.hpp"
25 #include "../base.hpp"
26 //SYSTEM: X NEG Y POS
27 
28 namespace pic {
29 
38 PIC_INLINE float *ReadHDR(std::string nameFile, float *data, int &width,
39  int &height)
40 {
41  FILE *file = fopen(nameFile.c_str(), "rb");
42 
43  if(file == NULL) {
44  return NULL;
45  }
46 
47  char tmp[512];
48 
49  //Is it a Radiance file?
50  fscanf(file, "%s\n", tmp);
51 
52  if(strcmp(tmp, "#?RADIANCE") != 0) {
53  return NULL;
54  }
55 
56  while(true) { //Reading Radiance Header
57  std::string line = "";
58 
59  while(true) { //read property line
60  char *tmp2 = fgets(tmp, 512, file);
61 
62  if(tmp2 == NULL) {
63  return NULL;
64  }
65 
66  line += tmp2;
67  size_t pos = line.find("\n");
68 
69  if(pos != std::string::npos) {
70  break;
71  }
72  }
73 
74  if(line.compare("\n") == 0) {
75  break;
76  }
77 
78  //Properties:
79  if(line.find("FORMAT") != std::string::npos) { //Format
80  if(line.find("32-bit_rle_rgbe") == std::string::npos) {
81  return NULL;
82  }
83  }
84 
85  if(line.find("EXPOSURE=") != std::string::npos) { //Exposure
86  //TODO: ...
87  }
88  }
89 
90  //width and height
91  fscanf(file, "-Y %d +X %d", &height, &width);
92  fgetc(file);
93 
94  if(data == NULL) {
95  data = new float[width * height * 3];
96  }
97 
98  //File size
99  long int s_cur = ftell(file);
100  fseek(file, 0 , SEEK_END);
101  long int s_end = ftell(file);
102  fseek(file, s_cur, SEEK_SET);
103  int total = s_end - s_cur;
104 
105 #ifdef PIC_DEBUG
106  printf("%d %d\n", total, width * height * 4);
107 #endif
108 
109  //Compressed?
110  if(total == (width * height * 4)) { //uncompressed
111  unsigned char colRGBE[4];
112 
113  int c = 0;
114 
115  for(int i = 0; i < width; i++) {
116  for(int j = 0; j < height; j++) {
117  fread(colRGBE, 1, 4, file);
118  fromRGBEToFloat(colRGBE, &data[c]);
119  c += 3;
120  }
121  }
122  } else { //RLE compressed
123  unsigned char *buffer = new unsigned char[total];
124  fread(buffer, sizeof(unsigned char)*total, 1, file);
125 
126  int line_width3 = width * 3;
127  int line_width4 = width * 4;
128 
129  unsigned char *buffer_line_start;
130  unsigned char *buffer_line = new unsigned char[line_width4];
131  int c = 4;
132  int c_buffer_line = 0;
133 
134  //for each line
135  for(int i = 0; i < height; i++) {
136  buffer_line_start = &buffer[c - 4];
137 
138  int width_check = buffer_line_start[2];
139  int width_check2 = buffer_line_start[3];
140 
141  bool b1 = buffer_line_start[0] != 2;
142  bool b2 = buffer_line_start[1] != 2;
143  bool b3 = width_check != (width >> 8);
144  bool b4 = width_check2 != (width & 0xFF);
145 
146  if(b1 || b2 || b3 || b4) {
147  #ifdef PIC_DEBUG
148  printf("ReadHDR ERROR: the file is not a RLE encoded .hdr file.\n");
149  #endif
150 
151  fclose(file);
152 
153  return NULL;
154  }
155 
156  for(int j = 0; j < 4; j++) {
157  int k = 0;
158 
159  //decompression of a single channel line
160  while(k < width) {
161  int num = buffer[c];
162 
163  if(num > 128) {
164  num -= 128;
165 
166  for(int l = k; l < (k + num); l++) {
167  buffer_line[l * 4 + j] = buffer[c + 1];
168  }
169 
170  c += 2;
171  k += num;
172  } else {
173  for(int l = 0; l < num; l++) {
174  buffer_line[(l + k) * 4 + j] = buffer[c + 1 + l];
175  }
176 
177  c += num + 1;
178  k += num;
179  }
180  }
181  }
182 
183  //From RGBE to Float
184  for(int j = 0; j < width; j++) {
185  fromRGBEToFloat(&buffer_line[j * 4], &data[c_buffer_line + j * 3]);
186  }
187 
188  c += 4;
189  c_buffer_line += line_width3;
190  }
191 
192  delete[] buffer_line;
193  delete[] buffer;
194  }
195 
196  fclose(file);
197  return data;
198 }
199 
206 PIC_INLINE void WriteLineHDR(FILE *file, unsigned char *buffer_line, int width)
207 {
208  int cur_pointer = 0;
209 
210  while(cur_pointer < width) {
211  int run_length = 0;
212  int run_length_old = 0;
213 
214  int run_start = cur_pointer;
215 
216  //we need to find a long run; length>3
217  while((run_length < 4 ) && (run_start < width)) {
218  run_start += run_length;
219  run_length_old = run_length;
220 
221  int start = (run_start + 1);
222  int end = MIN(run_start + 127, width);
223  unsigned char tmp = buffer_line[run_start];
224  run_length = 1;
225 
226  //finding a run
227  for(int i=start; i<end; i++) {
228  if(tmp == buffer_line[i]) {
229  run_length++;
230  } else {
231  break;
232  }
233  }
234  }
235 
236  //do we have a short run <4 before a long one?
237  if((run_length_old > 1) && (run_length_old == (run_start - cur_pointer))){
238  unsigned char length_to_write = run_length_old + 128;
239  unsigned char value_to_write = buffer_line[cur_pointer];
240  fwrite(&length_to_write, sizeof(unsigned char), 1, file);
241  fwrite(&value_to_write, sizeof(unsigned char), 1, file);
242 
243  cur_pointer = run_start;
244  }
245 
246  //writing non-runs
247  while(cur_pointer < run_start) {
248  int non_run_length = run_start - cur_pointer;
249 
250  if(non_run_length > 128) {
251  unsigned char length_to_write = 128;
252  fwrite(&length_to_write, sizeof(unsigned char), 1, file);
253  fwrite(&buffer_line[cur_pointer], sizeof(unsigned char)*length_to_write, 1, file);
254 
255  cur_pointer += length_to_write;
256  } else {
257  fwrite(&non_run_length, sizeof(unsigned char), 1, file);
258  fwrite(&buffer_line[cur_pointer], sizeof(unsigned char)*non_run_length, 1, file);
259 
260  cur_pointer += non_run_length;
261  }
262  }
263 
264  //writing the found long run
265  if(run_length > 3) {
266  unsigned char length_to_write = run_length + 128;
267  unsigned char value_to_write = buffer_line[run_start];
268  fwrite(&length_to_write, sizeof(unsigned char), 1, file);
269  fwrite(&value_to_write, sizeof(unsigned char), 1, file);
270 
271  cur_pointer += run_length;
272  }
273 
274  }
275 }
276 
288 PIC_INLINE bool WriteHDR(std::string nameFile, float *data, int width,
289  int height, int channels, float appliedExposure = 1.0f, bool bRLE = true)
290 {
291  FILE *file;
292 
293  if(data==NULL) {
294  return false;
295  }
296 
297  file = fopen(nameFile.c_str(), "wb");
298 
299  if( file == NULL) {
300  return false;
301  }
302 
303  if((channels == 2) || (channels == 0)) {
304  return false;
305  }
306 
307  //writing the header...
308  fprintf(file, "#?RADIANCE\n");
309  fprintf(file, "#Spiced by Piccante\n");
310  fprintf(file, "FORMAT=32-bit_rle_rgbe\n");
311  fprintf(file, "EXPOSURE= %f\n\n", appliedExposure);
312  fprintf(file, "-Y %d +X %d\n", height, width);
313 
314  //RLE encoding is not allowed in some cases
315  if(((width < 8) || (width > 32767)) && bRLE) {
316  bRLE = false;
317  }
318 
319  if(bRLE) {
320  //buffers
321  unsigned char *buffer_line = new unsigned char[width * 4];
322  unsigned char buffer_rgbe[4];
323  unsigned char buffer_line_start[4];
324 
325  //new line start "header"
326  buffer_line_start[0] = 2;
327  buffer_line_start[1] = 2;
328  buffer_line_start[2] = width >> 8;
329  buffer_line_start[3] = width & 0xFF;
330 
331  int width2 = width * 2;
332  int width3 = width * 3;
333 
334  for(int i=0; i<height; i++) {
335  int ind = i * width;
336 
337  //Converting the line data into the RGBE format
338  for(int j = 0; j < width; j++) {
339  int ind2 = (ind + j) * channels;
340 
341  if(channels == 1) {
342  fromSingleFloatToRGBE(&data[ind2], buffer_rgbe);
343  } else {
344  fromFloatToRGBE(&data[ind2], buffer_rgbe);
345  }
346 
347  buffer_line[ j] = buffer_rgbe[0];
348  buffer_line[width + j] = buffer_rgbe[1];
349  buffer_line[width2 + j] = buffer_rgbe[2];
350  buffer_line[width3 + j] = buffer_rgbe[3];
351  }
352 
353  //Here a new line start
354  fwrite(buffer_line_start, sizeof(unsigned char)*4, 1, file);
355 
356  //RLE encoding for each line
357  for(int j=0; j<4; j++) {
358  WriteLineHDR(file, &buffer_line[j * width], width);
359  }
360  }
361 
362  } else {
363  unsigned char colRGBE[4];
364  for(int j = 0; j < height; j++) {
365  int ind = j * width;
366 
367  for(int i = 0; i < width; i++) {
368  int c = (ind + i);
369 
370  if(channels == 3) {
371  c *= 3;
372  fromFloatToRGBE(&data[c], colRGBE);
373  } else {
374  fromSingleFloatToRGBE(&data[c], colRGBE);
375  }
376 
377  fwrite(colRGBE, 1, 4 * sizeof(unsigned char), file);
378  }
379  }
380  }
381 
382  fclose(file);
383  return true;
384 }
385 
397 PIC_INLINE bool WriteHDRBlock(std::string nameFile, float *buffer_line, int width,
398  int height, int channels, int blockID, int nBlocks)
399 {
400  FILE *file;
401 
402  if((file = fopen(nameFile.c_str(), "wb")) == NULL || (buffer_line == NULL)) {
403  return false;
404  }
405 
406  //TODO: compressed version!
407 
408  //writing the header...
409  if(nBlocks < 1) {
410  nBlocks = 10;
411  }
412 
413  int blockWidth = width / nBlocks;
414 
415  int xStart = blockWidth * blockID;
416  int xEnd = xStart + blockWidth;
417 
418  if(xEnd > width) {
419  xEnd = width;
420  }
421 
422  blockWidth = xEnd - xStart;
423 
424  fprintf(file, "#?RADIANCE\n");
425  fprintf(file, "#Spiced by Piccante\n");
426  fprintf(file, "FORMAT=32-bit_rle_rgbe\n");
427  fprintf(file, "EXPOSURE= 1.0\n\n");
428  fprintf(file, "-Y %d +X %d\n", height, blockWidth);
429 
430  unsigned char colRGBE[4];
431 
432  for(int j = 0; j < height; j++) {
433  int ind = j * width;
434 
435  for(int i = xStart; i < xEnd; i++) {
436  int c = (ind + i);
437 
438  if(channels == 3) {
439  c *= 3;
440  fromFloatToRGBE(&buffer_line[c], colRGBE);
441  } else {
442  fromSingleFloatToRGBE(&buffer_line[c], colRGBE);
443  }
444 
445  fwrite(colRGBE, 1, 4 * sizeof(unsigned char), file);
446  }
447  }
448 
449  fclose(file);
450  return true;
451 }
452 
453 } // end namespace pic
454 
455 #endif /* PIC_IO_HDR_HPP */
456 
PIC_INLINE void fromFloatToRGBE(float *colFloat, unsigned char *colRGBE)
fromFloatToRGBE
Definition: rgbe.hpp:38
PIC_INLINE void fromRGBEToFloat(unsigned char *colRGBE, float *colFloat)
fromRGBEToFloat
Definition: rgbe.hpp:102
PIC_INLINE void WriteLineHDR(FILE *file, unsigned char *buffer_line, int width)
WriteLineHDR writes a scanline of an image using RLE and RGBE encoding.
Definition: hdr.hpp:206
PIC_INLINE bool WriteHDR(std::string nameFile, float *data, int width, int height, int channels, float appliedExposure=1.0f, bool bRLE=true)
WriteHDR writes a .hdr/.pic file.
Definition: hdr.hpp:288
PIC_INLINE void fromSingleFloatToRGBE(float *colFloat, unsigned char *colRGBE)
fromSingleFloatToRGBE
Definition: rgbe.hpp:74
#define PIC_INLINE
Definition: base.hpp:33
#define MIN(a, b)
Definition: math.hpp:69
Definition: bilateral_separation.hpp:25
PIC_INLINE float * ReadHDR(std::string nameFile, float *data, int &width, int &height)
ReadHDR reads a .hdr/.pic file.
Definition: hdr.hpp:38
PIC_INLINE bool WriteHDRBlock(std::string nameFile, float *buffer_line, int width, int height, int channels, int blockID, int nBlocks)
WriteHDRBlock writes a .hdr file.
Definition: hdr.hpp:397