- Main Page
- Related Pages
- Modules
- Classes
- Examples

# iffPpmCmd.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.
    // ==========================================================================
    //+

    #include <maya/MPxCommand.h>
    #include <maya/MIOStream.h>
    #include <maya/MStatus.h>
    #include <maya/MArgList.h>
    #include <maya/MFnPlugin.h>
    #include <maya/MObject.h>
    #include <maya/MGlobal.h>
    #include <maya/MString.h>
    #include <maya/MPoint.h>
    #include <float.h>
    #include "iffreader.h"
    #include <maya/MFStream.h>
    #if defined (OSMac_)
    using namespace std;
    #endif

    #define IFFCHECKERR(stat, call) \
    if (!stat) { \
        MString string = reader.errorString(); \
        string += " in method "; \
        string += #call; \
        displayError (string); \
        return MS::kFailure; \
    }

    class iffPpm : public MPxCommand
    {
    public:
                    iffPpm();
        virtual     ~iffPpm();

        MStatus     doIt ( const MArgList& args );
        MStatus     redoIt ();
        MStatus     undoIt ();
        bool        isUndoable() const;

        static      void* creator();

    private:
        MString     ppmFile;
        MString     fileName;
        bool        useDepth;
    };

    iffPpm::iffPpm()
    {
    }

    iffPpm::~iffPpm() {}

    void* iffPpm::creator()
    {
        return new iffPpm;
    }

    bool iffPpm::isUndoable() const
    {
        return true;
    }

    MStatus iffPpm::undoIt()
    {
        return MS::kSuccess;
    }

    MString itoa (int n)
    {
        char buffer [256];
        sprintf (buffer, "%d", n);
        return MString (buffer);
    }

    MStatus iffPpm::doIt( const MArgList& args )
    {
        MString componentName;
        if (args.length () < 2 || args.length () > 3) {
            displayError ("Syntax: iffPpm ifffile ppmfile [-depth]");
            return MS::kFailure;
        }

        args.get (0, fileName);
        args.get (1, ppmFile);
        if (args.length () == 3)
        {
            MString lastArg;
            args.get (2, lastArg);
            if (lastArg != MString ("-depth")) {
                displayError ("Syntax: iffPpm ifffile ppmfile [-depth]");
                return MS::kFailure;
            }
            useDepth = true;
        }
        else
            useDepth = false;

        return redoIt();
    }

    MStatus iffPpm::redoIt()
    {
        clearResult();

        IFFimageReader reader;
        MStatus stat;

        stat = reader.open (fileName);
        IFFCHECKERR (stat, open);

        int imageWidth,imageHeight,bytesPerChannel;
        stat = reader.getSize (imageWidth,imageHeight);
        IFFCHECKERR (stat, getSize);

        bytesPerChannel = reader.getBytesPerChannel ();

        stat = reader.readImage ();
        IFFCHECKERR (stat, readImage);

        ofstream out (ppmFile.asChar ());
        if (!out.good ())
        {
            displayError ("Could not create output file");
            return MS::kFailure;
        }
        out << "P3" << endl << imageWidth << " " << imageHeight << endl;
        if (useDepth) {
            if (!reader.hasDepthMap ()) {
                displayError ("Image has no depth map");
                return MS::kFailure;
            }

            // Step 1: calculate the range of depth values in the data.
            // We'll normalize against this range.
            float minDepth=FLT_MAX, maxDepth=(-FLT_MAX);

            const float *depthMap = reader.getDepthMap ();
            for(int index=0; index<imageWidth*imageHeight; index++)
            {
                float depth=depthMap[index];
                if (depth!=0.) // 0 values indicate nothing there
                {
                    float realDepth= -1.0f/depth;
                    if (realDepth<minDepth)
                        minDepth=realDepth;
                    if (realDepth>maxDepth)
                        maxDepth=realDepth;
                }
            }

            // Step 2: output data, normalizing to 0-255

            out << "255" << endl;
            float scaleFactor = (float) (255.0 / ((double)maxDepth - (double)minDepth));
            float offset = minDepth * scaleFactor;

            const float *entry = depthMap;

            for(int y=0; y < imageHeight; y++)
                for(int x=0; x < imageWidth; x++, entry++)
                {
                    if (*entry == 0.)
                        out << "0 0 0" << endl;
                    else {
                        float realDepth = -scaleFactor / *entry - offset;
                        out << (int)realDepth << " " << (int)realDepth << " " <<
                            (int) realDepth << endl;
                    }
                }
        } else {
            if (!reader.isRGB () && !reader.isGrayscale ()) {
                displayError ("Image has no RGB data");
                return MS::kFailure;
            }
            if (bytesPerChannel==1)
                out << "255" << endl;
            else
                out << "65535" << endl;
            const byte *bitmap = reader.getPixelMap ();
            const byte *pixel = bitmap;
            int bytesPerPixel = (bytesPerChannel == 1) ? 4 : 8;
            for(int y=0; y < imageHeight; y++)
                for(int x=0; x < imageWidth; x++, pixel += bytesPerPixel)
                {
                    // Note that if the image was greyscale then the ILload
                    // function will have expanded the grey into rgb now.

                    //
                    if (bytesPerChannel==1)
                    {
    #if defined(_WIN32) || defined(LINUX)
                        // The actual internal storage on NT is BGRA
                        out << (int)pixel[2] << " " <<
                            (int)pixel[1] << " " <<
                            (int)pixel[0] << endl;
    #else
                        // The actual internal storage on IRIX is ABGR
                        out << (int)pixel[3] << " " <<
                            (int)pixel[2] << " " <<
                            (int)pixel[1] << endl;
    #endif
                    }
                    else // 16 bit
                    {
    #if defined(_WIN32) || defined(LINUX)
                        out << ((int)pixel[4]<<8)+(int)pixel[5] << " "
                            << ((int)pixel[2]<<8)+(int)pixel[3] << " "
                            << ((int)pixel[0]<<8)+(int)pixel[1] << endl;
    #else
                        out << ((int)pixel[6]<<8)+(int)pixel[7] << " "
                            << ((int)pixel[4]<<8)+(int)pixel[5] << " "
                            << ((int)pixel[2]<<8)+(int)pixel[3] << endl;
    #endif
                    }
                }
        }

        IFFCHECKERR (stat, getPixel);

        stat = reader.close ();
        IFFCHECKERR (stat, close);

        return MS::kSuccess;
    }

    MStatus initializePlugin( MObject obj )
    {
        MStatus status;
        MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any");
        status = plugin.registerCommand( "iffPpm", iffPpm::creator );

        if (!status)
            status.perror("registerCommand");

        return status;
    }

    MStatus uninitializePlugin( MObject obj )
    {
        MStatus status;
        MFnPlugin plugin( obj );
        status = plugin.deregisterCommand( "iffPpm" );

        if (!status)
            status.perror("deregisterCommand");

        return status;
    }