root/OpenSceneGraph/trunk/src/osgPlugins/rgb/ReaderWriterRGB.cpp @ 11563

Revision 11563, 20.2 kB (checked in by robert, 4 years ago)

From Mathias Froehlich, "While tracking some valgrind problems in flightgear, I found a remaining off by
one error in the rgb loader.

Previously we limited the current line to the image with + 1. With that change
it is correctly limited to the width of the image.
Also flightgear seems to run nice with that change.
"

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// Released under the OSGPL license, as part of the OpenSceneGraph distribution.
2//
3// ReaderWriter for sgi's .rgb format.
4// specification can be found at http://local.wasp.uwa.edu.au/~pbourke/dataformats/sgirgb/sgiversion.html
5
6#include <osg/Image>
7#include <osg/Notify>
8
9#include <osg/Geode>
10
11#include <osg/GL>
12
13#include <osgDB/FileNameUtils>
14#include <osgDB/FileUtils>
15#include <osgDB/Registry>
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20
21#ifndef SEEK_SET
22define SEEK_SET 0
23#endif
24
25#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE)
26    #define GL_BITMAP               0x1A00
27    #define GL_RED                  0x1903
28    #define GL_GREEN                0x1904
29    #define GL_BLUE                 0x1905
30    #define GL_COLOR_INDEX          0x1900
31#endif
32
33#if defined(OSG_GL3_AVAILABLE)
34    #define GL_BITMAP               0x1A00
35    #define GL_COLOR_INDEX          0x1900
36#endif
37
38using namespace osg;
39
40
41typedef struct _rawImageRec
42{
43    unsigned short imagic;
44    unsigned short type;
45    unsigned short dim;
46    unsigned short sizeX, sizeY, sizeZ;
47    unsigned long min, max;
48    unsigned long wasteBytes;
49    char name[80];
50    unsigned long colorMap;
51    std::istream *file;
52    unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA;
53    unsigned long rleEnd;
54    GLuint *rowStart;
55    GLint *rowSize;
56    GLenum swapFlag;
57    short bpc;
58 
59    typedef unsigned char * BytePtr;
60
61    bool needsBytesSwapped()
62    {
63        union {
64            int testWord;
65            char testByte[sizeof(int)];
66        }endianTest;
67        endianTest.testWord = 1;
68        if( endianTest.testByte[0] == 1 )
69            return true;
70        else
71            return false;
72    }
73
74    template <class T>
75    inline void swapBytes(  T &s )
76    {
77        if( sizeof( T ) == 1 )
78            return;
79
80        T d = s;
81        BytePtr sptr = (BytePtr)&s;
82        BytePtr dptr = &(((BytePtr)&d)[sizeof(T)-1]);
83
84        for( unsigned int i = 0; i < sizeof(T); i++ )
85            *(sptr++) = *(dptr--);
86    }
87
88    void swapBytes()
89    {
90        swapBytes( imagic );
91        swapBytes( type );
92        swapBytes( dim );
93        swapBytes( sizeX );
94        swapBytes( sizeY );
95        swapBytes( sizeZ );
96        swapBytes( wasteBytes );
97        swapBytes( min );
98        swapBytes( max );
99        swapBytes( colorMap );
100    }
101} rawImageRec;
102
103static void ConvertShort(unsigned short *array, long length)
104{
105    unsigned long b1, b2;
106    unsigned char *ptr;
107
108    ptr = (unsigned char *)array;
109    while (length--)
110    {
111        b1 = *ptr++;
112        b2 = *ptr++;
113        *array++ = (unsigned short) ((b1 << 8) | (b2));
114    }
115}
116
117static void ConvertLong(GLuint *array, long length)
118{
119    unsigned long b1, b2, b3, b4;
120    unsigned char *ptr;
121
122    ptr = (unsigned char *)array;
123    while (length--)
124    {
125        b1 = *ptr++;
126        b2 = *ptr++;
127        b3 = *ptr++;
128        b4 = *ptr++;
129        *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
130    }
131}
132
133
134static void RawImageClose(rawImageRec *raw)
135{
136    if (raw)
137    {
138       
139        if (raw->tmp) delete [] raw->tmp;
140        if (raw->tmpR) delete [] raw->tmpR;
141        if (raw->tmpG) delete [] raw->tmpG;
142        if (raw->tmpB) delete [] raw->tmpB;
143        if (raw->tmpA) delete [] raw->tmpA;
144
145        if (raw->rowStart) delete [] raw->rowStart;       
146        if (raw->rowSize) delete [] raw->rowSize;       
147
148        delete raw;
149    }
150}
151
152
153static rawImageRec *RawImageOpen(std::istream& fin)
154{
155    union
156    {
157        int testWord;
158        char testByte[4];
159    } endianTest;
160    rawImageRec *raw;
161    int x;
162
163    raw = new rawImageRec;
164    if (raw == NULL)
165    {
166        OSG_WARN<< "Out of memory!"<< std::endl;
167        return NULL;
168    }
169
170    //Set istream pointer
171    raw->file = &fin;
172
173    endianTest.testWord = 1;
174    if (endianTest.testByte[0] == 1)
175    {
176        raw->swapFlag = GL_TRUE;
177    }
178    else
179    {
180        raw->swapFlag = GL_FALSE;
181    }
182
183    fin.read((char*)raw,12);
184    if (!fin.good())
185        return NULL;
186
187    if (raw->swapFlag)
188    {
189        ConvertShort(&raw->imagic, 6);
190    }
191
192    raw->tmp = raw->tmpR = raw->tmpG = raw->tmpB = raw->tmpA = 0L;
193    raw->rowStart = 0;
194    raw->rowSize = 0;
195    raw->bpc = (raw->type & 0x00FF);
196
197    raw->tmp = new unsigned char [raw->sizeX*256*raw->bpc];
198    if (raw->tmp == NULL )
199    {
200        OSG_FATAL<< "Out of memory!"<< std::endl;
201        RawImageClose(raw);
202        return NULL;
203    }
204
205    if( raw->sizeZ >= 1 )
206    {
207        if( (raw->tmpR = new unsigned char [raw->sizeX*raw->bpc]) == NULL )
208        {
209            OSG_FATAL<< "Out of memory!"<< std::endl;
210            RawImageClose(raw);
211            return NULL;
212        }
213    }
214    if( raw->sizeZ >= 2 )
215    {
216        if( (raw->tmpG = new unsigned char [raw->sizeX*raw->bpc]) == NULL )
217        {
218            OSG_FATAL<< "Out of memory!"<< std::endl;
219            RawImageClose(raw);
220            return NULL;
221        }
222    }
223    if( raw->sizeZ >= 3 )
224    {
225        if( (raw->tmpB = new unsigned char [raw->sizeX*raw->bpc]) == NULL )
226        {
227            OSG_FATAL<< "Out of memory!"<< std::endl;
228            RawImageClose(raw);
229            return NULL;
230        }
231    }
232    if (raw->sizeZ >= 4)
233    {
234        if( (raw->tmpA = new unsigned char [raw->sizeX*raw->bpc]) == NULL )
235        {
236            OSG_FATAL<< "Out of memory!"<< std::endl;
237            RawImageClose(raw);
238            return NULL;
239        }
240    }
241   
242    if ((raw->type & 0xFF00) == 0x0100)
243    {
244        unsigned int ybyz = raw->sizeY * raw->sizeZ;
245        if ( (raw->rowStart = new GLuint [ybyz]) == NULL )
246        {
247            OSG_FATAL<< "Out of memory!"<< std::endl;
248            RawImageClose(raw);
249            return NULL;
250        }
251
252        if ( (raw->rowSize = new GLint [ybyz]) == NULL )
253        {
254            OSG_FATAL<< "Out of memory!"<< std::endl;
255            RawImageClose(raw);
256            return NULL;
257        }
258        x = ybyz * sizeof(GLuint);
259        raw->rleEnd = 512 + (2 * x);
260                fin.seekg(512,std::ios::beg);
261        fin.read((char*)raw->rowStart,x);
262        fin.read((char*)raw->rowSize,x);
263        if (raw->swapFlag)
264        {
265            ConvertLong(raw->rowStart, (long) (x/sizeof(GLuint)));
266            ConvertLong((GLuint *)raw->rowSize, (long) (x/sizeof(GLint)));
267        }
268    }
269    return raw;
270}
271
272
273static void RawImageGetRow(rawImageRec *raw, unsigned char *buf, int y, int z)
274{
275    unsigned char *iPtr, *oPtr;
276    unsigned short pixel;
277    int count, done = 0;
278    unsigned short *tempShort;
279
280    if ((raw->type & 0xFF00) == 0x0100)
281    {
282        raw->file->seekg((long) raw->rowStart[y+z*raw->sizeY], std::ios::beg);
283        raw->file->read((char*)raw->tmp, (unsigned int)raw->rowSize[y+z*raw->sizeY]);
284
285        iPtr = raw->tmp;
286        oPtr = buf;
287        while (!done)
288        {
289            if (raw->bpc == 1)
290                pixel = *iPtr++;
291            else
292            {
293                tempShort = reinterpret_cast<unsigned short*>(iPtr);
294                pixel = *tempShort;
295                tempShort++;
296                iPtr = reinterpret_cast<unsigned char *>(tempShort);
297            }
298           
299            if(raw->bpc != 1)
300                ConvertShort(&pixel, 1);
301
302            count = (int)(pixel & 0x7F);
303           
304            // limit the count value to the remiaing row size
305            if (raw->sizeX*raw->bpc <= (oPtr - buf))
306            {
307                count = raw->sizeX - (oPtr - buf) / raw->bpc;
308            }
309               
310            if (count<=0)
311            {
312                done = 1;
313                return;
314            }
315           
316            if (pixel & 0x80)
317            {
318                while (count--)
319                {
320                    if(raw->bpc == 1)
321                        *oPtr++ = *iPtr++;
322                    else{
323                        tempShort = reinterpret_cast<unsigned short*>(iPtr);
324                        pixel = *tempShort;
325                        tempShort++;
326                        iPtr = reinterpret_cast<unsigned char *>(tempShort);
327                       
328                        ConvertShort(&pixel, 1);
329
330                        tempShort = reinterpret_cast<unsigned short*>(oPtr);
331                        *tempShort = pixel;
332                        tempShort++;
333                        oPtr = reinterpret_cast<unsigned char *>(tempShort);
334                    }
335                }
336            }
337            else
338            {
339                if (raw->bpc == 1)
340                {
341                    pixel = *iPtr++;
342                }
343                else
344                {
345                    tempShort = reinterpret_cast<unsigned short*>(iPtr);
346                    pixel = *tempShort;
347                    tempShort++;
348                    iPtr = reinterpret_cast<unsigned char *>(tempShort);
349                }
350                if(raw->bpc != 1)
351                    ConvertShort(&pixel, 1);
352                while (count--)
353                {
354                    if(raw->bpc == 1)
355                        *oPtr++ = pixel;
356                    else
357                    {
358                        tempShort = reinterpret_cast<unsigned short*>(oPtr);
359                        *tempShort = pixel;
360                        tempShort++;
361                        oPtr = reinterpret_cast<unsigned char *>(tempShort);
362                    }
363                }
364            }
365        }
366    }
367    else
368    {
369        raw->file->seekg(512+(y*raw->sizeX*raw->bpc)+(z*raw->sizeX*raw->sizeY*raw->bpc),std::ios::beg);
370        raw->file->read((char*)buf, raw->sizeX*raw->bpc);
371        if(raw->swapFlag && raw->bpc != 1){
372            ConvertShort(reinterpret_cast<unsigned short*>(buf), raw->sizeX);
373        }
374    }
375}
376
377
378static void RawImageGetData(rawImageRec *raw, unsigned char **data )
379{
380    unsigned char *ptr;
381    int i, j;
382    unsigned short *tempShort;
383
384    //     // round the width to a factor 4
385    //     int width = (int)(floorf((float)raw->sizeX/4.0f)*4.0f);
386    //     if (width!=raw->sizeX) width += 4;
387
388    // byte aligned.
389   
390    OSG_INFO<<"raw->sizeX = "<<raw->sizeX<<std::endl;
391    OSG_INFO<<"raw->sizeY = "<<raw->sizeY<<std::endl;
392    OSG_INFO<<"raw->sizeZ = "<<raw->sizeZ<<std::endl;
393    OSG_INFO<<"raw->bpc = "<<raw->bpc<<std::endl;
394   
395    *data = new unsigned char [(raw->sizeX)*(raw->sizeY)*(raw->sizeZ)*(raw->bpc)];
396
397    ptr = *data;
398    for (i = 0; i < (int)(raw->sizeY); i++)
399    {
400        if( raw->sizeZ >= 1 )
401            RawImageGetRow(raw, raw->tmpR, i, 0);
402        if( raw->sizeZ >= 2 )
403            RawImageGetRow(raw, raw->tmpG, i, 1);
404        if( raw->sizeZ >= 3 )
405            RawImageGetRow(raw, raw->tmpB, i, 2);
406        if( raw->sizeZ >= 4 )
407            RawImageGetRow(raw, raw->tmpA, i, 3);
408        for (j = 0; j < (int)(raw->sizeX); j++)
409        {
410          if(raw->bpc == 1){
411            if( raw->sizeZ >= 1 )
412                *ptr++ = *(raw->tmpR + j);
413            if( raw->sizeZ >= 2 )
414                *ptr++ = *(raw->tmpG + j);
415            if( raw->sizeZ >= 3 )
416                *ptr++ = *(raw->tmpB + j);
417            if( raw->sizeZ >= 4 )
418                *ptr++ = *(raw->tmpA + j);
419          }else{
420            if( raw->sizeZ >= 1 )
421            {
422                tempShort = reinterpret_cast<unsigned short*>(ptr);
423                *tempShort = *(reinterpret_cast<unsigned short*>(raw->tmpR) + j);
424                tempShort++;
425                ptr = reinterpret_cast<unsigned char *>(tempShort);
426            }
427            if( raw->sizeZ >= 2 )
428            {
429                tempShort = reinterpret_cast<unsigned short*>(ptr);
430                *tempShort = *(reinterpret_cast<unsigned short*>(raw->tmpG) + j);
431                tempShort++;
432                ptr = reinterpret_cast<unsigned char *>(tempShort);
433            }
434            if( raw->sizeZ >= 3 )
435            {
436                tempShort = reinterpret_cast<unsigned short*>(ptr);
437                *tempShort = *(reinterpret_cast<unsigned short*>(raw->tmpB) + j);
438                tempShort++;
439                ptr = reinterpret_cast<unsigned char *>(tempShort);
440            }
441            if( raw->sizeZ >= 4 )
442            {
443                tempShort = reinterpret_cast<unsigned short*>(ptr);
444                *tempShort = *(reinterpret_cast<unsigned short*>(raw->tmpA) + j);
445                tempShort++;
446                ptr = reinterpret_cast<unsigned char *>(tempShort);
447            }
448          }
449        }
450        //         // pad the image width with blanks to bring it up to the rounded width.
451        //         for(;j<width;++j) *ptr++ = 0;
452    }
453}
454
455
456class ReaderWriterRGB : public osgDB::ReaderWriter
457{
458    public:
459   
460        ReaderWriterRGB()
461        {
462            supportsExtension("rgb","rgb image format");
463            supportsExtension("rgba","rgba image format");
464            supportsExtension("sgi","sgi image format");
465            supportsExtension("int","int image format");
466            supportsExtension("inta","inta image format");
467            supportsExtension("bw","bw image format");
468        }
469   
470        virtual const char* className() const { return "RGB Image Reader/Writer"; }
471       
472        ReadResult readRGBStream(std::istream& fin) const
473        {
474            rawImageRec *raw;
475
476            if( (raw = RawImageOpen(fin)) == NULL )
477            {
478                return ReadResult::ERROR_IN_READING_FILE;
479            }
480
481            int s = raw->sizeX;
482            int t = raw->sizeY;
483            int r = 1;
484
485        #if 0
486            int internalFormat = raw->sizeZ == 3 ? GL_RGB5 :
487            raw->sizeZ == 4 ? GL_RGB5_A1 : GL_RGB;
488        #else
489            int internalFormat = raw->sizeZ;
490        #endif
491            unsigned int pixelFormat =
492                raw->sizeZ == 1 ? GL_LUMINANCE :
493                raw->sizeZ == 2 ? GL_LUMINANCE_ALPHA :
494                raw->sizeZ == 3 ? GL_RGB :
495                raw->sizeZ == 4 ? GL_RGBA : (GLenum)-1;
496
497            unsigned int dataType = raw->bpc == 1 ? GL_UNSIGNED_BYTE :
498              GL_UNSIGNED_SHORT;
499
500            unsigned char *data;
501            RawImageGetData(raw, &data);
502            RawImageClose(raw);
503
504            Image* image = new Image();
505            image->setImage(s,t,r,
506                internalFormat,
507                pixelFormat,
508                dataType,
509                data,
510                osg::Image::USE_NEW_DELETE);
511
512            OSG_INFO << "image read ok "<<s<<"  "<<t<< std::endl;
513            return image;
514        }
515
516        virtual ReadResult readObject(std::istream& fin,const osgDB::ReaderWriter::Options* options =NULL) const
517        {
518            return readImage(fin, options);
519        }
520
521        virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const
522        {
523            return readImage(file, options);
524        }
525
526        virtual ReadResult readImage(std::istream& fin,const osgDB::ReaderWriter::Options* =NULL) const
527        {
528            return readRGBStream(fin);
529        }
530
531        virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
532        {
533            std::string ext = osgDB::getLowerCaseFileExtension(file);
534            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
535
536            std::string fileName = osgDB::findDataFile( file, options );
537            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
538
539            osgDB::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary);
540            if(!istream) return ReadResult::FILE_NOT_HANDLED;
541            ReadResult rr = readRGBStream(istream);
542            if(rr.validImage()) rr.getImage()->setFileName(file);
543            return rr;
544        }
545
546        WriteResult writeRGBStream(const osg::Image& img, std::ostream &fout, const std::string& name) const
547        {
548            rawImageRec raw;
549            raw.imagic = 0732;
550
551            GLenum dataType = img.getDataType();
552
553            raw.type  = dataType == GL_UNSIGNED_BYTE ? 1 :
554                dataType == GL_BYTE ? 1 :
555                dataType == GL_BITMAP ? 1 :
556                dataType == GL_UNSIGNED_SHORT ? 2 :
557                dataType == GL_SHORT ? 2 :
558                dataType == GL_UNSIGNED_INT ? 4 :
559                dataType == GL_INT ? 4 :
560                dataType == GL_FLOAT ? 4 :
561                dataType == GL_UNSIGNED_BYTE_3_3_2 ? 1 :
562                dataType == GL_UNSIGNED_BYTE_2_3_3_REV ? 1 :
563                dataType == GL_UNSIGNED_SHORT_5_6_5 ? 2 :
564                dataType == GL_UNSIGNED_SHORT_5_6_5_REV ? 2 :
565                dataType == GL_UNSIGNED_SHORT_4_4_4_4 ? 2 :
566                dataType == GL_UNSIGNED_SHORT_4_4_4_4_REV ? 2 :
567                dataType == GL_UNSIGNED_SHORT_5_5_5_1 ? 2 :
568                dataType == GL_UNSIGNED_SHORT_1_5_5_5_REV ? 2 :
569                dataType == GL_UNSIGNED_INT_8_8_8_8 ? 4 :
570                dataType == GL_UNSIGNED_INT_8_8_8_8_REV ? 4 :
571                dataType == GL_UNSIGNED_INT_10_10_10_2 ? 4 :
572                dataType == GL_UNSIGNED_INT_2_10_10_10_REV ? 4 : 4;
573
574            GLenum pixelFormat = img.getPixelFormat();
575
576            raw.dim    = 3;
577            raw.sizeX = img.s();
578            raw.sizeY = img.t();
579            raw.sizeZ =
580                pixelFormat == GL_COLOR_INDEX? 1 :
581                pixelFormat == GL_RED? 1 :
582                pixelFormat == GL_GREEN? 1 :
583                pixelFormat == GL_BLUE? 1 :
584                pixelFormat == GL_ALPHA? 1 :
585                pixelFormat == GL_RGB? 3 :
586                pixelFormat == GL_BGR ? 3 :
587                pixelFormat == GL_RGBA? 4 :
588                pixelFormat == GL_BGRA? 4 :
589                pixelFormat == GL_LUMINANCE? 1 :
590                pixelFormat == GL_LUMINANCE_ALPHA ? 2 : 1;
591            raw.min = 0;
592            raw.max = 0xFF;
593            raw.wasteBytes = 0;
594            strncpy( raw.name, name.c_str(), 80);
595            raw.colorMap = 0;
596            raw.bpc = (img.getPixelSizeInBits()/raw.sizeZ)/8;
597
598            int isize = img.getImageSizeInBytes();
599            unsigned char *buffer = new unsigned char[isize];
600            if(raw.bpc == 1)
601            {
602                unsigned char *dptr = buffer;
603                int i, j;
604                for( i = 0; i < raw.sizeZ; ++i )
605                {
606                    const unsigned char *ptr = img.data();
607                    ptr += i;
608                    for( j = 0; j < isize/raw.sizeZ; ++j )
609                    {
610                        *(dptr++) = *ptr;
611                        ptr += raw.sizeZ;
612                    }
613                }
614            }
615            else
616            { // bpc == 2
617                unsigned short *dptr = reinterpret_cast<unsigned short*>(buffer);
618                int i, j;
619                for( i = 0; i < raw.sizeZ; ++i )
620                {
621                    const unsigned short *ptr = reinterpret_cast<const unsigned short*>(img.data());
622                    ptr += i;
623                    for( j = 0; j < isize/(raw.sizeZ*2); ++j )
624                    {
625                        *dptr = *ptr;
626                        ConvertShort(dptr++, 1);
627                        ptr += raw.sizeZ;
628                    }
629                }
630            }
631
632       
633            if( raw.needsBytesSwapped() )
634                raw.swapBytes();
635
636            /*
637            swapBytes( raw.imagic );
638            swapBytes( raw.type );
639            swapBytes( raw.dim );
640            swapBytes( raw.sizeX );
641            swapBytes( raw.sizeY );
642            swapBytes( raw.sizeZ );
643            swapBytes( raw.min );
644            swapBytes( raw.max );
645            swapBytes( raw.colorMap );
646            */
647
648
649            char pad[512 - sizeof(rawImageRec)];
650            memset( pad, 0, sizeof(pad));
651
652            fout.write((const char*)&raw,sizeof(rawImageRec));
653            fout.write((const char*)pad,sizeof(pad));
654            fout.write((const char*)buffer,isize);
655
656            delete [] buffer;
657
658            return WriteResult::FILE_SAVED;
659        }
660
661        virtual WriteResult writeImage(const osg::Image& img,std::ostream& fout,const osgDB::ReaderWriter::Options*) const
662        {
663            return writeRGBStream(img,fout,"");
664        }
665
666        virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options*) const
667        {
668            std::string ext = osgDB::getFileExtension(fileName);
669            if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
670
671            osgDB::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary);
672            if(!fout) return WriteResult::ERROR_IN_WRITING_FILE;
673
674            return writeRGBStream(img,fout,fileName);
675        }
676
677};
678
679// now register with Registry to instantiate the above
680// reader/writer.
681REGISTER_OSGPLUGIN(rgb, ReaderWriterRGB)
Note: See TracBrowser for help on using the browser.