root/OpenSceneGraph/trunk/src/osgPlugins/pnm/ReaderWriterPNM.cpp @ 13041

Revision 13041, 13.8 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// PNM Reader -- Written by Eric Sokolowsky
2// Reads Ascii and Binary files in the PPM, PGM, and PBM formats.
3
4#include <osg/Image>
5#include <osg/Notify>
6#include <osg/Endian>
7
8#include <osgDB/Registry>
9#include <osgDB/FileNameUtils>
10#include <osgDB/FileUtils>
11#include <osgDB/fstream>
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16
17#include <sstream>
18
19using namespace osg;
20
21template <class T>
22    unsigned char* read_bitmap_ascii(std::istream& fin, int width, int height)
23{
24    T* data = new T[width*height];
25    T* end = data + width*height;
26
27    int x = 0;
28    T* dst = end - width;
29    int value = 0;
30
31    while(dst >= data)
32    {
33        fin >> value;
34        if (!fin.good())
35        {
36            delete [] data;
37            return NULL;
38        }
39
40        // place value in the image. 0 is white and anything else is black.
41        *(dst++) = value ? 0 : 255;
42
43        // At end of each row, jump back two rows
44        ++x;
45        if (x == width)
46        {
47            x = 0;
48            dst -= 2*width;
49        }
50    }
51
52    return reinterpret_cast<unsigned char*>(data);
53}
54
55template <class T>
56    unsigned char* read_grayscale_ascii(std::istream& fin, int width, int height, int max_value)
57{
58    T* data = new T[width*height];
59    T* end = data + width*height;
60
61    int x = 0;
62    T* dst = end - width;
63    int value = 0;
64    float max = (sizeof(T) == 1) ? 255.0 : 65535.0;
65
66    while(dst >= data)
67    {
68        fin >> value;
69        if (!fin.good())
70        {
71            delete [] data;
72            return NULL;
73        }
74
75        // place value in the image
76        *(dst++) = T(float(value)/float(max_value)*max);
77
78        // At end of each row, jump back two rows
79        ++x;
80        if (x == width)
81        {
82            x = 0;
83            dst -= 2*width;
84        }
85    }
86
87    return reinterpret_cast<unsigned char*>(data);
88}
89
90template <class T>
91    unsigned char* read_color_ascii(std::istream& fin, int width, int height, int max_value)
92{
93    T* data = new T[3*width*height];
94    T* end = data + 3*width*height;
95
96    int x = 0;
97    T* dst = end - 3*width;
98    int value = 0;
99    float max = (sizeof(T) == 1) ? 255.0 : 65535.0;
100
101    while(dst >= data)
102    {
103        fin >> value;
104        if (!fin.good())
105        {
106            delete [] data;
107            return NULL;
108        }
109
110        // place value in the image
111        *(dst++) = T(float(value)/float(max_value)*max);
112
113        // At end of the row, jump back two rows
114        ++x;
115        if (x == width*3)
116        {
117            x = 0;
118            dst -= 6*width;
119        }
120    }
121
122    return reinterpret_cast<unsigned char*>(data);
123}
124
125template <class T>
126    unsigned char* read_bitmap_binary(std::istream& fin, int width, int height)
127{
128    T* data = new T[width*height];
129
130    for(int y = height-1; y >= 0; --y)
131    {
132        T* dst = data + (y+0)*width;
133        T* end = data + (y+1)*width;
134
135        while(dst < end)
136        {
137            unsigned char b = (unsigned char) fin.get();
138            if (!fin.good())
139            {
140                delete [] data;
141                return NULL;
142            }
143
144            for(int i = 7; i >= 0 && dst < end; i--)
145            {
146                // 1 means black, 0 means white
147                T data_value = (b & (1<<i)) ? 0 : 255;
148                *(dst++) = data_value;
149            }
150        }
151    }
152
153    return reinterpret_cast<unsigned char*>(data);
154}
155
156template <class T>
157    unsigned char* read_grayscale_binary(std::istream& fin, int width, int height)
158{
159    T* data = new T[width*height];
160
161    for(int y = height-1; y >= 0; --y)
162    {
163        T* dst = data + y*width;
164        fin.read((char*)dst, sizeof(T)*width);
165        if (!fin.good())
166        {
167            delete [] data;
168            return NULL;
169        }
170    }
171
172    // if the machine is little endian swap the bytes around
173    if (sizeof(T) == 2 && getCpuByteOrder() == osg::LittleEndian)
174    {
175        unsigned char *bs = reinterpret_cast<unsigned char *>(data);
176        unsigned char *end = bs + sizeof(T)*width*height;
177        for (; bs < end; bs += 2)
178        {
179            std::swap(bs[0], bs[1]);
180        }
181    }
182
183    return reinterpret_cast<unsigned char *>(data);
184}
185
186template <class T>
187    unsigned char* read_color_binary(std::istream& fin, int width, int height)
188{
189    T* data = new T[3*width*height];
190
191    for(int y = height-1; y >= 0; --y)
192    {
193        T* dst = data + y*3*width;
194        fin.read((char*)dst, sizeof(T)*3*width);
195        if (!fin.good())
196        {
197            delete [] data;
198            return NULL;
199        }
200    }
201
202    // if the machine is little endian swap the bytes around
203    if (sizeof(T) == 2 && getCpuByteOrder() == osg::LittleEndian)
204    {
205        unsigned char *bs = reinterpret_cast<unsigned char *>(data);
206        unsigned char *end = bs + sizeof(T)*3*width*height;
207        for (; bs < end; bs+=2)
208        {
209            std::swap(bs[0], bs[1]);
210        }
211    }
212
213    return reinterpret_cast<unsigned char*>(data);
214}
215
216class ReaderWriterPNM : public osgDB::ReaderWriter
217{
218    public:
219        ReaderWriterPNM()
220        {
221            supportsExtension("pnm","PNM Image format");
222            supportsExtension("ppm","PNM Image format");
223            supportsExtension("pgm","PNM Image format");
224            supportsExtension("pbm","PNM Image format");
225        }
226
227        virtual const char* className() const { return "PNM Image Reader/Writer"; }
228
229        virtual ReadResult readImage(std::istream& fin, const osgDB::ReaderWriter::Options* options=NULL) const
230        {
231            int ppmtype = 0;    /* P1, P2, etc. */
232            int width = 0;
233            int height = 0;
234            int max_value = 0;
235
236            // Read header items.
237            std::string line;
238            int row;
239            for (row = 1; row <= 3; row++)
240            {
241                getline(fin, line);
242                if (!fin.good())
243                    return ReadResult::ERROR_IN_READING_FILE;
244
245                const char *cp = line.c_str();
246                while (*cp && isspace(*cp))
247                    cp++;
248                if (! *cp || *cp == '#')
249                {
250                    // Skip comment lines.
251                    row--;
252                }
253                else if (row == 1)
254                {
255                    // Get the image type.
256                    if (line[0] == 'p' || line[0] == 'P')
257                    {
258                        ppmtype = line[1] - '0';
259                    }
260                }
261                else if (row == 2)
262                {
263                    std::istringstream istr(line);
264
265                    istr >> width;
266                    istr >> height;
267
268                    // pbm files don't have row 3
269                    if (ppmtype == 1 || ppmtype == 4)
270                    {
271                        max_value = 1;
272                        break;
273                    }
274                }
275                else if (row == 3)
276                {
277                    // Get the maximum value
278                    std::istringstream istr(line);
279                    istr >> max_value;
280                }
281            }
282
283            // Check for valid values.
284            if (width <= 0 || height <= 0 ||
285                max_value <= 0 || max_value > 65535 ||
286                ppmtype < 1 || ppmtype > 6)
287            {
288                return ReadResult::ERROR_IN_READING_FILE;
289            }
290
291            int pixelFormat = 0;
292            int dataType = 0;
293            unsigned char* data = NULL;
294
295            if (max_value > 255)
296            {
297                dataType = GL_UNSIGNED_SHORT;
298                switch(ppmtype)
299                {
300                    case 2:    // grayscale ascii
301                        pixelFormat = GL_LUMINANCE;
302                        data = read_grayscale_ascii<unsigned short>(fin, width, height, max_value);
303                        break;
304                    case 3:    // color ascii
305                        pixelFormat = GL_RGB;
306                        data = read_color_ascii<unsigned short>(fin, width, height, max_value);
307                        break;
308                    case 5:    // grayscale binary
309                        pixelFormat = GL_LUMINANCE;
310                        data = read_grayscale_binary<unsigned short>(fin, width, height);
311                        break;
312                    case 6:    // color binary
313                        pixelFormat = GL_RGB;
314                        data = read_color_binary<unsigned short>(fin, width, height);
315                        break;
316                    default:
317                        return ReadResult::ERROR_IN_READING_FILE;
318                        break;
319                }
320            }
321            else
322            {
323                dataType = GL_UNSIGNED_BYTE;
324                switch(ppmtype)
325                {
326                    case 1:    // bitmap ascii
327                        pixelFormat = GL_LUMINANCE;
328                        data = read_bitmap_ascii<unsigned char>(fin, width, height);
329                        break;
330                    case 2:    // grayscale ascii
331                        pixelFormat = GL_LUMINANCE;
332                        data = read_grayscale_ascii<unsigned char>(fin, width, height, max_value);
333                        break;
334                    case 3:    // color ascii
335                        pixelFormat = GL_RGB;
336                        data = read_color_ascii<unsigned char>(fin, width, height, max_value);
337                        break;
338                    case 4:    // bitmap binary
339                        pixelFormat = GL_LUMINANCE;
340                        data = read_bitmap_binary<unsigned char>(fin, width, height);
341                        break;
342                    case 5:    // grayscale binary
343                        pixelFormat = GL_LUMINANCE;
344                        data = read_grayscale_binary<unsigned char>(fin, width, height);
345                        break;
346                    case 6:    // color binary
347                        pixelFormat = GL_RGB;
348                        data = read_color_binary<unsigned char>(fin, width, height);
349                        break;
350                    default:
351                        return ReadResult::ERROR_IN_READING_FILE;
352                        break;
353                }
354            }
355
356            if (data == NULL)
357            {
358                return ReadResult::FILE_NOT_HANDLED;
359            }
360
361            osg::Image* pOsgImage = new osg::Image();
362
363            pOsgImage->setImage(width, height, 1,
364                pixelFormat,
365                pixelFormat,
366                dataType,
367                data,
368                osg::Image::USE_NEW_DELETE);
369
370            if (options && options->getOptionString().find("flip")!=std::string::npos)
371            {
372                pOsgImage->flipVertical();
373            }
374
375            return pOsgImage;
376        }
377
378        virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
379        {
380            std::string ext = osgDB::getLowerCaseFileExtension(file);
381            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
382
383            std::string fileName = osgDB::findDataFile( file, options );
384            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
385
386            std::ifstream fin(fileName.c_str(), std::ios_base::in | std::ios_base::binary);
387            if (!fin.good())
388                return ReadResult::ERROR_IN_READING_FILE;
389
390            ReadResult rr = readImage(fin, options);
391            fin.close();
392            if (rr.validImage()) rr.getImage()->setFileName(file);
393            return rr;
394        }
395
396        virtual WriteResult writeImage(const osg::Image& image,std::ostream& fout,const osgDB::ReaderWriter::Options* options) const
397        {
398            bool ascii = (options && options->getOptionString().find("ascii")!=std::string::npos);
399
400            if (ascii)
401            {
402                // ascii ppm format.
403                fout<<"P3"<<std::endl;
404                fout<<image.s()<<" "<<image.t()<<std::endl;
405                fout<<"255"<<std::endl;
406                for(int row = image.t()-1; row >= 0; --row)
407                {
408                    const unsigned char* ptr = image.data(0,row);
409                    for(int col = 0; col < image.s(); ++col)
410                    {
411                        fout<<static_cast<int>(*(ptr++));
412                        fout<<" "<<static_cast<int>(*(ptr++));
413                        fout<<" "<<static_cast<int>(*(ptr++))<<"  ";
414                    }
415                    fout<<std::endl;
416                }
417            }
418            else
419            {
420                // binary ppm format
421                fout<<"P6"<<std::endl;
422                fout<<image.s()<<" "<<image.t()<<std::endl;
423                fout<<"255"<<std::endl;
424                for(int row = image.t()-1; row >= 0; --row)
425                {
426                    const unsigned char* ptr = image.data(0,row);
427                    for(int col = 0; col < image.s(); ++col)
428                    {
429                        fout.put(*(ptr++));
430                        fout.put(*(ptr++));
431                        fout.put(*(ptr++));
432                    }
433                }
434            }
435            return WriteResult::FILE_SAVED;
436        }
437
438        virtual WriteResult writeImage(const osg::Image& image,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
439        {
440            // Only ppm format output supported
441            std::string ext = osgDB::getFileExtension(fileName);
442            if ( !osgDB::equalCaseInsensitive(ext, "ppm") ) return WriteResult::FILE_NOT_HANDLED;
443
444            // only support rgb images right now.
445            if (image.getPixelFormat()!=GL_RGB || image.getDataType()!=GL_UNSIGNED_BYTE) return WriteResult("Error image pixel format not supported by pnm writer.");
446
447            osgDB::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary);
448            if(!fout) return WriteResult::ERROR_IN_WRITING_FILE;
449
450            return writeImage(image,fout,options);
451        }
452
453
454};
455
456// now register with Registry to instantiate the above
457// reader/writer.
458REGISTER_OSGPLUGIN(pnm, ReaderWriterPNM)
Note: See TracBrowser for help on using the browser.