I have encountered some images that aren't handled correctly because they
have more than 4 samples per pixel. I don't actually need the information
in those channels, so I thought I'd try to fix the plugin to just read the
first four channels, using the simple TIFFReadRGBAImage function from the
libtiff library. The results work for me, and are included here. This is
based on the current 3.6 branch (I updated my working copy today).
#include <osg/Image>
#include <osg/Notify>
#include <osg/Geode>
#include <osg/GL>
#include <osg/FrameBufferObject>

#include <osgDB/Registry>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>

#include <stdio.h>
#include <tiffio.h>

/****************************************************************************
 *
 * Follows is code extracted from the simage library.  Original Authors:
 *
 *      Systems in Motion,
 *      <URL:http://www.sim.no>
 *
 *      Peder Blekken <[email protected]>
 *      Morten Eriksen <[email protected]>
 *      Marius Bugge Monsen <[email protected]>
 *
 * The original COPYING notice
 *
 *      All files in this library are public domain, except simage_rgb.cpp which is
 *      Copyright (c) Mark J Kilgard <[email protected]>. I will contact Mark
 *      very soon to hear if this source also can become public domain.
 *
 *      Please send patches for bugs and new features to: <[email protected]>.
 *
 *      Peder Blekken
 *
 *
 * Ported into the OSG as a plugin, Robert Osfield Decemeber 2000.
 * Note, reference above to license of simage_rgb is not relevant to the OSG
 * as the OSG does not use it.  Also for patches, bugs and new features
 * please send them direct to the OSG dev team rather than address above.
 *
 **********************************************************************/

#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include <stdlib.h>

#define ERR_NO_ERROR    0
#define ERR_OPEN        1
#define ERR_READ        2
#define ERR_MEM         3
#define ERR_UNSUPPORTED 4
#define ERR_TIFFLIB     5

/* Functions to read TIFF image from memory
 *
 */

tsize_t libtiffStreamReadProc(thandle_t fd, tdata_t buf, tsize_t size)
{
    std::istream *fin = (std::istream*)fd;

    fin->read((char*)buf,size);

    if(fin->bad())
        return -1;

    if(fin->gcount() < size)
        return 0;

    return size;
}

tsize_t libtiffStreamWriteProc(thandle_t, tdata_t, tsize_t)
{
    return 0;
}

toff_t libtiffStreamSeekProc(thandle_t fd, toff_t off, int i)
{
    std::istream *fin = (std::istream*)fd;

    toff_t ret;
    switch(i)
    {
        case SEEK_SET:
            fin->seekg(off,std::ios::beg);
            ret = fin->tellg();
            if(fin->bad())
                ret = 0;
            break;

        case SEEK_CUR:
            fin->seekg(off,std::ios::cur);
            ret = fin->tellg();
            if(fin->bad())
                ret = 0;
            break;

        case SEEK_END:
            fin->seekg(off,std::ios::end);
            ret = fin->tellg();
            if(fin->bad())
                ret = 0;
            break;
        default:
            ret = 0;
            break;
    }
    return ret;
}

int libtiffStreamCloseProc(thandle_t)
{
    return 0;
}

toff_t libtiffStreamSizeProc(thandle_t fd)
{
    std::istream *fin = (std::istream*)fd;

    std::streampos curPos = fin->tellg();

    fin->seekg(0, std::ios::end);
    toff_t size = fin->tellg();
    fin->seekg(curPos, std::ios::beg);

    return size;
}

int libtiffStreamMapProc(thandle_t, tdata_t*, toff_t*)
{
    return 0;
}

void libtiffStreamUnmapProc(thandle_t, tdata_t, toff_t)
{
}

/* Functions to write TIFF image from memory
 *
 */

tsize_t libtiffOStreamReadProc(thandle_t, tdata_t, tsize_t)
{
    return 0;
}

tsize_t libtiffOStreamWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
{
    std::ostream *fout = (std::ostream*)fd;

    fout->write((const char*)buf,size);

    if(fout->bad()) {
        return -1;
    }

    return size;
}

toff_t libtiffOStreamSizeProc(thandle_t fd)
{
    std::ostream *fout = (std::ostream*)fd;

    std::streampos curPos = fout->tellp();

    fout->seekp(0, std::ios::end);
    toff_t size = fout->tellp();
    fout->seekp(curPos, std::ios::beg);

    return size;
}

