/*! \class QtMayaHandler \since 4.4 \brief The QtMayaHandler class provides support for the MAYA file format. \internal */ #include <windows.h> #include <process.h> #include "qmayahandler.h" #include <QtCore/qendian.h> #include <QtGui/QImage> #include <QtGui/QColor> #include <QtCore/QFile> #include <QtCore/QTextStream> #include <QtCore/QTemporaryFile> #include <QtCore/QBuffer> #include <QtCore/QDir> #include <QtGui/QMessageBox> #include <strsafe.h> #pragma pack( push ) #pragma pack( 1 ) struct TgaHeader { quint8 idLength; quint8 colorMapType; quint8 imageType; // color map specification quint16 firstEntryIndex; quint16 colorMapLength; quint8 colorMapEntrySize; // image specification quint16 xOrigin; quint16 yOrigin; quint16 width; quint16 height; quint8 depth; quint8 descriptor; }; struct TgaFooter { quint32 extAreaOffset; quint32 devDirOffset; quint8 signature[16]; quint8 resChar; quint8 zeroStr; }; class TgaReader { public: enum imageType{ UNKNOWN, GREYSCALE, COLOR_MAP, COLOR, GREYSCALE_RLE, COLOR_RLE, COLOR_MAP_RLE }; TgaReader ( const QString & fileName ); ~TgaReader (); QImage GetImage (); bool ReadHeader (); QImage Read24BitImage (); QImage Read32BitImage (); TgaFooter ftr; TgaHeader hdr; imageType type; qint32 alphaValue; bool newFormat; // flip image horizontally and/or vertically bool flipTopToBottom; bool flipLeftToRight; QFile * m_tgaFile; }; class MayaRenderer { public: MayaRenderer(); QImage RenderImage ( const QString & pathName, const QString & fileNameMaya ); static void GetMayaRenderPath ( QString & path ); static void GetMayaRenderArgs ( QString & args ); static bool canRead (); bool m_canRead; }; void ScottMessage( QString & message ) { wchar_t wstr[ 1024 ]; int len = message.toWCharArray( wstr ); wstr[ len ] = 0; ::MessageBox( NULL, wstr, TEXT("Scott Message"), 0 ); } TgaReader::TgaReader( const QString & fileName ) { m_tgaFile = new QFile( fileName ); m_tgaFile->open( QIODevice::ReadOnly ); } TgaReader::~TgaReader() { m_tgaFile->close(); m_tgaFile->remove(); delete m_tgaFile; } bool TgaReader::ReadHeader() { if( !m_tgaFile ) return 0; else { qint64 s = 0; m_tgaFile->seek( s ); if( m_tgaFile->read( ( char *)&hdr, sizeof( TgaHeader ) ) == sizeof( TgaHeader ) ) { return 1; } else { return 0; } } } QImage TgaReader::GetImage() { QImage img; if( !ReadHeader() ) return img; if( !( (hdr.depth == 32) || (hdr.depth == 24) ) ) return img; switch( hdr.imageType ) { case 2: type = COLOR; break; case 3: type = GREYSCALE; break; case 10: type = COLOR_RLE; break; case 11: type = GREYSCALE_RLE; break; default: return img; } if( type == UNKNOWN ) return img; quint8 mask = 15; // 00001111 alphaValue = hdr.descriptor & mask; if( alphaValue != 8 && alphaValue != 0 ) return img; // Fourth, figure out if we need to flip the image mask = 16; // 00010000 flipLeftToRight = hdr.descriptor & mask; mask = 32; // 00100000 flipTopToBottom = hdr.descriptor & mask; // Skip the image ID field qint64 o = m_tgaFile->pos() + hdr.idLength; m_tgaFile->seek( o ); // At the image data Woo Hoo!!!!! if( hdr.depth == 32 && type == COLOR ) { img = Read32BitImage(); } else if( hdr.depth == 24 && type == COLOR ) { img = Read24BitImage(); } return img; } QImage TgaReader::Read24BitImage() { // QT doesn't support 24 bit images, so we make a 32 bit image and read and write // the triplets to the QImage ourselves QImage img( hdr.width, hdr.height, QImage::Format_ARGB32 ); int h = hdr.height; uchar* buf = new uchar[hdr.width*3]; while (0 < --h) { if (m_tgaFile->read((char *)buf, hdr.width*3) != hdr.width*3) { img = QImage(); break; } for( int i = 0; i < hdr.width*3; i += 3 ) { QColor p( buf[i+2], buf[i+1], buf[i] ); img.setPixel( i/3, h, p.rgb() ); } } img = img.mirrored( flipLeftToRight, flipTopToBottom ); delete[] buf; return img; } QImage TgaReader::Read32BitImage() { QImage img( hdr.width, hdr.height, QImage::Format_ARGB32 ); int h = hdr.height; int bpl = img.bytesPerLine(); while (0 < --h) { if (m_tgaFile->read((char *)img.scanLine( h ), bpl) != bpl) { img = QImage(); break; } } img = img.mirrored( flipLeftToRight, flipTopToBottom ); return img; } MayaRenderer::MayaRenderer() { m_canRead = canRead(); } QImage MayaRenderer::RenderImage( const QString & pathName, const QString & fileNameMaya ) { QImage image; // Maya render exec QString renderPath; GetMayaRenderPath( renderPath ); // Convert to wide char for CreateProcess wchar_t command [ 512 ]; int commandLength = renderPath.toWCharArray( command ); command[ commandLength ] = 0; // Maya Render arguments QString preArgs = QString( "\"%1\"").arg( renderPath ); QString renderArgs; GetMayaRenderArgs( renderArgs ); QString postArgs = QString("-fnc 3 -of tga -rd %1 -im p4TgaImage %2").arg( pathName ).arg( fileNameMaya ); QString args = QString( "%1 %2 %3" ).arg( preArgs ).arg( renderArgs ).arg( postArgs ); // Convert to wide char for CreateProcess wchar_t commandArgs [ 2048 ]; int commandArgsLength = args.toWCharArray( commandArgs ); commandArgs[ commandArgsLength ] = 0; // Process info STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; ZeroMemory( &pi, sizeof(pi) ); if ( CreateProcess( command, commandArgs, NULL, NULL, false, 0, NULL, NULL, &si, &pi ) ) { // Wait until child process exits. WaitForSingleObject( pi.hProcess, INFINITE ); // Close process and thread handles. CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); QString tgaFileName = QString( "%1p4TgaImage.1.tga" ).arg( pathName ); // See if renderer succeeded if ( QFile::exists( tgaFileName ) ) { TgaReader reader( tgaFileName ); image = reader.GetImage(); } } return image; } void MayaRenderer::GetMayaRenderPath( QString & path ) { QFile mayaConfigFile(".\\plugins\\imageformats\\mayaconfig.ini"); if ( !mayaConfigFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) { return; } QTextStream in( &mayaConfigFile ); bool loop = true; while ( !in.atEnd() && loop ) { QString line = in.readLine(); if ( line.startsWith( "<MayaRender>", Qt::CaseInsensitive ) ) { while ( !in.atEnd() && loop ) { QString line2 = in.readLine(); if ( !( line2.startsWith( "#" ) || line2.startsWith( "//" ) || line2.isEmpty() ) ) { path = line2; loop = false; } } } } mayaConfigFile.close(); } void MayaRenderer::GetMayaRenderArgs( QString & args ) { QFile mayaConfigFile(".\\plugins\\imageformats\\mayaconfig.ini"); if ( !mayaConfigFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) { return; } QTextStream in( &mayaConfigFile ); bool loop = true; while ( !in.atEnd() && loop ) { QString line = in.readLine(); if ( line.startsWith( "<MayaRenderArgs>", Qt::CaseInsensitive ) ) { while ( !in.atEnd() && loop ) { QString line2 = in.readLine(); if ( line2.startsWith( "-" ) ) { args = line2; loop = false; } } } } mayaConfigFile.close(); } // static bool MayaRenderer::canRead() { bool canRead = false; QString path; GetMayaRenderPath( path ); canRead = QFile::exists( path ); return canRead; } /*! Constructs an instance of QtIcoHandler initialized to use \a device. */ QtMayaHandler::QtMayaHandler(QIODevice *device) { setDevice( device ); m_pMayaRenderer = new MayaRenderer(); } /*! Destructor for QtIcoHandler. */ QtMayaHandler::~QtMayaHandler() { delete m_pMayaRenderer; } /*! * Verifies if some values (magic bytes) are set as expected in the header of the file. * If the magic bytes were found, it is assumed that the QtMayaHandler can read the file. * */ bool QtMayaHandler::canRead() const { if ( canRead( device() ) ) { setFormat( "ma" ); return true; } return false; } bool QtMayaHandler::canRead( QIODevice * device ) { Q_ASSERT(device); if (!device) { qWarning( "QMayaHandler::canRead() called with no device" ); return false; } QByteArray header = device->peek( 12 ); bool mayaBinary = header.contains( "FOR4" ); // FOR4 (Maya binary) bool mayaAscii = header.contains( "//Maya ASCII" ); // Maya ASCII (Maya ascii) bool mayaRenderer = MayaRenderer::canRead(); return ( ( mayaBinary || mayaAscii ) && mayaRenderer ); } /*! \reimp */ bool QtMayaHandler::read( QImage * image ) { if ( !canRead() ) { return false; } bool bSuccess = false; QString tempDir = QString( "%1/" ).arg( QDir::tempPath() ); // tempDir.replace( '/', '\\' ); QTemporaryFile tempFile( "MayaTemp" ); if ( tempFile.open() ) { QString tempFileName = QString( "%1%2" ).arg( tempDir ).arg( tempFile.fileName() ); qint64 fileSize = device()->size(); char * fileBuffer = new char [ fileSize ]; qint64 sizeRead = device()->read( fileBuffer, fileSize ); qint64 sizeWrite = tempFile.write( fileBuffer, sizeRead ); tempFile.flush(); tempFile.close(); if ( sizeWrite == sizeRead ) { QImage img = m_pMayaRenderer->RenderImage( tempDir, tempFileName ); if ( !img.isNull() ) { bSuccess = true; *image = img; } } } return bSuccess; } QByteArray QtMayaHandler::name() const { return "ma"; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 7260 | Scott Murray |
Maya plugin for generating thumbnails and previews. For use with the P4V client or P4Thumb. Included is the source, project and compiled dll along with a configuration file so you can customize your rendering preferences :-) |