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

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

Removed "interlace" debugging message

  • 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.