toff_t libtiffOStreamSeekProc(thandle_t fd, toff_t off, int i)
{
    std::ostream *fout = (std::ostream*)fd;

    toff_t pos_required = 0;
    toff_t stream_end = 0;
    switch(i)
    {
        case SEEK_SET:
        {
            if (off==0)
            {
                std::streampos checkEmpty = fout->tellp();
                if(checkEmpty < 0)
                {
                    return 0;
                }
            }
            pos_required = off;

            fout->seekp(0, std::ios::end);
            stream_end = fout->tellp();
            break;
        }
        case SEEK_CUR:
        {
            toff_t stream_curr = fout->tellp();
            pos_required = stream_curr + off;

            fout->seekp(0, std::ios::end);
            stream_end = fout->tellp();
            break;
        }
        case SEEK_END:
        {
            fout->seekp(0, std::ios::end);
            stream_end = fout->tellp();
            pos_required = stream_end + off;
            break;
        }
        default:
            break;
    }

    if (pos_required>stream_end)
    {
        // position required past the end of the stream so we need to insert extra characters to
        // ensure the stream is big enough to encompass the new the position.
        fout->seekp(0, std::ios::end);
        for(toff_t is=stream_end; is<pos_required; ++is)
        {
            fout->put(char(0));
        }
    }

    fout->seekp(pos_required,std::ios::beg);
    toff_t ret = fout->tellp();
    if (fout->bad())
    {
        ret = 0;
    }
    return ret;
}

static int tifferror = ERR_NO_ERROR;

int
simage_tiff_error(char * buffer, int buflen)
{
    switch (tifferror)
    {
        case ERR_OPEN:
            strncpy(buffer, "TIFF loader: Error opening file", buflen);
            break;
        case ERR_READ:
            strncpy(buffer, "TIFF loader: Error reading/decoding file", buflen);
            break;
        case ERR_MEM:
            strncpy(buffer, "TIFF loader: Out of memory error", buflen);
            break;
        case ERR_UNSUPPORTED:
            strncpy(buffer, "TIFF loader: Unsupported image type", buflen);
            break;
        case ERR_TIFFLIB:
            strncpy(buffer, "TIFF loader: Illegal tiff file", buflen);
            break;
        default:
            strncpy(buffer, "TIFF loader: unknown error", buflen);
            break;
    }
    return tifferror;
}


/// Generates a std::string from a printf format string and a va_list.
/// Took & adapted from the man page of printf.
///\todo Externalize this function to make is usable for all OSG?
std::string doFormat(const char* fmt, va_list ap) {
    static const int MSG_BUFSIZE = 256;            // Initial size of the buffer used for formatting
    static const int MAX_BUFSIZE = 256*1024;    // Maximum size of the buffer used for formatting
    for(int size=MSG_BUFSIZE; size<MAX_BUFSIZE; )
    {
        // 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.
        //           Hence the commented code, to avoid the burden.
        //try {
        char * p = new char[size];
        //} catch (std::bad_alloc &) {
        //    return std::string();
        //}

        /* Try to print in the allocated space. */
        int n = vsnprintf (p, size, fmt, ap);
        // Now reset the state of the va_list (TIFF calling method will call

        /* If that worked, return the string. */
        if (n >= 0 && n < size) {
            std::string res(p);
            delete[] p;
            return res;
        }
        /* Else try again with more space. */
        if (n > 0)      /* glibc 2.1 */
            size = n+1; /* precisely what is needed */
        else            /* glibc 2.0 */
            size *= 2;  /* twice the old size */
        delete[] p;
    }
    return std::string(fmt, fmt+MSG_BUFSIZE) + "...";        // Fallback: Message is not formatted and truncated, but that's better than no message
}

static void
tiff_error(const char*, const char* fmt, va_list ap)
{
    // values are (const char* module, const char* fmt, va_list list)
    /* FIXME: store error message ? */
    OSG_WARN << "TIFF reader: " << doFormat(fmt, ap) << std::endl;
}


static void
tiff_warn(const char*, const char* fmt, va_list ap)
{
    // values are (const char* module, const char* fmt, va_list list)
    /* FIXME: notify? */
    OSG_NOTICE << "TIFF reader: " << doFormat(fmt, ap) << std::endl;
}


static int
checkcmap(int n, uint16* r, uint16* g, uint16* b)
{
    while (n-- > 0)
        if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
            return (16);
    /* Assuming 8-bit colormap */
    return (8);
}

