#include <qimage.h> #include <qfile.h> #include <qbuffer.h> #include "qttgaimageformat.h" // packing makes it easy to read the data directly into our structures #if defined Q_OS_WIN32 #pragma pack( push ) #pragma pack( 1 ) #define TGAFORMAT_PACKED #elif defined Q_CC_GNU #define TGAFORMAT_PACKED __attribute__((packed)) #else #define TGAFORMAT_PACKED #endif typedef struct { Q_UINT8 idLength; Q_UINT8 colorMapType; Q_UINT8 imageType; // color map specification Q_UINT16 firstEntryIndex; Q_UINT16 colorMapLength; Q_UINT8 colorMapEntrySize; // image specification Q_UINT16 xOrigin; Q_UINT16 yOrigin; Q_UINT16 width; Q_UINT16 height; Q_UINT8 depth; Q_UINT8 descriptor; } TGAFORMAT_PACKED TGAHEADER; typedef struct { Q_UINT32 extAreaOffset; Q_UINT32 devDirOffset; Q_UINT8 signature[16]; Q_UINT8 resChar; Q_UINT8 zeroStr; } TGAFORMAT_PACKED TGAFOOTER; class TGAReader { public: TGAReader(QIODevice* iodevice) : iod( iodevice ), newFormat( false), alphaValue( 0 ), flipLeftToRight( FALSE ), flipTopToBottom( FALSE ) {}; QImage GetImage(); enum imageType{ UNKNOWN, GREYSCALE, COLOR_MAP, COLOR, GREYSCALE_RLE, COLOR_RLE, COLOR_MAP_RLE }; private: // reads the TGA header and footer bool ReadFooter(); bool ReadHeader(); QImage Read24BitImage(); QImage Read32BitImage(); QIODevice* iod; TGAFOOTER ftr; TGAHEADER hdr; imageType type; int alphaValue; // is the file the new format with developer customizable areas? bool newFormat; // flip image horizontally and/or vertically bool flipTopToBottom; bool flipLeftToRight; }; bool TGAReader::ReadFooter() { if( !iod ) return 0; else { int s = iod->size() - 26; iod->at( s ); if( iod->readBlock((char*)&ftr, sizeof(TGAFOOTER)) == sizeof(TGAFOOTER) ) { if( strcmp( (const char*)ftr.signature, "TRUEVISION-XFILE" ) == 0 ) newFormat = true; else newFormat = false; return 1; } else return 0; } } bool TGAReader::ReadHeader() { if( !iod ) return 0; else { int s = 0; iod->at( s ); if( iod->readBlock((char*)&hdr, sizeof(TGAHEADER)) == sizeof(TGAHEADER) ) return 1; else return 0; } } QImage TGAReader::GetImage() { QImage img; img.reset(); // First, read the footer to see if this is a new TGA file. // We don't care right now, but someday we might. if( !ReadFooter() ) return img; // Get the vitals on this file from the header if( !ReadHeader() ) return img; // Validate header information. First check to make sure the color depth is reasonable if( !( (hdr.depth == 32) || (hdr.depth == 24) ) ) return img; // Second, check to make sure we support the image type. // As long as there is no color map we'll read it. 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 by some chance a type hasn't been set at this point, bail if( type == UNKNOWN ) return img; // Third, make sure the alpha channel descriptor is reasonable Q_UINT8 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 int o = iod->at() + hdr.idLength; iod->at( 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; img.create( hdr.width, hdr.height, 32 ); int h = hdr.height; uchar* buf = new uchar[hdr.width*3]; while (0 < --h) { if (iod->readBlock((char *)buf, hdr.width*3) != hdr.width*3) { img.reset(); 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.mirror( flipLeftToRight, flipTopToBottom ); delete[] buf; return img; } QImage TGAReader::Read32BitImage() { QImage img; img.create( hdr.width, hdr.height, 32 ); int h = hdr.height; int bpl = img.bytesPerLine(); uchar **line = img.jumpTable(); while (0 < --h) { if (iod->readBlock((char *)line[h], bpl) != bpl) { img.reset(); break; } } img = img.mirror( flipLeftToRight, flipTopToBottom ); return img; } void readTGA( QImageIO* qio ) { qio->setStatus(1); TGAReader reader(qio->ioDevice()); QImage img = reader.GetImage(); if( !img.isNull() ) { qio->setImage(img); qio->setStatus(0); } } void QtTGAImageFormat::installIOHandler() { // QT can only determine image types by looking at the first 16 bytes. The horrible // regex below is attempt to catch TGA files QImageIO::defineIOHandler("TGA", "^\01\01\01|\02|\03|\011|\012|\013\01\01\01\01\01", 0, readTGA, NULL); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 4860 | Matt Attaway |
Adding information of Qt image plugins. This change includes sample source code, a list of useful links, and a compiled version of the TGA plugin for use with the r05.1 beta. |