fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / System / Image / FileIO / OSGHDRImageFileType.cpp
blob4c0da0f49c01467ddd1509546d61a1e42ed73bf3
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
39 //-------------------------------
40 // Includes
41 //-------------------------------
43 #include <cstdlib>
44 #include <cstdio>
45 #include <cmath>
46 #include <memory.h>
48 #include "OSGConfig.h"
50 #include <iostream>
51 #include <fstream>
53 #include "OSGLog.h"
54 #include "OSGImageFileHandler.h"
55 #include "OSGPathHandler.h"
56 #include "OSGFileSystem.h"
58 #include "OSGHDRImageFileType.h"
60 // Static Class Varible implementations:
61 static const OSG::Char8 *suffixArray[] =
63 "hdr"
66 OSG_BEGIN_NAMESPACE
68 #define MINELEN 8 // minimum scanline length for encoding
69 #define MAXELEN 0x7fff // maximum scanline length for encoding
70 #define MINRUN 4 // minimum run length
71 #define RED 0
72 #define GRN 1
73 #define BLU 2
74 #define EXP 3
75 #define COLXS 128
77 // copy source -> dest
78 #define copy_rgbe(c1, c2) (c2[RED]=c1[RED],c2[GRN]=c1[GRN],c2[BLU]=c1[BLU],c2[EXP]=c1[EXP])
80 /*! \class HDRImageFileType
82 Image File Type to read/write and store/restore Image objects as
83 HDR data.
85 All the type specific code is included in the class. Does
86 not depend on external libs.
90 /*****************************
91 * Types
92 *****************************/
94 HDRImageFileType HDRImageFileType::_the("image/x-hdr",
95 suffixArray, sizeof(suffixArray),
96 OSG_READ_SUPPORTED |
97 OSG_WRITE_SUPPORTED );
100 /*****************************
101 * Classvariables
102 *****************************/
105 /********************************
106 * Class methodes
107 *******************************/
110 /*******************************
111 *public
112 *******************************/
114 //-------------------------------------------------------------------------
116 Tries to fill the image object with the data read from
117 the given input stream. Returns true on success.
120 bool HDRImageFileType::read( Image *image,
121 std::istream &is,
122 const std::string &mimetype)
124 int width, height;
126 if (!checkHDR(is, width, height))
128 FWARNING(("No valid RADIANCE picture format\n"));
129 return false;
132 bool use16BitFloat = false;
134 if(this->hasOption("use16BitFloat") == true)
136 this->getOptionAs("use16BitFloat", use16BitFloat);
139 image->set(Image::OSG_RGB_PF,
140 width,
141 height,
142 1, 1, 1, 0.0, 0,
143 (use16BitFloat == true) ?
144 Image::OSG_FLOAT16_IMAGEDATA : Image::OSG_FLOAT32_IMAGEDATA);
146 if(!image->isValid())
147 return false;
149 image->clear();
151 if(use16BitFloat)
153 Real16 *data = reinterpret_cast<Real16 *>(image->editData());
155 return radiance2fp(is, data, width, height);
157 else
159 Real32 *data = reinterpret_cast<Real32 *>(image->editData());
161 return radiance2fp(is, data, width, height);
165 //-------------------------------------------------------------------------
167 Tries to write the image object to the given output stream.
168 Returns true on success.
171 bool HDRImageFileType::write(const Image *image,
172 std::ostream &os,
173 const std::string &mimetype)
175 if( (image->getDataType() != Image::OSG_FLOAT32_IMAGEDATA) &&
176 (image->getDataType() != Image::OSG_FLOAT16_IMAGEDATA) )
178 FWARNING(("HDRImageFileType::write: Image has non float data "
179 "type!\n"));
180 return false;
183 if(!os.good())
184 return false;
186 int width = image->getWidth();
187 int height = image->getHeight();
189 os << "#?RADIANCE" << std::endl;
190 os << "# Written with OpenSG" << std::endl;
191 os << "FORMAT=32-bit_rle_rgbe" << std::endl;
192 os << "EXPOSURE=" << 1.0f << std::endl << std::endl;
193 os << "-Y " << height << " +X " << width << std::endl;
195 RGBE *rgbe_scan = new RGBE[width];
197 if( image->getDataType() == Image::OSG_FLOAT32_IMAGEDATA)
199 const Real32 *data = reinterpret_cast<const Real32 *>(image->getData());
201 //upside down !!!
202 for(int y=height-1;y>=0;y--)
204 if (fwritecolrs(os,
205 &data[y * width * 3],
206 rgbe_scan,
207 width,
208 height) < 0)
210 delete [] rgbe_scan;
211 return false;
215 else // OSG_FLOAT16_IMAGEDATA
217 const Real16 *data = reinterpret_cast<const Real16 *>(image->getData());
219 //upside down !!!
220 for(int y=height-1;y>=0;y--)
222 if(fwritecolrs(os,
223 &data[y * width * 3],
224 rgbe_scan,
225 width,
226 height) < 0)
228 delete [] rgbe_scan;
229 return false;
234 delete [] rgbe_scan;
235 return true;
238 //-------------------------------------------------------------------------
240 Tries to restore the image data from the given memblock.
241 Returns the amount of data read.
244 UInt64 HDRImageFileType::restoreData( Image *image,
245 const UChar8 *buffer,
246 Int32 ) const
248 image->setData(buffer);
250 return image->getSize();
253 //-------------------------------------------------------------------------
255 Tries to store the image data to the given memblock.
256 Returns the amount of data written.
259 UInt64 HDRImageFileType::storeData(const Image *image,
260 UChar8 *buffer,
261 Int32 OSG_CHECK_ARG(memSize)) const
263 UInt32 dataSize = image->getSize();
265 const UChar8 *src = image->getData();
267 if(dataSize && src && buffer)
268 memcpy(buffer, src, dataSize);
270 return dataSize;
274 //-------------------------------------------------------------------------
276 Constructor used for the singleton object
279 HDRImageFileType::HDRImageFileType(const Char8 *mimeType,
280 const Char8 *suffixArray[],
281 UInt16 suffixByteCount,
282 UInt32 flags ) :
283 Inherited(mimeType,
284 suffixArray,
285 suffixByteCount,
286 flags )
290 //-------------------------------------------------------------------------
292 Destructor
295 HDRImageFileType::~HDRImageFileType(void)
299 // check header and get resolution (streaming type)
300 bool HDRImageFileType::checkHDR(std::istream &is, int &width, int &height)
302 char cs[256], st1[80], st2[80];
303 bool resok = false;
304 bool HDRok = false;
305 int i = 0;
307 while (!is.eof() && !resok)
309 is.getline(cs, 255);
311 if (strstr(cs, "32-bit_rle_rgbe"))
312 HDRok = true;
314 if (HDRok && (cs[0] == '\r' || cs[0] == '\n' || cs[0] == '\0'))
316 // empty line found, next is resolution info, format: -Y N +X N
317 // directly followed by data
318 is.getline(cs, 255);
320 i = sscanf(cs, "%79s %d %79s %d", st1, &height, st2, &width);
321 if (i == 4)
322 resok = true;
326 return HDRok;
328 // convert radiance hdr to float image (streaming type)
329 bool HDRImageFileType::radiance2fp(std::istream &is,
330 Real16 *data,
331 int width,
332 int height)
334 int x,y,yx;
335 RGBE *sline = new RGBE[width];
337 if (!sline)
338 return false;
340 for(y=height-1;y>=0;y--)
342 yx = y*width;
343 if (!freadcolrs(is, sline, width))
344 return false;
345 Real16 *fcol = &data[yx * 3];
346 for (x=0;x<width;x++)
348 RGBE2Half(sline[x], fcol);
349 fcol += 3;
352 delete[] sline;
354 return true;
358 // convert radiance hdr to float image (streaming type)
359 bool HDRImageFileType::radiance2fp(std::istream &is,
360 Real32 *data,
361 int width,
362 int height)
364 int x,y,yx;
365 RGBE *sline = new RGBE[width];
367 if (!sline)
368 return false;
370 for(y=height-1;y>=0;y--)
372 yx = y*width;
373 if (!freadcolrs(is, sline, width))
374 return false;
375 Real32 *fcol = &data[yx * 3];
376 for (x=0;x<width;x++)
378 RGBE2Float(sline[x], fcol);
379 fcol += 3;
383 delete[] sline;
385 return true;
388 // read and decode a rgbe scanline (streaming type)
389 bool HDRImageFileType::freadcolrs(std::istream &is, RGBE *scan, int width)
391 int i,j,code,val,size;
392 unsigned char byte;
394 if ((width < MINELEN) | (width > MAXELEN))
396 FWARNING(("Sorry, format probably too old\n"));
397 return false;
400 byte = static_cast<unsigned char>(is.get());
401 if (is.eof())
402 return false;
404 byte = static_cast<unsigned char>(is.get());
405 scan[0][GRN] = byte;
407 byte = static_cast<unsigned char>(is.get());
408 scan[0][BLU] = byte;
410 size = (int(scan[0][BLU])) << 8;
411 i = is.get();
413 if ( (size | i) != width )
414 return false;
416 for(i=0;i<4;i++)
418 for (j=0;j<width;)
420 if (is.eof())
421 return false;
423 code = is.get();
425 if (code > 128)
427 code &= 127;
428 val = is.get();
430 while (code--)
431 scan[j++][i] = static_cast<unsigned char>(val);
433 else
435 while (code--)
436 scan[j++][i] = is.get();
441 return is.eof() ? false : true;
445 //rgbe -> float color
446 void HDRImageFileType::RGBE2Float(RGBE rgbe, Real32 *fcol)
448 if (rgbe[EXP] == 0)
450 *(fcol + RED) = *(fcol + GRN) = *(fcol + BLU) = 0;
452 else
454 Real32 f = ldexp(1., rgbe[EXP]-(COLXS+8));
455 *(fcol + RED) = (rgbe[RED]+.5)*f;
456 *(fcol + GRN) = (rgbe[GRN]+.5)*f;
457 *(fcol + BLU) = (rgbe[BLU]+.5)*f;
461 void HDRImageFileType::RGBE2Half(RGBE rgbe, Real16 *fcol)
463 if(rgbe[EXP] == 0)
465 *(fcol + RED) = *(fcol + GRN) = *(fcol + BLU) = 0;
467 else
469 Real32 f = ldexp(1., rgbe[EXP]-(COLXS+8));
471 *(fcol + RED) = Real16( ( rgbe[RED]+.5) * f);
472 *(fcol + GRN) = Real16( ( rgbe[GRN]+.5) * f);
473 *(fcol + BLU) = Real16( ( rgbe[BLU]+.5) * f);
477 int HDRImageFileType::fwritecolrs(std:: ostream &os,
478 const Real32 *scan,
479 RGBE *rgbe_scan,
480 int width,
481 int height )
483 // convert scanline
484 for (int i=0;i<width;i++)
486 float2RGBE(scan, rgbe_scan[i]);
487 scan += 3;
490 return fwriteRGBE(os, rgbe_scan, width, height);
493 int HDRImageFileType::fwritecolrs(std:: ostream &os,
494 const Real16 *scan,
495 RGBE *rgbe_scan,
496 int width,
497 int height)
499 // convert scanline
500 for(int i=0;i<width;i++)
502 half2RGBE(scan, rgbe_scan[i]);
503 scan += 3;
506 return fwriteRGBE(os, rgbe_scan, width, height);
509 int HDRImageFileType::fwriteRGBE(std::ostream &os,
510 RGBE *rgbe_scan,
511 int width,
512 int height)
514 int i, j, beg, c2, cnt=0;
516 if ((width < MINELEN) | (width > MAXELEN))
518 // OOBs, write out flat
519 os.write(reinterpret_cast<char *>(rgbe_scan), width);
520 return 0;
523 // put magic header
524 os << static_cast<unsigned char>(2);
525 os << static_cast<unsigned char>(2);
526 os << static_cast<unsigned char>(width>>8);
527 os << static_cast<unsigned char>(width&255);
529 // put components seperately
530 for (i=0;i<4;i++)
532 for (j=0;j<width;j+=cnt)
534 // find next run
535 for (beg=j;beg<width;beg+=cnt)
537 for(cnt=1;
538 (cnt<127)&&
539 ((beg+cnt)<width)&&
540 (rgbe_scan[beg+cnt][i]==rgbe_scan[beg][i]);
541 cnt++) ;
543 if (cnt>=MINRUN)
544 break;
545 // long enough
547 if (((beg-j)>1) && ((beg-j) < MINRUN))
549 c2 = j+1;
550 while (rgbe_scan[c2++][i] == rgbe_scan[j][i])
552 if (c2 == beg)
554 // short run
555 os << static_cast<unsigned char>(128+beg-j);
556 os << static_cast<unsigned char>(rgbe_scan[j][i]);
557 j = beg;
558 break;
562 while (j < beg)
564 // write out non-run
565 if ((c2 = beg-j) > 128)
566 c2 = 128;
567 os << static_cast<unsigned char>(c2);
569 while (c2--)
570 os << rgbe_scan[j++][i];
572 if (cnt >= MINRUN)
574 // write out run
575 os << static_cast<unsigned char>(128+cnt);
576 os << rgbe_scan[beg][i];
578 else
580 cnt = 0;
584 return (os.fail() ? -1 : 0);
587 //float color -> rgbe
588 void HDRImageFileType::float2RGBE(const Real32 *fcol, RGBE rgbe)
590 Real32 d = (*(fcol + RED) > *(fcol + GRN)) ? *(fcol + RED) : *(fcol + GRN);
592 if(*(fcol + BLU) > d)
594 d = *(fcol + BLU);
596 if(d <= 1e-32f)
598 rgbe[RED] = rgbe[GRN] = rgbe[BLU] = rgbe[EXP] = 0;
600 else
602 int e;
603 d = frexp(d, &e) * 256.f / d;
604 rgbe[RED] = static_cast<unsigned char>(*(fcol + RED) * d);
605 rgbe[GRN] = static_cast<unsigned char>(*(fcol + GRN) * d);
606 rgbe[BLU] = static_cast<unsigned char>(*(fcol + BLU) * d);
607 rgbe[EXP] = static_cast<unsigned char>(e + COLXS);
611 //half color -> rgbe
612 void HDRImageFileType::half2RGBE(const Real16 *fcol, RGBE rgbe)
614 Real32 d = (*(fcol + RED) > *(fcol + GRN)) ? *(fcol + RED) : *(fcol + GRN);
616 if(*(fcol + BLU) > d)
618 d = *(fcol + BLU);
620 if(d <= 1e-32f)
622 rgbe[RED] = rgbe[GRN] = rgbe[BLU] = rgbe[EXP] = 0;
624 else
626 int e;
627 d = frexp(d, &e) * 256.f / d;
628 rgbe[RED] = static_cast<unsigned char>(*(fcol + RED) * d);
629 rgbe[GRN] = static_cast<unsigned char>(*(fcol + GRN) * d);
630 rgbe[BLU] = static_cast<unsigned char>(*(fcol + BLU) * d);
631 rgbe[EXP] = static_cast<unsigned char>(e + COLXS);
635 OSG_END_NAMESPACE