static void
invert_row(unsigned char *ptr, unsigned char *data, int n, int invert, uint16 bitspersample)
{
    // OSG_NOTICE<<"invert_row "<<invert<<std::endl;
    if (bitspersample == 8)
    {
        while (n--)
        {
            if (invert) *ptr++ = 255 - *data++;
            else *ptr++ = *data++;
        }
    }
    else if (bitspersample == 16)
    {
        unsigned short *ptr1 = (unsigned short *)ptr;
        unsigned short *data1 = (unsigned short *)data;

        while (n--)
        {
            if (invert) *ptr1++ = 65535 - *data1++;
            else *ptr1++ = *data1++;
        }
    }
    else if (bitspersample == 32)
    {
        float *ptr1 = (float *)ptr;
        float *data1 = (float *)data;

        while (n--)
        {
            if (invert) *ptr1++ = 1.0 - *data1++;
            else *ptr1++ = *data1++;
        }
    }
}


static void
remap_row(unsigned char *ptr, unsigned char *data, int n,
unsigned short *rmap, unsigned short *gmap, unsigned short *bmap)
{
    // OSG_NOTICE<<"remap row"<<std::endl;
    unsigned int ix;
    while (n--)
    {
        ix = *data++;
        *ptr++ = (unsigned char) rmap[ix];
        *ptr++ = (unsigned char) gmap[ix];
        *ptr++ = (unsigned char) bmap[ix];
    }
}

static void interleave_row(unsigned char *ptr,
                           unsigned char *red, unsigned char *green, unsigned char *blue,
                           int n, int numSamples, uint16 bitspersample)
{
    // OSG_NOTICE<<"Interleave row RGB"<<std::endl;
    if (bitspersample == 8)
    {
        while (n--)
        {
            *ptr++ = *red++;
            *ptr++ = *green++;
            *ptr++ = *blue++;
            if (numSamples==4) *ptr++ = 255;
        }
    }
    else if (bitspersample == 16)
    {
        unsigned short *ptr1 = (unsigned short *)ptr;
        unsigned short *red1 = (unsigned short *)red;
        unsigned short *green1 = (unsigned short *)green;
        unsigned short *blue1 = (unsigned short *)blue;

        while (n--)
        {
            *ptr1++ = *red1++;
            *ptr1++ = *green1++;
            *ptr1++ = *blue1++;
            if (numSamples==4) *ptr1++ = 65535;
        }
    }
    else if (bitspersample == 32)
    {
        float *ptr1 = (float *)ptr;
        float *red1 = (float *)red;
        float *green1 = (float *)green;
        float *blue1 = (float *)blue;

        while (n--)
        {
            *ptr1++ = *red1++;
            *ptr1++ = *green1++;
            *ptr1++ = *blue1++;
            if (numSamples==4) *ptr1++ = 1.0f;
        }
    }
}

static void interleave_row(unsigned char *ptr,
                           unsigned char *red, unsigned char *green, unsigned char *blue, unsigned char *alpha,
                           int n, int numSamples, uint16 bitspersample)
{
    // OSG_NOTICE<<"Interleave row RGBA"<<std::endl;
    if (bitspersample == 8)
    {
        while (n--)
        {
            *ptr++ = *red++;
            *ptr++ = *green++;
            *ptr++ = *blue++;
            if (numSamples==4) *ptr++ = *alpha++;
        }
    }
    else if (bitspersample == 16)
    {
        unsigned short *ptr1 = (unsigned short *)ptr;
        unsigned short *red1 = (unsigned short *)red;
        unsigned short *green1 = (unsigned short *)green;
        unsigned short *blue1 = (unsigned short *)blue;
        unsigned short *alpha1 = (unsigned short *)alpha;

        while (n--)
        {
            *ptr1++ = *red1++;
            *ptr1++ = *green1++;
            *ptr1++ = *blue1++;
            if (numSamples==4) *ptr1++ = *alpha1++;
        }
    }
    else if (bitspersample == 32)
    {
        float *ptr1 = (float *)ptr;
        float *red1 = (float *)red;
        float *green1 = (float *)green;
        float *blue1 = (float *)blue;
        float *alpha1 = (float *)alpha;

        while (n--)
        {
            *ptr1++ = *red1++;
            *ptr1++ = *green1++;
            *ptr1++ = *blue1++;
            if (numSamples==4) *ptr1++ = *alpha1++;
        }
    }
}

