root/OpenSceneGraph/trunk/src/osgPlugins/tiff/ReaderWriterTIFF.cpp @ 13041

Revision 13041, 28.1 kB (checked in by robert, 3 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
2#include <osg/Image>
3#include <osg/Notify>
4#include <osg/Geode>
5#include <osg/GL>
6#include <osg/FrameBufferObject>
7
8#include <osgDB/Registry>
9#include <osgDB/FileUtils>
10#include <osgDB/FileNameUtils>
11
12#include <stdio.h>
13#include <tiffio.h>
14
15/****************************************************************************
16 *
17 * Follows is code extracted from the simage library.  Original Authors:
18 *
19 *      Systems in Motion,
20 *      <URL:http://www.sim.no>
21 *
22 *      Peder Blekken <pederb@sim.no>
23 *      Morten Eriksen <mortene@sim.no>
24 *      Marius Bugge Monsen <mariusbu@sim.no>
25 *
26 * The original COPYING notice
27 *
28 *      All files in this library are public domain, except simage_rgb.cpp which is
29 *      Copyright (c) Mark J Kilgard <mjk@nvidia.com>. I will contact Mark
30 *      very soon to hear if this source also can become public domain.
31 *
32 *      Please send patches for bugs and new features to: <pederb@sim.no>.
33 *
34 *      Peder Blekken
35 *
36 *
37 * Ported into the OSG as a plugin, Robert Osfield Decemeber 2000.
38 * Note, reference above to license of simage_rgb is not relevent to the OSG
39 * as the OSG does not use it.  Also for patches, bugs and new features
40 * please send them direct to the OSG dev team rather than address above.
41 *
42 **********************************************************************/
43
44#include <string.h>
45#include <stdarg.h>
46#include <assert.h>
47#include <stdlib.h>
48
49#define ERR_NO_ERROR    0
50#define ERR_OPEN        1
51#define ERR_READ        2
52#define ERR_MEM         3
53#define ERR_UNSUPPORTED 4
54#define ERR_TIFFLIB     5
55
56/* Functions to read TIFF image from memory
57 *
58 */
59
60tsize_t libtiffStreamReadProc(thandle_t fd, tdata_t buf, tsize_t size)
61{
62    std::istream *fin = (std::istream*)fd;
63
64    fin->read((char*)buf,size);
65
66    if(fin->bad())
67        return -1;
68
69    if(fin->gcount() < size)
70        return 0;
71
72    return size;
73}
74
75tsize_t libtiffStreamWriteProc(thandle_t, tdata_t, tsize_t)
76{
77    return 0;
78}
79
80toff_t libtiffStreamSeekProc(thandle_t fd, toff_t off, int i)
81{
82    std::istream *fin = (std::istream*)fd;
83
84    toff_t ret;
85    switch(i)
86    {
87        case SEEK_SET:
88            fin->seekg(off,std::ios::beg);
89            ret = fin->tellg();
90            if(fin->bad())
91                ret = 0;
92            break;
93
94        case SEEK_CUR:
95            fin->seekg(off,std::ios::cur);
96            ret = fin->tellg();
97            if(fin->bad())
98                ret = 0;
99            break;
100
101        case SEEK_END:
102            fin->seekg(off,std::ios::end);
103            ret = fin->tellg();
104            if(fin->bad())
105                ret = 0;
106            break;
107        default:
108            ret = 0;
109            break;
110    }
111    return ret;
112}
113
114int libtiffStreamCloseProc(thandle_t)
115{
116    return 0;
117}
118
119toff_t libtiffStreamSizeProc(thandle_t fd)
120{
121    std::istream *fin = (std::istream*)fd;
122
123    std::streampos curPos = fin->tellg();
124
125    fin->seekg(0, std::ios::end);
126    toff_t size = fin->tellg();
127    fin->seekg(curPos, std::ios::beg);
128
129    return size;
130}
131
132int libtiffStreamMapProc(thandle_t, tdata_t*, toff_t*)
133{
134    return 0;
135}
136
137void libtiffStreamUnmapProc(thandle_t, tdata_t, toff_t)
138{
139}
140
141/* Functions to write TIFF image from memory
142 *
143 */
144
145tsize_t libtiffOStreamReadProc(thandle_t, tdata_t, tsize_t)
146{
147    return 0;
148}
149
150tsize_t libtiffOStreamWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
151{
152    std::ostream *fout = (std::ostream*)fd;
153
154    fout->write((const char*)buf,size);
155
156    if(fout->bad()) {
157        return -1;
158    }
159
160    return size;
161}
162
163toff_t libtiffOStreamSizeProc(thandle_t fd)
164{
165    std::ostream *fout = (std::ostream*)fd;
166
167    std::streampos curPos = fout->tellp();
168
169    fout->seekp(0, std::ios::end);
170    toff_t size = fout->tellp();
171    fout->seekp(curPos, std::ios::beg);
172
173    return size;
174}
175
176toff_t libtiffOStreamSeekProc(thandle_t fd, toff_t off, int i)
177{
178    std::ostream *fout = (std::ostream*)fd;
179
180    toff_t pos_required = 0;
181    toff_t stream_end = 0;
182    switch(i)
183    {
184        case SEEK_SET:
185        {
186            if (off==0)
187            {
188                std::streampos checkEmpty = fout->tellp();
189                if(checkEmpty < 0)
190                {
191                    return 0;
192                }
193            }
194            pos_required = off;
195
196            fout->seekp(0, std::ios::end);
197            stream_end = fout->tellp();
198            break;
199        }
200        case SEEK_CUR:
201        {
202            toff_t stream_curr = fout->tellp();
203            pos_required = stream_curr + off;
204
205            fout->seekp(0, std::ios::end);
206            stream_end = fout->tellp();
207            break;
208        }
209        case SEEK_END:
210        {
211            fout->seekp(0, std::ios::end);
212            stream_end = fout->tellp();
213            pos_required = stream_end + off;
214            break;
215        }
216        default:
217            break;
218    }
219
220    if (pos_required>stream_end)
221    {
222        // position required past the end of the stream so we need to insert extra characters to
223        // ensure the stream is big enough to encompass the new the position.
224        fout->seekp(0, std::ios::end);
225        for(toff_t i=stream_end; i<pos_required; ++i)
226        {
227            fout->put(char(0));
228        }
229    }
230
231    fout->seekp(pos_required,std::ios::beg);
232    toff_t ret = fout->tellp();
233    if (fout->bad())
234    {
235        ret = 0;
236    }
237    return ret;
238}
239
240static int tifferror = ERR_NO_ERROR;
241
242int
243simage_tiff_error(char * buffer, int buflen)
244{
245    switch (tifferror)
246    {
247        case ERR_OPEN:
248            strncpy(buffer, "TIFF loader: Error opening file", buflen);
249            break;
250        case ERR_READ:
251            strncpy(buffer, "TIFF loader: Error reding/decoding file", buflen);
252            break;
253        case ERR_MEM:
254            strncpy(buffer, "TIFF loader: Out of memory error", buflen);
255            break;
256        case ERR_UNSUPPORTED:
257            strncpy(buffer, "TIFF loader: Unsupported image type", buflen);
258            break;
259        case ERR_TIFFLIB:
260            strncpy(buffer, "TIFF loader: Illegal tiff file", buflen);
261            break;
262        default:
263            strncpy(buffer, "TIFF loader: unknown error", buflen);
264            break;
265    }
266    return tifferror;
267}
268
269
270/// Generates a std::string from a printf format string and a va_list.
271/// Took & adapted from the man page of printf.
272///\todo Externalize this function to make is useable for all OSG?
273std::string doFormat(const char* fmt, va_list ap) {
274    static const int MSG_BUFSIZE = 256;            // Initial size of the buffer used for formatting
275    static const int MAX_BUFSIZE = 256*1024;    // Maximum size of the buffer used for formatting
276    for(int size=MSG_BUFSIZE; size<MAX_BUFSIZE; )
277    {
278        // Sukender: Here we could try/catch(std::bad_alloc &), but this is clearly an and-of-all-things condition knowing the fact 'size' is kept small.
279        //           Hence the commented code, to avoid the burden.
280        //try {
281        char * p = new char[size];
282        //} catch (std::bad_alloc &) {
283        //    return std::string();
284        //}
285
286        /* Try to print in the allocated space. */
287        int n = vsnprintf (p, size, fmt, ap);
288        // Now reset the state of the va_list (TIFF calling method will call
289
290        /* If that worked, return the string. */
291        if (n >= 0 && n < size) {
292            std::string res(p);
293            delete[] p;
294            return res;
295        }
296        /* Else try again with more space. */
297        if (n > 0)      /* glibc 2.1 */
298            size = n+1; /* precisely what is needed */
299        else            /* glibc 2.0 */
300            size *= 2;  /* twice the old size */
301        delete[] p;
302    }
303    return std::string(fmt, fmt+MSG_BUFSIZE) + "...";        // Fallback: Message is not formatted and truncated, but that's better than no message
304}
305
306static void
307tiff_error(const char*, const char* fmt, va_list ap)
308{
309    // values are (const char* module, const char* fmt, va_list list)
310    /* FIXME: store error message ? */
311    OSG_WARN << "TIFF rader: " << doFormat(fmt, ap) << std::endl;
312}
313
314
315static void
316tiff_warn(const char*, const char* fmt, va_list ap)
317{
318    // values are (const char* module, const char* fmt, va_list list)
319    /* FIXME: notify? */
320    OSG_NOTICE << "TIFF rader: " << doFormat(fmt, ap) << std::endl;
321}
322
323
324static int
325checkcmap(int n, uint16* r, uint16* g, uint16* b)
326{
327    while (n-- > 0)
328        if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
329            return (16);
330    /* Assuming 8-bit colormap */
331    return (8);
332}
333
334static void
335invert_row(unsigned char *ptr, unsigned char *data, int n, int invert, uint16 bitspersample)
336{
337    // OSG_NOTICE<<"invert_row "<<invert<<std::endl;
338    if (bitspersample == 8)
339    {
340        while (n--)
341        {
342            if (invert) *ptr++ = 255 - *data++;
343            else *ptr++ = *data++;
344        }
345    }
346    else if (bitspersample == 16)
347    {
348        unsigned short *ptr1 = (unsigned short *)ptr;
349        unsigned short *data1 = (unsigned short *)data;
350
351        while (n--)
352        {
353            if (invert) *ptr1++ = 65535 - *data1++;
354            else *ptr1++ = *data1++;
355        }
356    }
357    else if (bitspersample == 32)
358    {
359        float *ptr1 = (float *)ptr;
360        float *data1 = (float *)data;
361
362        while (n--)
363        {
364            if (invert) *ptr1++ = 1.0 - *data1++;
365            else *ptr1++ = *data1++;
366        }
367    }
368}
369
370
371static void
372remap_row(unsigned char *ptr, unsigned char *data, int n,
373unsigned short *rmap, unsigned short *gmap, unsigned short *bmap)
374{
375    // OSG_NOTICE<<"remap row"<<std::endl;
376    unsigned int ix;
377    while (n--)
378    {
379        ix = *data++;
380        *ptr++ = (unsigned char) rmap[ix];
381        *ptr++ = (unsigned char) gmap[ix];
382        *ptr++ = (unsigned char) bmap[ix];
383    }
384}
385
386static void interleave_row(unsigned char *ptr,
387                           unsigned char *red, unsigned char *green, unsigned char *blue,
388                           int n, int numSamples, uint16 bitspersample)
389{
390    // OSG_NOTICE<<"Interleave row RGB"<<std::endl;
391    if (bitspersample == 8)
392    {
393        while (n--)
394        {
395            *ptr++ = *red++;
396            *ptr++ = *green++;
397            *ptr++ = *blue++;
398            if (numSamples==4) *ptr++ = 255;
399        }
400    }
401    else if (bitspersample == 16)
402    {
403        unsigned short *ptr1 = (unsigned short *)ptr;
404        unsigned short *red1 = (unsigned short *)red;
405        unsigned short *green1 = (unsigned short *)green;
406        unsigned short *blue1 = (unsigned short *)blue;
407
408        while (n--)
409        {
410            *ptr1++ = *red1++;
411            *ptr1++ = *green1++;
412            *ptr1++ = *blue1++;
413            if (numSamples==4) *ptr1++ = 65535;
414        }
415    }
416    else if (bitspersample == 32)
417    {
418        float *ptr1 = (float *)ptr;
419        float *red1 = (float *)red;
420        float *green1 = (float *)green;
421        float *blue1 = (float *)blue;
422
423        while (n--)
424        {
425            *ptr1++ = *red1++;
426            *ptr1++ = *green1++;
427            *ptr1++ = *blue1++;
428            if (numSamples==4) *ptr1++ = 1.0f;
429        }
430    }
431}
432
433static void interleave_row(unsigned char *ptr,
434                           unsigned char *red, unsigned char *green, unsigned char *blue, unsigned char *alpha,
435                           int n, int numSamples, uint16 bitspersample)
436{
437    // OSG_NOTICE<<"Interleave row RGBA"<<std::endl;
438    if (bitspersample == 8)
439    {
440        while (n--)
441        {
442            *ptr++ = *red++;
443            *ptr++ = *green++;
444            *ptr++ = *blue++;
445            if (numSamples==4) *ptr++ = *alpha++;
446        }
447    }
448    else if (bitspersample == 16)
449    {
450        unsigned short *ptr1 = (unsigned short *)ptr;
451        unsigned short *red1 = (unsigned short *)red;
452        unsigned short *green1 = (unsigned short *)green;
453        unsigned short *blue1 = (unsigned short *)blue;
454        unsigned short *alpha1 = (unsigned short *)alpha;
455
456        while (n--)
457        {
458            *ptr1++ = *red1++;
459            *ptr1++ = *green1++;
460            *ptr1++ = *blue1++;
461            if (numSamples==4) *ptr1++ = *alpha1++;
462        }
463    }
464    else if (bitspersample == 32)
465    {
466        float *ptr1 = (float *)ptr;
467        float *red1 = (float *)red;
468        float *green1 = (float *)green;
469        float *blue1 = (float *)blue;
470        float *alpha1 = (float *)alpha;
471
472        while (n--)
473        {
474            *ptr1++ = *red1++;
475            *ptr1++ = *green1++;
476            *ptr1++ = *blue1++;
477            if (numSamples==4) *ptr1++ = *alpha1++;
478        }
479    }
480}
481
482int
483simage_tiff_identify(const char *,
484const unsigned char *header,
485int headerlen)
486{
487    static unsigned char tifcmp[] = {0x4d, 0x4d, 0x0, 0x2a};
488    static unsigned char tifcmp2[] = {0x49, 0x49, 0x2a, 0};
489
490    if (headerlen < 4) return 0;
491    if (memcmp((const void*)header, (const void*)tifcmp, 4) == 0) return 1;
492    if (memcmp((const void*)header, (const void*)tifcmp2, 4) == 0) return 1;
493    return 0;
494}
495
496
497/* useful defines (undef'ed below) */
498#define CVT(x)      (((x) * 255L) / ((1L<<16)-1))
499#define pack(a,b)   ((a)<<8 | (b))
500
501unsigned char *
502simage_tiff_load(std::istream& fin,
503                 int& width_ret,
504                 int& height_ret,
505                 int& numComponents_ret,
506                 uint16& bitspersample)
507{
508    TIFF *in;
509    uint16 dataType;
510    uint16 samplesperpixel;
511    uint16 photometric;
512    uint32 w, h;
513    uint16 config;
514    uint16* red;
515    uint16* green;
516    uint16* blue;
517    unsigned char *inbuf = NULL;
518    tsize_t rowsize;
519    uint32 row;
520    int format;
521    unsigned char *buffer;
522    int width;
523    int height;
524    unsigned char *currPtr;
525
526    TIFFSetErrorHandler(tiff_error);
527    TIFFSetWarningHandler(tiff_warn);
528
529    in = TIFFClientOpen("inputstream", "r", (thandle_t)&fin,
530            libtiffStreamReadProc, //Custom read function
531            libtiffStreamWriteProc, //Custom write function
532            libtiffStreamSeekProc, //Custom seek function
533            libtiffStreamCloseProc, //Custom close function
534            libtiffStreamSizeProc, //Custom size function
535            libtiffStreamMapProc, //Custom map function
536            libtiffStreamUnmapProc); //Custom unmap function
537
538    if (in == NULL)
539    {
540        tifferror = ERR_OPEN;
541        return NULL;
542    }
543    if (TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric) == 1)
544    {
545        if (photometric != PHOTOMETRIC_RGB && photometric != PHOTOMETRIC_PALETTE &&
546            photometric != PHOTOMETRIC_MINISWHITE &&
547            photometric != PHOTOMETRIC_MINISBLACK)
548        {
549            OSG_NOTICE << "Photometric type "<<photometric<<" not handled; can only handle Grayscale, RGB and Palette images" << std::endl;
550            TIFFClose(in);
551            tifferror = ERR_UNSUPPORTED;
552            return NULL;
553        }
554    }
555    else
556    {
557        tifferror = ERR_READ;
558        TIFFClose(in);
559        return NULL;
560    }
561
562    if (TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel) == 1)
563    {
564        if (samplesperpixel != 1 &&
565            samplesperpixel != 2 &&
566            samplesperpixel != 3 &&
567            samplesperpixel != 4)
568        {
569            OSG_DEBUG << "Bad samples/pixel" << std::endl;
570            tifferror = ERR_UNSUPPORTED;
571            TIFFClose(in);
572            return NULL;
573        }
574    }
575    else
576    {
577        tifferror = ERR_READ;
578        TIFFClose(in);
579        return NULL;
580    }
581
582    if (TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample) == 1)
583    {
584         if (bitspersample != 8 && bitspersample != 16 && bitspersample != 32)
585        {
586            OSG_NOTICE << "can only handle 8, 16 and 32 bit samples" << std::endl;
587            TIFFClose(in);
588            tifferror = ERR_UNSUPPORTED;
589            return NULL;
590        }
591    }
592    else
593    {
594        tifferror = ERR_READ;
595        TIFFClose(in);
596        return NULL;
597    }
598
599    if (TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w) != 1 ||
600        TIFFGetField(in, TIFFTAG_IMAGELENGTH, &h) != 1 ||
601        TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config) != 1)
602    {
603        TIFFClose(in);
604        tifferror = ERR_READ;
605        return NULL;
606    }
607
608
609    TIFFGetField(in, TIFFTAG_DATATYPE, &dataType);
610    OSG_INFO<<"TIFFTAG_DATATYPE="<<dataType<<std::endl;
611
612
613    /*
614    if (photometric == PHOTOMETRIC_MINISWHITE ||
615        photometric == PHOTOMETRIC_MINISBLACK)
616        format = 1;
617    else
618        format = 3;
619    */
620    // if it has a palette, data returned is 3 byte rgb
621    // so set format to 3.
622    if (photometric == PHOTOMETRIC_PALETTE)
623        format = 3;
624    else
625        format = samplesperpixel * bitspersample / 8;
626
627
628    int bytespersample = bitspersample / 8;
629    int bytesperpixel = bytespersample * samplesperpixel;
630
631    OSG_INFO<<"format="<<format<<std::endl;
632    OSG_INFO<<"bytespersample="<<bytespersample<<std::endl;
633    OSG_INFO<<"bytesperpixel="<<bytesperpixel<<std::endl;
634
635    buffer = new unsigned char [w*h*format];
636
637    if (!buffer)
638    {
639        tifferror = ERR_MEM;
640        TIFFClose(in);
641        return NULL;
642    }
643
644    // initialize memory
645    for(unsigned char* ptr=buffer;ptr<buffer+w*h*format;++ptr) *ptr = 0;
646
647    width = w;
648    height = h;
649
650    currPtr = buffer + (h-1)*w*format;
651
652    tifferror = ERR_NO_ERROR;
653
654    switch (pack(photometric, config))
655    {
656        case pack(PHOTOMETRIC_MINISWHITE, PLANARCONFIG_CONTIG):
657        case pack(PHOTOMETRIC_MINISBLACK, PLANARCONFIG_CONTIG):
658        case pack(PHOTOMETRIC_MINISWHITE, PLANARCONFIG_SEPARATE):
659        case pack(PHOTOMETRIC_MINISBLACK, PLANARCONFIG_SEPARATE):
660            inbuf = new unsigned char [TIFFScanlineSize(in)];
661            for (row = 0; row < h; row++)
662            {
663                if (TIFFReadScanline(in, inbuf, row, 0) < 0)
664                {
665                    tifferror = ERR_READ;
666                    break;
667                }
668                invert_row(currPtr, inbuf, samplesperpixel*w, photometric == PHOTOMETRIC_MINISWHITE, bitspersample);
669                currPtr -= format*w;
670            }
671            break;
672
673        case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_CONTIG):
674        case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_SEPARATE):
675            if (TIFFGetField(in, TIFFTAG_COLORMAP, &red, &green, &blue) != 1)
676                tifferror = ERR_READ;
677            /* */
678            /* Convert 16-bit colormap to 8-bit (unless it looks */
679            /* like an old-style 8-bit colormap). */
680            /* */
681            if (!tifferror && checkcmap(1<<bitspersample, red, green, blue) == 16)
682            {
683                int i;
684                for (i = (1<<bitspersample)-1; i >= 0; i--)
685                {
686                    red[i] = CVT(red[i]);
687                    green[i] = CVT(green[i]);
688                    blue[i] = CVT(blue[i]);
689                }
690            }
691
692            inbuf = new unsigned char [TIFFScanlineSize(in)];
693            for (row = 0; row < h; row++)
694            {
695                if (TIFFReadScanline(in, inbuf, row, 0) < 0)
696                {
697                    tifferror = ERR_READ;
698                    break;
699                }
700                remap_row(currPtr, inbuf, w, red, green, blue);
701                currPtr -= format*w;
702            }
703            break;
704
705        case pack(PHOTOMETRIC_RGB, PLANARCONFIG_CONTIG):
706            inbuf = new unsigned char [TIFFScanlineSize(in)];
707            for (row = 0; row < h; row++)
708            {
709                if (TIFFReadScanline(in, inbuf, row, 0) < 0)
710                {
711                    tifferror = ERR_READ;
712                    break;
713                }
714                memcpy(currPtr, inbuf, format*w);
715                currPtr -= format*w;
716            }
717            break;
718
719        case pack(PHOTOMETRIC_RGB, PLANARCONFIG_SEPARATE):
720            rowsize = TIFFScanlineSize(in);
721            inbuf = new unsigned char [format*rowsize];
722            for (row = 0; !tifferror && row < h; row++)
723            {
724                int s;
725                for (s = 0; s < format; s++)
726                {
727                    if (TIFFReadScanline(in, (tdata_t)(inbuf+s*rowsize), (uint32)row, (tsample_t)s) < 0)
728                    {
729                        tifferror = ERR_READ; break;
730                    }
731                }
732                if (!tifferror)
733                {
734                    if (format==3) interleave_row(currPtr, inbuf, inbuf+rowsize, inbuf+2*rowsize, w, format, bitspersample);
735                    else if (format==4) interleave_row(currPtr, inbuf, inbuf+rowsize, inbuf+2*rowsize, inbuf+3*rowsize, w, format, bitspersample);
736                    currPtr -= format*w;
737                }
738            }
739            break;
740        default:
741            tifferror = ERR_UNSUPPORTED;
742            break;
743    }
744
745    if (inbuf) delete [] inbuf;
746    TIFFClose(in);
747
748    if (tifferror)
749    {
750        if (buffer) delete [] buffer;
751        return NULL;
752    }
753    width_ret = width;
754    height_ret = height;
755    if (photometric == PHOTOMETRIC_PALETTE)
756        numComponents_ret = format;
757    else
758        numComponents_ret = samplesperpixel;
759
760    return buffer;
761}
762
763
764#undef CVT
765#undef pack
766
767class ReaderWriterTIFF : public osgDB::ReaderWriter
768{
769    public:
770
771        ReaderWriterTIFF()
772        {
773            supportsExtension("tiff","Tiff image format");
774            supportsExtension("tif","Tiff image format");
775        }
776
777        virtual const char* className() const { return "TIFF Image Reader"; }
778        virtual bool acceptsExtension(const std::string& extension) const
779        {
780            if( osgDB::equalCaseInsensitive(extension,"tiff")) return true;
781            if( osgDB::equalCaseInsensitive(extension,"tif") ) return true;
782            return false;
783        }
784
785        ReadResult readTIFStream(std::istream& fin) const
786        {
787            unsigned char *imageData = NULL;
788            int width_ret = -1;
789            int height_ret = -1;
790            int numComponents_ret = -1;
791            uint16 bitspersample_ret = 0;
792
793            imageData = simage_tiff_load(fin, width_ret, height_ret, numComponents_ret, bitspersample_ret);
794
795            if (imageData==NULL)
796            {
797                char err_msg[256];
798                simage_tiff_error( err_msg, sizeof(err_msg));
799                OSG_WARN << err_msg << std::endl;
800                return ReadResult::FILE_NOT_HANDLED;
801            }
802
803            int s = width_ret;
804            int t = height_ret;
805            int r = 1;
806
807            int internalFormat = numComponents_ret;
808
809            unsigned int pixelFormat =
810                numComponents_ret == 1 ? GL_LUMINANCE :
811                numComponents_ret == 2 ? GL_LUMINANCE_ALPHA :
812                numComponents_ret == 3 ? GL_RGB :
813                numComponents_ret == 4 ? GL_RGBA : (GLenum)-1;
814
815
816            unsigned int dataType =
817                bitspersample_ret == 8 ? GL_UNSIGNED_BYTE :
818                bitspersample_ret == 16 ? GL_UNSIGNED_SHORT :
819                bitspersample_ret == 32 ? GL_FLOAT : (GLenum)-1;
820
821            osg::Image* pOsgImage = new osg::Image;
822            pOsgImage->setImage(s,t,r,
823                internalFormat,
824                pixelFormat,
825                dataType,
826                imageData,
827                osg::Image::USE_NEW_DELETE);
828
829            return pOsgImage;
830        }
831
832        WriteResult::WriteStatus writeTIFStream(std::ostream& fout, const osg::Image& img) const
833        {
834            //Code is based from the following article on CodeProject.com
835            //http://www.codeproject.com/bitmap/BitmapsToTiffs.asp
836
837            TIFF *image;
838            int samplesPerPixel;
839            int bitsPerSample;
840            uint16 photometric;
841
842            image = TIFFClientOpen("outputstream", "w", (thandle_t)&fout,
843                                    libtiffOStreamReadProc, //Custom read function
844                                    libtiffOStreamWriteProc, //Custom write function
845                                    libtiffOStreamSeekProc, //Custom seek function
846                                    libtiffStreamCloseProc, //Custom close function
847                                    libtiffOStreamSizeProc, //Custom size function
848                                    libtiffStreamMapProc, //Custom map function
849                                    libtiffStreamUnmapProc); //Custom unmap function
850
851            if(image == NULL)
852            {
853                return WriteResult::ERROR_IN_WRITING_FILE;
854            }
855
856            switch(img.getPixelFormat()) {
857                case GL_DEPTH_COMPONENT:
858                case GL_LUMINANCE:
859                case GL_ALPHA:
860                    photometric = PHOTOMETRIC_MINISBLACK;
861                    samplesPerPixel = 1;
862                    break;
863                case GL_LUMINANCE_ALPHA:
864                    photometric = PHOTOMETRIC_MINISBLACK;
865                    samplesPerPixel = 2;
866                    break;
867                case GL_RGB:
868                    photometric = PHOTOMETRIC_RGB;
869                    samplesPerPixel = 3;
870                    break;
871                case GL_RGBA:
872                    photometric = PHOTOMETRIC_RGB;
873                    samplesPerPixel = 4;
874                    break;
875                default:
876                    return WriteResult::ERROR_IN_WRITING_FILE;
877                    break;
878            }
879
880            switch(img.getDataType()){
881                case GL_FLOAT:
882                    TIFFSetField(image, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
883                    TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, 1);
884                    bitsPerSample = 32;
885                    break;
886                case GL_SHORT:
887                    TIFFSetField(image, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT);
888                    bitsPerSample = 16;
889                    break;
890                default:
891                    bitsPerSample = 8;
892                    break;
893            }
894
895            TIFFSetField(image, TIFFTAG_IMAGEWIDTH,img.s());
896            TIFFSetField(image, TIFFTAG_IMAGELENGTH,img.t());
897            TIFFSetField(image, TIFFTAG_BITSPERSAMPLE,bitsPerSample);
898            TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL,samplesPerPixel);
899            TIFFSetField(image, TIFFTAG_PHOTOMETRIC, photometric);
900            TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
901            TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
902            TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
903
904            //uint32 rowsperstrip = TIFFDefaultStripSize(image, -1);
905            //TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
906
907            // Write the information to the file
908            for(int i = 0; i < img.t(); ++i) {
909                TIFFWriteScanline(image,(tdata_t)img.data(0,img.t()-i-1),i,0);
910            }
911
912            // Close the file
913            TIFFClose(image);
914
915            return WriteResult::FILE_SAVED;
916        }
917
918        virtual ReadResult readObject(std::istream& fin,const osgDB::ReaderWriter::Options* options =NULL) const
919        {
920            return readImage(fin, options);
921        }
922
923        virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const
924        {
925            return readImage(file, options);
926        }
927
928        virtual ReadResult readImage(std::istream& fin,const osgDB::ReaderWriter::Options* =NULL) const
929        {
930            return readTIFStream(fin);
931        }
932
933        virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
934        {
935            std::string ext = osgDB::getLowerCaseFileExtension(file);
936            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
937
938            std::string fileName = osgDB::findDataFile( file, options );
939            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
940
941            osgDB::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary);
942            if(!istream) return ReadResult::FILE_NOT_HANDLED;
943            ReadResult rr = readTIFStream(istream);
944            if(rr.validImage()) rr.getImage()->setFileName(file);
945            return rr;
946        }
947
948        virtual WriteResult writeImage(const osg::Image& img,std::ostream& fout,const osgDB::ReaderWriter::Options* /*options*/) const
949        {
950            WriteResult::WriteStatus ws = writeTIFStream(fout,img);
951            return ws;
952        }
953
954        virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options *options) const
955        {
956            std::string ext = osgDB::getFileExtension(fileName);
957            if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
958
959            osgDB::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary);
960            if(!fout) return WriteResult::ERROR_IN_WRITING_FILE;
961
962            return writeImage(img,fout,options);
963        }
964};
965
966// now register with Registry to instantiate the above
967// reader/writer.
968REGISTER_OSGPLUGIN(tiff, ReaderWriterTIFF)
Note: See TracBrowser for help on using the browser.