root/OpenSceneGraph/trunk/src/osgPlugins/hdr/hdrwriter.cpp @ 12292

Revision 12292, 8.1 kB (checked in by robert, 3 years ago)

Ran svn propset -R svn:eol-style native . on the OpenSceneGraph

  • Property svn:eol-style set to native
Line 
1/*
2 The following code was based on code from the following location:
3    http://www.graphics.cornell.edu/online/formats/rgbe/
4
5 It includes the following information :
6
7    "This file contains code to read and write four byte rgbe file format
8    developed by Greg Ward.  It handles the conversions between rgbe and
9    pixels consisting of floats.  The data is assumed to be an array of floats.
10    By default there are three floats per pixel in the order red, green, blue.
11    (RGBE_DATA_??? values control this.)  Only the mimimal header reading and
12    writing is implemented.  Each routine does error checking and will return
13    a status value as defined below.  This code is intended as a skeleton so
14    feel free to modify it to suit your needs.
15
16    (Place notice here if you modified the code.)
17    posted to http://www.graphics.cornell.edu/~bjw/
18    written by Bruce Walter  (bjw@graphics.cornell.edu)  5/26/95
19    based on code written by Greg Ward"
20
21 Modified for OSG September 2007 david.spilling@gmail.com :
22    The file format is described fully in http://radsite.lbl.gov/radiance/refer/filefmts.pdf
23    For the moment, we don't output most of the header fields
24
25 
26*/
27
28#include <stdlib.h>
29
30#include "hdrwriter.h"
31
32#include <sstream>
33#include <ostream>
34#include <string>
35#include <math.h>
36#include <ctype.h>
37
38
39bool HDRWriter::writeRLE(const osg::Image *img, std::ostream& fout)
40{
41    return writePixelsRLE(fout,(float*) img->data(), img->s(), img->t());
42}
43
44bool HDRWriter::writeRAW(const osg::Image *img, std::ostream& fout)
45{
46    return writePixelsRAW(fout,(unsigned char*) img->data(), img->s() * img->t());
47}
48
49
50
51
52
53/* number of floats per pixel */
54#define RGBE_DATA_SIZE   3
55
56/* offsets to red, green, and blue components in a data (float) pixel */
57#define R            0
58#define G            1
59#define B            2
60#define E            3
61
62#define  MINELEN    8                // minimum scanline length for encoding
63#define  MAXELEN    0x7fff            // maximum scanline length for encoding
64
65/* default minimal header. modify if you want more information in header */
66bool HDRWriter::writeHeader(const osg::Image *img, std::ostream& fout)
67{
68    std::stringstream stream;    // for conversion to strings
69
70    stream << "#?RADIANCE\n";    // Could be RGBE, but some 3rd party software doesn't interpret the file correctly
71                                // if it is.
72    stream << "FORMAT=32-bit_rle_rgbe\n\n";
73
74    // Our image data is usually arranged row major, with the origin at the bottom left of the image.
75    // Based on the Radiance file format, this would be "+Y blah +X blah". However, no software (including
76    // HDRShop v1!) seems to support this; they all expect -Y blah +X blah, and then flip the image. This
77    // is unfortunate, and is what provokes the default behaviour of OSG having to flip the image prior to
78    // write.
79    stream << "-Y "<<img->s()<<" +X "<<img->t()<<"\n";
80
81    fout.write(stream.str().c_str(), stream.str().length());
82
83    return true;
84}
85
86/* simple write routine that does not use run length encoding */
87/* These routines can be made faster by allocating a larger buffer and
88   fread-ing and fwrite-ing the data in larger chunks */
89bool HDRWriter::writePixelsNoRLE( std::ostream& fout, float* data, int numpixels)
90{
91  unsigned char rgbe[4];
92
93  while (numpixels-- > 0)
94  {
95    float2rgbe(
96        rgbe,
97        data[R],
98        data[G],
99        data[B]
100        );
101    data += RGBE_DATA_SIZE;
102    fout.write(reinterpret_cast<const char*>(rgbe), sizeof(rgbe)); //img->getTotalSizeInBytesIncludingMipmaps()
103  }
104  return true;
105}
106
107bool HDRWriter::writePixelsRAW( std::ostream& fout, unsigned char* data, int numpixels)
108{
109  unsigned char rgbe[4];
110
111  while (numpixels-- > 0)
112  {
113    rgbe[0] = (unsigned char) *(data+R);
114    rgbe[1] = (unsigned char) *(data+G);
115    rgbe[2] = (unsigned char) *(data+B);
116    rgbe[3] = (unsigned char) *(data+E);
117    data += RGBE_DATA_SIZE;
118    fout.write(reinterpret_cast<const char*>(rgbe), sizeof(rgbe)); //img->getTotalSizeInBytesIncludingMipmaps()
119  }
120  return true;
121}
122
123/* The code below is only needed for the run-length encoded files. */
124/* Run length encoding adds considerable complexity but does */
125/* save some space.  For each scanline, each channel (r,g,b,e) is */
126/* encoded separately for better compression. */
127bool HDRWriter::writeBytesRLE(std::ostream& fout, unsigned char *data, int numbytes)
128{
129#define MINRUNLENGTH 4
130    int cur, beg_run, run_count, old_run_count, nonrun_count;
131    unsigned char buf[2];
132
133    cur = 0;
134    while(cur < numbytes)
135    {
136        beg_run = cur;
137        /* find next run of length at least 4 if one exists */
138        run_count = old_run_count = 0;
139        while((run_count < MINRUNLENGTH) && (beg_run < numbytes))
140        {
141            beg_run += run_count;
142            old_run_count = run_count;
143            run_count = 1;
144            while((data[beg_run] == data[beg_run + run_count])
145                && (beg_run + run_count < numbytes)
146                && (run_count < 127))
147            {
148                run_count++;
149            }
150        }
151        /* if data before next big run is a short run then write it as such */
152        if ((old_run_count > 1)&&(old_run_count == beg_run - cur))
153        {
154            buf[0] = 128 + old_run_count;   /*write short run*/
155            buf[1] = data[cur];
156            fout.write(reinterpret_cast<const char*>(buf), sizeof(buf[0])*2);
157            //if (fwrite(buf,sizeof(buf[0])*2,1,fp) < 1) return false
158            cur = beg_run;
159        }
160        /* write out bytes until we reach the start of the next run */
161        while(cur < beg_run)
162        {
163            nonrun_count = beg_run - cur;
164            if (nonrun_count > 128) nonrun_count = 128;
165            buf[0] = nonrun_count;
166            fout.write(reinterpret_cast<const char*>(buf),sizeof(buf[0]));
167            //if (fwrite(buf,sizeof(buf[0]),1,fp) < 1) return false
168            fout.write(reinterpret_cast<const char*>(&data[cur]),sizeof(data[0])*nonrun_count);
169            // if (fwrite(&data[cur],sizeof(data[0])*nonrun_count,1,fp) < 1) return false;
170            cur += nonrun_count;
171        }
172        /* write out next run if one was found */
173        if (run_count >= MINRUNLENGTH)
174        {
175            buf[0] = 128 + run_count;
176            buf[1] = data[beg_run];
177            fout.write(reinterpret_cast<const char*>(buf),sizeof(buf[0])*2);
178            //if (fwrite(buf,sizeof(buf[0])*2,1,fp) < 1) return false;
179            cur += run_count;
180        }
181    }
182    return true;
183#undef MINRUNLENGTH
184}
185
186bool HDRWriter::writePixelsRLE( std::ostream& fout, float* data, int scanline_width, int num_scanlines )
187
188{
189    unsigned char rgbe[4];
190    unsigned char *buffer;
191
192    if ((scanline_width < MINELEN)||(scanline_width > MAXELEN))
193        // run length encoding is not allowed so write flat
194        return writePixelsNoRLE(fout,data,scanline_width*num_scanlines);
195
196    buffer = (unsigned char *)malloc(sizeof(unsigned char)*4*scanline_width);
197    if (buffer == NULL)
198        // no buffer space so write flat
199        return writePixelsNoRLE(fout,data,scanline_width*num_scanlines);
200
201    while(num_scanlines-- > 0)
202    {
203        rgbe[0] = 2;
204        rgbe[1] = 2;
205        rgbe[2] = scanline_width >> 8;
206        rgbe[3] = scanline_width & 0xFF;
207
208        fout.write(reinterpret_cast<const char*>(rgbe), sizeof(rgbe));
209        /*
210        if (fwrite(rgbe, sizeof(rgbe), 1, fp) < 1)
211        {
212            free(buffer);
213            return rgbe_error(rgbe_write_error,NULL);
214        }
215        */
216        for(int i=0;i<scanline_width;i++)
217        {
218            float2rgbe(rgbe,data[R], data[G],data[B]);
219            buffer[i] = rgbe[0];
220            buffer[i+scanline_width] = rgbe[1];
221            buffer[i+2*scanline_width] = rgbe[2];
222            buffer[i+3*scanline_width] = rgbe[3];
223            data += RGBE_DATA_SIZE;
224        }
225        /* write out each of the four channels separately run length encoded */
226        /* first red, then green, then blue, then exponent */
227        for(int i=0;i<4;i++)
228        {
229            if (writeBytesRLE(fout,&buffer[i*scanline_width],scanline_width) != true)
230            {
231                free(buffer);
232                return false;
233            }
234        }
235    }
236
237    free(buffer);
238    return true;
239}
Note: See TracBrowser for help on using the browser.