int
simage_tiff_identify(const char *,
const unsigned char *header,
int headerlen)
{
    static unsigned char tifcmp[] = {0x4d, 0x4d, 0x0, 0x2a};
    static unsigned char tifcmp2[] = {0x49, 0x49, 0x2a, 0};

    if (headerlen < 4) return 0;
    if (memcmp((const void*)header, (const void*)tifcmp, 4) == 0) return 1;
    if (memcmp((const void*)header, (const void*)tifcmp2, 4) == 0) return 1;
    return 0;
}


/* useful defines (undef'ed below) */
#define CVT(x)      (((x) * 255L) / ((1L<<16)-1))
#define pack(a,b)   ((a)<<8 | (b))

unsigned char *
simage_tiff_load(std::istream& fin,
                 int& width_ret,
                 int& height_ret,
                 int& numComponents_ret,
                 uint16& bitspersample)
{
    TIFF *in;
    uint16 dataType;
    uint16 samplesperpixel;
    uint16 photometric;
    uint32 w, h;
    uint16 config;
    uint16* red;
    uint16* green;
    uint16* blue;
    unsigned char *inbuf = NULL;
    tsize_t rowsize;
    uint32 row;
    int format;
    unsigned char *buffer;
    int width;
    int height;
    unsigned char *currPtr;

    TIFFSetErrorHandler(tiff_error);
    TIFFSetWarningHandler(tiff_warn);

    in = TIFFClientOpen("inputstream", "r", (thandle_t)&fin,
            libtiffStreamReadProc, //Custom read function
            libtiffStreamWriteProc, //Custom write function
            libtiffStreamSeekProc, //Custom seek function
            libtiffStreamCloseProc, //Custom close function
            libtiffStreamSizeProc, //Custom size function
            libtiffStreamMapProc, //Custom map function
            libtiffStreamUnmapProc); //Custom unmap function

    if (in == NULL)
    {
        tifferror = ERR_OPEN;
        return NULL;
    }
    if (TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric) == 1)
    {
        if (photometric != PHOTOMETRIC_RGB && photometric != PHOTOMETRIC_PALETTE &&
            photometric != PHOTOMETRIC_MINISWHITE &&
            photometric != PHOTOMETRIC_MINISBLACK)
        {
            OSG_NOTICE << "Photometric type "<<photometric<<" not handled; can only handle Grayscale, RGB and Palette images" << std::endl;
            TIFFClose(in);
            tifferror = ERR_UNSUPPORTED;
            return NULL;
        }
    }
    else
    {
        tifferror = ERR_READ;
        TIFFClose(in);
        return NULL;
    }

    if (TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w) != 1 ||
        TIFFGetField(in, TIFFTAG_IMAGELENGTH, &h) != 1 ||
        TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config) != 1)
    {
        TIFFClose(in);
        tifferror = ERR_READ;
        return NULL;
    }

    if (TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample) == 1)
    {
         if (bitspersample != 8 && bitspersample != 16 && bitspersample != 32)
        {
            OSG_NOTICE << "can only handle 8, 16 and 32 bit samples" << std::endl;
            TIFFClose(in);
            tifferror = ERR_UNSUPPORTED;
            return NULL;
        }
    }
    else
    {
        tifferror = ERR_READ;
        TIFFClose(in);
        return NULL;
    }


    if (TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel) == 1)
    {
        if (samplesperpixel != 1 &&
            samplesperpixel != 2 &&
            samplesperpixel != 3 &&
            samplesperpixel != 4)
        {
            // Instead of just giving up, see if the basic TIFF function 
            // will get something useful.
            buffer = new unsigned char[w * h * 4];
            if (buffer != NULL)
            {
                if (TIFFReadRGBAImage(in, w, h, (uint32*)buffer, 0) == 1)
                {
                    width_ret = w;
                    height_ret = h;
                    numComponents_ret = 4;
                    TIFFClose(in);
                    return buffer;
                }
                delete[] buffer;
                buffer = NULL;
            }

            OSG_DEBUG << "Bad samples/pixel" << std::endl;
            tifferror = ERR_UNSUPPORTED;
            TIFFClose(in);
            return NULL;
        }
    }
    else
    {
        tifferror = ERR_READ;
        TIFFClose(in);
        return NULL;
    }

    TIFFGetField(in, TIFFTAG_DATATYPE, &dataType);
    OSG_INFO<<"TIFFTAG_DATATYPE="<<dataType<<std::endl;


    /*
    if (photometric == PHOTOMETRIC_MINISWHITE ||
        photometric == PHOTOMETRIC_MINISBLACK)
        format = 1;
    else
        format = 3;
    */
    // if it has a palette, data returned is 3 byte rgb
    // so set format to 3.
    if (photometric == PHOTOMETRIC_PALETTE)
        format = 3;
    else
        format = samplesperpixel * bitspersample / 8;


    int bytespersample = bitspersample / 8;
    int bytesperpixel = bytespersample * samplesperpixel;

    OSG_INFO<<"format="<<format<<std::endl;
    OSG_INFO<<"bytespersample="<<bytespersample<<std::endl;
    OSG_INFO<<"bytesperpixel="<<bytesperpixel<<std::endl;

    buffer = new unsigned char [w*h*format];

    if (!buffer)
    {
        tifferror = ERR_MEM;
        TIFFClose(in);
        return NULL;
    }

    // initialize memory
    for(unsigned char* ptr=buffer;ptr<buffer+w*h*format;++ptr) *ptr = 0;

    width = w;
    height = h;

    currPtr = buffer + (h-1)*w*format;

    tifferror = ERR_NO_ERROR;

    switch (pack(photometric, config))
    {
        case pack(PHOTOMETRIC_MINISWHITE, PLANARCONFIG_CONTIG):
        case pack(PHOTOMETRIC_MINISBLACK, PLANARCONFIG_CONTIG):
        case pack(PHOTOMETRIC_MINISWHITE, PLANARCONFIG_SEPARATE):
        case pack(PHOTOMETRIC_MINISBLACK, PLANARCONFIG_SEPARATE):
            inbuf = new unsigned char [TIFFScanlineSize(in)];
            for (row = 0; row < h; row++)
            {
                if (TIFFReadScanline(in, inbuf, row, 0) < 0)
                {
                    tifferror = ERR_READ;
                    break;
                }
                invert_row(currPtr, inbuf, samplesperpixel*w, photometric == PHOTOMETRIC_MINISWHITE, bitspersample);
                currPtr -= format*w;
            }
            break;

        case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_CONTIG):
        case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_SEPARATE):

            if (TIFFGetField(in, TIFFTAG_COLORMAP, &red, &green, &blue) != 1)
            {
                tifferror = ERR_READ;
                break;
            }

            /* */
            /* Convert 16-bit colormap to 8-bit (unless it looks */
            /* like an old-style 8-bit colormap). */
            /* */
            if (!tifferror && bitspersample!=32 && checkcmap(1<<bitspersample, red, green, blue) == 16)
            {
                int i;
                for (i = (1<<bitspersample)-1; i >= 0; i--)
                {
                    red[i] = CVT(red[i]);
                    green[i] = CVT(green[i]);
                    blue[i] = CVT(blue[i]);
                }
            }

            inbuf = new unsigned char [TIFFScanlineSize(in)];
            for (row = 0; row < h; row++)
            {
                if (TIFFReadScanline(in, inbuf, row, 0) < 0)
                {
                    tifferror = ERR_READ;
                    break;
                }
                remap_row(currPtr, inbuf, w, red, green, blue);
                currPtr -= format*w;
            }
            break;

        case pack(PHOTOMETRIC_RGB, PLANARCONFIG_CONTIG):
            inbuf = new unsigned char [TIFFScanlineSize(in)];
            for (row = 0; row < h; row++)
            {
                if (TIFFReadScanline(in, inbuf, row, 0) < 0)
                {
                    tifferror = ERR_READ;
                    break;
                }
                memcpy(currPtr, inbuf, format*w);
                currPtr -= format*w;
            }
            break;

        case pack(PHOTOMETRIC_RGB, PLANARCONFIG_SEPARATE):
            rowsize = TIFFScanlineSize(in);
            inbuf = new unsigned char [format*rowsize];
            for (row = 0; !tifferror && row < h; row++)
            {
                int s;
                for (s = 0; s < format; s++)
                {
                    if (TIFFReadScanline(in, (tdata_t)(inbuf+s*rowsize), (uint32)row, (tsample_t)s) < 0)
                    {
                        tifferror = ERR_READ; break;
                    }
                }
                if (!tifferror)
                {
                    if (format==3) interleave_row(currPtr, inbuf, inbuf+rowsize, inbuf+2*rowsize, w, format, bitspersample);
                    else if (format==4) interleave_row(currPtr, inbuf, inbuf+rowsize, inbuf+2*rowsize, inbuf+3*rowsize, w, format, bitspersample);
                    currPtr -= format*w;
                }
            }
            break;
        default:
            tifferror = ERR_UNSUPPORTED;
            break;
    }

    if (inbuf) delete [] inbuf;
    TIFFClose(in);

    if (tifferror)
    {
        if (buffer) delete [] buffer;
        return NULL;
    }
    width_ret = width;
    height_ret = height;
    if (photometric == PHOTOMETRIC_PALETTE)
        numComponents_ret = format;
    else
        numComponents_ret = samplesperpixel;

    return buffer;
}


