root/OpenSceneGraph/trunk/src/osgPlugins/gif/ReaderWriterGIF.cpp @ 2501

Revision 2501, 11.3 kB (checked in by robert, 10 years ago)

Moved the responsibility for finding file to load on to the ReaderWriter? plugins,
instead of osgDB::Registry where it original lay. This has been done to allow
fileName strings to be encode data rather than just file names, such as one
requires when using PagedLOD along with plugins for doing dynamic tesselation.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osg/Image>
2#include <osg/Notify>
3#include <osg/Geode>
4#include <osg/GL>
5
6#include <osgDB/FileNameUtils>
7#include <osgDB/FileUtils>
8#include <osgDB/Registry>
9
10
11/****************************************************************************
12 *
13 * Follows is code extracted from the simage library.  Original Authors:
14 *
15 *      Systems in Motion,
16 *      <URL:http://www.sim.no>
17 *
18 *      Peder Blekken <pederb@sim.no>
19 *      Morten Eriksen <mortene@sim.no>
20 *      Marius Bugge Monsen <mariusbu@sim.no>
21 *
22 * The original COPYING notice
23 *
24 *      All files in this library are public domain, except simage_rgb.cpp which is
25 *      Copyright (c) Mark J Kilgard <mjk@nvidia.com>. I will contact Mark
26 *      very soon to hear if this source also can become public domain.
27 *
28 *      Please send patches for bugs and new features to: <pederb@sim.no>.
29 *
30 *      Peder Blekken
31 *
32 *
33 * Ported into the OSG as a plugin, Robert Osfield Decemeber 2000.
34 * Note, reference above to license of simage_rgb is not relevent to the OSG
35 * as the OSG does not use it.  Also for patches, bugs and new features
36 * please send them direct to the OSG dev team rather than address above.
37 *
38 **********************************************************************/
39
40/*!
41  GIF loader, using libungif
42  Based, in part, on source code found in libungif, gif2rgb.c
43*/
44#include <stdlib.h>
45#include <string.h>
46#include <stdio.h>
47
48extern  "C"
49{
50    #include <gif_lib.h>
51};
52
53#define ERR_NO_ERROR     0
54#define ERR_OPEN         1
55#define ERR_READ         2
56#define ERR_MEM          3
57
58#define MY_GIF_DEBUG 1
59
60static int giferror = ERR_NO_ERROR;
61
62int
63simage_gif_error(char * buffer, int buflen)
64{
65    switch (giferror)
66    {
67        case ERR_OPEN:
68            strncpy(buffer, "GIF loader: Error opening file", buflen);
69            break;
70        case ERR_READ:
71            strncpy(buffer, "GIF loader: Error reading file", buflen);
72            break;
73        case ERR_MEM:
74            strncpy(buffer, "GIF loader: Out of memory error", buflen);
75            break;
76    }
77    return giferror;
78}
79
80
81int
82simage_gif_identify(const char *,
83const unsigned char *header,
84int headerlen)
85{
86    static unsigned char gifcmp[] = {'G', 'I', 'F'};
87    if (headerlen < 3) return 0;
88    if (memcmp((const void*)header,
89        (const void*)gifcmp, 3) == 0) return 1;
90    return 0;
91}
92
93
94static void
95decode_row(GifFileType * giffile,
96unsigned char * buffer,
97unsigned char * rowdata,
98int x, int y, int len,
99int transparent)
100{
101    GifColorType * cmentry;
102    ColorMapObject * colormap;
103    int colormapsize;
104    unsigned char col;
105    unsigned char * ptr;
106    y = giffile->SHeight - (y+1);
107    ptr = buffer + (giffile->SWidth * y + x) * 4;
108
109    colormap = (giffile->Image.ColorMap
110        ? giffile->Image.ColorMap
111        : giffile->SColorMap);
112    colormapsize = colormap ? colormap->ColorCount : 255;
113
114    while (len--)
115    {
116        col = *rowdata++;
117                                 /* just in case */
118        if (col >= colormapsize) col = 0;
119        cmentry = colormap ? &colormap->Colors[col] : NULL;
120        if (cmentry)
121        {
122            *ptr++ = cmentry->Red;
123            *ptr++ = cmentry->Green;
124            *ptr++ = cmentry->Blue;
125        }
126        else
127        {
128            *ptr++ = col;
129            *ptr++ = col;
130            *ptr++ = col;
131        }
132        *ptr++ = (col == transparent ? 0x00 : 0xff);
133    }
134}
135
136
137unsigned char *
138simage_gif_load(const char *filename,
139int *width_ret,
140int *height_ret,
141int *numComponents_ret)
142{
143    int i, j, n, row, col, width, height, extcode;
144    unsigned char * rowdata;
145    unsigned char * buffer, * ptr;
146    unsigned char bg;
147    int transparent;
148    GifRecordType recordtype;
149    GifByteType * extension;
150    GifFileType * giffile;
151    GifColorType * bgcol;
152
153    /* The way an interlaced image should be read - offsets and jumps */
154    int interlacedoffset[] = { 0, 4, 2, 1 };
155    int interlacedjumps[] = { 8, 8, 4, 2 };
156
157    giffile = DGifOpenFileName(filename);
158    if (!giffile)
159    {
160        giferror = ERR_OPEN;
161        return NULL;
162    }
163
164    transparent = -1;            /* no transparent color by default */
165
166    n = giffile->SHeight * giffile->SWidth;
167    buffer = new unsigned char [n * 4];
168    if (!buffer)
169    {
170        giferror = ERR_MEM;
171        return NULL;
172    }
173    rowdata = new unsigned char [giffile->SWidth];
174    if (!rowdata)
175    {
176        giferror = ERR_MEM;
177        delete [] buffer;
178        return NULL;
179    }
180
181    bg = giffile->SBackGroundColor;
182    if (giffile->SColorMap && bg < giffile->SColorMap->ColorCount)
183    {
184        bgcol = &giffile->SColorMap->Colors[bg];
185    }
186    else bgcol = NULL;
187    ptr = buffer;
188    for (i = 0; i < n; i++)
189    {
190        if (bgcol)
191        {
192            *ptr++ = bgcol->Red;
193            *ptr++ = bgcol->Green;
194            *ptr++ = bgcol->Blue;
195            *ptr++ = 0xff;
196        }
197        else
198        {
199            *ptr++ = 0x00;
200            *ptr++ = 0x00;
201            *ptr++ = 0x00;
202            *ptr++ = 0xff;
203        }
204    }
205
206    /* Scan the content of the GIF file and load the image(s) in: */
207    do
208    {
209        if (DGifGetRecordType(giffile, &recordtype) == GIF_ERROR)
210        {
211            giferror = ERR_READ;
212            delete [] buffer;
213            delete [] rowdata;
214            return NULL;
215        }
216        switch (recordtype)
217        {
218            case IMAGE_DESC_RECORD_TYPE:
219                if (DGifGetImageDesc(giffile) == GIF_ERROR)
220                {
221                    giferror = ERR_READ;
222                    delete [] buffer;
223                    delete [] rowdata;
224                    return NULL;
225                }
226                                 /* subimage position in composite image */
227                row = giffile->Image.Top;
228                col = giffile->Image.Left;
229                width = giffile->Image.Width;
230                height = giffile->Image.Height;
231                if (giffile->Image.Left + giffile->Image.Width > giffile->SWidth ||
232                    giffile->Image.Top + giffile->Image.Height > giffile->SHeight)
233                {
234                    /* image is not confined to screen dimension */
235                    giferror = ERR_READ;
236                    delete [] buffer;
237                    delete [] rowdata;
238                    return NULL;
239                }
240                if (giffile->Image.Interlace)
241                {
242                    fprintf(stderr,"interlace\n");
243                    /* Need to perform 4 passes on the images: */
244                    for (i = 0; i < 4; i++)
245                    {
246                        for (j = row + interlacedoffset[i]; j < row + height;
247                            j += interlacedjumps[i])
248                        {
249                            if (DGifGetLine(giffile, rowdata, width) == GIF_ERROR)
250                            {
251                                giferror = ERR_READ;
252                                delete [] buffer;
253                                delete [] rowdata;
254                                return NULL;
255                            }
256                            else decode_row(giffile, buffer, rowdata, col, j, width, transparent);
257                        }
258                    }
259                }
260                else
261                {
262                    for (i = 0; i < height; i++, row++)
263                    {
264                        if (DGifGetLine(giffile, rowdata, width) == GIF_ERROR)
265                        {
266                            giferror = ERR_READ;
267                            delete [] buffer;
268                            delete [] rowdata;
269                            return NULL;
270                        }
271                        else decode_row(giffile, buffer, rowdata, col, row, width, transparent);
272                    }
273                }
274                break;
275            case EXTENSION_RECORD_TYPE:
276                /* Skip any extension blocks in file: */
277                if (DGifGetExtension(giffile, &extcode, &extension) == GIF_ERROR)
278                {
279                    giferror = ERR_READ;
280                    delete [] buffer;
281                    delete [] rowdata;
282                    return NULL;
283                }
284                /* transparent test from the gimp gif-plugin. Open Source rulez! */
285                else if (extcode == 0xf9)
286                {
287                    if (extension[0] >= 4 && extension[1] & 0x1) transparent = extension[4];
288                    else transparent = -1;
289                }
290                while (extension != NULL)
291                {
292                    if (DGifGetExtensionNext(giffile, &extension) == GIF_ERROR)
293                    {
294                        giferror = ERR_READ;
295                        delete [] buffer;
296                        delete [] rowdata;
297                        return NULL;
298                    }
299                }
300                break;
301            case TERMINATE_RECORD_TYPE:
302                break;
303            default:             /* Should be trapped by DGifGetRecordType. */
304                break;
305        }
306    }
307    while (recordtype != TERMINATE_RECORD_TYPE);
308
309    delete [] rowdata;
310    *width_ret = giffile->SWidth;
311    *height_ret = giffile->SHeight;
312    *numComponents_ret = 4;
313    DGifCloseFile(giffile);
314    return buffer;
315}
316
317
318class ReaderWriterGIF : public osgDB::ReaderWriter
319{
320    public:
321        virtual const char* className() { return "GIF Image Reader"; }
322        virtual bool acceptsExtension(const std::string& extension)
323        {
324            return osgDB::equalCaseInsensitive(extension,"gif");
325        }
326
327        virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options*)
328        {
329            std::string ext = osgDB::getLowerCaseFileExtension(file);
330            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
331
332            std::string fileName = osgDB::findDataFile( file );
333            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
334
335            unsigned char *imageData = NULL;
336            int width_ret;
337            int height_ret;
338            int numComponents_ret;
339
340            imageData = simage_gif_load(fileName.c_str(),&width_ret,&height_ret,&numComponents_ret);
341
342            switch (giferror)
343            {
344                case ERR_OPEN:
345                    return ReadResult("GIF loader: Error opening file");
346                case ERR_READ:
347                    return ReadResult("GIF loader: Error reading file");
348                case ERR_MEM:
349                    return ReadResult("GIF loader: Out of memory error");
350            }
351
352            if (imageData==NULL) return ReadResult::FILE_NOT_HANDLED;
353
354            int s = width_ret;
355            int t = height_ret;
356            int r = 1;
357
358            int internalFormat = numComponents_ret;
359
360            unsigned int pixelFormat =
361                numComponents_ret == 1 ? GL_LUMINANCE :
362            numComponents_ret == 2 ? GL_LUMINANCE_ALPHA :
363            numComponents_ret == 3 ? GL_RGB :
364            numComponents_ret == 4 ? GL_RGBA : (GLenum)-1;
365
366            unsigned int dataType = GL_UNSIGNED_BYTE;
367
368            osg::Image* pOsgImage = new osg::Image;
369            pOsgImage->setFileName(fileName.c_str());
370            pOsgImage->setImage(s,t,r,
371                internalFormat,
372                pixelFormat,
373                dataType,
374                imageData,
375                osg::Image::USE_NEW_DELETE);
376
377            return pOsgImage;
378
379        }
380};
381
382// now register with Registry to instantiate the above
383// reader/writer.
384osgDB::RegisterReaderWriterProxy<ReaderWriterGIF> g_readerWriter_GIF_Proxy;
Note: See TracBrowser for help on using the browser.