Hi Robert,

attached is a patch to src/osgPlugins/quicktime/QTImportExport.cpp that fixes loading images using the quicktime loader. Also fixes some minor bugs like uninitialized variables and incorrect deletes.

I'm a bit puzzled why this didn't pop up for more people as it's quite severe: basically the filename was never set!

Cheers!
/ulrich
Index: src/osgPlugins/quicktime/QTImportExport.cpp
===================================================================
--- src/osgPlugins/quicktime/QTImportExport.cpp (revision 8710)
+++ src/osgPlugins/quicktime/QTImportExport.cpp (working copy)
@@ -247,10 +247,11 @@
  
      // Convert From CString in filename to a PascalString in pstr
      if (filename.length() > 255) {
-         CopyCStringToPascal(filename.c_str(), pstr);
          //hmm...not good, pascal string limit is 255!
          //do some error handling maybe?!
+         throw QTImportExportException(0, "filename length limit exceeded");
      }
+     CopyCStringToPascal(filename.c_str(), pstr);
  
     // Add filename extension
      /*err = */PtrToHand(pstr, &fileNameHandle, filename.length() + 1);
@@ -282,7 +283,7 @@
     ImageDescriptionHandle desc = 0;
     int depth = 32;
     unsigned int xsize, ysize;
-    unsigned char* imageData;
+    unsigned char* imageData = 0;
     
     // Data Handle for file data ( & load data from file )
     Handle dataRef = getPtrDataRef(data, sizeData, fileTypeHint);
@@ -359,7 +360,7 @@
         DisposeHandle(reinterpret_cast<char **>(desc));
         DisposeHandle(dataRef);
     } 