#undef CVT
#undef pack

class ReaderWriterTIFF : public osgDB::ReaderWriter
{
    public:

        ReaderWriterTIFF()
        {
            supportsExtension("tiff","Tiff image format");
            supportsExtension("tif","Tiff image format");
        }

        virtual const char* className() const { return "TIFF Image Reader"; }
        virtual bool acceptsExtension(const std::string& extension) const
        {
            if( osgDB::equalCaseInsensitive(extension,"tiff")) return true;
            if( osgDB::equalCaseInsensitive(extension,"tif") ) return true;
            return false;
        }

        ReadResult readTIFStream(std::istream& fin) const
        {
            unsigned char *imageData = NULL;
            int width_ret = -1;
            int height_ret = -1;
            int numComponents_ret = -1;
            uint16 bitspersample_ret = 0;

            imageData = simage_tiff_load(fin, width_ret, height_ret, numComponents_ret, bitspersample_ret);

            if (imageData==NULL)
            {
                char err_msg[256];
                simage_tiff_error( err_msg, sizeof(err_msg));
                OSG_WARN << err_msg << std::endl;
                return ReadResult::FILE_NOT_HANDLED;
            }

            int s = width_ret;
            int t = height_ret;
            int r = 1;

            int internalFormat = numComponents_ret;

            unsigned int pixelFormat =
                numComponents_ret == 1 ? GL_LUMINANCE :
                numComponents_ret == 2 ? GL_LUMINANCE_ALPHA :
                numComponents_ret == 3 ? GL_RGB :
                numComponents_ret == 4 ? GL_RGBA : (GLenum)-1;


            unsigned int dataType =
                bitspersample_ret == 8 ? GL_UNSIGNED_BYTE :
                bitspersample_ret == 16 ? GL_UNSIGNED_SHORT :
                bitspersample_ret == 32 ? GL_FLOAT : (GLenum)-1;

            osg::Image* pOsgImage = new osg::Image;
            pOsgImage->setImage(s,t,r,
                internalFormat,
                pixelFormat,
                dataType,
                imageData,
                osg::Image::USE_NEW_DELETE);

            return pOsgImage;
        }

