OpenGL ES SDK for Android ARM Developer Center
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
HDRImage.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2012-2017, ARM Limited and Contributors
2  *
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge,
6  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 #include <cassert>
22 #include <cmath>
23 #include <cstring>
24 #include <cstdio>
25 #include <string>
26 
27 #include "HDRImage.h"
28 #include "Platform.h"
29 
30 using std::string;
31 
32 #ifndef _WIN32
33  #define MAXSHORT 0x7fff
34  #define MAXCHAR 0x7f
35 #endif _WIN32
36 
37 static const string radianceHeader = "?#RADIANCE";
38 const int radianceHeaderLength = 11;
39 
40 const int rgbComponentsCount = 3;
41 const int rgbeComponentsCount = 4;
42 const int minLineLength = 8;
43 const int maxLineLength = MAXSHORT;
44 
45 const char startOfText = '\002';
46 
47 namespace MaliSDK
48 {
50  {
51  width = 0;
52  height = 0;
53  rgbData = NULL;
54  }
55 
56  HDRImage::HDRImage(const std::string& filePath)
57  {
58  loadFromFile(filePath);
59  }
60 
62  {
63  if (rgbData != NULL)
64  {
65  delete [] rgbData;
66  rgbData = NULL;
67  }
68  }
69 
71  {
72  if(this != &another)
73  {
74  delete [] rgbData;
75  this->width = another.width;
76  this->height = another.height;
77  this->rgbData = new float[this->width * this->height * rgbComponentsCount];
78  memcpy(this->rgbData, another.rgbData, this->width * this->width * rgbComponentsCount * sizeof(float));
79  }
80 
81  return *this;
82  }
83 
85  {
86  if(this != &another)
87  {
88  this->width = another.width;
89  this->height = another.height;
90  this->rgbData = new float[this->width * this->height * rgbComponentsCount];
91  memcpy(this->rgbData, another.rgbData, this->width * this->width * rgbComponentsCount * sizeof(float));
92  }
93  }
94 
95  void HDRImage::loadFromFile(const std::string& filePath)
96  {
97  FILE* file;
98 
99  file = fopen(filePath.c_str(), "rb");
100 
101  if (file == NULL)
102  {
103  LOGE("Could not open file %s", filePath.c_str());
104  return;
105  }
106 
107  /* Read header. */
108  char header[radianceHeaderLength];
109 
110  fread(header, 1, radianceHeaderLength, file);
111  header[radianceHeaderLength - 1] = 0;
112  string readHeader = header;
113 
114  if (!readHeader.compare(radianceHeader))
115  {
116  LOGE("File header has not been recognized.\n");
117  fclose(file);
118  return;
119  }
120 
121  /* Search for resolution data. */
122  char currentChar = 0;
123  char previousChar = 0;
124 
125  while ((previousChar != '\n' || currentChar != '\n') && currentChar != EOF)
126  {
127  previousChar = currentChar;
128  currentChar = fgetc(file);
129  }
130 
131  int imageWidth = 0;
132  int imageHeight = 0;
133 
134  fscanf(file, "-Y %d ", &imageHeight);
135  fscanf(file, "+X %d ", &imageWidth);
136 
137  if (imageWidth < minLineLength || imageWidth > maxLineLength)
138  {
139  LOGE("Cannot decode image with width lower than %d or higher than %d", minLineLength, maxLineLength);
140  return;
141  }
142 
143  height = imageHeight;
144  width = imageWidth;
145 
146  RGBEPixel* scanLine = NULL;
147 
148  try
149  {
150  rgbData = new float[imageWidth * imageHeight * rgbComponentsCount];
151  scanLine = new RGBEPixel[imageWidth * rgbeComponentsCount];
152  }
153  catch (std::bad_alloc& ba)
154  {
155  LOGE("Exception caught: %s", ba.what());
156  return;
157  }
158 
159  for (int y = 0; y < imageHeight; ++y)
160  {
161  if (!decodeLine(file, imageWidth, scanLine))
162  {
163  LOGE("One of the scan lines has not been encoded correctly.\n");
164 
165  delete [] scanLine;
166  fclose(file);
167 
168  return;
169  }
170 
171  for (int x = 0; x < imageWidth; ++x)
172  {
173  int rgbPixelMove = (y * imageWidth + x) * 3;
174  convertRGBEPixel(scanLine[x], rgbData + rgbPixelMove);
175  }
176  }
177 
178  delete [] scanLine;
179 
180  fclose(file);
181  }
182 
183  inline void HDRImage::convertRGBEPixel(const RGBEPixel& pixel, float* rgbData)
184  {
185  int exponent = pixel.e - 128;
186 
187  rgbData[0] = convertSingleComponent(pixel.r, exponent);
188  rgbData[1] = convertSingleComponent(pixel.g, exponent);
189  rgbData[2] = convertSingleComponent(pixel.b, exponent);
190  }
191 
192  inline float HDRImage::convertSingleComponent(unsigned char value, int exponent)
193  {
194  float floatValue = static_cast<float> (value) / MAXCHAR;
195  float multiplier = pow(2.0f, exponent);
196 
197  return floatValue * multiplier;
198  }
199 
200  bool HDRImage::decodeLine(FILE* file, int lineLength, RGBEPixel* scanLine)
201  {
202  /* Check if line beginning is correct. */
203  char startLineChar1 = fgetc(file);
204  char startLineChar2 = fgetc(file);
205  char startLineChar3 = fgetc(file);
206 
207  if (startLineChar1 != startOfText || startLineChar2 != startOfText || startLineChar3 & 0x80)
208  {
209  LOGE("Error occured while encoding HDR data. Unknown line beginnings.");
210 
211  return false;
212  }
213 
214  /* Move file position indicator by one character. */
215  fgetc(file);
216 
217  for (int componentIndex = 0; componentIndex < rgbeComponentsCount; ++componentIndex)
218  {
219  int pixelIndex = 0;
220 
221  while (pixelIndex < lineLength)
222  {
223  /* Code for RLE compression algorithm. */
224  unsigned char rleCode = fgetc(file);
225 
226  if (rleCode > MAXCHAR + 1)
227  {
228  /*
229  * Read code indicates how many pixels are written with the same value,
230  *.so it is read only once.
231  */
232  unsigned char value = fgetc(file);
233 
234  rleCode &= MAXCHAR;
235 
236  while (rleCode--)
237  {
238  writeDecodedComponent(componentIndex, value, &scanLine[pixelIndex++]);
239  }
240  }
241  else
242  {
243  while (rleCode--)
244  {
245  /*
246  * Read code indicates how many pixels are written next to each other,
247  * so their value must be read each time this loop is executed.
248  */
249  unsigned char value = fgetc(file);
250 
251  writeDecodedComponent(componentIndex, value, &scanLine[pixelIndex++]);
252  }
253  }
254  }
255  }
256 
257  return true;
258  }
259 
260  inline void HDRImage::writeDecodedComponent(int componentIndicator, unsigned char value, RGBEPixel* rgbePixel)
261  {
262  if (rgbePixel == NULL)
263  {
264  LOGE("Cannot write encoded component to a NULL pointer.\n");
265 
266  return;
267  }
268 
269  switch (componentIndicator)
270  {
271  case 0:
272  rgbePixel->r = value;
273  break;
274 
275  case 1:
276  rgbePixel->g = value;
277  break;
278 
279  case 2:
280  rgbePixel->b = value;
281  break;
282 
283  case 3:
284  rgbePixel->e = value;
285  break;
286 
287  default:
288  LOGE("Invalid value of componentIndicator was passed.\n");
289  }
290  }
291 }
static float convertSingleComponent(unsigned char value, int exponent)
Definition: HDRImage.cpp:192
virtual ~HDRImage(void)
Destructor.
Definition: HDRImage.cpp:61
static bool decodeLine(FILE *file, int lineLength, RGBEPixel *scanLine)
Definition: HDRImage.cpp:200
int width
The width of the HDR image.
Definition: HDRImage.h:85
const int rgbComponentsCount
Definition: HDRImage.cpp:40
void loadFromFile(const std::string &filePath)
Load a HDRImage from a file.
Definition: HDRImage.cpp:95
GLint GLsizei GLsizei height
Definition: gl2ext.h:179
const int rgbeComponentsCount
Definition: HDRImage.cpp:41
GLint value
Definition: gl2ext.h:558
HDRImage(void)
Default constructor.
Definition: HDRImage.cpp:49
const int minLineLength
Definition: HDRImage.cpp:42
float * rgbData
The HDR image data.
Definition: HDRImage.h:80
GLfloat GLfloat f
Definition: gl2ext.h:2707
const char startOfText
Definition: HDRImage.cpp:45
GLint GLint GLint GLint GLint x
Definition: gl2ext.h:574
Class to load an manage HDR images.
Definition: HDRImage.h:33
#define MAXSHORT
Definition: HDRImage.cpp:33
HDRImage & operator=(const HDRImage &another)
Overloading assignment operater to do deep copy of the HDRImage data.
Definition: HDRImage.cpp:70
#define LOGE(...)
Definition: AstcTextures.h:30
GLint GLsizei width
Definition: gl2ext.h:179
static void writeDecodedComponent(int componentIndicator, unsigned char value, RGBEPixel *pixel)
Definition: HDRImage.cpp:260
const int maxLineLength
Definition: HDRImage.cpp:43
const int radianceHeaderLength
Definition: HDRImage.cpp:38
static const string radianceHeader
Definition: HDRImage.cpp:37
#define MAXCHAR
Definition: HDRImage.cpp:34
GLint y
Definition: gl2ext.h:179
static void convertRGBEPixel(const RGBEPixel &pixel, float *rgbData)
Definition: HDRImage.cpp:183
int height
The height of the HDR image.
Definition: HDRImage.h:90