-    catch (QTImportExportException e) 
+    catch (QTImportExportException& e) 
     {
         setError(e.what());
         
@@ -383,9 +384,9 @@
     
 
     
+    unsigned int bytesPerPixel = depth / 8;
     unsigned int glpixelFormat;
-            
-    switch(depth >> 3) {
+    switch(bytesPerPixel) {
         case 3 :
             glpixelFormat = GL_RGB;
             break;
@@ -393,20 +394,20 @@
             glpixelFormat = GL_RGBA;
             break;
         default :
-            delete imageData;
+            delete[] imageData;
             setError("unknown pixelformat");
             return NULL;
             break;
     }
     
-    unsigned char* swizzled = pepareBufferForOSG(imageData, depth >> 3, xsize, 
ysize);
+    unsigned char* swizzled = pepareBufferForOSG(imageData, bytesPerPixel, 
xsize, ysize);
     
     delete[] imageData;
  
     osg::Image* image = new osg::Image();
     image->setFileName(fileTypeHint.c_str());
     image->setImage(xsize,ysize,1,
-        depth >> 3,
+        bytesPerPixel,
         glpixelFormat,
         GL_UNSIGNED_BYTE,
         swizzled,
@@ -510,7 +511,7 @@
     }
     
     
-    catch (QTImportExportException e) 
+    catch (QTImportExportException& e) 
     {
         setError(e.what());
         
/*
 *  QTImportExport.cpp
 *  cefix
 *
 *  Created by Stephan Huber on 07.02.08.
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
 *
 */
#include <map>
#include <sstream>
#include "QTImportExport.h"
#include "QTUtils.h"

#include <osgDB/FileNameUtils>


/** small exception class bundling a error-message */
class QTImportExportException : public std::exception {

    public:
        QTImportExportException(int err, const std::string& msg) : 
std::exception(), _err(err), _msg(msg) {}
        
        virtual const char* what() { return _msg.c_str(); }
        int getErrorCode() { return _err; }
        
        virtual ~QTImportExportException() throw () {}
        
    private:
        int _err;
        std::string _msg;
};

QuicktimeImportExport::QuicktimeImportExport() 
:    _error(0), 
    _lastError("")
{
    initQuicktime();
}


// 
----------------------------------------------------------------------------------------------------------
// flipImage
// 
----------------------------------------------------------------------------------------------------------

void QuicktimeImportExport::flipImage(unsigned char* pixels, int bytesPerPixel, 
unsigned int width, unsigned height) 
{
    // Flip the image
    unsigned imageSize = width * height * bytesPerPixel;
    char *tBuffer = new char [imageSize];
    unsigned int rowBytes = width * bytesPerPixel;
    unsigned int i,j;
    for (i = 0, j = imageSize - rowBytes; i < imageSize; i += rowBytes, j -= 
rowBytes)
        memcpy( &tBuffer[j], &pixels[i], (size_t)rowBytes );

    memcpy(pixels, tBuffer, (size_t)imageSize);
    delete[] tBuffer;
}




// 
----------------------------------------------------------------------------------------------------------
// prepareBufferForOSG
// 
----------------------------------------------------------------------------------------------------------

unsigned char* QuicktimeImportExport::pepareBufferForOSG(unsigned char * 
buffer, int bytesPerPixel, unsigned int width, unsigned int height)
{
    unsigned char *pixels = new unsigned char [height * width * 4];
    unsigned char *dstp = pixels;
    unsigned char *srcp = buffer;
    unsigned int i, j;
    
    int roffset, goffset, boffset, aoffset;
    aoffset = -1;
    int sourceStep;
    
    switch (bytesPerPixel) {
        case 1:
            sourceStep = 1;
            roffset = goffset = boffset = 0;
            break;
        case 3:
            sourceStep = 3;
            roffset = 0;
            goffset = 1;
            boffset = 2;
            break;
        case 4:
            sourceStep = 4;
            aoffset = 1;
            roffset = 2;
            goffset = 3;
            boffset = 0;
            break;
            
    }
                    
    for (i = 0; i < height; ++i ) 
    {
        for (j = 0; j < width; ++j ) 
        {
            dstp[0] = (aoffset < 0) ? 0 : srcp[aoffset];
            dstp[1] = srcp[roffset];
            dstp[2] = srcp[goffset];
            dstp[3] = srcp[boffset];
            srcp+=sourceStep;
            dstp+=4;
            
        }
    }
    
    flipImage(pixels, bytesPerPixel, width, height);
    return pixels;

}



// 
----------------------------------------------------------------------------------------------------------
// prepareBufferForQuicktime
// 
----------------------------------------------------------------------------------------------------------

unsigned char* QuicktimeImportExport::prepareBufferForQuicktime(unsigned char* 
buffer, GLenum pixelFormat, int bytesPerPixel, unsigned int width, unsigned int 
height) 
{
    unsigned char *pixels = new unsigned char [height * width * 4];
    unsigned char *dstp = pixels;
    unsigned char *srcp = buffer;
    unsigned int i, j;
    
    int roffset, goffset, boffset, aoffset;
    aoffset = -1;
    int sourceStep;
    
    switch (bytesPerPixel) {
        case 1:
            sourceStep = 1;
            roffset = goffset = boffset = 0;
            break;
        case 3:
            sourceStep = 3;
            roffset = 0;
            goffset = 1;
            boffset = 2;
            break;
        case 4:
            sourceStep = 4;
            switch (pixelFormat) {
                case GL_RGBA:
                    aoffset = 3;
                    roffset = 0;
                    goffset = 1;
                    boffset = 2;
                    break;
                
                case GL_BGRA_EXT:
                    aoffset = 0;
                    roffset = 1;
                    goffset = 2;
                    boffset = 3;
                    break;
            }
    }
                    
            
    for (i = 0; i < height; ++i ) 
    {
        for (j = 0; j < width; ++j ) 
        {
            dstp[0] = (aoffset < 0) ? 0 : srcp[aoffset];
            dstp[1] = srcp[roffset];
            dstp[2] = srcp[goffset];
            dstp[3] = srcp[boffset];
            srcp+=sourceStep;
            dstp+=4;
            
        }
    }
    
    flipImage(pixels, 4, width, height);
    
    return pixels;

}

// 
----------------------------------------------------------------------------------------------------------
// readFromStream
// 
----------------------------------------------------------------------------------------------------------

osg::Image* QuicktimeImportExport::readFromStream(std::istream & inStream, 
const std::string& fileTypeHint, long sizeHint) 
{
    char* content = NULL;
    long length = 0;
     if (sizeHint != 0) 
    {
        length = sizeHint;
        content = new char[length];
        inStream.read (content,length);
    }
    else 
    {
        int readBytes(0), newBytes(0);
        
        char buffer[10240];
        
        while (!inStream.eof()) {
            inStream.read(buffer, 10240);
            newBytes = inStream.gcount();
            if (newBytes > 0) {
                char* newcontent = new char[readBytes + newBytes];
            
                if (readBytes > 0)
                    memcpy(newcontent, content, readBytes);
                
                memcpy(&newcontent[readBytes], &buffer, newBytes);
                readBytes += newBytes;
                if (content) delete[] content;
                content = newcontent;
            }
        }
        length = readBytes;
    }
    
    osg::Image* img = doImport(reinterpret_cast<unsigned char*>(content), 
length, fileTypeHint);
    
    if (content) delete[] content;
    return img;
 }
 
 
Handle getPtrDataRef(unsigned char *data, unsigned int size, const std::string 
&filename)
{
     // Load Data Reference
     Handle dataRef;
     Handle fileNameHandle;
     PointerDataRefRecord ptrDataRefRec;
     ComponentInstance dataRefHandler;
     unsigned char pstr[255];
 
     ptrDataRefRec.data = data;
     ptrDataRefRec.dataLength = size;
 
     /*err = */PtrToHand(&ptrDataRefRec, &dataRef, 
sizeof(PointerDataRefRecord));
 
     // Open a Data Handler for the Data Reference
     /*err = */OpenADataHandler(dataRef, PointerDataHandlerSubType, NULL,
         (OSType)0, NULL, kDataHCanRead, &dataRefHandler);
 
     // Convert From CString in filename to a PascalString in pstr
     if (filename.length() > 255) {
         //hmm...not good, pascal string limit is 255!
         //do some error handling maybe?!
         throw QTImportExportException(0, "filename length limit exceeded");
     }
     CopyCStringToPascal(filename.c_str(), pstr);
 
    // Add filename extension
     /*err = */PtrToHand(pstr, &fileNameHandle, filename.length() + 1);
     /*err = */DataHSetDataRefExtension(dataRefHandler, fileNameHandle,
         kDataRefExtensionFileName);
     DisposeHandle(fileNameHandle);
 
     // Release old handler which does not have the extensions
     DisposeHandle(dataRef);
 
     // Grab the SAFE_NEW version of the data ref from the data handler
     /*err = */ DataHGetDataRef(dataRefHandler, &dataRef);
     
     CloseComponent(dataRefHandler);
     
     return dataRef;
}


osg::Image* QuicktimeImportExport::doImport(unsigned char* data, unsigned int 
sizeData, const std::string& fileTypeHint)
{
    GWorldPtr gworld = 0;
    OSType pixelFormat;
    int rowStride;
    GraphicsImportComponent gicomp = 0;
    Rect rectImage;
    GDHandle origDevice = 0;
    CGrafPtr origPort = 0;
    ImageDescriptionHandle desc = 0;
    int depth = 32;
    unsigned int xsize, ysize;
    unsigned char* imageData = 0;
    
    // Data Handle for file data ( & load data from file )
    Handle dataRef = getPtrDataRef(data, sizeData, fileTypeHint);
    
    try {
        OSErr err = noErr;
        
        // GraphicsImporter - Get Importer for our filetype
        GetGraphicsImporterForDataRef(dataRef, 'ptr ', &gicomp);

        // GWorld - Get Texture Info
        err = GraphicsImportGetNaturalBounds(gicomp, &rectImage);
        if (err != noErr) {
            throw QTImportExportException(err, "GraphicsImportGetNaturalBounds 
failed");
            
        }
        xsize = (unsigned int)(rectImage.right - rectImage.left);
        ysize = (unsigned int)(rectImage.bottom - rectImage.top);

        // ImageDescription - Get Image Description
        err = GraphicsImportGetImageDescription(gicomp, &desc);
        if (err != noErr) {
            throw QTImportExportException(err, 
"GraphicsImportGetImageDescription failed");
        }

        // ImageDescription - Get Bit Depth
        HLock(reinterpret_cast<char **>(desc));
        

        // GWorld - Pixel Format stuff
        pixelFormat = k32ARGBPixelFormat; // Make sure its forced...NOTE: i'm 
pretty sure this cannot be RGBA!

        // GWorld - Row stride
        rowStride = xsize * 4; // (width * depth_bpp / 8)

        // GWorld - Allocate output buffer
        imageData = new unsigned char[rowStride * ysize];

        // GWorld - Actually Create IT!
        QTNewGWorldFromPtr(&gworld, pixelFormat, &rectImage, 0, 0, 0, 
imageData, rowStride);
        if (!gworld) {
            throw QTImportExportException(-1, "QTNewGWorldFromPtr failed");
        }

        // Save old Graphics Device and Graphics Port to reset to later
        GetGWorld (&origPort, &origDevice);

        // GraphicsImporter - Set Destination GWorld (our buffer)
        err = GraphicsImportSetGWorld(gicomp, gworld, 0);
        if (err != noErr) {
            throw QTImportExportException(err, "GraphicsImportSetGWorld 
failed");
        }

        // GraphicsImporter - Set Quality Level
        err = GraphicsImportSetQuality(gicomp, codecLosslessQuality);
        if (err != noErr) {
            throw QTImportExportException(err, "GraphicsImportSetQuality 
failed");
        }

        // Lock pixels so that we can draw to our memory texture
        if (!GetGWorldPixMap(gworld) || !LockPixels(GetGWorldPixMap(gworld))) {
            throw QTImportExportException(0, "GetGWorldPixMap failed");
        }
        
           
        //*** Draw GWorld into our Memory Texture!
        GraphicsImportDraw(gicomp);
 
        // Clean up
        UnlockPixels(GetGWorldPixMap(gworld));
        SetGWorld(origPort, origDevice); // set graphics port to offscreen (we 
don't need it now)
        DisposeGWorld(gworld);
        CloseComponent(gicomp);
        DisposeHandle(reinterpret_cast<char **>(desc));
        DisposeHandle(dataRef);
    } 
    catch (QTImportExportException& e) 
    {
        setError(e.what());
        
        if (gworld) {
            UnlockPixels(GetGWorldPixMap(gworld));
            SetGWorld(origPort, origDevice); // set graphics port to offscreen 
(we don't need it now)
            DisposeGWorld(gworld);
        }
        if (gicomp)
            CloseComponent(gicomp);
        if (desc) 
            DisposeHandle(reinterpret_cast<char **>(desc));
        
        if (imageData) 
            delete[] imageData;
        if (dataRef)
            DisposeHandle(dataRef);
            
        return NULL;
    }
    

    
    unsigned int bytesPerPixel = depth / 8;
    unsigned int glpixelFormat;
    switch(bytesPerPixel) {
        case 3 :
            glpixelFormat = GL_RGB;
            break;
        case 4 :
            glpixelFormat = GL_RGBA;
            break;
        default :
            delete[] imageData;
            setError("unknown pixelformat");
            return NULL;
            break;
    }
    
    unsigned char* swizzled = pepareBufferForOSG(imageData, bytesPerPixel, 
xsize, ysize);
    
    delete[] imageData;
 
    osg::Image* image = new osg::Image();
    image->setFileName(fileTypeHint.c_str());
    image->setImage(xsize,ysize,1,
        bytesPerPixel,
        glpixelFormat,
        GL_UNSIGNED_BYTE,
        swizzled,
        osg::Image::USE_NEW_DELETE );
    
 
    return image;
}


 void QuicktimeImportExport::writeToStream(std::ostream& outStream, osg::Image* 
image, const std::string& fileTypeHint) 
 {

    std::string ext = osgDB::getFileExtension(fileTypeHint);
    //Build map  of extension <-> osFileTypes
    static std::map<std::string, OSType> extmap;
    if (extmap.size() == 0) {
        extmap["jpg"]  = kQTFileTypeJPEG;
        extmap["jpeg"] = kQTFileTypeJPEG;
        extmap["bmp"]  = kQTFileTypeBMP;
        extmap["tif"]  = kQTFileTypeTIFF;
        extmap["tiff"] = kQTFileTypeTIFF;
        extmap["png"]  = kQTFileTypePNG;
        extmap["gif"]  = kQTFileTypeGIF;
        extmap["psd"]  = kQTFileTypePhotoShop;
        extmap["sgi"]  = kQTFileTypeSGIImage;
        extmap["rgb"]  = kQTFileTypeSGIImage;
        extmap["rgba"] = kQTFileTypeSGIImage;
    }

    
    std::map<std::string, OSType>::iterator cur = extmap.find(ext);
    
    // can not handle this type of file, perhaps a movie?
    if (cur == extmap.end())
        return;
    
    unsigned int numBytes = 
image->computeNumComponents(image->getPixelFormat());
    unsigned char* pixels = prepareBufferForQuicktime(
        image->data(),
        image->getPixelFormat(), 
        numBytes,
        image->s(),
        image->t()
    );
    
        
    OSType desiredType = cur->second;
    GraphicsExportComponent geComp = NULL;
    GWorldPtr gw = 0;
    Handle dataHandle;
    dataHandle = NewHandle(0);

    try {
        OSErr err = OpenADefaultComponent(GraphicsExporterComponentType, 
desiredType, &geComp);
        Rect bounds = {0,0, image->t(), image->s()};
        
        err = QTNewGWorldFromPtr(&gw, k32ARGBPixelFormat, &bounds, 0,0,0, 
pixels, image->s()*4);
        if (err != noErr) {
            throw QTImportExportException(err,  "could not create gworld for 
type " + ext);
        }
        
        err = GraphicsExportSetInputGWorld(geComp, gw);
        if (err != noErr) {
            throw QTImportExportException(err, "could not set input gworld for 
type " + ext);
        }
        
        err = GraphicsExportSetOutputHandle( geComp, dataHandle);
        if (err != noErr) {
            throw QTImportExportException(err, "could not set output file for 
type " + ext);
        } 
        
        // Set the compression quality (needed for JPEG, not necessarily for 
other formats)
        if (desiredType == kQTFileTypeJPEG) {
            err = GraphicsExportSetCompressionQuality(geComp, 
codecLosslessQuality);
            if (err != noErr) {
                throw QTImportExportException(err, "could not set compression 
for type " + ext);
            }
        }
        
        if(4 == numBytes)
        {
            err = GraphicsExportSetDepth( geComp, k32ARGBPixelFormat );    // 
depth
        }
        // else k24RGBPixelFormat???
        
        // do the export
        err = GraphicsExportDoExport(geComp, NULL);
        if (err != noErr) {
            throw QTImportExportException(err, "could not do the export for 
type " + ext);
        } 
        
        if (geComp != NULL)
            CloseComponent(geComp);
            
        if (gw) DisposeGWorld (gw);
        if (pixels) free(pixels);
        
        outStream.write(*dataHandle, GetHandleSize(dataHandle));
        DisposeHandle(dataHandle);
    }
    
    
    catch (QTImportExportException& e) 
    {
        setError(e.what());
        
        if (geComp != NULL) CloseComponent(geComp);      
        if (gw != NULL) DisposeGWorld (gw);
        if (pixels) free(pixels);
        
        DisposeHandle(dataHandle);

    }

}

_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to