        WriteResult::WriteStatus writeTIFStream(std::ostream& fout, const osg::Image& img, const osgDB::ReaderWriter::Options* options) const
        {
            int compressionType = COMPRESSION_PACKBITS;
            if (options) {
                std::istringstream iss(options->getOptionString());
                std::string opt;
                while (iss >> opt) {
                    opt = osgDB::convertToLowerCase(opt);

                    std::size_t eqInd = opt.find("=");
                    if (opt.substr(0, eqInd) == "tiff_compression") {
                        std::string compressTypeOpt;
                        compressTypeOpt = opt.substr(eqInd + 1);
                        compressTypeOpt = osgDB::convertToLowerCase(compressTypeOpt);
                        if (compressTypeOpt == "packbits") {
                            compressionType = COMPRESSION_PACKBITS;
                        }
                        else if (compressTypeOpt == "lzw") {
                            compressionType = COMPRESSION_LZW;
                        }
                        else if (compressTypeOpt == "jpeg") {
                            compressionType = COMPRESSION_JPEG;
                        }
                        else if (compressTypeOpt == "none") {
                            compressionType = COMPRESSION_NONE;
                        }
                    }
                }
            }


            //Code is based from the following article on CodeProject.com
            //http://www.codeproject.com/bitmap/BitmapsToTiffs.asp

            TIFF *image;
            int samplesPerPixel;
            int bitsPerSample;
            uint16 photometric;

            image = TIFFClientOpen("outputstream", "w", (thandle_t)&fout,
                                    libtiffOStreamReadProc, //Custom read function
                                    libtiffOStreamWriteProc, //Custom write function
                                    libtiffOStreamSeekProc, //Custom seek function
                                    libtiffStreamCloseProc, //Custom close function
                                    libtiffOStreamSizeProc, //Custom size function
                                    libtiffStreamMapProc, //Custom map function
                                    libtiffStreamUnmapProc); //Custom unmap function

            if(image == NULL)
            {
                return WriteResult::ERROR_IN_WRITING_FILE;
            }

            switch(img.getPixelFormat()) {
                case GL_DEPTH_COMPONENT:
                case GL_LUMINANCE:
                case GL_ALPHA:
                case GL_RED:
                    photometric = PHOTOMETRIC_MINISBLACK;
                    samplesPerPixel = 1;
                    break;
                case GL_LUMINANCE_ALPHA:
                case GL_RG:
                    photometric = PHOTOMETRIC_MINISBLACK;
                    samplesPerPixel = 2;
                    break;
                case GL_RGB:
                    photometric = PHOTOMETRIC_RGB;
                    samplesPerPixel = 3;
                    break;
                case GL_RGBA:
                    photometric = PHOTOMETRIC_RGB;
                    samplesPerPixel = 4;
                    break;
                default:
                    return WriteResult::ERROR_IN_WRITING_FILE;
                    break;
            }

            uint32 rowsperstrip = 0;

            switch(img.getDataType()){
                case GL_FLOAT:
                    TIFFSetField(image, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
                    rowsperstrip = 1;
                    bitsPerSample = 32;
                    break;
                case GL_SHORT:
                    TIFFSetField(image, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT);
                    bitsPerSample = 16;
                    break;
                case GL_UNSIGNED_SHORT:
                    TIFFSetField(image, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
                    bitsPerSample = 16;
                    break;
                default:
                    bitsPerSample = 8;
                    break;
            }

            TIFFSetField(image, TIFFTAG_IMAGEWIDTH,img.s());
            TIFFSetField(image, TIFFTAG_IMAGELENGTH,img.t());
            TIFFSetField(image, TIFFTAG_BITSPERSAMPLE,bitsPerSample);
            TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL,samplesPerPixel);
            TIFFSetField(image, TIFFTAG_PHOTOMETRIC, photometric);
            TIFFSetField(image, TIFFTAG_COMPRESSION, compressionType);
            TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
            TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);

            if (rowsperstrip==0) rowsperstrip = TIFFDefaultStripSize(image, 0);
            TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, rowsperstrip);

