tiffFloatReader.cpp

//-
// ==========================================================================
// Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk
// license agreement provided at the time of installation or download,
// or which otherwise accompanies this software in either electronic
// or hard copy form.
// ==========================================================================
//+

//
// DESCRIPTION: 
//  tiffFloatReader : Example floating point tif image file reader.
//

#include <maya/MPxImageFile.h>
#include <maya/MImageFileInfo.h>
#include <maya/MImage.h>
#include <maya/MFnPlugin.h>
#include <maya/MStringArray.h>
#include <maya/MIOStream.h>
#include <maya/MGlobal.h>

// #pragma warning( disable : 4290 )        // Disable STL warnings.

// Uncomment this to build with tif library
#define _TIFF_LIBRARY_AVAILABLE_
#if defined(_TIFF_LIBRARY_AVAILABLE_)
#include <tiff.h>
#include <tiffio.h>
#endif

MString kImagePluginName( "TIFF Float Reader");

#define _TIFF_SUCCESS   1

class tiffFloatReader : public MPxImageFile
{
public:
                    tiffFloatReader();
    virtual         ~tiffFloatReader();
    static void*    creator();
    virtual MStatus open( MString pathname, MImageFileInfo* info);
    virtual MStatus load( MImage& image, unsigned int idx);
    virtual MStatus close();

protected:
    unsigned int    fWidth;             // Width
    unsigned int    fHeight;            // Height
    unsigned int    fChannels;          // Number of channels

#if defined(_TIFF_LIBRARY_AVAILABLE_)
    TIFF            *fInputFile;        // Tif interface
#else
    void            *fInputFile;        
#endif
};

//
// DESCRIPTION:
tiffFloatReader::tiffFloatReader()
: fInputFile( NULL), 
  fChannels( 0), 
  fWidth(0),
  fHeight(0)
{

}

//
// DESCRIPTION:
//      Destructor : close the file if opened
tiffFloatReader::~tiffFloatReader()
{
    close();
}

//
// DESCRIPTION:
//      Create a new instance of the reader
void * tiffFloatReader::creator()
{
    return new tiffFloatReader();
}

//
// DESCRIPTION:
//      Open up the file for read. Return "info" if requested.
MStatus tiffFloatReader::open( MString pathname, MImageFileInfo* info)
{
#if defined(_TIFF_LIBRARY_AVAILABLE_)
    try
    {
        // Open the tif file for read
        // (TIFF *) cast from integer required on Mac.
        fInputFile = (TIFF *) TIFFOpen( pathname.asChar(), "r" );
    }
    catch( ... )
    {
    }

    if( !fInputFile)
    {
        return MS::kFailure;
    }

    unsigned short num_samps;
    unsigned short bitsPerChannel;
    unsigned short sampleType = 0;
    short config;

    if (_TIFF_SUCCESS != TIFFGetField(fInputFile, TIFFTAG_IMAGEWIDTH, &fWidth ) || 
        fWidth < 1)
        goto no_support;
    if (_TIFF_SUCCESS != TIFFGetField(fInputFile, TIFFTAG_IMAGELENGTH, &fHeight ) || 
        fHeight < 1)
        goto no_support;


    // Suport 3 and 4 channel images only
    if (_TIFF_SUCCESS != TIFFGetField(fInputFile, TIFFTAG_SAMPLESPERPIXEL, &num_samps))
        goto no_support;
    if ((num_samps != 3) && (num_samps!= 4))
        goto no_support;
    fChannels = num_samps;

    // This is more robust than TIFFTAG_SAMPLEFORMAT since it may not be supported
    // properly as it's an extension. 

    if (_TIFF_SUCCESS != TIFFGetField(fInputFile, TIFFTAG_BITSPERSAMPLE, &bitsPerChannel))
        goto no_support;
    if (bitsPerChannel != 32)
        goto no_support;

    // Check the sample type. We only care about 32 bit 
    // floating point samples for this reader.
    // SAMPLEFORMAT_IEEEFP is specified as IEEE floating point.
    if (_TIFF_SUCCESS != TIFFGetField(fInputFile, TIFFTAG_SAMPLEFORMAT, &sampleType) ||
        sampleType != SAMPLEFORMAT_IEEEFP)
    {
        goto no_support;
    }

    // See how the data is stored in the scan line. Only support
    // contiguous scan line for now.
    // - PLANARCONFIG_SEPARATE is not supported.
    if (_TIFF_SUCCESS != TIFFGetField(fInputFile, TIFFTAG_PLANARCONFIG, &config) ||
        (config != PLANARCONFIG_CONTIG))
    {
        goto no_support;
    }

    // Compression not supported yet.. 
#if 0
    unsigned short compression;
    if (_TIFF_SUCCESS != TIFFGetField(fInputFile, TIFFTAG_COMPRESSION, &compression) ||
        (compression != COMPRESSION_NONE))
    {
        goto no_support;
    }
#endif

    //printf("Opened tif file successfully: w=%d,h=%d, ch=%d\n",
    //  fWidth, fHeight, fChannels );

    if( info)
    {
        // Set up the info structure to return
        //
        info->width( fWidth );
        info->height( fHeight );
        info->channels( fChannels );
        info->numberOfImages( 1 );
        info->pixelType( MImage::kFloat);
    }
    return MS::kSuccess;

no_support:
    close();
    return MS::kFailure;
#else
    return MS::kFailure;
#endif
}

//
// DESCRIPTION:
//      Close any open file
/* virtual */
MStatus tiffFloatReader::close()
{
#if defined(_TIFF_LIBRARY_AVAILABLE_)
    if (fInputFile)
        TIFFClose( fInputFile );
    fInputFile = NULL;
    return MS::kSuccess;
#else
    return MS::kFailure;
#endif
}

//
// DESCRIPTION:
//      Load the image into system memory (MImage)
MStatus tiffFloatReader::load( MImage& image, unsigned int imageNumber)
{
    MStatus rval = MS::kFailure;
#if defined(_TIFF_LIBRARY_AVAILABLE_)
    if (!fInputFile)
        return rval;

    // Configure our Maya image to hold the result
    image.create( fWidth, fHeight, fChannels, MImage::kFloat);
    float* outputBuffer = image.floatPixels();
    if (outputBuffer == NULL)
        return rval;
    
    // Maya expects images upside down
    unsigned int row = 0;
    bool flipVertically = true;
    if (flipVertically)
    {
        outputBuffer += (fHeight-1) * (fWidth * fChannels);
        for (row = 0; row < fHeight; row++)
        {
            TIFFReadScanline (fInputFile, outputBuffer, row);
            outputBuffer -= (fWidth * fChannels);
        }
    }
    else
    {
        for (row = 0; row < fHeight; row++)
        {
            TIFFReadScanline (fInputFile, outputBuffer, row);
            outputBuffer += (fWidth * fChannels);
        }
    }
    rval = MS::kSuccess;
#endif
    return rval;
}


MStatus initializePlugin( MObject obj )
{
    MFnPlugin plugin( obj, PLUGIN_COMPANY, "8.0", "Any" );
    MStringArray extensions;
    extensions.append( "tif");
    CHECK_MSTATUS( plugin.registerImageFile( 
                    kImagePluginName,
                    tiffFloatReader::creator, 
                    extensions));
    
    return MS::kSuccess;
}

// DESCRIPTION:
MStatus uninitializePlugin( MObject obj )
{
    MFnPlugin plugin( obj );
    CHECK_MSTATUS( plugin.deregisterImageFile( kImagePluginName ) );

    return MS::kSuccess;
}