            // Write the information to the file
            for(int i = 0; i < img.t(); ++i) {
                TIFFWriteScanline(image,(tdata_t)img.data(0,img.t()-i-1),i,0);
            }

            // Close the file
            TIFFClose(image);

            return WriteResult::FILE_SAVED;
        }

        virtual ReadResult readObject(std::istream& fin,const osgDB::ReaderWriter::Options* options =NULL) const
        {
            return readImage(fin, options);
        }

        virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const
        {
            return readImage(file, options);
        }

        virtual ReadResult readImage(std::istream& fin,const osgDB::ReaderWriter::Options* =NULL) const
        {
            return readTIFStream(fin);
        }

        virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
        {
            std::string ext = osgDB::getLowerCaseFileExtension(file);
            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

            std::string fileName = osgDB::findDataFile( file, options );
            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;

            osgDB::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary);
            if(!istream) return ReadResult::FILE_NOT_HANDLED;
            ReadResult rr = readTIFStream(istream);
            if(rr.validImage()) rr.getImage()->setFileName(file);
            return rr;
        }

        virtual WriteResult writeImage(const osg::Image& img,std::ostream& fout,const osgDB::ReaderWriter::Options* options) const
        {
            WriteResult::WriteStatus ws = writeTIFStream(fout,img, options);
            return ws;
        }

        virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options *options) const
        {
            std::string ext = osgDB::getFileExtension(fileName);
            if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;

            osgDB::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary);
            if(!fout) return WriteResult::ERROR_IN_WRITING_FILE;

            return writeImage(img,fout,options);
        }
};

// now register with Registry to instantiate the above
// reader/writer.
REGISTER_OSGPLUGIN(tiff, ReaderWriterTIFF)
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to